2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afs/param.h>
15 #pragma warning(disable: 4005)
28 #include <rx/rx_prototypes.h>
29 #include <WINNT\afsreg.h>
32 #include "lanahelper.h"
34 #define STRSAFE_NO_DEPRECATE
37 /* These characters are illegal in Windows filenames */
38 static clientchar_t *illegalChars = _C("\\/:*?\"<>|");
40 static int smbShutdownFlag = 0;
41 static int smb_ListenerState = SMB_LISTENER_UNINITIALIZED;
43 int smb_LogoffTokenTransfer;
44 time_t smb_LogoffTransferTimeout;
46 int smb_StoreAnsiFilenames = 0;
48 DWORD last_msg_time = 0;
52 unsigned int sessionGen = 0;
54 extern void afsi_log(char *pattern, ...);
55 extern HANDLE afsi_file;
56 extern int powerStateSuspended;
58 osi_hyper_t hzero = {0, 0};
59 osi_hyper_t hones = {0xFFFFFFFF, -1};
62 osi_rwlock_t smb_globalLock;
63 osi_rwlock_t smb_rctLock;
64 osi_mutex_t smb_ListenerLock;
65 osi_mutex_t smb_StartedLock;
67 unsigned char smb_LANadapter = LANA_INVALID;
68 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
69 int smb_LanAdapterChangeDetected = 0;
70 afs_uint32 smb_AsyncStore = 1;
71 afs_uint32 smb_AsyncStoreSize = CM_CONFIGDEFAULT_ASYNCSTORESIZE;
73 BOOL isGateway = FALSE;
76 long smb_maxObsConcurrentCalls=0;
77 long smb_concurrentCalls=0;
79 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
81 smb_packet_t *smb_packetFreeListp;
82 smb_ncb_t *smb_ncbFreeListp;
84 afs_uint32 smb_NumServerThreads;
86 afs_uint32 numNCBs, numSessions, numVCs;
88 int smb_maxVCPerServer;
89 int smb_maxMpxRequests;
91 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
93 ULONG smb_lsaSecPackage;
94 LSA_STRING smb_lsaLogonOrigin;
96 #define NCB_MAX MAXIMUM_WAIT_OBJECTS
97 EVENT_HANDLE NCBavails[NCB_MAX], NCBevents[NCB_MAX];
98 EVENT_HANDLE **NCBreturns;
99 EVENT_HANDLE **NCBShutdown;
100 EVENT_HANDLE *smb_ServerShutdown;
101 EVENT_HANDLE ListenerShutdown[256];
102 DWORD NCBsessions[NCB_MAX];
104 struct smb_packet *bufs[NCB_MAX];
106 #define SESSION_MAX MAXIMUM_WAIT_OBJECTS - 4
107 EVENT_HANDLE SessionEvents[SESSION_MAX];
108 unsigned short LSNs[SESSION_MAX];
109 int lanas[SESSION_MAX];
110 BOOL dead_sessions[SESSION_MAX];
113 osi_mutex_t smb_RawBufLock;
116 #define SMB_MASKFLAG_TILDE 1
117 #define SMB_MASKFLAG_CASEFOLD 2
119 #define RAWTIMEOUT INFINITE
122 typedef struct raw_write_cont {
131 /* dir search stuff */
132 long smb_dirSearchCounter = 1;
133 smb_dirSearch_t *smb_firstDirSearchp;
134 smb_dirSearch_t *smb_lastDirSearchp;
136 /* hide dot files? */
137 int smb_hideDotFiles;
139 /* Negotiate Unicode support? */
142 /* global state about V3 protocols */
143 int smb_useV3; /* try to negotiate V3 */
145 static int showErrors = 0;
146 /* MessageBox or something like it */
147 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT)
151 * Time in Unix format of midnight, 1/1/1970 local time.
152 * When added to dosUTime, gives Unix (AFS) time.
154 time_t smb_localZero = 0;
156 #define USE_NUMERIC_TIME_CONV 1
158 #ifndef USE_NUMERIC_TIME_CONV
159 /* Time difference for converting to kludge-GMT */
160 afs_uint32 smb_NowTZ;
161 #endif /* USE_NUMERIC_TIME_CONV */
163 char *smb_localNamep = NULL;
165 smb_vc_t *smb_allVCsp;
166 smb_vc_t *smb_deadVCsp;
168 smb_username_t *usernamesp = NULL;
170 smb_waitingLockRequest_t *smb_allWaitingLocks;
172 DWORD smb_TlsRequestSlot = -1;
175 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
176 NCB *ncbp, raw_write_cont_t *rwcp);
177 int smb_NetbiosInit(int);
180 void smb_LogPacket(smb_packet_t *packet);
181 #endif /* LOG_PACKET */
183 clientchar_t smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = _C(""); /* domain name */
184 int smb_ServerDomainNameLength = 0;
185 clientchar_t smb_ServerOS[] = _C("Windows 5.0"); /* Faux OS String */
186 int smb_ServerOSLength = lengthof(smb_ServerOS);
187 clientchar_t smb_ServerLanManager[] = _C("Windows 2000 LAN Manager"); /* Faux LAN Manager string */
188 int smb_ServerLanManagerLength = lengthof(smb_ServerLanManager);
190 /* Faux server GUID. This is never checked. */
191 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
193 void smb_InitReq(cm_req_t *reqp)
196 reqp->flags |= CM_REQ_SOURCE_SMB;
199 void smb_ResetServerPriority()
201 void * p = TlsGetValue(smb_TlsRequestSlot);
204 TlsSetValue(smb_TlsRequestSlot, NULL);
205 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
209 void smb_SetRequestStartTime()
211 time_t * tp = TlsGetValue(smb_TlsRequestSlot);
213 tp = malloc(sizeof(time_t));
217 if (!TlsSetValue(smb_TlsRequestSlot, tp))
222 void smb_UpdateServerPriority()
224 time_t *tp = TlsGetValue(smb_TlsRequestSlot);
227 time_t now = osi_Time();
229 /* Give one priority boost for each 15 seconds */
230 SetThreadPriority(GetCurrentThread(), (int)((now - *tp) / 15));
235 const char * ncb_error_string(int code)
239 case 0x01: s = "llegal buffer length"; break;
240 case 0x03: s = "illegal command"; break;
241 case 0x05: s = "command timed out"; break;
242 case 0x06: s = "message incomplete, issue another command"; break;
243 case 0x07: s = "illegal buffer address"; break;
244 case 0x08: s = "session number out of range"; break;
245 case 0x09: s = "no resource available"; break;
246 case 0x0a: s = "session closed"; break;
247 case 0x0b: s = "command cancelled"; break;
248 case 0x0d: s = "duplicate name"; break;
249 case 0x0e: s = "name table full"; break;
250 case 0x0f: s = "no deletions, name has active sessions"; break;
251 case 0x11: s = "local session table full"; break;
252 case 0x12: s = "remote session table full"; break;
253 case 0x13: s = "illegal name number"; break;
254 case 0x14: s = "no callname"; break;
255 case 0x15: s = "cannot put * in NCB_NAME"; break;
256 case 0x16: s = "name in use on remote adapter"; break;
257 case 0x17: s = "name deleted"; break;
258 case 0x18: s = "session ended abnormally"; break;
259 case 0x19: s = "name conflict detected"; break;
260 case 0x21: s = "interface busy, IRET before retrying"; break;
261 case 0x22: s = "too many commands outstanding, retry later";break;
262 case 0x23: s = "ncb_lana_num field invalid"; break;
263 case 0x24: s = "command completed while cancel occurring "; break;
264 case 0x26: s = "command not valid to cancel"; break;
265 case 0x30: s = "name defined by anther local process"; break;
266 case 0x34: s = "environment undefined. RESET required"; break;
267 case 0x35: s = "required OS resources exhausted"; break;
268 case 0x36: s = "max number of applications exceeded"; break;
269 case 0x37: s = "no saps available for netbios"; break;
270 case 0x38: s = "requested resources are not available"; break;
271 case 0x39: s = "invalid ncb address or length > segment"; break;
272 case 0x3B: s = "invalid NCB DDID"; break;
273 case 0x3C: s = "lock of user area failed"; break;
274 case 0x3f: s = "NETBIOS not loaded"; break;
275 case 0x40: s = "system error"; break;
276 default: s = "unknown error";
282 char * myCrt_Dispatch(int i)
287 return "(00)ReceiveCoreMakeDir";
289 return "(01)ReceiveCoreRemoveDir";
291 return "(02)ReceiveCoreOpen";
293 return "(03)ReceiveCoreCreate";
295 return "(04)ReceiveCoreClose";
297 return "(05)ReceiveCoreFlush";
299 return "(06)ReceiveCoreUnlink";
301 return "(07)ReceiveCoreRename";
303 return "(08)ReceiveCoreGetFileAttributes";
305 return "(09)ReceiveCoreSetFileAttributes";
307 return "(0a)ReceiveCoreRead";
309 return "(0b)ReceiveCoreWrite";
311 return "(0c)ReceiveCoreLockRecord";
313 return "(0d)ReceiveCoreUnlockRecord";
315 return "(0e)SendCoreBadOp";
317 return "(0f)ReceiveCoreCreate";
319 return "(10)ReceiveCoreCheckPath";
321 return "(11)SendCoreBadOp";
323 return "(12)ReceiveCoreSeek";
325 return "(1a)ReceiveCoreReadRaw";
327 return "(1d)ReceiveCoreWriteRawDummy";
329 return "(22)ReceiveV3SetAttributes";
331 return "(23)ReceiveV3GetAttributes";
333 return "(24)ReceiveV3LockingX";
335 return "(25)ReceiveV3Trans";
337 return "(26)ReceiveV3Trans[aux]";
339 return "(29)SendCoreBadOp";
341 return "(2b)ReceiveCoreEcho";
343 return "(2d)ReceiveV3OpenX";
345 return "(2e)ReceiveV3ReadX";
347 return "(2f)ReceiveV3WriteX";
349 return "(32)ReceiveV3Tran2A";
351 return "(33)ReceiveV3Tran2A[aux]";
353 return "(34)ReceiveV3FindClose";
355 return "(35)ReceiveV3FindNotifyClose";
357 return "(70)ReceiveCoreTreeConnect";
359 return "(71)ReceiveCoreTreeDisconnect";
361 return "(72)ReceiveNegotiate";
363 return "(73)ReceiveV3SessionSetupX";
365 return "(74)ReceiveV3UserLogoffX";
367 return "(75)ReceiveV3TreeConnectX";
369 return "(80)ReceiveCoreGetDiskAttributes";
371 return "(81)ReceiveCoreSearchDir";
375 return "(83)FindUnique";
377 return "(84)FindClose";
379 return "(A0)ReceiveNTTransact";
381 return "(A2)ReceiveNTCreateX";
383 return "(A4)ReceiveNTCancel";
385 return "(A5)ReceiveNTRename";
387 return "(C0)OpenPrintFile";
389 return "(C1)WritePrintFile";
391 return "(C2)ClosePrintFile";
393 return "(C3)GetPrintQueue";
395 return "(D8)ReadBulk";
397 return "(D9)WriteBulk";
399 return "(DA)WriteBulkData";
401 return "unknown SMB op";
405 char * myCrt_2Dispatch(int i)
410 return "unknown SMB op-2";
412 return "S(00)CreateFile_ReceiveTran2Open";
414 return "S(01)FindFirst_ReceiveTran2SearchDir";
416 return "S(02)FindNext_ReceiveTran2SearchDir"; /* FindNext */
418 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
420 return "S(04)SetFileSystem_ReceiveTran2SetFSInfo";
422 return "S(05)QueryPathInfo_ReceiveTran2QPathInfo";
424 return "S(06)SetPathInfo_ReceiveTran2SetPathInfo";
426 return "S(07)QueryFileInfo_ReceiveTran2QFileInfo";
428 return "S(08)SetFileInfo_ReceiveTran2SetFileInfo";
430 return "S(09)_ReceiveTran2FSCTL";
432 return "S(0a)_ReceiveTran2IOCTL";
434 return "S(0b)_ReceiveTran2FindNotifyFirst";
436 return "S(0c)_ReceiveTran2FindNotifyNext";
438 return "S(0d)_ReceiveTran2CreateDirectory";
440 return "S(0e)_ReceiveTran2SessionSetup";
442 return "S(0f)_QueryFileSystemInformationFid";
444 return "S(10)_ReceiveTran2GetDfsReferral";
446 return "S(11)_ReceiveTran2ReportDfsInconsistency";
450 char * myCrt_RapDispatch(int i)
455 return "unknown RAP OP";
457 return "RAP(0)NetShareEnum";
459 return "RAP(1)NetShareGetInfo";
461 return "RAP(13)NetServerGetInfo";
463 return "RAP(63)NetWkStaGetInfo";
467 /* scache must be locked */
468 unsigned int smb_Attributes(cm_scache_t *scp)
472 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
473 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
474 scp->fileType == CM_SCACHETYPE_INVALID)
476 attrs = SMB_ATTR_DIRECTORY;
477 #ifdef SPECIAL_FOLDERS
478 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
479 #endif /* SPECIAL_FOLDERS */
480 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
481 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
486 * We used to mark a file RO if it was in an RO volume, but that
487 * turns out to be impolitic in NT. See defect 10007.
490 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
491 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
493 if ((scp->unixModeBits & 0222) == 0)
494 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
500 /* Check if the named file/dir is a dotfile/dotdir */
501 /* String pointed to by lastComp can have leading slashes, but otherwise should have
502 no other patch components */
503 unsigned int smb_IsDotFile(clientchar_t *lastComp) {
507 /* skip over slashes */
508 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
513 /* nulls, curdir and parent dir doesn't count */
519 if(*(s+1) == _C('.') && !*(s + 2))
526 static int ExtractBits(WORD bits, short start, short len)
533 num = bits << (16 - end);
534 num = num >> ((16 - end) + start);
539 void ShowUnixTime(char *FuncName, time_t unixTime)
544 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
546 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
547 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
549 int day, month, year, sec, min, hour;
552 day = ExtractBits(wDate, 0, 5);
553 month = ExtractBits(wDate, 5, 4);
554 year = ExtractBits(wDate, 9, 7) + 1980;
556 sec = ExtractBits(wTime, 0, 5);
557 min = ExtractBits(wTime, 5, 6);
558 hour = ExtractBits(wTime, 11, 5);
560 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
561 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
565 /* Determine if we are observing daylight savings time */
566 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
568 TIME_ZONE_INFORMATION timeZoneInformation;
569 SYSTEMTIME utc, local, localDST;
571 /* Get the time zone info. NT uses this to calc if we are in DST. */
572 GetTimeZoneInformation(&timeZoneInformation);
574 /* Return the daylight bias */
575 *pDstBias = timeZoneInformation.DaylightBias;
577 /* Return the bias */
578 *pBias = timeZoneInformation.Bias;
580 /* Now determine if DST is being observed */
582 /* Get the UTC (GMT) time */
585 /* Convert UTC time to local time using the time zone info. If we are
586 observing DST, the calculated local time will include this.
588 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
590 /* Set the daylight bias to 0. The daylight bias is the amount of change
591 * in time that we use for daylight savings time. By setting this to 0
592 * we cause there to be no change in time during daylight savings time.
594 timeZoneInformation.DaylightBias = 0;
596 /* Convert the utc time to local time again, but this time without any
597 adjustment for daylight savings time.
599 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
601 /* If the two times are different, then it means that the localDST that
602 we calculated includes the daylight bias, and therefore we are
603 observing daylight savings time.
605 *pDST = localDST.wHour != local.wHour;
609 void CompensateForSmbClientLastWriteTimeBugs(afs_uint32 *pLastWriteTime)
611 BOOL dst; /* Will be TRUE if observing DST */
612 LONG dstBias; /* Offset from local time if observing DST */
613 LONG bias; /* Offset from GMT for local time */
616 * This function will adjust the last write time to compensate
617 * for two bugs in the smb client:
619 * 1) During Daylight Savings Time, the LastWriteTime is ahead
620 * in time by the DaylightBias (ignoring the sign - the
621 * DaylightBias is always stored as a negative number). If
622 * the DaylightBias is -60, then the LastWriteTime will be
623 * ahead by 60 minutes.
625 * 2) If the local time zone is a positive offset from GMT, then
626 * the LastWriteTime will be the correct local time plus the
627 * Bias (ignoring the sign - a positive offset from GMT is
628 * always stored as a negative Bias). If the Bias is -120,
629 * then the LastWriteTime will be ahead by 120 minutes.
631 * These bugs can occur at the same time.
634 GetTimeZoneInfo(&dst, &dstBias, &bias);
636 /* First adjust for DST */
638 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
640 /* Now adjust for a positive offset from GMT (a negative bias). */
642 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
645 #ifndef USE_NUMERIC_TIME_CONV
647 * Calculate the difference (in seconds) between local time and GMT.
648 * This enables us to convert file times to kludge-GMT.
654 struct tm gmt_tm, local_tm;
655 int days, hours, minutes, seconds;
658 gmt_tm = *(gmtime(&t));
659 local_tm = *(localtime(&t));
661 days = local_tm.tm_yday - gmt_tm.tm_yday;
662 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour;
663 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
664 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
668 #endif /* USE_NUMERIC_TIME_CONV */
670 #ifdef USE_NUMERIC_TIME_CONV
671 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
673 // Note that LONGLONG is a 64-bit value
676 ll = Int32x32To64(unixTime, 10000000) + 116444736000000000;
677 largeTimep->dwLowDateTime = (DWORD)(ll & 0xFFFFFFFF);
678 largeTimep->dwHighDateTime = (DWORD)(ll >> 32);
681 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
686 time_t ersatz_unixTime;
689 * Must use kludge-GMT instead of real GMT.
690 * kludge-GMT is computed by adding time zone difference to localtime.
693 * ltp = gmtime(&unixTime);
695 ersatz_unixTime = unixTime - smb_NowTZ;
696 ltp = localtime(&ersatz_unixTime);
698 /* if we fail, make up something */
701 localJunk.tm_year = 89 - 20;
702 localJunk.tm_mon = 4;
703 localJunk.tm_mday = 12;
704 localJunk.tm_hour = 0;
705 localJunk.tm_min = 0;
706 localJunk.tm_sec = 0;
709 stm.wYear = ltp->tm_year + 1900;
710 stm.wMonth = ltp->tm_mon + 1;
711 stm.wDayOfWeek = ltp->tm_wday;
712 stm.wDay = ltp->tm_mday;
713 stm.wHour = ltp->tm_hour;
714 stm.wMinute = ltp->tm_min;
715 stm.wSecond = ltp->tm_sec;
716 stm.wMilliseconds = 0;
718 SystemTimeToFileTime(&stm, largeTimep);
720 #endif /* USE_NUMERIC_TIME_CONV */
722 #ifdef USE_NUMERIC_TIME_CONV
723 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
725 // Note that LONGLONG is a 64-bit value
728 ll = largeTimep->dwHighDateTime;
730 ll += largeTimep->dwLowDateTime;
732 ll -= 116444736000000000;
735 *unixTimep = (DWORD)ll;
737 #else /* USE_NUMERIC_TIME_CONV */
738 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
744 FileTimeToSystemTime(largeTimep, &stm);
746 lt.tm_year = stm.wYear - 1900;
747 lt.tm_mon = stm.wMonth - 1;
748 lt.tm_wday = stm.wDayOfWeek;
749 lt.tm_mday = stm.wDay;
750 lt.tm_hour = stm.wHour;
751 lt.tm_min = stm.wMinute;
752 lt.tm_sec = stm.wSecond;
755 save_timezone = _timezone;
756 _timezone += smb_NowTZ;
757 *unixTimep = mktime(<);
758 _timezone = save_timezone;
760 #endif /* USE_NUMERIC_TIME_CONV */
762 void smb_SearchTimeFromUnixTime(afs_uint32 *searchTimep, time_t unixTime)
772 /* if we fail, make up something */
775 localJunk.tm_year = 89 - 20;
776 localJunk.tm_mon = 4;
777 localJunk.tm_mday = 12;
778 localJunk.tm_hour = 0;
779 localJunk.tm_min = 0;
780 localJunk.tm_sec = 0;
783 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
784 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
785 *searchTimep = (dosDate<<16) | dosTime;
788 void smb_UnixTimeFromSearchTime(time_t *unixTimep, afs_uint32 searchTime)
790 unsigned short dosDate;
791 unsigned short dosTime;
794 dosDate = (unsigned short) (searchTime & 0xffff);
795 dosTime = (unsigned short) ((searchTime >> 16) & 0xffff);
797 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
798 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
799 localTm.tm_mday = (dosDate) & 0x1f;
800 localTm.tm_hour = (dosTime>>11) & 0x1f;
801 localTm.tm_min = (dosTime >> 5) & 0x3f;
802 localTm.tm_sec = (dosTime & 0x1f) * 2;
803 localTm.tm_isdst = -1; /* compute whether DST in effect */
805 *unixTimep = mktime(&localTm);
808 void smb_DosUTimeFromUnixTime(afs_uint32 *dosUTimep, time_t unixTime)
810 time_t diff_t = unixTime - smb_localZero;
811 #if defined(DEBUG) && !defined(_USE_32BIT_TIME_T)
812 osi_assertx(diff_t < _UI32_MAX, "time_t > _UI32_MAX");
814 *dosUTimep = (afs_uint32)diff_t;
817 void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
819 *unixTimep = dosTime + smb_localZero;
822 #ifdef DEBUG_SMB_REFCOUNT
823 smb_vc_t *smb_FindVCDbg(unsigned short lsn, int flags, int lana, char *file, long line)
825 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
830 lock_ObtainWrite(&smb_globalLock); /* for numVCs */
831 lock_ObtainWrite(&smb_rctLock);
832 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
833 if (vcp->magic != SMB_VC_MAGIC)
834 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
837 if (lsn == vcp->lsn && lana == vcp->lana &&
838 !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
839 smb_HoldVCNoLock(vcp);
843 if (!vcp && (flags & SMB_FLAG_CREATE)) {
844 vcp = malloc(sizeof(*vcp));
845 memset(vcp, 0, sizeof(*vcp));
846 vcp->vcID = ++numVCs;
847 vcp->magic = SMB_VC_MAGIC;
848 vcp->refCount = 2; /* smb_allVCsp and caller */
851 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
852 vcp->nextp = smb_allVCsp;
854 lock_InitializeMutex(&vcp->mx, "vc_t mutex", LOCK_HIERARCHY_SMB_VC);
859 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
860 /* We must obtain a challenge for extended auth
861 * in case the client negotiates smb v3
863 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
864 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
865 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp = NULL;
866 ULONG lsaRespSize = 0;
868 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
870 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
877 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS) {
878 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
879 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
880 afsi_log("MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize %u",
881 nts, ntsEx, lsaRespSize);
883 osi_assertx(nts == STATUS_SUCCESS, "LsaCallAuthenticationPackage failed"); /* this had better work! */
885 if (ntsEx == STATUS_SUCCESS) {
886 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
889 * This will cause the subsequent authentication to fail but
890 * that is better than us dereferencing a NULL pointer and
893 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
896 LsaFreeReturnBuffer(lsaResp);
899 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
901 if (numVCs >= CM_SESSION_RESERVED) {
903 osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
906 #ifdef DEBUG_SMB_REFCOUNT
908 afsi_log("%s:%d smb_FindVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
909 osi_Log4(smb_logp,"%s:%d smb_FindVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
912 lock_ReleaseWrite(&smb_rctLock);
913 lock_ReleaseWrite(&smb_globalLock);
917 int smb_IsStarMask(clientchar_t *maskp)
922 for(i=0; i<11; i++) {
924 if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
930 #ifdef DEBUG_SMB_REFCOUNT
931 void smb_ReleaseVCInternalDbg(smb_vc_t *vcp, char * file, long line)
932 #define smb_ReleaseVCInternal(a) smb_ReleaseVCInternalDbg(a, file, line)
934 void smb_ReleaseVCInternal(smb_vc_t *vcp)
940 lock_AssertWrite(&smb_rctLock);
943 if (vcp->refCount == 0) {
944 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
945 #ifdef DEBUG_SMB_REFCOUNT
946 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
947 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
949 /* remove VCP from smb_deadVCsp */
950 for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
956 lock_FinalizeMutex(&vcp->mx);
957 memset(vcp,0,sizeof(smb_vc_t));
960 #ifdef DEBUG_SMB_REFCOUNT
961 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is alive ref %d", file, line, vcp, vcp->refCount);
963 for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
967 osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
968 avcp?"":"not ",vcp, vcp->refCount);
970 /* This is a wrong. However, I suspect that there is an undercount
971 * and I don't want to release 1.4.1 in a state that will allow
972 * smb_vc_t objects to be deallocated while still in the
973 * smb_allVCsp list. The list is supposed to keep a reference
974 * to the smb_vc_t. Put it back.
978 #ifdef DEBUG_SMB_REFCOUNT
979 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
980 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
984 } else if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
985 /* The reference count is non-zero but the VC is dead.
986 * This implies that some FIDs, TIDs, etc on the VC have yet to
987 * be cleaned up. If we were not called by smb_CleanupDeadVC(),
988 * add a reference that will be dropped by
989 * smb_CleanupDeadVC() and try to cleanup the VC again.
990 * Eventually the refCount will drop to zero when all of the
991 * active threads working with the VC end their task.
993 if (!(vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS)) {
994 vcp->refCount++; /* put the refCount back */
995 lock_ReleaseWrite(&smb_rctLock);
996 smb_CleanupDeadVC(vcp);
997 #ifdef DEBUG_SMB_REFCOUNT
998 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
999 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
1001 lock_ObtainWrite(&smb_rctLock);
1004 #ifdef DEBUG_SMB_REFCOUNT
1005 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1006 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1011 #ifdef DEBUG_SMB_REFCOUNT
1012 void smb_ReleaseVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
1014 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
1017 lock_AssertWrite(&smb_rctLock);
1018 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
1019 smb_ReleaseVCInternal(vcp);
1022 #ifdef DEBUG_SMB_REFCOUNT
1023 void smb_ReleaseVCDbg(smb_vc_t *vcp, char * file, long line)
1025 void smb_ReleaseVC(smb_vc_t *vcp)
1028 lock_ObtainWrite(&smb_rctLock);
1029 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
1030 smb_ReleaseVCInternal(vcp);
1031 lock_ReleaseWrite(&smb_rctLock);
1034 #ifdef DEBUG_SMB_REFCOUNT
1035 void smb_HoldVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
1037 void smb_HoldVCNoLock(smb_vc_t *vcp)
1040 lock_AssertWrite(&smb_rctLock);
1042 #ifdef DEBUG_SMB_REFCOUNT
1043 afsi_log("%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1044 osi_Log4(smb_logp,"%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1046 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
1050 #ifdef DEBUG_SMB_REFCOUNT
1051 void smb_HoldVCDbg(smb_vc_t *vcp, char * file, long line)
1053 void smb_HoldVC(smb_vc_t *vcp)
1056 lock_ObtainWrite(&smb_rctLock);
1058 #ifdef DEBUG_SMB_REFCOUNT
1059 afsi_log("%s:%d smb_HoldVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1060 osi_Log4(smb_logp,"%s:%d smb_HoldVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1062 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
1064 lock_ReleaseWrite(&smb_rctLock);
1067 void smb_CleanupDeadVC(smb_vc_t *vcp)
1069 smb_fid_t *fidpIter;
1070 smb_fid_t *fidpNext;
1072 smb_tid_t *tidpIter;
1073 smb_tid_t *tidpNext;
1075 smb_user_t *uidpIter;
1076 smb_user_t *uidpNext;
1078 afs_uint32 refCount = 0;
1080 lock_ObtainMutex(&vcp->mx);
1081 if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
1082 lock_ReleaseMutex(&vcp->mx);
1083 osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
1086 vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
1087 lock_ReleaseMutex(&vcp->mx);
1088 osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
1090 lock_ObtainWrite(&smb_rctLock);
1091 /* remove VCP from smb_allVCsp */
1092 for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
1093 if ((*vcpp)->magic != SMB_VC_MAGIC)
1094 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
1095 __FILE__, __LINE__);
1098 vcp->nextp = smb_deadVCsp;
1100 /* Hold onto the reference until we are done with this function */
1105 for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
1106 fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
1108 if (fidpIter->deleteOk)
1111 fid = fidpIter->fid;
1112 osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1114 smb_HoldFIDNoLock(fidpIter);
1115 lock_ReleaseWrite(&smb_rctLock);
1117 smb_CloseFID(vcp, fidpIter, NULL, 0);
1118 smb_ReleaseFID(fidpIter);
1120 lock_ObtainWrite(&smb_rctLock);
1121 fidpNext = vcp->fidsp;
1124 for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1125 tidpNext = tidpIter->nextp;
1126 if (tidpIter->deleteOk)
1128 tidpIter->deleteOk = 1;
1130 tid = tidpIter->tid;
1131 osi_Log2(smb_logp, " Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1133 smb_HoldTIDNoLock(tidpIter);
1134 smb_ReleaseTID(tidpIter, TRUE);
1135 tidpNext = vcp->tidsp;
1138 for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1139 uidpNext = uidpIter->nextp;
1140 if (uidpIter->deleteOk)
1142 uidpIter->deleteOk = 1;
1144 /* do not add an additional reference count for the smb_user_t
1145 * as the smb_vc_t already is holding a reference */
1146 lock_ReleaseWrite(&smb_rctLock);
1148 smb_ReleaseUID(uidpIter);
1150 lock_ObtainWrite(&smb_rctLock);
1151 uidpNext = vcp->usersp;
1154 /* The vcp is now on the deadVCsp list. We intentionally drop the
1155 * reference so that the refcount can reach 0 and we can delete it
1157 * If the refCount == 1 going into the ReleaseVCNoLock call
1158 * the object will be freed and it won't be safe to clear
1161 refCount = vcp->refCount;
1162 smb_ReleaseVCNoLock(vcp);
1164 lock_ObtainMutex(&vcp->mx);
1165 vcp->flags &= ~SMB_VCFLAG_CLEAN_IN_PROGRESS;
1166 lock_ReleaseMutex(&vcp->mx);
1169 lock_ReleaseWrite(&smb_rctLock);
1170 osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1173 #ifdef DEBUG_SMB_REFCOUNT
1174 smb_tid_t *smb_FindTIDDbg(smb_vc_t *vcp, unsigned short tid, int flags, char * file, long line)
1176 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1181 lock_ObtainWrite(&smb_rctLock);
1183 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1184 if (tidp->refCount == 0 && tidp->deleteOk) {
1186 smb_ReleaseTID(tidp, TRUE);
1190 if (tid == tidp->tid) {
1195 if (!tidp && (flags & SMB_FLAG_CREATE)) {
1196 tidp = malloc(sizeof(*tidp));
1197 memset(tidp, 0, sizeof(*tidp));
1198 tidp->nextp = vcp->tidsp;
1201 smb_HoldVCNoLock(vcp);
1203 lock_InitializeMutex(&tidp->mx, "tid_t mutex", LOCK_HIERARCHY_SMB_TID);
1206 #ifdef DEBUG_SMB_REFCOUNT
1208 afsi_log("%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1209 osi_Log4(smb_logp,"%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1212 lock_ReleaseWrite(&smb_rctLock);
1216 #ifdef DEBUG_SMB_REFCOUNT
1217 void smb_HoldTIDNoLockDbg(smb_tid_t *tidp, char * file, long line)
1219 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1222 lock_AssertWrite(&smb_rctLock);
1224 #ifdef DEBUG_SMB_REFCOUNT
1225 afsi_log("%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1226 osi_Log4(smb_logp,"%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1230 #ifdef DEBUG_SMB_REFCOUNT
1231 void smb_ReleaseTIDDbg(smb_tid_t *tidp, afs_uint32 locked, char *file, long line)
1233 void smb_ReleaseTID(smb_tid_t *tidp, afs_uint32 locked)
1238 cm_user_t *userp = NULL;
1239 smb_vc_t *vcp = NULL;
1242 lock_ObtainWrite(&smb_rctLock);
1244 lock_AssertWrite(&smb_rctLock);
1246 osi_assertx(tidp->refCount-- > 0, "smb_tid_t refCount 0");
1247 #ifdef DEBUG_SMB_REFCOUNT
1248 afsi_log("%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1249 osi_Log5(smb_logp,"%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1251 if (tidp->refCount == 0) {
1252 if (tidp->deleteOk) {
1253 ltpp = &tidp->vcp->tidsp;
1254 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1258 osi_assertx(tp != NULL, "null smb_tid_t");
1260 lock_FinalizeMutex(&tidp->mx);
1261 userp = tidp->userp; /* remember to drop ref later */
1269 lock_ReleaseWrite(&smb_rctLock);
1271 cm_ReleaseUser(userp);
1273 smb_ReleaseVCNoLock(vcp);
1276 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1278 smb_user_t *uidp = NULL;
1280 lock_ObtainWrite(&smb_rctLock);
1281 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1282 if (uid == uidp->userID) {
1284 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%S]",
1286 ((uidp->unp)? osi_LogSaveClientString(smb_logp, uidp->unp->name):_C("")));
1290 if (!uidp && (flags & SMB_FLAG_CREATE)) {
1291 uidp = malloc(sizeof(*uidp));
1292 memset(uidp, 0, sizeof(*uidp));
1293 uidp->nextp = vcp->usersp;
1294 uidp->refCount = 2; /* one for the vcp and one for the caller */
1296 smb_HoldVCNoLock(vcp);
1298 lock_InitializeMutex(&uidp->mx, "user_t mutex", LOCK_HIERARCHY_SMB_UID);
1300 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%S]",
1302 ((uidp->unp)?osi_LogSaveClientString(smb_logp,uidp->unp->name):_C("")));
1304 lock_ReleaseWrite(&smb_rctLock);
1308 smb_username_t *smb_FindUserByName(clientchar_t *usern, clientchar_t *machine,
1311 smb_username_t *unp= NULL;
1313 lock_ObtainWrite(&smb_rctLock);
1314 for(unp = usernamesp; unp; unp = unp->nextp) {
1315 if (cm_ClientStrCmpI(unp->name, usern) == 0 &&
1316 cm_ClientStrCmpI(unp->machine, machine) == 0) {
1321 if (!unp && (flags & SMB_FLAG_CREATE)) {
1322 unp = malloc(sizeof(*unp));
1323 memset(unp, 0, sizeof(*unp));
1325 unp->nextp = usernamesp;
1326 unp->name = cm_ClientStrDup(usern);
1327 unp->machine = cm_ClientStrDup(machine);
1329 lock_InitializeMutex(&unp->mx, "username_t mutex", LOCK_HIERARCHY_SMB_USERNAME);
1330 if (flags & SMB_FLAG_AFSLOGON)
1331 unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1334 lock_ReleaseWrite(&smb_rctLock);
1338 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, clientchar_t *usern)
1340 smb_user_t *uidp= NULL;
1342 lock_ObtainWrite(&smb_rctLock);
1343 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1346 if (cm_stricmp_utf16(uidp->unp->name, usern) == 0) {
1348 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%S]",
1349 vcp,uidp->userID,osi_LogSaveClientString(smb_logp,usern));
1354 lock_ReleaseWrite(&smb_rctLock);
1358 void smb_ReleaseUsername(smb_username_t *unp)
1361 smb_username_t **lupp;
1362 cm_user_t *userp = NULL;
1363 time_t now = osi_Time();
1365 lock_ObtainWrite(&smb_rctLock);
1366 osi_assertx(unp->refCount-- > 0, "smb_username_t refCount 0");
1367 if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1368 (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1370 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1374 osi_assertx(up != NULL, "null smb_username_t");
1376 up->nextp = NULL; /* do not remove this */
1377 lock_FinalizeMutex(&unp->mx);
1383 lock_ReleaseWrite(&smb_rctLock);
1385 cm_ReleaseUser(userp);
1388 void smb_HoldUIDNoLock(smb_user_t *uidp)
1390 lock_AssertWrite(&smb_rctLock);
1394 void smb_ReleaseUID(smb_user_t *uidp)
1398 smb_username_t *unp = NULL;
1400 lock_ObtainWrite(&smb_rctLock);
1401 osi_assertx(uidp->refCount-- > 0, "smb_user_t refCount 0");
1402 if (uidp->refCount == 0) {
1403 lupp = &uidp->vcp->usersp;
1404 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1408 osi_assertx(up != NULL, "null smb_user_t");
1410 lock_FinalizeMutex(&uidp->mx);
1412 smb_ReleaseVCNoLock(uidp->vcp);
1416 lock_ReleaseWrite(&smb_rctLock);
1420 cm_ReleaseUserVCRef(unp->userp);
1421 smb_ReleaseUsername(unp);
1425 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1427 cm_user_t *up = NULL;
1432 lock_ObtainMutex(&uidp->mx);
1434 up = uidp->unp->userp;
1437 lock_ReleaseMutex(&uidp->mx);
1443 /* retrieve a held reference to a user structure corresponding to an incoming
1445 * corresponding release function is cm_ReleaseUser.
1447 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1450 cm_user_t *up = NULL;
1453 smbp = (smb_t *) inp;
1454 uidp = smb_FindUID(vcp, smbp->uid, 0);
1458 up = smb_GetUserFromUID(uidp);
1460 smb_ReleaseUID(uidp);
1465 * Return a pointer to a pathname extracted from a TID structure. The
1466 * TID structure is not held; assume it won't go away.
1468 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, clientchar_t ** treepath)
1473 tidp = smb_FindTID(vcp, tid, 0);
1477 if (tidp->flags & SMB_TIDFLAG_IPC) {
1478 code = CM_ERROR_TIDIPC;
1479 /* tidp->pathname would be NULL, but that's fine */
1481 *treepath = tidp->pathname;
1482 smb_ReleaseTID(tidp, FALSE);
1487 /* check to see if we have a chained fid, that is, a fid that comes from an
1488 * OpenAndX message that ran earlier in this packet. In this case, the fid
1489 * field in a read, for example, request, isn't set, since the value is
1490 * supposed to be inherited from the openAndX call.
1492 int smb_ChainFID(int fid, smb_packet_t *inp)
1494 if (inp->fid == 0 || inp->inCount == 0)
1500 /* are we a priv'd user? What does this mean on NT? */
1501 int smb_SUser(cm_user_t *userp)
1506 /* find a file ID. If we pass in 0 we select an unused File ID.
1507 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1508 * smb_fid_t data structure if desired File ID cannot be found.
1510 #ifdef DEBUG_SMB_REFCOUNT
1511 smb_fid_t *smb_FindFIDDbg(smb_vc_t *vcp, unsigned short fid, int flags, char *file, long line)
1513 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1519 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1522 lock_ObtainWrite(&smb_rctLock);
1523 /* figure out if we need to allocate a new file ID */
1526 fid = vcp->fidCounter;
1530 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1531 if (fidp->refCount == 0 && fidp->deleteOk) {
1533 lock_ReleaseWrite(&smb_rctLock);
1534 smb_ReleaseFID(fidp);
1535 lock_ObtainWrite(&smb_rctLock);
1538 if (fid == fidp->fid) {
1541 if (fid == 0xFFFF) {
1543 "New FID number wraps on vcp 0x%x", vcp);
1553 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1554 char eventName[MAX_PATH];
1556 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1557 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1558 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1559 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1560 thrd_CloseHandle(event);
1562 if (fid == 0xFFFF) {
1563 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1569 fidp = malloc(sizeof(*fidp));
1570 memset(fidp, 0, sizeof(*fidp));
1571 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1574 smb_HoldVCNoLock(vcp);
1575 lock_InitializeMutex(&fidp->mx, "fid_t mutex", LOCK_HIERARCHY_SMB_FID);
1577 fidp->curr_chunk = fidp->prev_chunk = -2;
1578 fidp->raw_write_event = event;
1580 vcp->fidCounter = fid+1;
1581 if (vcp->fidCounter == 0xFFFF) {
1582 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1584 vcp->fidCounter = 1;
1589 #ifdef DEBUG_SMB_REFCOUNT
1591 afsi_log("%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1592 osi_Log4(smb_logp,"%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1595 lock_ReleaseWrite(&smb_rctLock);
1599 #ifdef DEBUG_SMB_REFCOUNT
1600 smb_fid_t *smb_FindFIDByScacheDbg(smb_vc_t *vcp, cm_scache_t * scp, char *file, long line)
1602 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1605 smb_fid_t *fidp = NULL;
1611 lock_ObtainWrite(&smb_rctLock);
1612 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1613 if (scp == fidp->scp) {
1618 #ifdef DEBUG_SMB_REFCOUNT
1620 afsi_log("%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1621 osi_Log4(smb_logp,"%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1624 lock_ReleaseWrite(&smb_rctLock);
1628 #ifdef DEBUG_SMB_REFCOUNT
1629 void smb_HoldFIDNoLockDbg(smb_fid_t *fidp, char *file, long line)
1631 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1634 lock_AssertWrite(&smb_rctLock);
1636 #ifdef DEBUG_SMB_REFCOUNT
1637 afsi_log("%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1638 osi_Log4(smb_logp,"%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1643 /* smb_ReleaseFID cannot be called while an cm_scache_t mutex lock is held */
1644 /* the sm_fid_t->mx and smb_rctLock must not be held */
1645 #ifdef DEBUG_SMB_REFCOUNT
1646 void smb_ReleaseFIDDbg(smb_fid_t *fidp, char *file, long line)
1648 void smb_ReleaseFID(smb_fid_t *fidp)
1651 cm_scache_t *scp = NULL;
1652 cm_user_t *userp = NULL;
1653 smb_vc_t *vcp = NULL;
1654 smb_ioctl_t *ioctlp;
1656 lock_ObtainMutex(&fidp->mx);
1657 lock_ObtainWrite(&smb_rctLock);
1658 osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
1659 #ifdef DEBUG_SMB_REFCOUNT
1660 afsi_log("%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1661 osi_Log5(smb_logp,"%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1663 if (fidp->refCount == 0) {
1664 if (fidp->deleteOk) {
1667 scp = fidp->scp; /* release after lock is released */
1669 lock_ObtainWrite(&scp->rw);
1670 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1671 lock_ReleaseWrite(&scp->rw);
1672 osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1675 userp = fidp->userp;
1679 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1680 thrd_CloseHandle(fidp->raw_write_event);
1682 /* and see if there is ioctl stuff to free */
1683 ioctlp = fidp->ioctlp;
1686 cm_FreeSpace(ioctlp->prefix);
1687 if (ioctlp->ioctl.inAllocp)
1688 free(ioctlp->ioctl.inAllocp);
1689 if (ioctlp->ioctl.outAllocp)
1690 free(ioctlp->ioctl.outAllocp);
1693 lock_ReleaseMutex(&fidp->mx);
1694 lock_FinalizeMutex(&fidp->mx);
1699 smb_ReleaseVCNoLock(vcp);
1703 lock_ReleaseMutex(&fidp->mx);
1705 lock_ReleaseWrite(&smb_rctLock);
1707 /* now release the scache structure */
1709 cm_ReleaseSCache(scp);
1712 cm_ReleaseUser(userp);
1716 * Case-insensitive search for one string in another;
1717 * used to find variable names in submount pathnames.
1719 static clientchar_t *smb_stristr(clientchar_t *str1, clientchar_t *str2)
1721 clientchar_t *cursor;
1723 for (cursor = str1; *cursor; cursor++)
1724 if (cm_ClientStrCmpI(cursor, str2) == 0)
1731 * Substitute a variable value for its name in a submount pathname. Variable
1732 * name has been identified by smb_stristr() and is in substr. Variable name
1733 * length (plus one) is in substr_size. Variable value is in newstr.
1735 static void smb_subst(clientchar_t *str1, int cchstr1, clientchar_t *substr,
1736 unsigned int substr_size, clientchar_t *newstr)
1738 clientchar_t temp[1024];
1740 cm_ClientStrCpy(temp, lengthof(temp), substr + substr_size - 1);
1741 cm_ClientStrCpy(substr, cchstr1 - (substr - str1), newstr);
1742 cm_ClientStrCat(str1, cchstr1, temp);
1745 clientchar_t VNUserName[] = _C("%USERNAME%");
1746 clientchar_t VNLCUserName[] = _C("%LCUSERNAME%");
1747 clientchar_t VNComputerName[] = _C("%COMPUTERNAME%");
1748 clientchar_t VNLCComputerName[] = _C("%LCCOMPUTERNAME%");
1750 typedef struct smb_findShare_rock {
1751 clientchar_t * shareName;
1752 clientchar_t * match;
1754 } smb_findShare_rock_t;
1756 #define SMB_FINDSHARE_EXACT_MATCH 1
1757 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1759 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1763 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1764 normchar_t normName[MAX_PATH];
1766 cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(normName[0]));
1768 if (!cm_ClientStrCmpNI(normName, vrock->shareName, 12)) {
1769 if(!cm_ClientStrCmpI(normName, vrock->shareName))
1770 matchType = SMB_FINDSHARE_EXACT_MATCH;
1772 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1773 if(vrock->match) free(vrock->match);
1774 vrock->match = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
1775 vrock->matchType = matchType;
1777 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1778 return CM_ERROR_STOPNOW;
1784 /* find a shareName in the table of submounts */
1785 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp,
1786 clientchar_t *shareName,
1787 clientchar_t **pathNamep)
1791 clientchar_t pathName[1024];
1794 clientchar_t *p, *q;
1795 fschar_t *cellname = NULL;
1798 DWORD allSubmount = 1;
1800 /* if allSubmounts == 0, only return the //mountRoot/all share
1801 * if in fact it has been been created in the subMounts table.
1802 * This is to allow sites that want to restrict access to the
1805 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1806 0, KEY_QUERY_VALUE, &parmKey);
1807 if (code == ERROR_SUCCESS) {
1808 cblen = sizeof(allSubmount);
1809 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1810 (BYTE *) &allSubmount, &cblen);
1811 if (code != ERROR_SUCCESS) {
1814 RegCloseKey (parmKey);
1817 if (allSubmount && cm_ClientStrCmpI(shareName, _C("all")) == 0) {
1822 /* In case, the all share is disabled we need to still be able
1823 * to handle ioctl requests
1825 if (cm_ClientStrCmpI(shareName, _C("ioctl$")) == 0) {
1826 *pathNamep = cm_ClientStrDup(_C("/.__ioctl__"));
1830 if (cm_ClientStrCmpIA(shareName, _C("IPC$")) == 0 ||
1831 cm_ClientStrCmpIA(shareName, _C("srvsvc")) == 0 ||
1832 cm_ClientStrCmpIA(shareName, _C("wkssvc")) == 0 ||
1833 cm_ClientStrCmpIA(shareName, _C(SMB_IOCTL_FILENAME_NOSLASH)) == 0 ||
1834 cm_ClientStrCmpIA(shareName, _C("DESKTOP.INI")) == 0
1840 /* Check for volume references
1842 * They look like <cell>{%,#}<volume>
1844 if (cm_ClientStrChr(shareName, '%') != NULL ||
1845 cm_ClientStrChr(shareName, '#') != NULL) {
1846 clientchar_t pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
1847 /* make room for '/@vol:' + mountchar + NULL terminator*/
1849 osi_Log1(smb_logp, "smb_FindShare found volume reference [%S]",
1850 osi_LogSaveClientString(smb_logp, shareName));
1852 cm_ClientStrPrintfN(pathstr, lengthof(pathstr),
1853 _C("/") _C(CM_PREFIX_VOL) _C("%s"), shareName);
1854 cchlen = (DWORD)(cm_ClientStrLen(pathstr) + 1);
1856 *pathNamep = malloc(cchlen * sizeof(clientchar_t));
1858 cm_ClientStrCpy(*pathNamep, cchlen, pathstr);
1859 cm_ClientStrLwr(*pathNamep);
1860 osi_Log1(smb_logp, " returning pathname [%S]",
1861 osi_LogSaveClientString(smb_logp, *pathNamep));
1869 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1870 0, KEY_QUERY_VALUE, &parmKey);
1871 if (code == ERROR_SUCCESS) {
1872 cblen = sizeof(pathName);
1873 code = RegQueryValueExW(parmKey, shareName, NULL, NULL,
1874 (BYTE *) pathName, &cblen);
1875 if (code != ERROR_SUCCESS)
1877 RegCloseKey (parmKey);
1881 cchlen = cblen / sizeof(clientchar_t);
1882 if (cchlen != 0 && cchlen != lengthof(pathName) - 1) {
1883 /* We can accept either unix or PC style AFS pathnames. Convert
1884 * Unix-style to PC style here for internal use.
1887 cchlen = lengthof(pathName);
1889 /* within this code block, we maintain, cchlen = writeable
1890 buffer length of p */
1892 if (cm_ClientStrCmpN(p, cm_mountRootC, cm_mountRootCLen) == 0) {
1893 p += cm_mountRootCLen; /* skip mount path */
1894 cchlen -= (DWORD)(p - pathName);
1899 if (*q == _C('/')) *q = _C('\\'); /* change to \ */
1905 clientchar_t temp[1024];
1907 if (var = smb_stristr(p, VNUserName)) {
1908 if (uidp && uidp->unp)
1909 smb_subst(p, cchlen, var, lengthof(VNUserName),uidp->unp->name);
1911 smb_subst(p, cchlen, var, lengthof(VNUserName), _C(" "));
1913 else if (var = smb_stristr(p, VNLCUserName))
1915 if (uidp && uidp->unp)
1916 cm_ClientStrCpy(temp, lengthof(temp), uidp->unp->name);
1918 cm_ClientStrCpy(temp, lengthof(temp), _C(" "));
1919 cm_ClientStrLwr(temp);
1920 smb_subst(p, cchlen, var, lengthof(VNLCUserName), temp);
1922 else if (var = smb_stristr(p, VNComputerName))
1924 sizeTemp = lengthof(temp);
1925 GetComputerNameW(temp, &sizeTemp);
1926 smb_subst(p, cchlen, var, lengthof(VNComputerName), temp);
1928 else if (var = smb_stristr(p, VNLCComputerName))
1930 sizeTemp = lengthof(temp);
1931 GetComputerName((LPTSTR)temp, &sizeTemp);
1932 cm_ClientStrLwr(temp);
1933 smb_subst(p, cchlen, var, lengthof(VNLCComputerName), temp);
1938 *pathNamep = cm_ClientStrDup(p);
1943 /* First lookup shareName in root.afs */
1945 smb_findShare_rock_t vrock;
1947 fschar_t ftemp[1024];
1948 clientchar_t * p = shareName;
1951 /* attempt to locate a partial match in root.afs. This is because
1952 when using the ANSI RAP calls, the share name is limited to 13 chars
1953 and hence is truncated. Of course we prefer exact matches. */
1955 thyper.HighPart = 0;
1958 vrock.shareName = cm_ClientStringToNormStringAlloc(shareName, -1, NULL);
1960 vrock.matchType = 0;
1962 cm_HoldSCache(cm_data.rootSCachep);
1963 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1964 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1965 cm_ReleaseSCache(cm_data.rootSCachep);
1967 free(vrock.shareName);
1968 vrock.shareName = NULL;
1970 if (vrock.matchType) {
1971 cm_ClientStrPrintfN(pathName, lengthof(pathName), _C("/%s/"), vrock.match);
1972 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
1977 /* if we get here, there was no match for the share in root.afs */
1978 /* so try to create \\<netbiosName>\<cellname> */
1983 /* Get the full name for this cell */
1984 cellname = cm_ClientStringToFsStringAlloc(p, -1, NULL);
1985 code = cm_SearchCellFile(cellname, ftemp, 0, 0);
1986 #ifdef AFS_AFSDB_ENV
1987 if (code && cm_dnsEnabled) {
1989 code = cm_SearchCellByDNS(cellname, ftemp, &ttl, 0, 0);
1995 /* construct the path */
1997 clientchar_t temp[1024];
1999 cm_FsStringToClientString(ftemp, -1, temp, 1024);
2000 cm_ClientStrPrintfN(pathName, (int)lengthof(pathName),
2001 rw ? _C("/.%S/") : _C("/%S/"), temp);
2002 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
2011 /* Client-side offline caching policy types */
2012 #define CSC_POLICY_MANUAL 0
2013 #define CSC_POLICY_DOCUMENTS 1
2014 #define CSC_POLICY_PROGRAMS 2
2015 #define CSC_POLICY_DISABLE 3
2017 int smb_FindShareCSCPolicy(clientchar_t *shareName)
2020 clientchar_t policy[1024];
2023 int retval = CSC_POLICY_MANUAL;
2025 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
2026 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
2029 REG_OPTION_NON_VOLATILE,
2035 len = sizeof(policy);
2036 if ( RegQueryValueExW( hkCSCPolicy, shareName, 0, &dwType, (LPBYTE) policy, &len ) ||
2038 retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
2040 else if (cm_ClientStrCmpIA(policy, _C("documents")) == 0)
2042 retval = CSC_POLICY_DOCUMENTS;
2044 else if (cm_ClientStrCmpIA(policy, _C("programs")) == 0)
2046 retval = CSC_POLICY_PROGRAMS;
2048 else if (cm_ClientStrCmpIA(policy, _C("disable")) == 0)
2050 retval = CSC_POLICY_DISABLE;
2053 RegCloseKey(hkCSCPolicy);
2057 /* find a dir search structure by cookie value, and return it held.
2058 * Must be called with smb_globalLock held.
2060 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
2062 smb_dirSearch_t *dsp;
2064 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2065 if (dsp->cookie == cookie) {
2066 if (dsp != smb_firstDirSearchp) {
2067 /* move to head of LRU queue, too, if we're not already there */
2068 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
2069 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2070 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2071 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2072 if (!smb_lastDirSearchp)
2073 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2081 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
2082 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2083 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
2089 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
2091 lock_ObtainMutex(&dsp->mx);
2092 osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p",
2093 dsp->cookie, dsp, dsp->scp);
2094 dsp->flags |= SMB_DIRSEARCH_DELETE;
2095 if (dsp->scp != NULL) {
2096 lock_ObtainWrite(&dsp->scp->rw);
2097 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
2098 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2099 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2100 dsp->scp->bulkStatProgress = hzero;
2102 lock_ReleaseWrite(&dsp->scp->rw);
2104 lock_ReleaseMutex(&dsp->mx);
2107 /* Must be called with the smb_globalLock held */
2108 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
2110 cm_scache_t *scp = NULL;
2112 osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
2113 if (dsp->refCount == 0) {
2114 lock_ObtainMutex(&dsp->mx);
2115 if (dsp->flags & SMB_DIRSEARCH_DELETE) {
2116 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
2117 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
2118 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2119 lock_ReleaseMutex(&dsp->mx);
2120 lock_FinalizeMutex(&dsp->mx);
2122 osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p",
2123 dsp->cookie, dsp, scp);
2126 lock_ReleaseMutex(&dsp->mx);
2129 /* do this now to avoid spurious locking hierarchy creation */
2131 cm_ReleaseSCache(scp);
2134 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
2136 lock_ObtainWrite(&smb_globalLock);
2137 smb_ReleaseDirSearchNoLock(dsp);
2138 lock_ReleaseWrite(&smb_globalLock);
2141 /* find a dir search structure by cookie value, and return it held */
2142 smb_dirSearch_t *smb_FindDirSearch(long cookie)
2144 smb_dirSearch_t *dsp;
2146 lock_ObtainWrite(&smb_globalLock);
2147 dsp = smb_FindDirSearchNoLock(cookie);
2148 lock_ReleaseWrite(&smb_globalLock);
2152 /* GC some dir search entries, in the address space expected by the specific protocol.
2153 * Must be called with smb_globalLock held; release the lock temporarily.
2155 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
2156 void smb_GCDirSearches(int isV3)
2158 smb_dirSearch_t *prevp;
2159 smb_dirSearch_t *dsp;
2160 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
2164 victimCount = 0; /* how many have we got so far */
2165 for (dsp = smb_lastDirSearchp; dsp; dsp=prevp) {
2166 /* we'll move tp from queue, so
2169 prevp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2170 /* if no one is using this guy, and we're either in the new protocol,
2171 * or we're in the old one and this is a small enough ID to be useful
2172 * to the old protocol, GC this guy.
2174 if (dsp->refCount == 0 && (isV3 || dsp->cookie <= 255)) {
2175 /* hold and delete */
2176 lock_ObtainMutex(&dsp->mx);
2177 dsp->flags |= SMB_DIRSEARCH_DELETE;
2178 lock_ReleaseMutex(&dsp->mx);
2179 victimsp[victimCount++] = dsp;
2183 /* don't do more than this */
2184 if (victimCount >= SMB_DIRSEARCH_GCMAX)
2188 /* now release them */
2189 for (i = 0; i < victimCount; i++) {
2190 smb_ReleaseDirSearchNoLock(victimsp[i]);
2194 /* function for allocating a dir search entry. We need these to remember enough context
2195 * since we don't get passed the path from call to call during a directory search.
2197 * Returns a held dir search structure, and bumps the reference count on the vnode,
2198 * since it saves a pointer to the vnode.
2200 smb_dirSearch_t *smb_NewDirSearch(int isV3)
2202 smb_dirSearch_t *dsp;
2208 lock_ObtainWrite(&smb_globalLock);
2211 /* what's the biggest ID allowed in this version of the protocol */
2212 /* TODO: do we really want a non v3 dir search request to wrap
2213 smb_dirSearchCounter? */
2214 maxAllowed = isV3 ? 65535 : 255;
2215 if (smb_dirSearchCounter > maxAllowed)
2216 smb_dirSearchCounter = 1;
2218 start = smb_dirSearchCounter;
2221 /* twice so we have enough tries to find guys we GC after one pass;
2222 * 10 extra is just in case I mis-counted.
2224 if (++counter > 2*maxAllowed+10)
2225 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2227 if (smb_dirSearchCounter > maxAllowed) {
2228 smb_dirSearchCounter = 1;
2230 if (smb_dirSearchCounter == start) {
2232 smb_GCDirSearches(isV3);
2235 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2237 /* don't need to watch for refcount zero and deleted, since
2238 * we haven't dropped the global lock.
2241 ++smb_dirSearchCounter;
2245 dsp = malloc(sizeof(*dsp));
2246 memset(dsp, 0, sizeof(*dsp));
2247 dsp->cookie = smb_dirSearchCounter;
2248 ++smb_dirSearchCounter;
2250 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t", LOCK_HIERARCHY_SMB_DIRSEARCH);
2251 dsp->lastTime = osi_Time();
2252 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2253 if (!smb_lastDirSearchp)
2254 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2256 osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p",
2260 lock_ReleaseWrite(&smb_globalLock);
2264 static smb_packet_t *smb_GetPacket(void)
2268 lock_ObtainWrite(&smb_globalLock);
2269 tbp = smb_packetFreeListp;
2271 smb_packetFreeListp = tbp->nextp;
2272 lock_ReleaseWrite(&smb_globalLock);
2274 tbp = calloc(sizeof(*tbp),1);
2275 tbp->magic = SMB_PACKETMAGIC;
2278 tbp->resumeCode = 0;
2284 tbp->ncb_length = 0;
2287 tbp->stringsp = NULL;
2289 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2294 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2297 tbp = smb_GetPacket();
2298 memcpy(tbp, pkt, sizeof(smb_packet_t));
2299 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2300 tbp->stringsp = NULL;
2302 smb_HoldVC(tbp->vcp);
2306 static NCB *smb_GetNCB(void)
2311 lock_ObtainWrite(&smb_globalLock);
2312 tbp = smb_ncbFreeListp;
2314 smb_ncbFreeListp = tbp->nextp;
2315 lock_ReleaseWrite(&smb_globalLock);
2317 tbp = calloc(sizeof(*tbp),1);
2318 tbp->magic = SMB_NCBMAGIC;
2321 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2323 memset(&tbp->ncb, 0, sizeof(NCB));
2328 static void FreeSMBStrings(smb_packet_t * pkt)
2333 for (s = pkt->stringsp; s; s = ns) {
2337 pkt->stringsp = NULL;
2340 void smb_FreePacket(smb_packet_t *tbp)
2342 smb_vc_t * vcp = NULL;
2343 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2345 lock_ObtainWrite(&smb_globalLock);
2346 tbp->nextp = smb_packetFreeListp;
2347 smb_packetFreeListp = tbp;
2348 tbp->magic = SMB_PACKETMAGIC;
2352 tbp->resumeCode = 0;
2358 tbp->ncb_length = 0;
2360 FreeSMBStrings(tbp);
2361 lock_ReleaseWrite(&smb_globalLock);
2367 static void smb_FreeNCB(NCB *bufferp)
2371 tbp = (smb_ncb_t *) bufferp;
2372 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2374 lock_ObtainWrite(&smb_globalLock);
2375 tbp->nextp = smb_ncbFreeListp;
2376 smb_ncbFreeListp = tbp;
2377 lock_ReleaseWrite(&smb_globalLock);
2380 /* get a ptr to the data part of a packet, and its count */
2381 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2385 unsigned char *afterParmsp;
2387 parmBytes = *smbp->wctp << 1;
2388 afterParmsp = smbp->wctp + parmBytes + 1;
2390 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2391 if (nbytesp) *nbytesp = dataBytes;
2393 /* don't forget to skip the data byte count, since it follows
2394 * the parameters; that's where the "2" comes from below.
2396 return (unsigned char *) (afterParmsp + 2);
2399 /* must set all the returned parameters before playing around with the
2400 * data region, since the data region is located past the end of the
2401 * variable number of parameters.
2403 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2405 unsigned char *afterParmsp;
2407 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2409 *afterParmsp++ = dsize & 0xff;
2410 *afterParmsp = (dsize>>8) & 0xff;
2413 /* return the parm'th parameter in the smbp packet */
2414 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2417 unsigned char *parmDatap;
2419 parmCount = *smbp->wctp;
2421 if (parm >= parmCount) {
2424 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2425 parm, parmCount, smbp->ncb_length);
2426 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2427 parm, parmCount, smbp->ncb_length);
2428 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2429 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2430 osi_panic(s, __FILE__, __LINE__);
2432 parmDatap = smbp->wctp + (2*parm) + 1;
2434 return parmDatap[0] + (parmDatap[1] << 8);
2437 /* return the parm'th parameter in the smbp packet */
2438 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2441 unsigned char *parmDatap;
2443 parmCount = *smbp->wctp;
2445 if (parm >= parmCount) {
2448 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2449 parm, parmCount, smbp->ncb_length);
2450 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2451 parm, parmCount, smbp->ncb_length);
2452 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2453 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2454 osi_panic(s, __FILE__, __LINE__);
2456 parmDatap = smbp->wctp + (2*parm) + 1;
2458 return parmDatap[0];
2461 /* return the parm'th parameter in the smbp packet */
2462 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2465 unsigned char *parmDatap;
2467 parmCount = *smbp->wctp;
2469 if (parm + 1 >= parmCount) {
2472 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2473 parm, parmCount, smbp->ncb_length);
2474 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2475 parm, parmCount, smbp->ncb_length);
2476 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2477 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2478 osi_panic(s, __FILE__, __LINE__);
2480 parmDatap = smbp->wctp + (2*parm) + 1;
2482 return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2485 /* return the parm'th parameter in the smbp packet */
2486 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2489 unsigned char *parmDatap;
2491 parmCount = *smbp->wctp;
2493 if (parm * 2 + offset >= parmCount * 2) {
2496 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2497 parm, offset, parmCount, smbp->ncb_length);
2498 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2499 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2500 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2501 parm, offset, parmCount, smbp->ncb_length);
2502 osi_panic(s, __FILE__, __LINE__);
2504 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2506 return parmDatap[0] + (parmDatap[1] << 8);
2509 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2511 unsigned char *parmDatap;
2513 /* make sure we have enough slots */
2514 if (*smbp->wctp <= slot)
2515 *smbp->wctp = slot+1;
2517 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2518 *parmDatap++ = parmValue & 0xff;
2519 *parmDatap = (parmValue>>8) & 0xff;
2522 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2524 unsigned char *parmDatap;
2526 /* make sure we have enough slots */
2527 if (*smbp->wctp <= slot)
2528 *smbp->wctp = slot+2;
2530 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2531 *parmDatap++ = parmValue & 0xff;
2532 *parmDatap++ = (parmValue>>8) & 0xff;
2533 *parmDatap++ = (parmValue>>16) & 0xff;
2534 *parmDatap = (parmValue>>24) & 0xff;
2537 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2539 unsigned char *parmDatap;
2542 /* make sure we have enough slots */
2543 if (*smbp->wctp <= slot)
2544 *smbp->wctp = slot+4;
2546 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2548 *parmDatap++ = *parmValuep++;
2551 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2553 unsigned char *parmDatap;
2555 /* make sure we have enough slots */
2556 if (*smbp->wctp <= slot) {
2557 if (smbp->oddByte) {
2559 *smbp->wctp = slot+1;
2564 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2565 *parmDatap++ = parmValue & 0xff;
2570 void smb_StripLastComponent(clientchar_t *outPathp, clientchar_t **lastComponentp,
2571 clientchar_t *inPathp)
2573 clientchar_t *lastSlashp;
2575 lastSlashp = cm_ClientStrRChr(inPathp, '\\');
2577 *lastComponentp = lastSlashp;
2580 if (inPathp == lastSlashp)
2582 *outPathp++ = *inPathp++;
2591 clientchar_t *smb_ParseASCIIBlock(smb_packet_t * pktp, unsigned char *inp,
2592 char **chainpp, int flags)
2600 if (!WANTS_UNICODE(pktp))
2601 flags |= SMB_STRF_FORCEASCII;
2604 cb = sizeof(pktp->data) - (inp - pktp->data);
2605 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2606 #ifdef DEBUG_UNICODE
2609 cb = sizeof(pktp->data);
2611 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2614 clientchar_t *smb_ParseString(smb_packet_t * pktp, unsigned char * inp,
2615 char ** chainpp, int flags)
2620 if (!WANTS_UNICODE(pktp))
2621 flags |= SMB_STRF_FORCEASCII;
2624 cb = sizeof(pktp->data) - (inp - pktp->data);
2625 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2626 #ifdef DEBUG_UNICODE
2629 cb = sizeof(pktp->data);
2631 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp,
2632 flags | SMB_STRF_SRCNULTERM);
2635 clientchar_t *smb_ParseStringCb(smb_packet_t * pktp, unsigned char * inp,
2636 size_t cb, char ** chainpp, int flags)
2639 if (!WANTS_UNICODE(pktp))
2640 flags |= SMB_STRF_FORCEASCII;
2643 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2646 clientchar_t *smb_ParseStringCch(smb_packet_t * pktp, unsigned char * inp,
2647 size_t cch, char ** chainpp, int flags)
2652 if (!WANTS_UNICODE(pktp))
2653 flags |= SMB_STRF_FORCEASCII;
2655 cb = cch * sizeof(wchar_t);
2658 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2662 smb_ParseStringBuf(const unsigned char * bufbase,
2663 cm_space_t ** stringspp,
2664 unsigned char *inp, size_t *pcb_max,
2665 char **chainpp, int flags)
2668 if (!(flags & SMB_STRF_FORCEASCII)) {
2670 cm_space_t * spacep;
2673 if (bufbase && ((inp - bufbase) % 2) != 0) {
2674 inp++; /* unicode strings are always word aligned */
2678 if (FAILED(StringCchLengthW((const wchar_t *) inp, *pcb_max / sizeof(wchar_t),
2680 cch_src = *pcb_max / sizeof(wchar_t);
2684 *pcb_max -= (cch_src + 1) * sizeof(wchar_t);
2691 spacep = cm_GetSpace();
2692 spacep->nextp = *stringspp;
2693 *stringspp = spacep;
2697 *chainpp = inp + sizeof(wchar_t);
2700 *(spacep->wdata) = 0;
2701 return spacep->wdata;
2704 StringCchCopyNW(spacep->wdata,
2705 lengthof(spacep->wdata),
2706 (const clientchar_t *) inp, cch_src);
2709 *chainpp = inp + (cch_src + null_terms)*sizeof(wchar_t);
2711 return spacep->wdata;
2715 cm_space_t * spacep;
2718 /* Not using Unicode */
2720 *chainpp = inp + strlen(inp) + 1;
2723 spacep = cm_GetSpace();
2724 spacep->nextp = *stringspp;
2725 *stringspp = spacep;
2727 cchdest = lengthof(spacep->wdata);
2728 cm_Utf8ToUtf16(inp, (int)((flags & SMB_STRF_SRCNULTERM)? -1 : *pcb_max),
2729 spacep->wdata, cchdest);
2731 return spacep->wdata;
2737 unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
2739 size_t * plen, int flags)
2745 /* we are only calculating the required size */
2752 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2754 StringCbLengthW(str, SMB_STRINGBUFSIZE * sizeof(wchar_t), plen);
2755 if (!(flags & SMB_STRF_IGNORENUL))
2756 *plen += sizeof(wchar_t);
2758 return (unsigned char *) 1; /* return TRUE if we are using unicode */
2768 cch_str = cm_ClientStrLen(str);
2769 cch_dest = cm_ClientStringToUtf8(str, (int)cch_str, NULL, 0);
2772 *plen = ((flags & SMB_STRF_IGNORENUL)? cch_dest: cch_dest+1);
2780 /* if outp != NULL ... */
2782 /* Number of bytes left in the buffer.
2784 If outp lies inside the packet data buffer, we assume that the
2785 buffer is the packet data buffer. Otherwise we assume that the
2786 buffer is sizeof(packet->data).
2789 if (outp >= pktp->data && outp < pktp->data + sizeof(pktp->data)) {
2790 align = (int)((outp - pktp->data) % 2);
2791 buffersize = (pktp->data + sizeof(pktp->data)) - ((char *) outp);
2793 align = (int)(((size_t) outp) % 2);
2794 buffersize = (int)sizeof(pktp->data);
2799 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2805 if (*str == _C('\0')) {
2807 if (buffersize < sizeof(wchar_t))
2810 *((wchar_t *) outp) = L'\0';
2811 if (plen && !(flags & SMB_STRF_IGNORENUL))
2812 *plen += sizeof(wchar_t);
2813 return outp + sizeof(wchar_t);
2816 nchars = cm_ClientStringToUtf16(str, -1, (wchar_t *) outp, (int)(buffersize / sizeof(wchar_t)));
2818 osi_Log2(smb_logp, "UnparseString: Can't convert string to Unicode [%S], GLE=%d",
2819 osi_LogSaveClientString(smb_logp, str),
2825 *plen += sizeof(wchar_t) * ((flags & SMB_STRF_IGNORENUL)? nchars - 1: nchars);
2827 return outp + sizeof(wchar_t) * nchars;
2835 cch_dest = cm_ClientStringToUtf8(str, -1, outp, (int)buffersize);
2838 *plen += ((flags & SMB_STRF_IGNORENUL)? cch_dest - 1: cch_dest);
2840 return outp + cch_dest;
2844 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2850 tlen = inp[0] + (inp[1]<<8);
2851 inp += 2; /* skip length field */
2854 *chainpp = inp + tlen;
2863 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2867 if (*inp++ != 0x1) return NULL;
2868 tlen = inp[0] + (inp[1]<<8);
2869 inp += 2; /* skip length field */
2872 *chainpp = inp + tlen;
2875 if (lengthp) *lengthp = tlen;
2880 /* format a packet as a response */
2881 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2886 outp = (smb_t *) op;
2888 /* zero the basic structure through the smb_wct field, and zero the data
2889 * size field, assuming that wct stays zero; otherwise, you have to
2890 * explicitly set the data size field, too.
2892 inSmbp = (smb_t *) inp;
2893 memset(outp, 0, sizeof(smb_t)+2);
2899 outp->com = inSmbp->com;
2900 outp->tid = inSmbp->tid;
2901 outp->pid = inSmbp->pid;
2902 outp->uid = inSmbp->uid;
2903 outp->mid = inSmbp->mid;
2904 outp->res[0] = inSmbp->res[0];
2905 outp->res[1] = inSmbp->res[1];
2906 op->inCom = inSmbp->com;
2908 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
2909 #ifdef SEND_CANONICAL_PATHNAMES
2910 outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
2912 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2914 if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
2915 outp->flg2 |= SMB_FLAGS2_UNICODE;
2918 /* copy fields in generic packet area */
2919 op->wctp = &outp->wct;
2922 /* send a (probably response) packet; vcp tells us to whom to send it.
2923 * we compute the length by looking at wct and bcc fields.
2925 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2935 ncbp = smb_GetNCB();
2939 memset((char *)ncbp, 0, sizeof(NCB));
2941 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2942 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2943 extra += tp[0] + (tp[1]<<8);
2944 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
2945 extra += 3; /* wct and length fields */
2947 ncbp->ncb_length = extra; /* bytes to send */
2948 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2949 ncbp->ncb_lana_num = vcp->lana;
2950 ncbp->ncb_command = NCBSEND; /* op means send data */
2951 ncbp->ncb_buffer = (char *) inp;/* packet */
2952 code = Netbios(ncbp);
2955 const char * s = ncb_error_string(code);
2956 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2957 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
2959 lock_ObtainMutex(&vcp->mx);
2960 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
2961 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
2963 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2964 lock_ReleaseMutex(&vcp->mx);
2965 lock_ObtainWrite(&smb_globalLock);
2966 dead_sessions[vcp->session] = TRUE;
2967 lock_ReleaseWrite(&smb_globalLock);
2968 smb_CleanupDeadVC(vcp);
2970 lock_ReleaseMutex(&vcp->mx);
2978 void smb_MapNTError(long code, unsigned long *NTStatusp)
2980 unsigned long NTStatus;
2982 /* map CM_ERROR_* errors to NT 32-bit status codes */
2983 /* NT Status codes are listed in ntstatus.h not winerror.h */
2984 if (code == CM_ERROR_NOSUCHCELL) {
2985 NTStatus = 0xC000000FL; /* No such file */
2987 else if (code == CM_ERROR_NOSUCHVOLUME) {
2988 NTStatus = 0xC000000FL; /* No such file */
2990 else if (code == CM_ERROR_TIMEDOUT) {
2992 NTStatus = 0xC00000CFL; /* Sharing Paused */
2994 NTStatus = 0x00000102L; /* Timeout */
2997 else if (code == CM_ERROR_RETRY) {
2998 NTStatus = 0xC000022DL; /* Retry */
3000 else if (code == CM_ERROR_NOACCESS) {
3001 NTStatus = 0xC0000022L; /* Access denied */
3003 else if (code == CM_ERROR_READONLY) {
3004 NTStatus = 0xC00000A2L; /* Write protected */
3006 else if (code == CM_ERROR_NOSUCHFILE ||
3007 code == CM_ERROR_BPLUS_NOMATCH) {
3008 NTStatus = 0xC000000FL; /* No such file */
3010 else if (code == CM_ERROR_NOSUCHPATH) {
3011 NTStatus = 0xC000003AL; /* Object path not found */
3013 else if (code == CM_ERROR_TOOBIG) {
3014 NTStatus = 0xC000007BL; /* Invalid image format */
3016 else if (code == CM_ERROR_INVAL) {
3017 NTStatus = 0xC000000DL; /* Invalid parameter */
3019 else if (code == CM_ERROR_BADFD) {
3020 NTStatus = 0xC0000008L; /* Invalid handle */
3022 else if (code == CM_ERROR_BADFDOP) {
3023 NTStatus = 0xC0000022L; /* Access denied */
3025 else if (code == CM_ERROR_EXISTS) {
3026 NTStatus = 0xC0000035L; /* Object name collision */
3028 else if (code == CM_ERROR_NOTEMPTY) {
3029 NTStatus = 0xC0000101L; /* Directory not empty */
3031 else if (code == CM_ERROR_CROSSDEVLINK) {
3032 NTStatus = 0xC00000D4L; /* Not same device */
3034 else if (code == CM_ERROR_NOTDIR) {
3035 NTStatus = 0xC0000103L; /* Not a directory */
3037 else if (code == CM_ERROR_ISDIR) {
3038 NTStatus = 0xC00000BAL; /* File is a directory */
3040 else if (code == CM_ERROR_BADOP) {
3042 /* I have no idea where this comes from */
3043 NTStatus = 0xC09820FFL; /* SMB no support */
3045 NTStatus = 0xC00000BBL; /* Not supported */
3046 #endif /* COMMENT */
3048 else if (code == CM_ERROR_BADSHARENAME) {
3049 NTStatus = 0xC00000CCL; /* Bad network name */
3051 else if (code == CM_ERROR_NOIPC) {
3053 NTStatus = 0xC0000022L; /* Access Denied */
3055 NTStatus = 0xC000013DL; /* Remote Resources */
3058 else if (code == CM_ERROR_CLOCKSKEW) {
3059 NTStatus = 0xC0000133L; /* Time difference at DC */
3061 else if (code == CM_ERROR_BADTID) {
3062 NTStatus = 0xC0982005L; /* SMB bad TID */
3064 else if (code == CM_ERROR_USESTD) {
3065 NTStatus = 0xC09820FBL; /* SMB use standard */
3067 else if (code == CM_ERROR_QUOTA) {
3068 NTStatus = 0xC0000044L; /* Quota exceeded */
3070 else if (code == CM_ERROR_SPACE) {
3071 NTStatus = 0xC000007FL; /* Disk full */
3073 else if (code == CM_ERROR_ATSYS) {
3074 NTStatus = 0xC0000033L; /* Object name invalid */
3076 else if (code == CM_ERROR_BADNTFILENAME) {
3077 NTStatus = 0xC0000033L; /* Object name invalid */
3079 else if (code == CM_ERROR_WOULDBLOCK) {
3080 NTStatus = 0xC0000055L; /* Lock not granted */
3082 else if (code == CM_ERROR_SHARING_VIOLATION) {
3083 NTStatus = 0xC0000043L; /* Sharing violation */
3085 else if (code == CM_ERROR_LOCK_CONFLICT) {
3086 NTStatus = 0xC0000054L; /* Lock conflict */
3088 else if (code == CM_ERROR_PARTIALWRITE) {
3089 NTStatus = 0xC000007FL; /* Disk full */
3091 else if (code == CM_ERROR_BUFFERTOOSMALL) {
3092 NTStatus = 0xC0000023L; /* Buffer too small */
3094 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3095 NTStatus = 0xC0000035L; /* Object name collision */
3097 else if (code == CM_ERROR_BADPASSWORD) {
3098 NTStatus = 0xC000006DL; /* unknown username or bad password */
3100 else if (code == CM_ERROR_BADLOGONTYPE) {
3101 NTStatus = 0xC000015BL; /* logon type not granted */
3103 else if (code == CM_ERROR_GSSCONTINUE) {
3104 NTStatus = 0xC0000016L; /* more processing required */
3106 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3108 NTStatus = 0xC0000280L; /* reparse point not resolved */
3110 NTStatus = 0xC0000022L; /* Access Denied */
3113 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3114 NTStatus = 0xC0000257L; /* Path Not Covered */
3116 else if (code == CM_ERROR_ALLBUSY) {
3117 NTStatus = 0xC000022DL; /* Retry */
3119 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3120 NTStatus = 0xC00000BEL; /* Bad Network Path */
3122 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3123 NTStatus = 0xC0000322L; /* No Kerberos key */
3125 else if (code == CM_ERROR_BAD_LEVEL) {
3126 NTStatus = 0xC0000148L; /* Invalid Level */
3128 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3129 NTStatus = 0xC000007EL; /* Range Not Locked */
3131 else if (code == CM_ERROR_NOSUCHDEVICE) {
3132 NTStatus = 0xC000000EL; /* No Such Device */
3134 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3135 NTStatus = 0xC0000055L; /* Lock Not Granted */
3137 NTStatus = 0xC0982001L; /* SMB non-specific error */
3140 *NTStatusp = NTStatus;
3141 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
3144 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
3145 unsigned char *classp)
3147 unsigned char class;
3148 unsigned short error;
3150 /* map CM_ERROR_* errors to SMB errors */
3151 if (code == CM_ERROR_NOSUCHCELL) {
3153 error = 3; /* bad path */
3155 else if (code == CM_ERROR_NOSUCHVOLUME) {
3157 error = 3; /* bad path */
3159 else if (code == CM_ERROR_TIMEDOUT) {
3161 error = 81; /* server is paused */
3163 else if (code == CM_ERROR_RETRY) {
3164 class = 2; /* shouldn't happen */
3167 else if (code == CM_ERROR_NOACCESS) {
3169 error = 4; /* bad access */
3171 else if (code == CM_ERROR_READONLY) {
3173 error = 19; /* read only */
3175 else if (code == CM_ERROR_NOSUCHFILE ||
3176 code == CM_ERROR_BPLUS_NOMATCH) {
3178 error = 2; /* ENOENT! */
3180 else if (code == CM_ERROR_NOSUCHPATH) {
3182 error = 3; /* Bad path */
3184 else if (code == CM_ERROR_TOOBIG) {
3186 error = 11; /* bad format */
3188 else if (code == CM_ERROR_INVAL) {
3189 class = 2; /* server non-specific error code */
3192 else if (code == CM_ERROR_BADFD) {
3194 error = 6; /* invalid file handle */
3196 else if (code == CM_ERROR_BADFDOP) {
3197 class = 1; /* invalid op on FD */
3200 else if (code == CM_ERROR_EXISTS) {
3202 error = 80; /* file already exists */
3204 else if (code == CM_ERROR_NOTEMPTY) {
3206 error = 5; /* delete directory not empty */
3208 else if (code == CM_ERROR_CROSSDEVLINK) {
3210 error = 17; /* EXDEV */
3212 else if (code == CM_ERROR_NOTDIR) {
3213 class = 1; /* bad path */
3216 else if (code == CM_ERROR_ISDIR) {
3217 class = 1; /* access denied; DOS doesn't have a good match */
3220 else if (code == CM_ERROR_BADOP) {
3224 else if (code == CM_ERROR_BADSHARENAME) {
3228 else if (code == CM_ERROR_NOIPC) {
3230 error = 4; /* bad access */
3232 else if (code == CM_ERROR_CLOCKSKEW) {
3233 class = 1; /* invalid function */
3236 else if (code == CM_ERROR_BADTID) {
3240 else if (code == CM_ERROR_USESTD) {
3244 else if (code == CM_ERROR_REMOTECONN) {
3248 else if (code == CM_ERROR_QUOTA) {
3249 if (vcp->flags & SMB_VCFLAG_USEV3) {
3251 error = 39; /* disk full */
3255 error = 5; /* access denied */
3258 else if (code == CM_ERROR_SPACE) {
3259 if (vcp->flags & SMB_VCFLAG_USEV3) {
3261 error = 39; /* disk full */
3265 error = 5; /* access denied */
3268 else if (code == CM_ERROR_PARTIALWRITE) {
3270 error = 39; /* disk full */
3272 else if (code == CM_ERROR_ATSYS) {
3274 error = 2; /* ENOENT */
3276 else if (code == CM_ERROR_WOULDBLOCK) {
3278 error = 33; /* lock conflict */
3280 else if (code == CM_ERROR_LOCK_CONFLICT) {
3282 error = 33; /* lock conflict */
3284 else if (code == CM_ERROR_SHARING_VIOLATION) {
3286 error = 33; /* lock conflict */
3288 else if (code == CM_ERROR_NOFILES) {
3290 error = 18; /* no files in search */
3292 else if (code == CM_ERROR_RENAME_IDENTICAL) {
3294 error = 183; /* Samba uses this */
3296 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
3297 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
3299 error = 2; /* bad password */
3301 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3303 error = 3; /* bad path */
3312 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
3315 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3317 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
3318 return CM_ERROR_BADOP;
3322 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3324 unsigned short EchoCount, i;
3325 char *data, *outdata;
3328 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
3330 for (i=1; i<=EchoCount; i++) {
3331 data = smb_GetSMBData(inp, &dataSize);
3332 smb_SetSMBParm(outp, 0, i);
3333 smb_SetSMBDataLength(outp, dataSize);
3334 outdata = smb_GetSMBData(outp, NULL);
3335 memcpy(outdata, data, dataSize);
3336 smb_SendPacket(vcp, outp);
3342 /* SMB_COM_READ_RAW */
3343 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3346 long count, minCount, finalCount;
3350 smb_t *smbp = (smb_t*) inp;
3352 cm_user_t *userp = NULL;
3355 char *rawBuf = NULL;
3360 fd = smb_GetSMBParm(inp, 0);
3361 count = smb_GetSMBParm(inp, 3);
3362 minCount = smb_GetSMBParm(inp, 4);
3363 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3365 if (*inp->wctp == 10) {
3366 /* we were sent a request with 64-bit file offsets */
3367 #ifdef AFS_LARGEFILES
3368 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
3370 if (LargeIntegerLessThanZero(offset)) {
3371 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
3375 if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
3376 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset. Dropping request.");
3379 offset.HighPart = 0;
3383 /* we were sent a request with 32-bit file offsets */
3384 offset.HighPart = 0;
3387 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
3388 fd, offset.HighPart, offset.LowPart, count);
3390 fidp = smb_FindFID(vcp, fd, 0);
3394 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3395 smb_CloseFID(vcp, fidp, NULL, 0);
3396 code = CM_ERROR_NOSUCHFILE;
3403 LARGE_INTEGER LOffset, LLength;
3406 key = cm_GenerateKey(vcp->vcID, pid, fd);
3408 LOffset.HighPart = offset.HighPart;
3409 LOffset.LowPart = offset.LowPart;
3410 LLength.HighPart = 0;
3411 LLength.LowPart = count;
3413 lock_ObtainWrite(&fidp->scp->rw);
3414 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
3415 lock_ReleaseWrite(&fidp->scp->rw);
3421 lock_ObtainMutex(&smb_RawBufLock);
3423 /* Get a raw buf, from head of list */
3424 rawBuf = smb_RawBufs;
3425 smb_RawBufs = *(char **)smb_RawBufs;
3427 lock_ReleaseMutex(&smb_RawBufLock);
3431 lock_ObtainMutex(&fidp->mx);
3432 if (fidp->flags & SMB_FID_IOCTL)
3434 lock_ReleaseMutex(&fidp->mx);
3435 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
3437 /* Give back raw buffer */
3438 lock_ObtainMutex(&smb_RawBufLock);
3439 *((char **) rawBuf) = smb_RawBufs;
3441 smb_RawBufs = rawBuf;
3442 lock_ReleaseMutex(&smb_RawBufLock);
3445 lock_ReleaseMutex(&fidp->mx);
3446 smb_ReleaseFID(fidp);
3449 lock_ReleaseMutex(&fidp->mx);
3451 userp = smb_GetUserFromVCP(vcp, inp);
3453 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
3459 cm_ReleaseUser(userp);
3462 smb_ReleaseFID(fidp);
3466 memset((char *)ncbp, 0, sizeof(NCB));
3468 ncbp->ncb_length = (unsigned short) finalCount;
3469 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
3470 ncbp->ncb_lana_num = vcp->lana;
3471 ncbp->ncb_command = NCBSEND;
3472 ncbp->ncb_buffer = rawBuf;
3474 code = Netbios(ncbp);
3476 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
3479 /* Give back raw buffer */
3480 lock_ObtainMutex(&smb_RawBufLock);
3481 *((char **) rawBuf) = smb_RawBufs;
3483 smb_RawBufs = rawBuf;
3484 lock_ReleaseMutex(&smb_RawBufLock);
3490 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3492 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3497 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3499 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3504 /* SMB_COM_NEGOTIATE */
3505 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3512 int VistaProtoIndex;
3513 int protoIndex; /* index we're using */
3518 char protocol_array[10][1024]; /* protocol signature of the client */
3519 int caps; /* capabilities */
3522 TIME_ZONE_INFORMATION tzi;
3524 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3527 namep = smb_GetSMBData(inp, &dbytes);
3530 coreProtoIndex = -1; /* not found */
3533 VistaProtoIndex = -1;
3534 while(namex < dbytes) {
3535 osi_Log1(smb_logp, "Protocol %s",
3536 osi_LogSaveString(smb_logp, namep+1));
3537 strcpy(protocol_array[tcounter], namep+1);
3539 /* namep points at the first protocol, or really, a 0x02
3540 * byte preceding the null-terminated ASCII name.
3542 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3543 coreProtoIndex = tcounter;
3545 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3546 v3ProtoIndex = tcounter;
3548 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3549 NTProtoIndex = tcounter;
3551 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3552 VistaProtoIndex = tcounter;
3555 /* compute size of protocol entry */
3556 entryLength = (int)strlen(namep+1);
3557 entryLength += 2; /* 0x02 bytes and null termination */
3559 /* advance over this protocol entry */
3560 namex += entryLength;
3561 namep += entryLength;
3562 tcounter++; /* which proto entry we're looking at */
3565 lock_ObtainMutex(&vcp->mx);
3567 if (VistaProtoIndex != -1) {
3568 protoIndex = VistaProtoIndex;
3569 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3572 if (NTProtoIndex != -1) {
3573 protoIndex = NTProtoIndex;
3574 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3576 else if (v3ProtoIndex != -1) {
3577 protoIndex = v3ProtoIndex;
3578 vcp->flags |= SMB_VCFLAG_USEV3;
3580 else if (coreProtoIndex != -1) {
3581 protoIndex = coreProtoIndex;
3582 vcp->flags |= SMB_VCFLAG_USECORE;
3584 else protoIndex = -1;
3585 lock_ReleaseMutex(&vcp->mx);
3587 if (protoIndex == -1)
3588 return CM_ERROR_INVAL;
3589 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3590 smb_SetSMBParm(outp, 0, protoIndex);
3591 if (smb_authType != SMB_AUTH_NONE) {
3592 smb_SetSMBParmByte(outp, 1,
3593 NEGOTIATE_SECURITY_USER_LEVEL |
3594 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3596 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3598 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3599 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3600 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3601 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3602 /* The session key is not a well documented field however most clients
3603 * will echo back the session key to the server. Currently we are using
3604 * the same value for all sessions. We should generate a random value
3605 * and store it into the vcp
3607 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3608 smb_SetSMBParm(outp, 8, 1);
3610 * Tried changing the capabilities to support for W2K - defect 117695
3611 * Maybe something else needs to be changed here?
3615 smb_SetSMBParmLong(outp, 9, 0x43fd);
3617 smb_SetSMBParmLong(outp, 9, 0x251);
3620 * 32-bit error codes *
3626 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3628 NTNEGOTIATE_CAPABILITY_DFS |
3630 #ifdef AFS_LARGEFILES
3631 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3633 NTNEGOTIATE_CAPABILITY_NTFIND |
3634 NTNEGOTIATE_CAPABILITY_RAWMODE |
3635 NTNEGOTIATE_CAPABILITY_NTSMB;
3637 if ( smb_authType == SMB_AUTH_EXTENDED )
3638 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3641 if ( smb_UseUnicode ) {
3642 caps |= NTNEGOTIATE_CAPABILITY_UNICODE;
3646 smb_SetSMBParmLong(outp, 9, caps);
3648 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3649 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3650 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3652 GetTimeZoneInformation(&tzi);
3653 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3655 if (smb_authType == SMB_AUTH_NTLM) {
3656 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3657 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3658 /* paste in encryption key */
3659 datap = smb_GetSMBData(outp, NULL);
3660 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3661 /* and the faux domain name */
3662 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3663 datap + MSV1_0_CHALLENGE_LENGTH,
3664 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3665 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3669 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3671 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3673 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3675 datap = smb_GetSMBData(outp, NULL);
3676 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3679 datap += sizeof(smb_ServerGUID);
3680 memcpy(datap, secBlob, secBlobLength);
3684 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3685 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3688 else if (v3ProtoIndex != -1) {
3689 smb_SetSMBParm(outp, 0, protoIndex);
3691 /* NOTE: Extended authentication cannot be negotiated with v3
3692 * therefore we fail over to NTLM
3694 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3695 smb_SetSMBParm(outp, 1,
3696 NEGOTIATE_SECURITY_USER_LEVEL |
3697 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3699 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3701 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3702 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3703 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3704 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3705 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3706 smb_SetSMBParm(outp, 7, 1);
3708 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3709 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3710 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3712 GetTimeZoneInformation(&tzi);
3713 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3715 /* NOTE: Extended authentication cannot be negotiated with v3
3716 * therefore we fail over to NTLM
3718 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3719 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3720 smb_SetSMBParm(outp, 12, 0); /* resvd */
3721 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3722 datap = smb_GetSMBData(outp, NULL);
3723 /* paste in a new encryption key */