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);
1669 #ifdef DEBUG_SMB_REFCOUNT
1670 smb_fid_t *smb_FindFIDByScacheDbg(smb_vc_t *vcp, cm_scache_t * scp, char *file, long line)
1672 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1675 smb_fid_t *fidp = NULL;
1681 lock_ObtainWrite(&smb_rctLock);
1682 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1683 if (scp == fidp->scp) {
1684 lock_ObtainMutex(&fidp->mx);
1685 if (scp == fidp->scp) {
1687 lock_ReleaseMutex(&fidp->mx);
1690 lock_ReleaseMutex(&fidp->mx);
1693 #ifdef DEBUG_SMB_REFCOUNT
1695 afsi_log("%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1696 osi_Log4(smb_logp,"%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1699 lock_ReleaseWrite(&smb_rctLock);
1703 #ifdef DEBUG_SMB_REFCOUNT
1704 void smb_HoldFIDNoLockDbg(smb_fid_t *fidp, char *file, long line)
1706 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1709 lock_AssertWrite(&smb_rctLock);
1711 #ifdef DEBUG_SMB_REFCOUNT
1712 afsi_log("%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1713 osi_Log4(smb_logp,"%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1718 /* smb_ReleaseFID cannot be called while an cm_scache_t mutex lock is held */
1719 /* the sm_fid_t->mx and smb_rctLock must not be held */
1720 #ifdef DEBUG_SMB_REFCOUNT
1721 void smb_ReleaseFIDDbg(smb_fid_t *fidp, char *file, long line)
1723 void smb_ReleaseFID(smb_fid_t *fidp)
1726 cm_scache_t *scp = NULL;
1727 cm_user_t *userp = NULL;
1728 smb_vc_t *vcp = NULL;
1729 smb_ioctl_t *ioctlp;
1731 lock_ObtainMutex(&fidp->mx);
1732 lock_ObtainWrite(&smb_rctLock);
1733 osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
1734 #ifdef DEBUG_SMB_REFCOUNT
1735 afsi_log("%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1736 osi_Log5(smb_logp,"%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1738 if (fidp->refCount == 0) {
1739 if (fidp->deleteOk) {
1742 scp = fidp->scp; /* release after lock is released */
1744 lock_ObtainWrite(&scp->rw);
1745 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1746 lock_ReleaseWrite(&scp->rw);
1747 osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1750 userp = fidp->userp;
1754 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1755 thrd_CloseHandle(fidp->raw_write_event);
1757 /* and see if there is ioctl stuff to free */
1758 ioctlp = fidp->ioctlp;
1761 cm_FreeSpace(ioctlp->prefix);
1762 if (ioctlp->ioctl.inAllocp)
1763 free(ioctlp->ioctl.inAllocp);
1764 if (ioctlp->ioctl.outAllocp)
1765 free(ioctlp->ioctl.outAllocp);
1768 lock_ReleaseMutex(&fidp->mx);
1769 lock_FinalizeMutex(&fidp->mx);
1774 smb_ReleaseVCNoLock(vcp);
1778 lock_ReleaseMutex(&fidp->mx);
1780 lock_ReleaseWrite(&smb_rctLock);
1782 /* now release the scache structure */
1784 cm_ReleaseSCache(scp);
1787 cm_ReleaseUser(userp);
1791 * Case-insensitive search for one string in another;
1792 * used to find variable names in submount pathnames.
1794 static clientchar_t *smb_stristr(clientchar_t *str1, clientchar_t *str2)
1796 clientchar_t *cursor;
1798 for (cursor = str1; *cursor; cursor++)
1799 if (cm_ClientStrCmpI(cursor, str2) == 0)
1806 * Substitute a variable value for its name in a submount pathname. Variable
1807 * name has been identified by smb_stristr() and is in substr. Variable name
1808 * length (plus one) is in substr_size. Variable value is in newstr.
1810 static void smb_subst(clientchar_t *str1, int cchstr1, clientchar_t *substr,
1811 unsigned int substr_size, clientchar_t *newstr)
1813 clientchar_t temp[1024];
1815 cm_ClientStrCpy(temp, lengthof(temp), substr + substr_size - 1);
1816 cm_ClientStrCpy(substr, cchstr1 - (substr - str1), newstr);
1817 cm_ClientStrCat(str1, cchstr1, temp);
1820 clientchar_t VNUserName[] = _C("%USERNAME%");
1821 clientchar_t VNLCUserName[] = _C("%LCUSERNAME%");
1822 clientchar_t VNComputerName[] = _C("%COMPUTERNAME%");
1823 clientchar_t VNLCComputerName[] = _C("%LCCOMPUTERNAME%");
1825 typedef struct smb_findShare_rock {
1826 clientchar_t * shareName;
1827 clientchar_t * match;
1829 } smb_findShare_rock_t;
1831 #define SMB_FINDSHARE_EXACT_MATCH 1
1832 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1834 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1838 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1839 normchar_t normName[MAX_PATH];
1841 if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(normName[0])) == 0) {
1842 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
1843 osi_LogSaveString(smb_logp, dep->name));
1847 if (!cm_ClientStrCmpNI(normName, vrock->shareName, 12)) {
1848 if(!cm_ClientStrCmpI(normName, vrock->shareName))
1849 matchType = SMB_FINDSHARE_EXACT_MATCH;
1851 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1854 vrock->match = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
1855 vrock->matchType = matchType;
1857 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1858 return CM_ERROR_STOPNOW;
1864 /* find a shareName in the table of submounts */
1865 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp,
1866 clientchar_t *shareName,
1867 clientchar_t **pathNamep)
1871 clientchar_t pathName[1024];
1874 clientchar_t *p, *q;
1875 fschar_t *cellname = NULL;
1878 DWORD allSubmount = 1;
1880 /* if allSubmounts == 0, only return the //mountRoot/all share
1881 * if in fact it has been been created in the subMounts table.
1882 * This is to allow sites that want to restrict access to the
1885 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1886 0, KEY_QUERY_VALUE, &parmKey);
1887 if (code == ERROR_SUCCESS) {
1888 cblen = sizeof(allSubmount);
1889 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1890 (BYTE *) &allSubmount, &cblen);
1891 if (code != ERROR_SUCCESS) {
1894 RegCloseKey (parmKey);
1897 if (allSubmount && cm_ClientStrCmpI(shareName, _C("all")) == 0) {
1902 /* In case, the all share is disabled we need to still be able
1903 * to handle ioctl requests
1905 if (cm_ClientStrCmpI(shareName, _C("ioctl$")) == 0) {
1906 *pathNamep = cm_ClientStrDup(_C("/.__ioctl__"));
1910 if (cm_ClientStrCmpIA(shareName, _C("IPC$")) == 0 ||
1911 cm_ClientStrCmpIA(shareName, _C("srvsvc")) == 0 ||
1912 cm_ClientStrCmpIA(shareName, _C("wkssvc")) == 0 ||
1913 cm_ClientStrCmpIA(shareName, _C(SMB_IOCTL_FILENAME_NOSLASH)) == 0 ||
1914 cm_ClientStrCmpIA(shareName, _C("DESKTOP.INI")) == 0
1920 /* Check for volume references
1922 * They look like <cell>{%,#}<volume>
1924 if (cm_ClientStrChr(shareName, '%') != NULL ||
1925 cm_ClientStrChr(shareName, '#') != NULL) {
1926 clientchar_t pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
1927 /* make room for '/@vol:' + mountchar + NULL terminator*/
1929 osi_Log1(smb_logp, "smb_FindShare found volume reference [%S]",
1930 osi_LogSaveClientString(smb_logp, shareName));
1932 cm_ClientStrPrintfN(pathstr, lengthof(pathstr),
1933 _C("/") _C(CM_PREFIX_VOL) _C("%s"), shareName);
1934 cchlen = (DWORD)(cm_ClientStrLen(pathstr) + 1);
1936 *pathNamep = malloc(cchlen * sizeof(clientchar_t));
1938 cm_ClientStrCpy(*pathNamep, cchlen, pathstr);
1939 cm_ClientStrLwr(*pathNamep);
1940 osi_Log1(smb_logp, " returning pathname [%S]",
1941 osi_LogSaveClientString(smb_logp, *pathNamep));
1949 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1950 0, KEY_QUERY_VALUE, &parmKey);
1951 if (code == ERROR_SUCCESS) {
1952 cblen = sizeof(pathName);
1953 code = RegQueryValueExW(parmKey, shareName, NULL, NULL,
1954 (BYTE *) pathName, &cblen);
1955 if (code != ERROR_SUCCESS)
1957 RegCloseKey (parmKey);
1961 cchlen = cblen / sizeof(clientchar_t);
1962 if (cchlen != 0 && cchlen != lengthof(pathName) - 1) {
1963 /* We can accept either unix or PC style AFS pathnames. Convert
1964 * Unix-style to PC style here for internal use.
1967 cchlen = lengthof(pathName);
1969 /* within this code block, we maintain, cchlen = writeable
1970 buffer length of p */
1972 if (cm_ClientStrCmpN(p, cm_mountRootC, cm_mountRootCLen) == 0) {
1973 p += cm_mountRootCLen; /* skip mount path */
1974 cchlen -= (DWORD)(p - pathName);
1979 if (*q == _C('/')) *q = _C('\\'); /* change to \ */
1985 clientchar_t temp[1024];
1987 if (var = smb_stristr(p, VNUserName)) {
1988 if (uidp && uidp->unp)
1989 smb_subst(p, cchlen, var, lengthof(VNUserName),uidp->unp->name);
1991 smb_subst(p, cchlen, var, lengthof(VNUserName), _C(" "));
1993 else if (var = smb_stristr(p, VNLCUserName))
1995 if (uidp && uidp->unp)
1996 cm_ClientStrCpy(temp, lengthof(temp), uidp->unp->name);
1998 cm_ClientStrCpy(temp, lengthof(temp), _C(" "));
1999 cm_ClientStrLwr(temp);
2000 smb_subst(p, cchlen, var, lengthof(VNLCUserName), temp);
2002 else if (var = smb_stristr(p, VNComputerName))
2004 sizeTemp = lengthof(temp);
2005 GetComputerNameW(temp, &sizeTemp);
2006 smb_subst(p, cchlen, var, lengthof(VNComputerName), temp);
2008 else if (var = smb_stristr(p, VNLCComputerName))
2010 sizeTemp = lengthof(temp);
2011 GetComputerName((LPTSTR)temp, &sizeTemp);
2012 cm_ClientStrLwr(temp);
2013 smb_subst(p, cchlen, var, lengthof(VNLCComputerName), temp);
2018 *pathNamep = cm_ClientStrDup(p);
2023 /* First lookup shareName in root.afs */
2025 smb_findShare_rock_t vrock;
2027 fschar_t ftemp[1024];
2028 clientchar_t * p = shareName;
2031 /* attempt to locate a partial match in root.afs. This is because
2032 when using the ANSI RAP calls, the share name is limited to 13 chars
2033 and hence is truncated. Of course we prefer exact matches. */
2035 thyper.HighPart = 0;
2038 vrock.shareName = cm_ClientStringToNormStringAlloc(shareName, -1, NULL);
2039 if (vrock.shareName == NULL)
2042 vrock.matchType = 0;
2044 cm_HoldSCache(cm_data.rootSCachep);
2045 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
2046 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
2047 cm_ReleaseSCache(cm_data.rootSCachep);
2049 free(vrock.shareName);
2050 vrock.shareName = NULL;
2052 if (vrock.matchType) {
2053 cm_ClientStrPrintfN(pathName, lengthof(pathName), _C("/%s/"), vrock.match);
2054 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
2059 /* if we get here, there was no match for the share in root.afs */
2060 /* so try to create \\<netbiosName>\<cellname> */
2065 /* Get the full name for this cell */
2066 cellname = cm_ClientStringToFsStringAlloc(p, -1, NULL);
2067 code = cm_SearchCellFile(cellname, ftemp, 0, 0);
2068 #ifdef AFS_AFSDB_ENV
2069 if (code && cm_dnsEnabled) {
2071 code = cm_SearchCellByDNS(cellname, ftemp, &ttl, 0, 0);
2077 /* construct the path */
2079 clientchar_t temp[1024];
2081 if (cm_FsStringToClientString(ftemp, -1, temp, 1024) != 0) {
2082 cm_ClientStrPrintfN(pathName, (int)lengthof(pathName),
2083 rw ? _C("/.%S/") : _C("/%S/"), temp);
2084 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
2094 /* Client-side offline caching policy types */
2095 #define CSC_POLICY_MANUAL 0
2096 #define CSC_POLICY_DOCUMENTS 1
2097 #define CSC_POLICY_PROGRAMS 2
2098 #define CSC_POLICY_DISABLE 3
2100 int smb_FindShareCSCPolicy(clientchar_t *shareName)
2103 clientchar_t policy[1024];
2106 int retval = CSC_POLICY_MANUAL;
2108 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
2109 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
2112 REG_OPTION_NON_VOLATILE,
2118 len = sizeof(policy);
2119 if ( RegQueryValueExW( hkCSCPolicy, shareName, 0, &dwType, (LPBYTE) policy, &len ) ||
2121 retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
2123 else if (cm_ClientStrCmpIA(policy, _C("documents")) == 0)
2125 retval = CSC_POLICY_DOCUMENTS;
2127 else if (cm_ClientStrCmpIA(policy, _C("programs")) == 0)
2129 retval = CSC_POLICY_PROGRAMS;
2131 else if (cm_ClientStrCmpIA(policy, _C("disable")) == 0)
2133 retval = CSC_POLICY_DISABLE;
2136 RegCloseKey(hkCSCPolicy);
2140 /* find a dir search structure by cookie value, and return it held.
2141 * Must be called with smb_globalLock held.
2143 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
2145 smb_dirSearch_t *dsp;
2147 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2148 if (dsp->cookie == cookie) {
2149 if (dsp != smb_firstDirSearchp) {
2150 /* move to head of LRU queue, too, if we're not already there */
2151 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
2152 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2153 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2154 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2155 if (!smb_lastDirSearchp)
2156 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2164 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
2165 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2166 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
2172 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
2174 lock_ObtainMutex(&dsp->mx);
2175 osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p",
2176 dsp->cookie, dsp, dsp->scp);
2177 dsp->flags |= SMB_DIRSEARCH_DELETE;
2178 if (dsp->scp != NULL) {
2179 lock_ObtainWrite(&dsp->scp->rw);
2180 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
2181 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2182 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2183 dsp->scp->bulkStatProgress = hzero;
2185 lock_ReleaseWrite(&dsp->scp->rw);
2187 lock_ReleaseMutex(&dsp->mx);
2190 /* Must be called with the smb_globalLock held */
2191 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
2193 cm_scache_t *scp = NULL;
2195 osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
2196 if (dsp->refCount == 0) {
2197 lock_ObtainMutex(&dsp->mx);
2198 if (dsp->flags & SMB_DIRSEARCH_DELETE) {
2199 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
2200 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
2201 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2202 lock_ReleaseMutex(&dsp->mx);
2203 lock_FinalizeMutex(&dsp->mx);
2205 osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p",
2206 dsp->cookie, dsp, scp);
2209 lock_ReleaseMutex(&dsp->mx);
2212 /* do this now to avoid spurious locking hierarchy creation */
2214 cm_ReleaseSCache(scp);
2217 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
2219 lock_ObtainWrite(&smb_globalLock);
2220 smb_ReleaseDirSearchNoLock(dsp);
2221 lock_ReleaseWrite(&smb_globalLock);
2224 /* find a dir search structure by cookie value, and return it held */
2225 smb_dirSearch_t *smb_FindDirSearch(long cookie)
2227 smb_dirSearch_t *dsp;
2229 lock_ObtainWrite(&smb_globalLock);
2230 dsp = smb_FindDirSearchNoLock(cookie);
2231 lock_ReleaseWrite(&smb_globalLock);
2235 /* GC some dir search entries, in the address space expected by the specific protocol.
2236 * Must be called with smb_globalLock held; release the lock temporarily.
2238 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
2239 void smb_GCDirSearches(int isV3)
2241 smb_dirSearch_t *prevp;
2242 smb_dirSearch_t *dsp;
2243 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
2247 victimCount = 0; /* how many have we got so far */
2248 for (dsp = smb_lastDirSearchp; dsp; dsp=prevp) {
2249 /* we'll move tp from queue, so
2252 prevp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2253 /* if no one is using this guy, and we're either in the new protocol,
2254 * or we're in the old one and this is a small enough ID to be useful
2255 * to the old protocol, GC this guy.
2257 if (dsp->refCount == 0 && (isV3 || dsp->cookie <= 255)) {
2258 /* hold and delete */
2259 lock_ObtainMutex(&dsp->mx);
2260 dsp->flags |= SMB_DIRSEARCH_DELETE;
2261 lock_ReleaseMutex(&dsp->mx);
2262 victimsp[victimCount++] = dsp;
2266 /* don't do more than this */
2267 if (victimCount >= SMB_DIRSEARCH_GCMAX)
2271 /* now release them */
2272 for (i = 0; i < victimCount; i++) {
2273 smb_ReleaseDirSearchNoLock(victimsp[i]);
2277 /* function for allocating a dir search entry. We need these to remember enough context
2278 * since we don't get passed the path from call to call during a directory search.
2280 * Returns a held dir search structure, and bumps the reference count on the vnode,
2281 * since it saves a pointer to the vnode.
2283 smb_dirSearch_t *smb_NewDirSearch(int isV3)
2285 smb_dirSearch_t *dsp;
2291 lock_ObtainWrite(&smb_globalLock);
2294 /* what's the biggest ID allowed in this version of the protocol */
2295 /* TODO: do we really want a non v3 dir search request to wrap
2296 smb_dirSearchCounter? */
2297 maxAllowed = isV3 ? 65535 : 255;
2298 if (smb_dirSearchCounter > maxAllowed)
2299 smb_dirSearchCounter = 1;
2301 start = smb_dirSearchCounter;
2304 /* twice so we have enough tries to find guys we GC after one pass;
2305 * 10 extra is just in case I mis-counted.
2307 if (++counter > 2*maxAllowed+10)
2308 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2310 if (smb_dirSearchCounter > maxAllowed) {
2311 smb_dirSearchCounter = 1;
2313 if (smb_dirSearchCounter == start) {
2315 smb_GCDirSearches(isV3);
2318 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2320 /* don't need to watch for refcount zero and deleted, since
2321 * we haven't dropped the global lock.
2324 ++smb_dirSearchCounter;
2328 dsp = malloc(sizeof(*dsp));
2329 memset(dsp, 0, sizeof(*dsp));
2330 dsp->cookie = smb_dirSearchCounter;
2331 ++smb_dirSearchCounter;
2333 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t", LOCK_HIERARCHY_SMB_DIRSEARCH);
2334 dsp->lastTime = osi_Time();
2335 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2336 if (!smb_lastDirSearchp)
2337 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2339 osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p",
2343 lock_ReleaseWrite(&smb_globalLock);
2347 static smb_packet_t *smb_GetPacket(void)
2351 lock_ObtainWrite(&smb_globalLock);
2352 tbp = smb_packetFreeListp;
2354 smb_packetFreeListp = tbp->nextp;
2355 lock_ReleaseWrite(&smb_globalLock);
2357 tbp = calloc(sizeof(*tbp),1);
2358 tbp->magic = SMB_PACKETMAGIC;
2361 tbp->resumeCode = 0;
2367 tbp->ncb_length = 0;
2370 tbp->stringsp = NULL;
2372 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2377 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2380 tbp = smb_GetPacket();
2381 memcpy(tbp, pkt, sizeof(smb_packet_t));
2382 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2383 tbp->stringsp = NULL;
2385 smb_HoldVC(tbp->vcp);
2389 static NCB *smb_GetNCB(void)
2394 lock_ObtainWrite(&smb_globalLock);
2395 tbp = smb_ncbFreeListp;
2397 smb_ncbFreeListp = tbp->nextp;
2398 lock_ReleaseWrite(&smb_globalLock);
2400 tbp = calloc(sizeof(*tbp),1);
2401 tbp->magic = SMB_NCBMAGIC;
2404 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2406 memset(&tbp->ncb, 0, sizeof(NCB));
2411 static void FreeSMBStrings(smb_packet_t * pkt)
2416 for (s = pkt->stringsp; s; s = ns) {
2420 pkt->stringsp = NULL;
2423 void smb_FreePacket(smb_packet_t *tbp)
2425 smb_vc_t * vcp = NULL;
2426 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2428 lock_ObtainWrite(&smb_globalLock);
2429 tbp->nextp = smb_packetFreeListp;
2430 smb_packetFreeListp = tbp;
2431 tbp->magic = SMB_PACKETMAGIC;
2435 tbp->resumeCode = 0;
2441 tbp->ncb_length = 0;
2443 FreeSMBStrings(tbp);
2444 lock_ReleaseWrite(&smb_globalLock);
2450 static void smb_FreeNCB(NCB *bufferp)
2454 tbp = (smb_ncb_t *) bufferp;
2455 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2457 lock_ObtainWrite(&smb_globalLock);
2458 tbp->nextp = smb_ncbFreeListp;
2459 smb_ncbFreeListp = tbp;
2460 lock_ReleaseWrite(&smb_globalLock);
2463 /* get a ptr to the data part of a packet, and its count */
2464 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2468 unsigned char *afterParmsp;
2470 parmBytes = *smbp->wctp << 1;
2471 afterParmsp = smbp->wctp + parmBytes + 1;
2473 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2474 if (nbytesp) *nbytesp = dataBytes;
2476 /* don't forget to skip the data byte count, since it follows
2477 * the parameters; that's where the "2" comes from below.
2479 return (unsigned char *) (afterParmsp + 2);
2482 /* must set all the returned parameters before playing around with the
2483 * data region, since the data region is located past the end of the
2484 * variable number of parameters.
2486 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2488 unsigned char *afterParmsp;
2490 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2492 *afterParmsp++ = dsize & 0xff;
2493 *afterParmsp = (dsize>>8) & 0xff;
2496 /* return the parm'th parameter in the smbp packet */
2497 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2500 unsigned char *parmDatap;
2502 parmCount = *smbp->wctp;
2504 if (parm >= parmCount) {
2507 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2508 parm, parmCount, smbp->ncb_length);
2509 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2510 parm, parmCount, smbp->ncb_length);
2511 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2512 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2513 osi_panic(s, __FILE__, __LINE__);
2515 parmDatap = smbp->wctp + (2*parm) + 1;
2517 return parmDatap[0] + (parmDatap[1] << 8);
2520 /* return the parm'th parameter in the smbp packet */
2521 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2524 unsigned char *parmDatap;
2526 parmCount = *smbp->wctp;
2528 if (parm >= parmCount) {
2531 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2532 parm, parmCount, smbp->ncb_length);
2533 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2534 parm, parmCount, smbp->ncb_length);
2535 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2536 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2537 osi_panic(s, __FILE__, __LINE__);
2539 parmDatap = smbp->wctp + (2*parm) + 1;
2541 return parmDatap[0];
2544 /* return the parm'th parameter in the smbp packet */
2545 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2548 unsigned char *parmDatap;
2550 parmCount = *smbp->wctp;
2552 if (parm + 1 >= parmCount) {
2555 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2556 parm, parmCount, smbp->ncb_length);
2557 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2558 parm, parmCount, smbp->ncb_length);
2559 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2560 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2561 osi_panic(s, __FILE__, __LINE__);
2563 parmDatap = smbp->wctp + (2*parm) + 1;
2565 return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2568 /* return the parm'th parameter in the smbp packet */
2569 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2572 unsigned char *parmDatap;
2574 parmCount = *smbp->wctp;
2576 if (parm * 2 + offset >= parmCount * 2) {
2579 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2580 parm, offset, parmCount, smbp->ncb_length);
2581 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2582 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2583 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2584 parm, offset, parmCount, smbp->ncb_length);
2585 osi_panic(s, __FILE__, __LINE__);
2587 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2589 return parmDatap[0] + (parmDatap[1] << 8);
2592 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2594 unsigned char *parmDatap;
2596 /* make sure we have enough slots */
2597 if (*smbp->wctp <= slot)
2598 *smbp->wctp = slot+1;
2600 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2601 *parmDatap++ = parmValue & 0xff;
2602 *parmDatap = (parmValue>>8) & 0xff;
2605 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2607 unsigned char *parmDatap;
2609 /* make sure we have enough slots */
2610 if (*smbp->wctp <= slot)
2611 *smbp->wctp = slot+2;
2613 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2614 *parmDatap++ = parmValue & 0xff;
2615 *parmDatap++ = (parmValue>>8) & 0xff;
2616 *parmDatap++ = (parmValue>>16) & 0xff;
2617 *parmDatap = (parmValue>>24) & 0xff;
2620 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2622 unsigned char *parmDatap;
2625 /* make sure we have enough slots */
2626 if (*smbp->wctp <= slot)
2627 *smbp->wctp = slot+4;
2629 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2631 *parmDatap++ = *parmValuep++;
2634 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2636 unsigned char *parmDatap;
2638 /* make sure we have enough slots */
2639 if (*smbp->wctp <= slot) {
2640 if (smbp->oddByte) {
2642 *smbp->wctp = slot+1;
2647 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2648 *parmDatap++ = parmValue & 0xff;
2653 void smb_StripLastComponent(clientchar_t *outPathp, clientchar_t **lastComponentp,
2654 clientchar_t *inPathp)
2656 clientchar_t *lastSlashp;
2658 lastSlashp = cm_ClientStrRChr(inPathp, '\\');
2660 *lastComponentp = lastSlashp;
2663 if (inPathp == lastSlashp)
2665 *outPathp++ = *inPathp++;
2674 clientchar_t *smb_ParseASCIIBlock(smb_packet_t * pktp, unsigned char *inp,
2675 char **chainpp, int flags)
2678 afs_uint32 type = *inp++;
2681 * The first byte specifies the type of the input string.
2682 * CIFS TR 1.0 3.2.10. This function only parses null terminated
2686 /* Length Counted */
2687 case 0x1: /* Data Block */
2688 case 0x5: /* Variable Block */
2689 cb = *inp++ << 16 | *inp++;
2692 /* Null-terminated string */
2693 case 0x4: /* ASCII */
2694 case 0x3: /* Pathname */
2695 case 0x2: /* Dialect */
2696 cb = sizeof(pktp->data) - (inp - pktp->data);
2697 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2698 #ifdef DEBUG_UNICODE
2701 cb = sizeof(pktp->data);
2706 return NULL; /* invalid input */
2710 if (type == 0x2 /* Dialect */ || !WANTS_UNICODE(pktp))
2711 flags |= SMB_STRF_FORCEASCII;
2714 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2717 clientchar_t *smb_ParseString(smb_packet_t * pktp, unsigned char * inp,
2718 char ** chainpp, int flags)
2723 if (!WANTS_UNICODE(pktp))
2724 flags |= SMB_STRF_FORCEASCII;
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);
2734 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp,
2735 flags | SMB_STRF_SRCNULTERM);
2738 clientchar_t *smb_ParseStringCb(smb_packet_t * pktp, unsigned char * inp,
2739 size_t cb, char ** chainpp, int flags)
2742 if (!WANTS_UNICODE(pktp))
2743 flags |= SMB_STRF_FORCEASCII;
2746 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2749 clientchar_t *smb_ParseStringCch(smb_packet_t * pktp, unsigned char * inp,
2750 size_t cch, char ** chainpp, int flags)
2755 if (!WANTS_UNICODE(pktp))
2756 flags |= SMB_STRF_FORCEASCII;
2758 cb = cch * sizeof(wchar_t);
2761 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2765 smb_ParseStringBuf(const unsigned char * bufbase,
2766 cm_space_t ** stringspp,
2767 unsigned char *inp, size_t *pcb_max,
2768 char **chainpp, int flags)
2771 if (!(flags & SMB_STRF_FORCEASCII)) {
2773 cm_space_t * spacep;
2776 if (bufbase && ((inp - bufbase) % 2) != 0) {
2777 inp++; /* unicode strings are always word aligned */
2781 if (FAILED(StringCchLengthW((const wchar_t *) inp, *pcb_max / sizeof(wchar_t),
2783 cch_src = *pcb_max / sizeof(wchar_t);
2787 *pcb_max -= (cch_src + 1) * sizeof(wchar_t);
2794 spacep = cm_GetSpace();
2795 spacep->nextp = *stringspp;
2796 *stringspp = spacep;
2800 *chainpp = inp + sizeof(wchar_t);
2803 *(spacep->wdata) = 0;
2804 return spacep->wdata;
2807 StringCchCopyNW(spacep->wdata,
2808 lengthof(spacep->wdata),
2809 (const clientchar_t *) inp, cch_src);
2812 *chainpp = inp + (cch_src + null_terms)*sizeof(wchar_t);
2814 return spacep->wdata;
2818 cm_space_t * spacep;
2821 /* Not using Unicode */
2823 *chainpp = inp + strlen(inp) + 1;
2826 spacep = cm_GetSpace();
2827 spacep->nextp = *stringspp;
2828 *stringspp = spacep;
2830 cchdest = lengthof(spacep->wdata);
2831 cm_Utf8ToUtf16(inp, (int)((flags & SMB_STRF_SRCNULTERM)? -1 : *pcb_max),
2832 spacep->wdata, cchdest);
2834 return spacep->wdata;
2840 unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
2842 size_t * plen, int flags)
2848 /* we are only calculating the required size */
2855 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2857 StringCbLengthW(str, SMB_STRINGBUFSIZE * sizeof(wchar_t), plen);
2858 if (!(flags & SMB_STRF_IGNORENUL))
2859 *plen += sizeof(wchar_t);
2861 return (unsigned char *) 1; /* return TRUE if we are using unicode */
2871 cch_str = cm_ClientStrLen(str);
2872 cch_dest = cm_ClientStringToUtf8(str, (int)cch_str, NULL, 0);
2875 *plen = ((flags & SMB_STRF_IGNORENUL)? cch_dest: cch_dest+1);
2883 /* if outp != NULL ... */
2885 /* Number of bytes left in the buffer.
2887 If outp lies inside the packet data buffer, we assume that the
2888 buffer is the packet data buffer. Otherwise we assume that the
2889 buffer is sizeof(packet->data).
2892 if (outp >= pktp->data && outp < pktp->data + sizeof(pktp->data)) {
2893 align = (int)((outp - pktp->data) % 2);
2894 buffersize = (pktp->data + sizeof(pktp->data)) - ((char *) outp);
2896 align = (int)(((size_t) outp) % 2);
2897 buffersize = (int)sizeof(pktp->data);
2902 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2908 if (*str == _C('\0')) {
2910 if (buffersize < sizeof(wchar_t))
2913 *((wchar_t *) outp) = L'\0';
2914 if (plen && !(flags & SMB_STRF_IGNORENUL))
2915 *plen += sizeof(wchar_t);
2916 return outp + sizeof(wchar_t);
2919 nchars = cm_ClientStringToUtf16(str, -1, (wchar_t *) outp, (int)(buffersize / sizeof(wchar_t)));
2921 osi_Log2(smb_logp, "UnparseString: Can't convert string to Unicode [%S], GLE=%d",
2922 osi_LogSaveClientString(smb_logp, str),
2928 *plen += sizeof(wchar_t) * ((flags & SMB_STRF_IGNORENUL)? nchars - 1: nchars);
2930 return outp + sizeof(wchar_t) * nchars;
2938 cch_dest = cm_ClientStringToUtf8(str, -1, outp, (int)buffersize);
2941 *plen += ((flags & SMB_STRF_IGNORENUL)? cch_dest - 1: cch_dest);
2943 return outp + cch_dest;
2947 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2953 tlen = inp[0] + (inp[1]<<8);
2954 inp += 2; /* skip length field */
2957 *chainpp = inp + tlen;
2966 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2970 if (*inp++ != 0x1) return NULL;
2971 tlen = inp[0] + (inp[1]<<8);
2972 inp += 2; /* skip length field */
2975 *chainpp = inp + tlen;
2978 if (lengthp) *lengthp = tlen;
2983 /* format a packet as a response */
2984 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2989 outp = (smb_t *) op;
2991 /* zero the basic structure through the smb_wct field, and zero the data
2992 * size field, assuming that wct stays zero; otherwise, you have to
2993 * explicitly set the data size field, too.
2995 inSmbp = (smb_t *) inp;
2996 memset(outp, 0, sizeof(smb_t)+2);
3002 outp->com = inSmbp->com;
3003 outp->tid = inSmbp->tid;
3004 outp->pid = inSmbp->pid;
3005 outp->uid = inSmbp->uid;
3006 outp->mid = inSmbp->mid;
3007 outp->res[0] = inSmbp->res[0];
3008 outp->res[1] = inSmbp->res[1];
3009 op->inCom = inSmbp->com;
3011 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
3012 #ifdef SEND_CANONICAL_PATHNAMES
3013 outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
3015 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
3017 if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
3018 outp->flg2 |= SMB_FLAGS2_UNICODE;
3021 /* copy fields in generic packet area */
3022 op->wctp = &outp->wct;
3025 /* send a (probably response) packet; vcp tells us to whom to send it.
3026 * we compute the length by looking at wct and bcc fields.
3028 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
3038 ncbp = smb_GetNCB();
3042 memset((char *)ncbp, 0, sizeof(NCB));
3044 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
3045 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
3046 extra += tp[0] + (tp[1]<<8);
3047 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
3048 extra += 3; /* wct and length fields */
3050 ncbp->ncb_length = extra; /* bytes to send */
3051 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
3052 ncbp->ncb_lana_num = vcp->lana;
3053 ncbp->ncb_command = NCBSEND; /* op means send data */
3054 ncbp->ncb_buffer = (char *) inp;/* packet */
3055 code = Netbios(ncbp);
3058 const char * s = ncb_error_string(code);
3059 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
3060 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
3062 lock_ObtainMutex(&vcp->mx);
3063 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
3064 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
3066 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
3067 lock_ReleaseMutex(&vcp->mx);
3068 lock_ObtainWrite(&smb_globalLock);
3069 dead_sessions[vcp->session] = TRUE;
3070 lock_ReleaseWrite(&smb_globalLock);
3071 smb_CleanupDeadVC(vcp);
3073 lock_ReleaseMutex(&vcp->mx);
3081 void smb_MapNTError(long code, unsigned long *NTStatusp)
3083 unsigned long NTStatus;
3085 /* map CM_ERROR_* errors to NT 32-bit status codes */
3086 /* NT Status codes are listed in ntstatus.h not winerror.h */
3090 else if (code == CM_ERROR_NOSUCHCELL) {
3091 NTStatus = 0xC000000FL; /* No such file */
3093 else if (code == CM_ERROR_NOSUCHVOLUME) {
3094 NTStatus = 0xC000000FL; /* No such file */
3096 else if (code == CM_ERROR_TIMEDOUT) {
3098 NTStatus = 0xC00000CFL; /* Sharing Paused */
3100 NTStatus = 0x00000102L; /* Timeout */
3103 else if (code == CM_ERROR_RETRY) {
3104 NTStatus = 0xC000022DL; /* Retry */
3106 else if (code == CM_ERROR_NOACCESS) {
3107 NTStatus = 0xC0000022L; /* Access denied */
3109 else if (code == CM_ERROR_READONLY) {
3110 NTStatus = 0xC00000A2L; /* Write protected */
3112 else if (code == CM_ERROR_NOSUCHFILE ||
3113 code == CM_ERROR_BPLUS_NOMATCH) {
3114 NTStatus = 0xC000000FL; /* No such file */
3116 else if (code == CM_ERROR_NOSUCHPATH) {
3117 NTStatus = 0xC000003AL; /* Object path not found */
3119 else if (code == CM_ERROR_TOOBIG) {
3120 NTStatus = 0xC000007BL; /* Invalid image format */
3122 else if (code == CM_ERROR_INVAL) {
3123 NTStatus = 0xC000000DL; /* Invalid parameter */
3125 else if (code == CM_ERROR_BADFD) {
3126 NTStatus = 0xC0000008L; /* Invalid handle */
3128 else if (code == CM_ERROR_BADFDOP) {
3129 NTStatus = 0xC0000022L; /* Access denied */
3131 else if (code == CM_ERROR_EXISTS) {
3132 NTStatus = 0xC0000035L; /* Object name collision */
3134 else if (code == CM_ERROR_NOTEMPTY) {
3135 NTStatus = 0xC0000101L; /* Directory not empty */
3137 else if (code == CM_ERROR_CROSSDEVLINK) {
3138 NTStatus = 0xC00000D4L; /* Not same device */
3140 else if (code == CM_ERROR_NOTDIR) {
3141 NTStatus = 0xC0000103L; /* Not a directory */
3143 else if (code == CM_ERROR_ISDIR) {
3144 NTStatus = 0xC00000BAL; /* File is a directory */
3146 else if (code == CM_ERROR_BADOP) {
3148 /* I have no idea where this comes from */
3149 NTStatus = 0xC09820FFL; /* SMB no support */
3151 NTStatus = 0xC00000BBL; /* Not supported */
3152 #endif /* COMMENT */
3154 else if (code == CM_ERROR_BADSHARENAME) {
3155 NTStatus = 0xC00000CCL; /* Bad network name */
3157 else if (code == CM_ERROR_NOIPC) {
3159 NTStatus = 0xC0000022L; /* Access Denied */
3161 NTStatus = 0xC000013DL; /* Remote Resources */
3164 else if (code == CM_ERROR_CLOCKSKEW) {
3165 NTStatus = 0xC0000133L; /* Time difference at DC */
3167 else if (code == CM_ERROR_BADTID) {
3168 NTStatus = 0xC0982005L; /* SMB bad TID */
3170 else if (code == CM_ERROR_USESTD) {
3171 NTStatus = 0xC09820FBL; /* SMB use standard */
3173 else if (code == CM_ERROR_QUOTA) {
3174 NTStatus = 0xC0000044L; /* Quota exceeded */
3176 else if (code == CM_ERROR_SPACE) {
3177 NTStatus = 0xC000007FL; /* Disk full */
3179 else if (code == CM_ERROR_ATSYS) {
3180 NTStatus = 0xC0000033L; /* Object name invalid */
3182 else if (code == CM_ERROR_BADNTFILENAME) {
3183 NTStatus = 0xC0000033L; /* Object name invalid */
3185 else if (code == CM_ERROR_WOULDBLOCK) {
3186 NTStatus = 0xC00000D8L; /* Can't wait */
3188 else if (code == CM_ERROR_SHARING_VIOLATION) {
3189 NTStatus = 0xC0000043L; /* Sharing violation */
3191 else if (code == CM_ERROR_LOCK_CONFLICT) {
3192 NTStatus = 0xC0000054L; /* Lock conflict */
3194 else if (code == CM_ERROR_PARTIALWRITE) {
3195 NTStatus = 0xC000007FL; /* Disk full */
3197 else if (code == CM_ERROR_BUFFERTOOSMALL) {
3198 NTStatus = 0xC0000023L; /* Buffer too small */
3200 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3201 NTStatus = 0xC0000035L; /* Object name collision */
3203 else if (code == CM_ERROR_BADPASSWORD) {
3204 NTStatus = 0xC000006DL; /* unknown username or bad password */
3206 else if (code == CM_ERROR_BADLOGONTYPE) {
3207 NTStatus = 0xC000015BL; /* logon type not granted */
3209 else if (code == CM_ERROR_GSSCONTINUE) {
3210 NTStatus = 0xC0000016L; /* more processing required */
3212 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3214 NTStatus = 0xC0000280L; /* reparse point not resolved */
3216 NTStatus = 0xC0000022L; /* Access Denied */
3219 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3220 NTStatus = 0xC0000257L; /* Path Not Covered */
3222 else if (code == CM_ERROR_ALLBUSY) {
3223 NTStatus = 0xC000022DL; /* Retry */
3225 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3226 NTStatus = 0xC00000BEL; /* Bad Network Path */
3228 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3229 NTStatus = 0xC0000322L; /* No Kerberos key */
3231 else if (code == CM_ERROR_BAD_LEVEL) {
3232 NTStatus = 0xC0000148L; /* Invalid Level */
3234 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3235 NTStatus = 0xC000007EL; /* Range Not Locked */
3237 else if (code == CM_ERROR_NOSUCHDEVICE) {
3238 NTStatus = 0xC000000EL; /* No Such Device */
3240 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3241 NTStatus = 0xC0000055L; /* Lock Not Granted */
3242 } else if (code == ENOMEM) {
3243 NTStatus = 0xC0000017L; /* Out of Memory */
3245 NTStatus = 0xC0982001L; /* SMB non-specific error */
3248 *NTStatusp = NTStatus;
3249 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
3252 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
3253 unsigned char *classp)
3255 unsigned char class;
3256 unsigned short error;
3258 /* map CM_ERROR_* errors to SMB errors */
3259 if (code == CM_ERROR_NOSUCHCELL) {
3261 error = 3; /* bad path */
3263 else if (code == CM_ERROR_NOSUCHVOLUME) {
3265 error = 3; /* bad path */
3267 else if (code == CM_ERROR_TIMEDOUT) {
3269 error = 81; /* server is paused */
3271 else if (code == CM_ERROR_RETRY) {
3272 class = 2; /* shouldn't happen */
3275 else if (code == CM_ERROR_NOACCESS) {
3277 error = 4; /* bad access */
3279 else if (code == CM_ERROR_READONLY) {
3281 error = 19; /* read only */
3283 else if (code == CM_ERROR_NOSUCHFILE ||
3284 code == CM_ERROR_BPLUS_NOMATCH) {
3286 error = 2; /* ENOENT! */
3288 else if (code == CM_ERROR_NOSUCHPATH) {
3290 error = 3; /* Bad path */
3292 else if (code == CM_ERROR_TOOBIG) {
3294 error = 11; /* bad format */
3296 else if (code == CM_ERROR_INVAL) {
3297 class = 2; /* server non-specific error code */
3300 else if (code == CM_ERROR_BADFD) {
3302 error = 6; /* invalid file handle */
3304 else if (code == CM_ERROR_BADFDOP) {
3305 class = 1; /* invalid op on FD */
3308 else if (code == CM_ERROR_EXISTS) {
3310 error = 80; /* file already exists */
3312 else if (code == CM_ERROR_NOTEMPTY) {
3314 error = 5; /* delete directory not empty */
3316 else if (code == CM_ERROR_CROSSDEVLINK) {
3318 error = 17; /* EXDEV */
3320 else if (code == CM_ERROR_NOTDIR) {
3321 class = 1; /* bad path */
3324 else if (code == CM_ERROR_ISDIR) {
3325 class = 1; /* access denied; DOS doesn't have a good match */
3328 else if (code == CM_ERROR_BADOP) {
3332 else if (code == CM_ERROR_BADSHARENAME) {
3336 else if (code == CM_ERROR_NOIPC) {
3338 error = 4; /* bad access */
3340 else if (code == CM_ERROR_CLOCKSKEW) {
3341 class = 1; /* invalid function */
3344 else if (code == CM_ERROR_BADTID) {
3348 else if (code == CM_ERROR_USESTD) {
3352 else if (code == CM_ERROR_REMOTECONN) {
3356 else if (code == CM_ERROR_QUOTA) {
3357 if (vcp->flags & SMB_VCFLAG_USEV3) {
3359 error = 39; /* disk full */
3363 error = 5; /* access denied */
3366 else if (code == CM_ERROR_SPACE) {
3367 if (vcp->flags & SMB_VCFLAG_USEV3) {
3369 error = 39; /* disk full */
3373 error = 5; /* access denied */
3376 else if (code == CM_ERROR_PARTIALWRITE) {
3378 error = 39; /* disk full */
3380 else if (code == CM_ERROR_ATSYS) {
3382 error = 2; /* ENOENT */
3384 else if (code == CM_ERROR_WOULDBLOCK) {
3386 error = 33; /* lock conflict */
3388 else if (code == CM_ERROR_LOCK_CONFLICT) {
3390 error = 33; /* lock conflict */
3392 else if (code == CM_ERROR_SHARING_VIOLATION) {
3394 error = 33; /* lock conflict */
3396 else if (code == CM_ERROR_NOFILES) {
3398 error = 18; /* no files in search */
3400 else if (code == CM_ERROR_RENAME_IDENTICAL) {
3402 error = 183; /* Samba uses this */
3404 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
3405 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
3407 error = 2; /* bad password */
3409 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3411 error = 3; /* bad path */
3420 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
3423 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3425 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
3426 return CM_ERROR_BADOP;
3430 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3432 unsigned short EchoCount, i;
3433 char *data, *outdata;
3436 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
3438 for (i=1; i<=EchoCount; i++) {
3439 data = smb_GetSMBData(inp, &dataSize);
3440 smb_SetSMBParm(outp, 0, i);
3441 smb_SetSMBDataLength(outp, dataSize);
3442 outdata = smb_GetSMBData(outp, NULL);
3443 memcpy(outdata, data, dataSize);
3444 smb_SendPacket(vcp, outp);
3450 /* SMB_COM_READ_RAW */
3451 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3454 long count, minCount, finalCount;
3458 smb_t *smbp = (smb_t*) inp;
3460 cm_user_t *userp = NULL;
3463 char *rawBuf = NULL;
3468 fd = smb_GetSMBParm(inp, 0);
3469 count = smb_GetSMBParm(inp, 3);
3470 minCount = smb_GetSMBParm(inp, 4);
3471 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3473 if (*inp->wctp == 10) {
3474 /* we were sent a request with 64-bit file offsets */
3475 #ifdef AFS_LARGEFILES
3476 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
3478 if (LargeIntegerLessThanZero(offset)) {
3479 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
3483 if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
3484 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset. Dropping request.");
3487 offset.HighPart = 0;
3491 /* we were sent a request with 32-bit file offsets */
3492 offset.HighPart = 0;
3495 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
3496 fd, offset.HighPart, offset.LowPart, count);
3498 fidp = smb_FindFID(vcp, fd, 0);
3502 lock_ObtainMutex(&fidp->mx);
3503 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3504 lock_ReleaseMutex(&fidp->mx);
3505 smb_CloseFID(vcp, fidp, NULL, 0);
3506 code = CM_ERROR_NOSUCHFILE;
3512 LARGE_INTEGER LOffset, LLength;
3515 key = cm_GenerateKey(vcp->vcID, pid, fd);
3517 LOffset.HighPart = offset.HighPart;
3518 LOffset.LowPart = offset.LowPart;
3519 LLength.HighPart = 0;
3520 LLength.LowPart = count;
3522 lock_ObtainWrite(&fidp->scp->rw);
3523 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
3524 lock_ReleaseWrite(&fidp->scp->rw);
3527 lock_ReleaseMutex(&fidp->mx);
3531 lock_ObtainMutex(&smb_RawBufLock);
3533 /* Get a raw buf, from head of list */
3534 rawBuf = smb_RawBufs;
3535 smb_RawBufs = *(char **)smb_RawBufs;
3537 lock_ReleaseMutex(&smb_RawBufLock);
3539 lock_ReleaseMutex(&fidp->mx);
3543 if (fidp->flags & SMB_FID_IOCTL)
3545 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
3547 /* Give back raw buffer */
3548 lock_ObtainMutex(&smb_RawBufLock);
3549 *((char **) rawBuf) = smb_RawBufs;
3551 smb_RawBufs = rawBuf;
3552 lock_ReleaseMutex(&smb_RawBufLock);
3555 lock_ReleaseMutex(&fidp->mx);
3556 smb_ReleaseFID(fidp);
3559 lock_ReleaseMutex(&fidp->mx);
3561 userp = smb_GetUserFromVCP(vcp, inp);
3563 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
3569 cm_ReleaseUser(userp);
3572 smb_ReleaseFID(fidp);
3576 memset((char *)ncbp, 0, sizeof(NCB));
3578 ncbp->ncb_length = (unsigned short) finalCount;
3579 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
3580 ncbp->ncb_lana_num = vcp->lana;
3581 ncbp->ncb_command = NCBSEND;
3582 ncbp->ncb_buffer = rawBuf;
3584 code = Netbios(ncbp);
3586 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
3589 /* Give back raw buffer */
3590 lock_ObtainMutex(&smb_RawBufLock);
3591 *((char **) rawBuf) = smb_RawBufs;
3593 smb_RawBufs = rawBuf;
3594 lock_ReleaseMutex(&smb_RawBufLock);
3600 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3602 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3607 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3609 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3614 /* SMB_COM_NEGOTIATE */
3615 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3622 int VistaProtoIndex;
3623 int protoIndex; /* index we're using */
3628 char protocol_array[10][1024]; /* protocol signature of the client */
3629 int caps; /* capabilities */
3632 TIME_ZONE_INFORMATION tzi;
3634 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3637 namep = smb_GetSMBData(inp, &dbytes);
3640 coreProtoIndex = -1; /* not found */
3643 VistaProtoIndex = -1;
3644 while(namex < dbytes) {
3645 osi_Log1(smb_logp, "Protocol %s",
3646 osi_LogSaveString(smb_logp, namep+1));
3647 strcpy(protocol_array[tcounter], namep+1);
3649 /* namep points at the first protocol, or really, a 0x02
3650 * byte preceding the null-terminated ASCII name.
3652 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3653 coreProtoIndex = tcounter;
3655 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3656 v3ProtoIndex = tcounter;
3658 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3659 NTProtoIndex = tcounter;
3661 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3662 VistaProtoIndex = tcounter;
3665 /* compute size of protocol entry */
3666 entryLength = (int)strlen(namep+1);
3667 entryLength += 2; /* 0x02 bytes and null termination */
3669 /* advance over this protocol entry */
3670 namex += entryLength;
3671 namep += entryLength;
3672 tcounter++; /* which proto entry we're looking at */
3675 lock_ObtainMutex(&vcp->mx);
3677 if (VistaProtoIndex != -1) {
3678 protoIndex = VistaProtoIndex;
3679 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3682 if (NTProtoIndex != -1) {
3683 protoIndex = NTProtoIndex;
3684 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3686 else if (v3ProtoIndex != -1) {
3687 protoIndex = v3ProtoIndex;
3688 vcp->flags |= SMB_VCFLAG_USEV3;
3690 else if (coreProtoIndex != -1) {
3691 protoIndex = coreProtoIndex;
3692 vcp->flags |= SMB_VCFLAG_USECORE;
3694 else protoIndex = -1;
3695 lock_ReleaseMutex(&vcp->mx);
3697 if (protoIndex == -1)
3698 return CM_ERROR_INVAL;
3699 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3700 smb_SetSMBParm(outp, 0, protoIndex);
3701 if (smb_authType != SMB_AUTH_NONE) {
3702 smb_SetSMBParmByte(outp, 1,
3703 NEGOTIATE_SECURITY_USER_LEVEL |
3704 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3706 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3708 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3709 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3710 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3711 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3712 /* The session key is not a well documented field however most clients
3713 * will echo back the session key to the server. Currently we are using
3714 * the same value for all sessions. We should generate a random value
3715 * and store it into the vcp
3717 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3718 smb_SetSMBParm(outp, 8, 1);
3720 * Tried changing the capabilities to support for W2K - defect 117695
3721 * Maybe something else needs to be changed here?
3725 smb_SetSMBParmLong(outp, 9, 0x43fd);
3727 smb_SetSMBParmLong(outp, 9, 0x251);
3730 * 32-bit error codes *
3736 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3738 NTNEGOTIATE_CAPABILITY_DFS