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 #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 static int smb_Is8Dot3StarMask(clientchar_t *maskp)
922 for(i=0; i<11; i++) {
924 if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
930 static int smb_IsStarMask(clientchar_t *maskp)
937 if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
943 #ifdef DEBUG_SMB_REFCOUNT
944 void smb_ReleaseVCInternalDbg(smb_vc_t *vcp, char * file, long line)
945 #define smb_ReleaseVCInternal(a) smb_ReleaseVCInternalDbg(a, file, line)
947 void smb_ReleaseVCInternal(smb_vc_t *vcp)
953 lock_AssertWrite(&smb_rctLock);
956 if (vcp->refCount == 0) {
957 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
958 #ifdef DEBUG_SMB_REFCOUNT
959 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
960 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
962 /* remove VCP from smb_deadVCsp */
963 for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
969 lock_FinalizeMutex(&vcp->mx);
970 memset(vcp,0,sizeof(smb_vc_t));
973 #ifdef DEBUG_SMB_REFCOUNT
974 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is alive ref %d", file, line, vcp, vcp->refCount);
976 for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
980 osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
981 avcp?"":"not ",vcp, vcp->refCount);
983 /* This is a wrong. However, I suspect that there is an undercount
984 * and I don't want to release 1.4.1 in a state that will allow
985 * smb_vc_t objects to be deallocated while still in the
986 * smb_allVCsp list. The list is supposed to keep a reference
987 * to the smb_vc_t. Put it back.
991 #ifdef DEBUG_SMB_REFCOUNT
992 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
993 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
997 } else if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
998 /* The reference count is non-zero but the VC is dead.
999 * This implies that some FIDs, TIDs, etc on the VC have yet to
1000 * be cleaned up. If we were not called by smb_CleanupDeadVC(),
1001 * add a reference that will be dropped by
1002 * smb_CleanupDeadVC() and try to cleanup the VC again.
1003 * Eventually the refCount will drop to zero when all of the
1004 * active threads working with the VC end their task.
1006 if (!(vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS)) {
1007 vcp->refCount++; /* put the refCount back */
1008 lock_ReleaseWrite(&smb_rctLock);
1009 smb_CleanupDeadVC(vcp);
1010 #ifdef DEBUG_SMB_REFCOUNT
1011 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
1012 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
1014 lock_ObtainWrite(&smb_rctLock);
1017 #ifdef DEBUG_SMB_REFCOUNT
1018 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1019 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1024 #ifdef DEBUG_SMB_REFCOUNT
1025 void smb_ReleaseVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
1027 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
1030 lock_AssertWrite(&smb_rctLock);
1031 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
1032 smb_ReleaseVCInternal(vcp);
1035 #ifdef DEBUG_SMB_REFCOUNT
1036 void smb_ReleaseVCDbg(smb_vc_t *vcp, char * file, long line)
1038 void smb_ReleaseVC(smb_vc_t *vcp)
1041 lock_ObtainWrite(&smb_rctLock);
1042 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
1043 smb_ReleaseVCInternal(vcp);
1044 lock_ReleaseWrite(&smb_rctLock);
1047 #ifdef DEBUG_SMB_REFCOUNT
1048 void smb_HoldVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
1050 void smb_HoldVCNoLock(smb_vc_t *vcp)
1053 lock_AssertWrite(&smb_rctLock);
1055 #ifdef DEBUG_SMB_REFCOUNT
1056 afsi_log("%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1057 osi_Log4(smb_logp,"%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1059 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
1063 #ifdef DEBUG_SMB_REFCOUNT
1064 void smb_HoldVCDbg(smb_vc_t *vcp, char * file, long line)
1066 void smb_HoldVC(smb_vc_t *vcp)
1069 lock_ObtainWrite(&smb_rctLock);
1071 #ifdef DEBUG_SMB_REFCOUNT
1072 afsi_log("%s:%d smb_HoldVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1073 osi_Log4(smb_logp,"%s:%d smb_HoldVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1075 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
1077 lock_ReleaseWrite(&smb_rctLock);
1080 void smb_CleanupDeadVC(smb_vc_t *vcp)
1082 smb_fid_t *fidpIter;
1083 smb_fid_t *fidpNext;
1085 smb_tid_t *tidpIter;
1086 smb_tid_t *tidpNext;
1088 smb_user_t *uidpIter;
1089 smb_user_t *uidpNext;
1091 afs_uint32 refCount = 0;
1093 lock_ObtainMutex(&vcp->mx);
1094 if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
1095 lock_ReleaseMutex(&vcp->mx);
1096 osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
1099 vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
1100 lock_ReleaseMutex(&vcp->mx);
1101 osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
1103 lock_ObtainWrite(&smb_rctLock);
1104 /* remove VCP from smb_allVCsp */
1105 for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
1106 if ((*vcpp)->magic != SMB_VC_MAGIC)
1107 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
1108 __FILE__, __LINE__);
1111 vcp->nextp = smb_deadVCsp;
1113 /* Hold onto the reference until we are done with this function */
1118 for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
1119 fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
1121 if (fidpIter->deleteOk)
1124 fid = fidpIter->fid;
1125 osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1127 smb_HoldFIDNoLock(fidpIter);
1128 lock_ReleaseWrite(&smb_rctLock);
1130 smb_CloseFID(vcp, fidpIter, NULL, 0);
1131 smb_ReleaseFID(fidpIter);
1133 lock_ObtainWrite(&smb_rctLock);
1134 fidpNext = vcp->fidsp;
1137 for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1138 tidpNext = tidpIter->nextp;
1139 if (tidpIter->deleteOk)
1141 tidpIter->deleteOk = 1;
1143 tid = tidpIter->tid;
1144 osi_Log2(smb_logp, " Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1146 smb_HoldTIDNoLock(tidpIter);
1147 smb_ReleaseTID(tidpIter, TRUE);
1148 tidpNext = vcp->tidsp;
1151 for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1152 uidpNext = uidpIter->nextp;
1153 if (uidpIter->deleteOk)
1155 uidpIter->deleteOk = 1;
1157 /* do not add an additional reference count for the smb_user_t
1158 * as the smb_vc_t already is holding a reference */
1159 lock_ReleaseWrite(&smb_rctLock);
1161 smb_ReleaseUID(uidpIter);
1163 lock_ObtainWrite(&smb_rctLock);
1164 uidpNext = vcp->usersp;
1167 /* The vcp is now on the deadVCsp list. We intentionally drop the
1168 * reference so that the refcount can reach 0 and we can delete it
1170 * If the refCount == 1 going into the ReleaseVCNoLock call
1171 * the object will be freed and it won't be safe to clear
1174 refCount = vcp->refCount;
1175 smb_ReleaseVCNoLock(vcp);
1177 lock_ObtainMutex(&vcp->mx);
1178 vcp->flags &= ~SMB_VCFLAG_CLEAN_IN_PROGRESS;
1179 lock_ReleaseMutex(&vcp->mx);
1182 lock_ReleaseWrite(&smb_rctLock);
1183 osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1186 #ifdef DEBUG_SMB_REFCOUNT
1187 smb_tid_t *smb_FindTIDDbg(smb_vc_t *vcp, unsigned short tid, int flags, char * file, long line)
1189 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1194 lock_ObtainWrite(&smb_rctLock);
1196 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1197 if (tidp->refCount == 0 && tidp->deleteOk) {
1199 smb_ReleaseTID(tidp, TRUE);
1203 if (tid == tidp->tid) {
1208 if (!tidp && (flags & SMB_FLAG_CREATE)) {
1209 tidp = malloc(sizeof(*tidp));
1210 memset(tidp, 0, sizeof(*tidp));
1211 tidp->nextp = vcp->tidsp;
1214 smb_HoldVCNoLock(vcp);
1216 lock_InitializeMutex(&tidp->mx, "tid_t mutex", LOCK_HIERARCHY_SMB_TID);
1219 #ifdef DEBUG_SMB_REFCOUNT
1221 afsi_log("%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1222 osi_Log4(smb_logp,"%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1225 lock_ReleaseWrite(&smb_rctLock);
1229 #ifdef DEBUG_SMB_REFCOUNT
1230 void smb_HoldTIDNoLockDbg(smb_tid_t *tidp, char * file, long line)
1232 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1235 lock_AssertWrite(&smb_rctLock);
1237 #ifdef DEBUG_SMB_REFCOUNT
1238 afsi_log("%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1239 osi_Log4(smb_logp,"%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1243 #ifdef DEBUG_SMB_REFCOUNT
1244 void smb_ReleaseTIDDbg(smb_tid_t *tidp, afs_uint32 locked, char *file, long line)
1246 void smb_ReleaseTID(smb_tid_t *tidp, afs_uint32 locked)
1251 cm_user_t *userp = NULL;
1252 smb_vc_t *vcp = NULL;
1255 lock_ObtainWrite(&smb_rctLock);
1257 lock_AssertWrite(&smb_rctLock);
1259 osi_assertx(tidp->refCount-- > 0, "smb_tid_t refCount 0");
1260 #ifdef DEBUG_SMB_REFCOUNT
1261 afsi_log("%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1262 osi_Log5(smb_logp,"%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1264 if (tidp->refCount == 0) {
1265 if (tidp->deleteOk) {
1266 ltpp = &tidp->vcp->tidsp;
1267 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1271 osi_assertx(tp != NULL, "null smb_tid_t");
1273 lock_FinalizeMutex(&tidp->mx);
1274 userp = tidp->userp; /* remember to drop ref later */
1282 lock_ReleaseWrite(&smb_rctLock);
1284 cm_ReleaseUser(userp);
1286 smb_ReleaseVCNoLock(vcp);
1289 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1291 smb_user_t *uidp = NULL;
1293 lock_ObtainWrite(&smb_rctLock);
1294 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1295 if (uid == uidp->userID) {
1297 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%S]",
1299 ((uidp->unp)? osi_LogSaveClientString(smb_logp, uidp->unp->name):_C("")));
1303 if (!uidp && (flags & SMB_FLAG_CREATE)) {
1304 uidp = malloc(sizeof(*uidp));
1305 memset(uidp, 0, sizeof(*uidp));
1306 uidp->nextp = vcp->usersp;
1307 uidp->refCount = 2; /* one for the vcp and one for the caller */
1309 smb_HoldVCNoLock(vcp);
1311 lock_InitializeMutex(&uidp->mx, "user_t mutex", LOCK_HIERARCHY_SMB_UID);
1313 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%S]",
1315 ((uidp->unp)?osi_LogSaveClientString(smb_logp,uidp->unp->name):_C("")));
1317 lock_ReleaseWrite(&smb_rctLock);
1321 smb_username_t *smb_FindUserByName(clientchar_t *usern, clientchar_t *machine,
1324 smb_username_t *unp= NULL;
1326 lock_ObtainWrite(&smb_rctLock);
1327 for(unp = usernamesp; unp; unp = unp->nextp) {
1328 if (cm_ClientStrCmpI(unp->name, usern) == 0 &&
1329 cm_ClientStrCmpI(unp->machine, machine) == 0) {
1334 if (!unp && (flags & SMB_FLAG_CREATE)) {
1335 unp = malloc(sizeof(*unp));
1336 memset(unp, 0, sizeof(*unp));
1338 unp->nextp = usernamesp;
1339 unp->name = cm_ClientStrDup(usern);
1340 unp->machine = cm_ClientStrDup(machine);
1342 lock_InitializeMutex(&unp->mx, "username_t mutex", LOCK_HIERARCHY_SMB_USERNAME);
1343 if (flags & SMB_FLAG_AFSLOGON)
1344 unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1347 lock_ReleaseWrite(&smb_rctLock);
1351 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, clientchar_t *usern)
1353 smb_user_t *uidp= NULL;
1355 lock_ObtainWrite(&smb_rctLock);
1356 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1359 if (cm_stricmp_utf16(uidp->unp->name, usern) == 0) {
1361 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%S]",
1362 vcp,uidp->userID,osi_LogSaveClientString(smb_logp,usern));
1367 lock_ReleaseWrite(&smb_rctLock);
1371 void smb_ReleaseUsername(smb_username_t *unp)
1374 smb_username_t **lupp;
1375 cm_user_t *userp = NULL;
1376 time_t now = osi_Time();
1378 lock_ObtainWrite(&smb_rctLock);
1379 osi_assertx(unp->refCount-- > 0, "smb_username_t refCount 0");
1380 if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1381 (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1383 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1387 osi_assertx(up != NULL, "null smb_username_t");
1389 up->nextp = NULL; /* do not remove this */
1390 lock_FinalizeMutex(&unp->mx);
1396 lock_ReleaseWrite(&smb_rctLock);
1398 cm_ReleaseUser(userp);
1401 void smb_HoldUIDNoLock(smb_user_t *uidp)
1403 lock_AssertWrite(&smb_rctLock);
1407 void smb_ReleaseUID(smb_user_t *uidp)
1411 smb_username_t *unp = NULL;
1413 lock_ObtainWrite(&smb_rctLock);
1414 osi_assertx(uidp->refCount-- > 0, "smb_user_t refCount 0");
1415 if (uidp->refCount == 0) {
1416 lupp = &uidp->vcp->usersp;
1417 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1421 osi_assertx(up != NULL, "null smb_user_t");
1423 lock_FinalizeMutex(&uidp->mx);
1425 smb_ReleaseVCNoLock(uidp->vcp);
1429 lock_ReleaseWrite(&smb_rctLock);
1433 cm_ReleaseUserVCRef(unp->userp);
1434 smb_ReleaseUsername(unp);
1438 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1440 cm_user_t *up = NULL;
1445 lock_ObtainMutex(&uidp->mx);
1447 up = uidp->unp->userp;
1450 lock_ReleaseMutex(&uidp->mx);
1456 /* retrieve a held reference to a user structure corresponding to an incoming
1458 * corresponding release function is cm_ReleaseUser.
1460 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1463 cm_user_t *up = NULL;
1466 smbp = (smb_t *) inp;
1467 uidp = smb_FindUID(vcp, smbp->uid, 0);
1471 up = smb_GetUserFromUID(uidp);
1473 smb_ReleaseUID(uidp);
1478 * Return a pointer to a pathname extracted from a TID structure. The
1479 * TID structure is not held; assume it won't go away.
1481 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, clientchar_t ** treepath)
1486 tidp = smb_FindTID(vcp, tid, 0);
1490 if (tidp->flags & SMB_TIDFLAG_IPC) {
1491 code = CM_ERROR_TIDIPC;
1492 /* tidp->pathname would be NULL, but that's fine */
1494 *treepath = tidp->pathname;
1495 smb_ReleaseTID(tidp, FALSE);
1500 /* check to see if we have a chained fid, that is, a fid that comes from an
1501 * OpenAndX message that ran earlier in this packet. In this case, the fid
1502 * field in a read, for example, request, isn't set, since the value is
1503 * supposed to be inherited from the openAndX call.
1505 int smb_ChainFID(int fid, smb_packet_t *inp)
1507 if (inp->fid == 0 || inp->inCount == 0)
1513 /* are we a priv'd user? What does this mean on NT? */
1514 int smb_SUser(cm_user_t *userp)
1519 /* find a file ID. If we pass in 0 we select an unused File ID.
1520 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1521 * smb_fid_t data structure if desired File ID cannot be found.
1523 #ifdef DEBUG_SMB_REFCOUNT
1524 smb_fid_t *smb_FindFIDDbg(smb_vc_t *vcp, unsigned short fid, int flags, char *file, long line)
1526 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1532 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1535 lock_ObtainWrite(&smb_rctLock);
1536 /* figure out if we need to allocate a new file ID */
1539 fid = vcp->fidCounter;
1543 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1544 if (fidp->refCount == 0 && fidp->deleteOk) {
1546 lock_ReleaseWrite(&smb_rctLock);
1547 smb_ReleaseFID(fidp);
1548 lock_ObtainWrite(&smb_rctLock);
1551 if (fid == fidp->fid) {
1554 if (fid == 0xFFFF) {
1556 "New FID number wraps on vcp 0x%x", vcp);
1566 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1567 char eventName[MAX_PATH];
1569 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1570 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1571 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1572 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1573 thrd_CloseHandle(event);
1575 if (fid == 0xFFFF) {
1576 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1582 fidp = malloc(sizeof(*fidp));
1583 memset(fidp, 0, sizeof(*fidp));
1584 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1587 smb_HoldVCNoLock(vcp);
1588 lock_InitializeMutex(&fidp->mx, "fid_t mutex", LOCK_HIERARCHY_SMB_FID);
1590 fidp->curr_chunk = fidp->prev_chunk = -2;
1591 fidp->raw_write_event = event;
1593 vcp->fidCounter = fid+1;
1594 if (vcp->fidCounter == 0xFFFF) {
1595 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1597 vcp->fidCounter = 1;
1602 #ifdef DEBUG_SMB_REFCOUNT
1604 afsi_log("%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1605 osi_Log4(smb_logp,"%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1608 lock_ReleaseWrite(&smb_rctLock);
1612 #ifdef DEBUG_SMB_REFCOUNT
1613 smb_fid_t *smb_FindFIDByScacheDbg(smb_vc_t *vcp, cm_scache_t * scp, char *file, long line)
1615 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1618 smb_fid_t *fidp = NULL;
1624 lock_ObtainWrite(&smb_rctLock);
1625 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1626 if (scp == fidp->scp) {
1631 #ifdef DEBUG_SMB_REFCOUNT
1633 afsi_log("%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1634 osi_Log4(smb_logp,"%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1637 lock_ReleaseWrite(&smb_rctLock);
1641 #ifdef DEBUG_SMB_REFCOUNT
1642 void smb_HoldFIDNoLockDbg(smb_fid_t *fidp, char *file, long line)
1644 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1647 lock_AssertWrite(&smb_rctLock);
1649 #ifdef DEBUG_SMB_REFCOUNT
1650 afsi_log("%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1651 osi_Log4(smb_logp,"%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1656 /* smb_ReleaseFID cannot be called while an cm_scache_t mutex lock is held */
1657 /* the sm_fid_t->mx and smb_rctLock must not be held */
1658 #ifdef DEBUG_SMB_REFCOUNT
1659 void smb_ReleaseFIDDbg(smb_fid_t *fidp, char *file, long line)
1661 void smb_ReleaseFID(smb_fid_t *fidp)
1664 cm_scache_t *scp = NULL;
1665 cm_user_t *userp = NULL;
1666 smb_vc_t *vcp = NULL;
1667 smb_ioctl_t *ioctlp;
1669 lock_ObtainMutex(&fidp->mx);
1670 lock_ObtainWrite(&smb_rctLock);
1671 osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
1672 #ifdef DEBUG_SMB_REFCOUNT
1673 afsi_log("%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1674 osi_Log5(smb_logp,"%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1676 if (fidp->refCount == 0) {
1677 if (fidp->deleteOk) {
1680 scp = fidp->scp; /* release after lock is released */
1682 lock_ObtainWrite(&scp->rw);
1683 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1684 lock_ReleaseWrite(&scp->rw);
1685 osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1688 userp = fidp->userp;
1692 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1693 thrd_CloseHandle(fidp->raw_write_event);
1695 /* and see if there is ioctl stuff to free */
1696 ioctlp = fidp->ioctlp;
1699 cm_FreeSpace(ioctlp->prefix);
1700 if (ioctlp->ioctl.inAllocp)
1701 free(ioctlp->ioctl.inAllocp);
1702 if (ioctlp->ioctl.outAllocp)
1703 free(ioctlp->ioctl.outAllocp);
1706 lock_ReleaseMutex(&fidp->mx);
1707 lock_FinalizeMutex(&fidp->mx);
1712 smb_ReleaseVCNoLock(vcp);
1716 lock_ReleaseMutex(&fidp->mx);
1718 lock_ReleaseWrite(&smb_rctLock);
1720 /* now release the scache structure */
1722 cm_ReleaseSCache(scp);
1725 cm_ReleaseUser(userp);
1729 * Case-insensitive search for one string in another;
1730 * used to find variable names in submount pathnames.
1732 static clientchar_t *smb_stristr(clientchar_t *str1, clientchar_t *str2)
1734 clientchar_t *cursor;
1736 for (cursor = str1; *cursor; cursor++)
1737 if (cm_ClientStrCmpI(cursor, str2) == 0)
1744 * Substitute a variable value for its name in a submount pathname. Variable
1745 * name has been identified by smb_stristr() and is in substr. Variable name
1746 * length (plus one) is in substr_size. Variable value is in newstr.
1748 static void smb_subst(clientchar_t *str1, int cchstr1, clientchar_t *substr,
1749 unsigned int substr_size, clientchar_t *newstr)
1751 clientchar_t temp[1024];
1753 cm_ClientStrCpy(temp, lengthof(temp), substr + substr_size - 1);
1754 cm_ClientStrCpy(substr, cchstr1 - (substr - str1), newstr);
1755 cm_ClientStrCat(str1, cchstr1, temp);
1758 clientchar_t VNUserName[] = _C("%USERNAME%");
1759 clientchar_t VNLCUserName[] = _C("%LCUSERNAME%");
1760 clientchar_t VNComputerName[] = _C("%COMPUTERNAME%");
1761 clientchar_t VNLCComputerName[] = _C("%LCCOMPUTERNAME%");
1763 typedef struct smb_findShare_rock {
1764 clientchar_t * shareName;
1765 clientchar_t * match;
1767 } smb_findShare_rock_t;
1769 #define SMB_FINDSHARE_EXACT_MATCH 1
1770 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1772 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1776 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1777 normchar_t normName[MAX_PATH];
1779 if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(normName[0])) == 0) {
1780 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
1781 osi_LogSaveString(smb_logp, dep->name));
1785 if (!cm_ClientStrCmpNI(normName, vrock->shareName, 12)) {
1786 if(!cm_ClientStrCmpI(normName, vrock->shareName))
1787 matchType = SMB_FINDSHARE_EXACT_MATCH;
1789 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1792 vrock->match = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
1793 vrock->matchType = matchType;
1795 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1796 return CM_ERROR_STOPNOW;
1802 /* find a shareName in the table of submounts */
1803 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp,
1804 clientchar_t *shareName,
1805 clientchar_t **pathNamep)
1809 clientchar_t pathName[1024];
1812 clientchar_t *p, *q;
1813 fschar_t *cellname = NULL;
1816 DWORD allSubmount = 1;
1818 /* if allSubmounts == 0, only return the //mountRoot/all share
1819 * if in fact it has been been created in the subMounts table.
1820 * This is to allow sites that want to restrict access to the
1823 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1824 0, KEY_QUERY_VALUE, &parmKey);
1825 if (code == ERROR_SUCCESS) {
1826 cblen = sizeof(allSubmount);
1827 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1828 (BYTE *) &allSubmount, &cblen);
1829 if (code != ERROR_SUCCESS) {
1832 RegCloseKey (parmKey);
1835 if (allSubmount && cm_ClientStrCmpI(shareName, _C("all")) == 0) {
1840 /* In case, the all share is disabled we need to still be able
1841 * to handle ioctl requests
1843 if (cm_ClientStrCmpI(shareName, _C("ioctl$")) == 0) {
1844 *pathNamep = cm_ClientStrDup(_C("/.__ioctl__"));
1848 if (cm_ClientStrCmpIA(shareName, _C("IPC$")) == 0 ||
1849 cm_ClientStrCmpIA(shareName, _C("srvsvc")) == 0 ||
1850 cm_ClientStrCmpIA(shareName, _C("wkssvc")) == 0 ||
1851 cm_ClientStrCmpIA(shareName, _C(SMB_IOCTL_FILENAME_NOSLASH)) == 0 ||
1852 cm_ClientStrCmpIA(shareName, _C("DESKTOP.INI")) == 0
1858 /* Check for volume references
1860 * They look like <cell>{%,#}<volume>
1862 if (cm_ClientStrChr(shareName, '%') != NULL ||
1863 cm_ClientStrChr(shareName, '#') != NULL) {
1864 clientchar_t pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
1865 /* make room for '/@vol:' + mountchar + NULL terminator*/
1867 osi_Log1(smb_logp, "smb_FindShare found volume reference [%S]",
1868 osi_LogSaveClientString(smb_logp, shareName));
1870 cm_ClientStrPrintfN(pathstr, lengthof(pathstr),
1871 _C("/") _C(CM_PREFIX_VOL) _C("%s"), shareName);
1872 cchlen = (DWORD)(cm_ClientStrLen(pathstr) + 1);
1874 *pathNamep = malloc(cchlen * sizeof(clientchar_t));
1876 cm_ClientStrCpy(*pathNamep, cchlen, pathstr);
1877 cm_ClientStrLwr(*pathNamep);
1878 osi_Log1(smb_logp, " returning pathname [%S]",
1879 osi_LogSaveClientString(smb_logp, *pathNamep));
1887 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1888 0, KEY_QUERY_VALUE, &parmKey);
1889 if (code == ERROR_SUCCESS) {
1890 cblen = sizeof(pathName);
1891 code = RegQueryValueExW(parmKey, shareName, NULL, NULL,
1892 (BYTE *) pathName, &cblen);
1893 if (code != ERROR_SUCCESS)
1895 RegCloseKey (parmKey);
1899 cchlen = cblen / sizeof(clientchar_t);
1900 if (cchlen != 0 && cchlen != lengthof(pathName) - 1) {
1901 /* We can accept either unix or PC style AFS pathnames. Convert
1902 * Unix-style to PC style here for internal use.
1905 cchlen = lengthof(pathName);
1907 /* within this code block, we maintain, cchlen = writeable
1908 buffer length of p */
1910 if (cm_ClientStrCmpN(p, cm_mountRootC, cm_mountRootCLen) == 0) {
1911 p += cm_mountRootCLen; /* skip mount path */
1912 cchlen -= (DWORD)(p - pathName);
1917 if (*q == _C('/')) *q = _C('\\'); /* change to \ */
1923 clientchar_t temp[1024];
1925 if (var = smb_stristr(p, VNUserName)) {
1926 if (uidp && uidp->unp)
1927 smb_subst(p, cchlen, var, lengthof(VNUserName),uidp->unp->name);
1929 smb_subst(p, cchlen, var, lengthof(VNUserName), _C(" "));
1931 else if (var = smb_stristr(p, VNLCUserName))
1933 if (uidp && uidp->unp)
1934 cm_ClientStrCpy(temp, lengthof(temp), uidp->unp->name);
1936 cm_ClientStrCpy(temp, lengthof(temp), _C(" "));
1937 cm_ClientStrLwr(temp);
1938 smb_subst(p, cchlen, var, lengthof(VNLCUserName), temp);
1940 else if (var = smb_stristr(p, VNComputerName))
1942 sizeTemp = lengthof(temp);
1943 GetComputerNameW(temp, &sizeTemp);
1944 smb_subst(p, cchlen, var, lengthof(VNComputerName), temp);
1946 else if (var = smb_stristr(p, VNLCComputerName))
1948 sizeTemp = lengthof(temp);
1949 GetComputerName((LPTSTR)temp, &sizeTemp);
1950 cm_ClientStrLwr(temp);
1951 smb_subst(p, cchlen, var, lengthof(VNLCComputerName), temp);
1956 *pathNamep = cm_ClientStrDup(p);
1961 /* First lookup shareName in root.afs */
1963 smb_findShare_rock_t vrock;
1965 fschar_t ftemp[1024];
1966 clientchar_t * p = shareName;
1969 /* attempt to locate a partial match in root.afs. This is because
1970 when using the ANSI RAP calls, the share name is limited to 13 chars
1971 and hence is truncated. Of course we prefer exact matches. */
1973 thyper.HighPart = 0;
1976 vrock.shareName = cm_ClientStringToNormStringAlloc(shareName, -1, NULL);
1977 if (vrock.shareName == NULL)
1980 vrock.matchType = 0;
1982 cm_HoldSCache(cm_data.rootSCachep);
1983 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1984 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1985 cm_ReleaseSCache(cm_data.rootSCachep);
1987 free(vrock.shareName);
1988 vrock.shareName = NULL;
1990 if (vrock.matchType) {
1991 cm_ClientStrPrintfN(pathName, lengthof(pathName), _C("/%s/"), vrock.match);
1992 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
1997 /* if we get here, there was no match for the share in root.afs */
1998 /* so try to create \\<netbiosName>\<cellname> */
2003 /* Get the full name for this cell */
2004 cellname = cm_ClientStringToFsStringAlloc(p, -1, NULL);
2005 code = cm_SearchCellFile(cellname, ftemp, 0, 0);
2006 #ifdef AFS_AFSDB_ENV
2007 if (code && cm_dnsEnabled) {
2009 code = cm_SearchCellByDNS(cellname, ftemp, &ttl, 0, 0);
2015 /* construct the path */
2017 clientchar_t temp[1024];
2019 if (cm_FsStringToClientString(ftemp, -1, temp, 1024) != 0) {
2020 cm_ClientStrPrintfN(pathName, (int)lengthof(pathName),
2021 rw ? _C("/.%S/") : _C("/%S/"), temp);
2022 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
2032 /* Client-side offline caching policy types */
2033 #define CSC_POLICY_MANUAL 0
2034 #define CSC_POLICY_DOCUMENTS 1
2035 #define CSC_POLICY_PROGRAMS 2
2036 #define CSC_POLICY_DISABLE 3
2038 int smb_FindShareCSCPolicy(clientchar_t *shareName)
2041 clientchar_t policy[1024];
2044 int retval = CSC_POLICY_MANUAL;
2046 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
2047 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
2050 REG_OPTION_NON_VOLATILE,
2056 len = sizeof(policy);
2057 if ( RegQueryValueExW( hkCSCPolicy, shareName, 0, &dwType, (LPBYTE) policy, &len ) ||
2059 retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
2061 else if (cm_ClientStrCmpIA(policy, _C("documents")) == 0)
2063 retval = CSC_POLICY_DOCUMENTS;
2065 else if (cm_ClientStrCmpIA(policy, _C("programs")) == 0)
2067 retval = CSC_POLICY_PROGRAMS;
2069 else if (cm_ClientStrCmpIA(policy, _C("disable")) == 0)
2071 retval = CSC_POLICY_DISABLE;
2074 RegCloseKey(hkCSCPolicy);
2078 /* find a dir search structure by cookie value, and return it held.
2079 * Must be called with smb_globalLock held.
2081 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
2083 smb_dirSearch_t *dsp;
2085 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2086 if (dsp->cookie == cookie) {
2087 if (dsp != smb_firstDirSearchp) {
2088 /* move to head of LRU queue, too, if we're not already there */
2089 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
2090 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2091 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2092 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2093 if (!smb_lastDirSearchp)
2094 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2102 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
2103 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2104 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
2110 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
2112 lock_ObtainMutex(&dsp->mx);
2113 osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p",
2114 dsp->cookie, dsp, dsp->scp);
2115 dsp->flags |= SMB_DIRSEARCH_DELETE;
2116 if (dsp->scp != NULL) {
2117 lock_ObtainWrite(&dsp->scp->rw);
2118 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
2119 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2120 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2121 dsp->scp->bulkStatProgress = hzero;
2123 lock_ReleaseWrite(&dsp->scp->rw);
2125 lock_ReleaseMutex(&dsp->mx);
2128 /* Must be called with the smb_globalLock held */
2129 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
2131 cm_scache_t *scp = NULL;
2133 osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
2134 if (dsp->refCount == 0) {
2135 lock_ObtainMutex(&dsp->mx);
2136 if (dsp->flags & SMB_DIRSEARCH_DELETE) {
2137 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
2138 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
2139 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2140 lock_ReleaseMutex(&dsp->mx);
2141 lock_FinalizeMutex(&dsp->mx);
2143 osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p",
2144 dsp->cookie, dsp, scp);
2147 lock_ReleaseMutex(&dsp->mx);
2150 /* do this now to avoid spurious locking hierarchy creation */
2152 cm_ReleaseSCache(scp);
2155 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
2157 lock_ObtainWrite(&smb_globalLock);
2158 smb_ReleaseDirSearchNoLock(dsp);
2159 lock_ReleaseWrite(&smb_globalLock);
2162 /* find a dir search structure by cookie value, and return it held */
2163 smb_dirSearch_t *smb_FindDirSearch(long cookie)
2165 smb_dirSearch_t *dsp;
2167 lock_ObtainWrite(&smb_globalLock);
2168 dsp = smb_FindDirSearchNoLock(cookie);
2169 lock_ReleaseWrite(&smb_globalLock);
2173 /* GC some dir search entries, in the address space expected by the specific protocol.
2174 * Must be called with smb_globalLock held; release the lock temporarily.
2176 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
2177 void smb_GCDirSearches(int isV3)
2179 smb_dirSearch_t *prevp;
2180 smb_dirSearch_t *dsp;
2181 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
2185 victimCount = 0; /* how many have we got so far */
2186 for (dsp = smb_lastDirSearchp; dsp; dsp=prevp) {
2187 /* we'll move tp from queue, so
2190 prevp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2191 /* if no one is using this guy, and we're either in the new protocol,
2192 * or we're in the old one and this is a small enough ID to be useful
2193 * to the old protocol, GC this guy.
2195 if (dsp->refCount == 0 && (isV3 || dsp->cookie <= 255)) {
2196 /* hold and delete */
2197 lock_ObtainMutex(&dsp->mx);
2198 dsp->flags |= SMB_DIRSEARCH_DELETE;
2199 lock_ReleaseMutex(&dsp->mx);
2200 victimsp[victimCount++] = dsp;
2204 /* don't do more than this */
2205 if (victimCount >= SMB_DIRSEARCH_GCMAX)
2209 /* now release them */
2210 for (i = 0; i < victimCount; i++) {
2211 smb_ReleaseDirSearchNoLock(victimsp[i]);
2215 /* function for allocating a dir search entry. We need these to remember enough context
2216 * since we don't get passed the path from call to call during a directory search.
2218 * Returns a held dir search structure, and bumps the reference count on the vnode,
2219 * since it saves a pointer to the vnode.
2221 smb_dirSearch_t *smb_NewDirSearch(int isV3)
2223 smb_dirSearch_t *dsp;
2229 lock_ObtainWrite(&smb_globalLock);
2232 /* what's the biggest ID allowed in this version of the protocol */
2233 /* TODO: do we really want a non v3 dir search request to wrap
2234 smb_dirSearchCounter? */
2235 maxAllowed = isV3 ? 65535 : 255;
2236 if (smb_dirSearchCounter > maxAllowed)
2237 smb_dirSearchCounter = 1;
2239 start = smb_dirSearchCounter;
2242 /* twice so we have enough tries to find guys we GC after one pass;
2243 * 10 extra is just in case I mis-counted.
2245 if (++counter > 2*maxAllowed+10)
2246 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2248 if (smb_dirSearchCounter > maxAllowed) {
2249 smb_dirSearchCounter = 1;
2251 if (smb_dirSearchCounter == start) {
2253 smb_GCDirSearches(isV3);
2256 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2258 /* don't need to watch for refcount zero and deleted, since
2259 * we haven't dropped the global lock.
2262 ++smb_dirSearchCounter;
2266 dsp = malloc(sizeof(*dsp));
2267 memset(dsp, 0, sizeof(*dsp));
2268 dsp->cookie = smb_dirSearchCounter;
2269 ++smb_dirSearchCounter;
2271 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t", LOCK_HIERARCHY_SMB_DIRSEARCH);
2272 dsp->lastTime = osi_Time();
2273 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2274 if (!smb_lastDirSearchp)
2275 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2277 osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p",
2281 lock_ReleaseWrite(&smb_globalLock);
2285 static smb_packet_t *smb_GetPacket(void)
2289 lock_ObtainWrite(&smb_globalLock);
2290 tbp = smb_packetFreeListp;
2292 smb_packetFreeListp = tbp->nextp;
2293 lock_ReleaseWrite(&smb_globalLock);
2295 tbp = calloc(sizeof(*tbp),1);
2296 tbp->magic = SMB_PACKETMAGIC;
2299 tbp->resumeCode = 0;
2305 tbp->ncb_length = 0;
2308 tbp->stringsp = NULL;
2310 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2315 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2318 tbp = smb_GetPacket();
2319 memcpy(tbp, pkt, sizeof(smb_packet_t));
2320 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2321 tbp->stringsp = NULL;
2323 smb_HoldVC(tbp->vcp);
2327 static NCB *smb_GetNCB(void)
2332 lock_ObtainWrite(&smb_globalLock);
2333 tbp = smb_ncbFreeListp;
2335 smb_ncbFreeListp = tbp->nextp;
2336 lock_ReleaseWrite(&smb_globalLock);
2338 tbp = calloc(sizeof(*tbp),1);
2339 tbp->magic = SMB_NCBMAGIC;
2342 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2344 memset(&tbp->ncb, 0, sizeof(NCB));
2349 static void FreeSMBStrings(smb_packet_t * pkt)
2354 for (s = pkt->stringsp; s; s = ns) {
2358 pkt->stringsp = NULL;
2361 void smb_FreePacket(smb_packet_t *tbp)
2363 smb_vc_t * vcp = NULL;
2364 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2366 lock_ObtainWrite(&smb_globalLock);
2367 tbp->nextp = smb_packetFreeListp;
2368 smb_packetFreeListp = tbp;
2369 tbp->magic = SMB_PACKETMAGIC;
2373 tbp->resumeCode = 0;
2379 tbp->ncb_length = 0;
2381 FreeSMBStrings(tbp);
2382 lock_ReleaseWrite(&smb_globalLock);
2388 static void smb_FreeNCB(NCB *bufferp)
2392 tbp = (smb_ncb_t *) bufferp;
2393 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2395 lock_ObtainWrite(&smb_globalLock);
2396 tbp->nextp = smb_ncbFreeListp;
2397 smb_ncbFreeListp = tbp;
2398 lock_ReleaseWrite(&smb_globalLock);
2401 /* get a ptr to the data part of a packet, and its count */
2402 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2406 unsigned char *afterParmsp;
2408 parmBytes = *smbp->wctp << 1;
2409 afterParmsp = smbp->wctp + parmBytes + 1;
2411 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2412 if (nbytesp) *nbytesp = dataBytes;
2414 /* don't forget to skip the data byte count, since it follows
2415 * the parameters; that's where the "2" comes from below.
2417 return (unsigned char *) (afterParmsp + 2);
2420 /* must set all the returned parameters before playing around with the
2421 * data region, since the data region is located past the end of the
2422 * variable number of parameters.
2424 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2426 unsigned char *afterParmsp;
2428 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2430 *afterParmsp++ = dsize & 0xff;
2431 *afterParmsp = (dsize>>8) & 0xff;
2434 /* return the parm'th parameter in the smbp packet */
2435 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2438 unsigned char *parmDatap;
2440 parmCount = *smbp->wctp;
2442 if (parm >= parmCount) {
2445 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2446 parm, parmCount, smbp->ncb_length);
2447 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2448 parm, parmCount, smbp->ncb_length);
2449 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2450 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2451 osi_panic(s, __FILE__, __LINE__);
2453 parmDatap = smbp->wctp + (2*parm) + 1;
2455 return parmDatap[0] + (parmDatap[1] << 8);
2458 /* return the parm'th parameter in the smbp packet */
2459 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2462 unsigned char *parmDatap;
2464 parmCount = *smbp->wctp;
2466 if (parm >= parmCount) {
2469 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2470 parm, parmCount, smbp->ncb_length);
2471 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2472 parm, parmCount, smbp->ncb_length);
2473 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2474 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2475 osi_panic(s, __FILE__, __LINE__);
2477 parmDatap = smbp->wctp + (2*parm) + 1;
2479 return parmDatap[0];
2482 /* return the parm'th parameter in the smbp packet */
2483 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2486 unsigned char *parmDatap;
2488 parmCount = *smbp->wctp;
2490 if (parm + 1 >= parmCount) {
2493 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2494 parm, parmCount, smbp->ncb_length);
2495 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2496 parm, parmCount, smbp->ncb_length);
2497 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2498 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2499 osi_panic(s, __FILE__, __LINE__);
2501 parmDatap = smbp->wctp + (2*parm) + 1;
2503 return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2506 /* return the parm'th parameter in the smbp packet */
2507 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2510 unsigned char *parmDatap;
2512 parmCount = *smbp->wctp;
2514 if (parm * 2 + offset >= parmCount * 2) {
2517 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2518 parm, offset, parmCount, smbp->ncb_length);
2519 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2520 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2521 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2522 parm, offset, parmCount, smbp->ncb_length);
2523 osi_panic(s, __FILE__, __LINE__);
2525 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2527 return parmDatap[0] + (parmDatap[1] << 8);
2530 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2532 unsigned char *parmDatap;
2534 /* make sure we have enough slots */
2535 if (*smbp->wctp <= slot)
2536 *smbp->wctp = slot+1;
2538 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2539 *parmDatap++ = parmValue & 0xff;
2540 *parmDatap = (parmValue>>8) & 0xff;
2543 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2545 unsigned char *parmDatap;
2547 /* make sure we have enough slots */
2548 if (*smbp->wctp <= slot)
2549 *smbp->wctp = slot+2;
2551 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2552 *parmDatap++ = parmValue & 0xff;
2553 *parmDatap++ = (parmValue>>8) & 0xff;
2554 *parmDatap++ = (parmValue>>16) & 0xff;
2555 *parmDatap = (parmValue>>24) & 0xff;
2558 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2560 unsigned char *parmDatap;
2563 /* make sure we have enough slots */
2564 if (*smbp->wctp <= slot)
2565 *smbp->wctp = slot+4;
2567 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2569 *parmDatap++ = *parmValuep++;
2572 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2574 unsigned char *parmDatap;
2576 /* make sure we have enough slots */
2577 if (*smbp->wctp <= slot) {
2578 if (smbp->oddByte) {
2580 *smbp->wctp = slot+1;
2585 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2586 *parmDatap++ = parmValue & 0xff;
2591 void smb_StripLastComponent(clientchar_t *outPathp, clientchar_t **lastComponentp,
2592 clientchar_t *inPathp)
2594 clientchar_t *lastSlashp;
2596 lastSlashp = cm_ClientStrRChr(inPathp, '\\');
2598 *lastComponentp = lastSlashp;
2601 if (inPathp == lastSlashp)
2603 *outPathp++ = *inPathp++;
2612 clientchar_t *smb_ParseASCIIBlock(smb_packet_t * pktp, unsigned char *inp,
2613 char **chainpp, int flags)
2616 afs_uint32 type = *inp++;
2619 * The first byte specifies the type of the input string.
2620 * CIFS TR 1.0 3.2.10. This function only parses null terminated
2624 /* Length Counted */
2625 case 0x1: /* Data Block */
2626 case 0x5: /* Variable Block */
2627 cb = *inp++ << 16 | *inp++;
2630 /* Null-terminated string */
2631 case 0x4: /* ASCII */
2632 case 0x3: /* Pathname */
2633 case 0x2: /* Dialect */
2634 cb = sizeof(pktp->data) - (inp - pktp->data);
2635 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2636 #ifdef DEBUG_UNICODE
2639 cb = sizeof(pktp->data);
2644 return NULL; /* invalid input */
2648 if (type == 0x2 /* Dialect */ || !WANTS_UNICODE(pktp))
2649 flags |= SMB_STRF_FORCEASCII;
2652 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2655 clientchar_t *smb_ParseString(smb_packet_t * pktp, unsigned char * inp,
2656 char ** chainpp, int flags)
2661 if (!WANTS_UNICODE(pktp))
2662 flags |= SMB_STRF_FORCEASCII;
2665 cb = sizeof(pktp->data) - (inp - pktp->data);
2666 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2667 #ifdef DEBUG_UNICODE
2670 cb = sizeof(pktp->data);
2672 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp,
2673 flags | SMB_STRF_SRCNULTERM);
2676 clientchar_t *smb_ParseStringCb(smb_packet_t * pktp, unsigned char * inp,
2677 size_t cb, char ** chainpp, int flags)
2680 if (!WANTS_UNICODE(pktp))
2681 flags |= SMB_STRF_FORCEASCII;
2684 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2687 clientchar_t *smb_ParseStringCch(smb_packet_t * pktp, unsigned char * inp,
2688 size_t cch, char ** chainpp, int flags)
2693 if (!WANTS_UNICODE(pktp))
2694 flags |= SMB_STRF_FORCEASCII;
2696 cb = cch * sizeof(wchar_t);
2699 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2703 smb_ParseStringBuf(const unsigned char * bufbase,
2704 cm_space_t ** stringspp,
2705 unsigned char *inp, size_t *pcb_max,
2706 char **chainpp, int flags)
2709 if (!(flags & SMB_STRF_FORCEASCII)) {
2711 cm_space_t * spacep;
2714 if (bufbase && ((inp - bufbase) % 2) != 0) {
2715 inp++; /* unicode strings are always word aligned */
2719 if (FAILED(StringCchLengthW((const wchar_t *) inp, *pcb_max / sizeof(wchar_t),
2721 cch_src = *pcb_max / sizeof(wchar_t);
2725 *pcb_max -= (cch_src + 1) * sizeof(wchar_t);
2732 spacep = cm_GetSpace();
2733 spacep->nextp = *stringspp;
2734 *stringspp = spacep;
2738 *chainpp = inp + sizeof(wchar_t);
2741 *(spacep->wdata) = 0;
2742 return spacep->wdata;
2745 StringCchCopyNW(spacep->wdata,
2746 lengthof(spacep->wdata),
2747 (const clientchar_t *) inp, cch_src);
2750 *chainpp = inp + (cch_src + null_terms)*sizeof(wchar_t);
2752 return spacep->wdata;
2756 cm_space_t * spacep;
2759 /* Not using Unicode */
2761 *chainpp = inp + strlen(inp) + 1;
2764 spacep = cm_GetSpace();
2765 spacep->nextp = *stringspp;
2766 *stringspp = spacep;
2768 cchdest = lengthof(spacep->wdata);
2769 cm_Utf8ToUtf16(inp, (int)((flags & SMB_STRF_SRCNULTERM)? -1 : *pcb_max),
2770 spacep->wdata, cchdest);
2772 return spacep->wdata;
2778 unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
2780 size_t * plen, int flags)
2786 /* we are only calculating the required size */
2793 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2795 StringCbLengthW(str, SMB_STRINGBUFSIZE * sizeof(wchar_t), plen);
2796 if (!(flags & SMB_STRF_IGNORENUL))
2797 *plen += sizeof(wchar_t);
2799 return (unsigned char *) 1; /* return TRUE if we are using unicode */
2809 cch_str = cm_ClientStrLen(str);
2810 cch_dest = cm_ClientStringToUtf8(str, (int)cch_str, NULL, 0);
2813 *plen = ((flags & SMB_STRF_IGNORENUL)? cch_dest: cch_dest+1);
2821 /* if outp != NULL ... */
2823 /* Number of bytes left in the buffer.
2825 If outp lies inside the packet data buffer, we assume that the
2826 buffer is the packet data buffer. Otherwise we assume that the
2827 buffer is sizeof(packet->data).
2830 if (outp >= pktp->data && outp < pktp->data + sizeof(pktp->data)) {
2831 align = (int)((outp - pktp->data) % 2);
2832 buffersize = (pktp->data + sizeof(pktp->data)) - ((char *) outp);
2834 align = (int)(((size_t) outp) % 2);
2835 buffersize = (int)sizeof(pktp->data);
2840 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2846 if (*str == _C('\0')) {
2848 if (buffersize < sizeof(wchar_t))
2851 *((wchar_t *) outp) = L'\0';
2852 if (plen && !(flags & SMB_STRF_IGNORENUL))
2853 *plen += sizeof(wchar_t);
2854 return outp + sizeof(wchar_t);
2857 nchars = cm_ClientStringToUtf16(str, -1, (wchar_t *) outp, (int)(buffersize / sizeof(wchar_t)));
2859 osi_Log2(smb_logp, "UnparseString: Can't convert string to Unicode [%S], GLE=%d",
2860 osi_LogSaveClientString(smb_logp, str),
2866 *plen += sizeof(wchar_t) * ((flags & SMB_STRF_IGNORENUL)? nchars - 1: nchars);
2868 return outp + sizeof(wchar_t) * nchars;
2876 cch_dest = cm_ClientStringToUtf8(str, -1, outp, (int)buffersize);
2879 *plen += ((flags & SMB_STRF_IGNORENUL)? cch_dest - 1: cch_dest);
2881 return outp + cch_dest;
2885 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2891 tlen = inp[0] + (inp[1]<<8);
2892 inp += 2; /* skip length field */
2895 *chainpp = inp + tlen;
2904 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2908 if (*inp++ != 0x1) return NULL;
2909 tlen = inp[0] + (inp[1]<<8);
2910 inp += 2; /* skip length field */
2913 *chainpp = inp + tlen;
2916 if (lengthp) *lengthp = tlen;
2921 /* format a packet as a response */
2922 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2927 outp = (smb_t *) op;
2929 /* zero the basic structure through the smb_wct field, and zero the data
2930 * size field, assuming that wct stays zero; otherwise, you have to
2931 * explicitly set the data size field, too.
2933 inSmbp = (smb_t *) inp;
2934 memset(outp, 0, sizeof(smb_t)+2);
2940 outp->com = inSmbp->com;
2941 outp->tid = inSmbp->tid;
2942 outp->pid = inSmbp->pid;
2943 outp->uid = inSmbp->uid;
2944 outp->mid = inSmbp->mid;
2945 outp->res[0] = inSmbp->res[0];
2946 outp->res[1] = inSmbp->res[1];
2947 op->inCom = inSmbp->com;
2949 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
2950 #ifdef SEND_CANONICAL_PATHNAMES
2951 outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
2953 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2955 if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
2956 outp->flg2 |= SMB_FLAGS2_UNICODE;
2959 /* copy fields in generic packet area */
2960 op->wctp = &outp->wct;
2963 /* send a (probably response) packet; vcp tells us to whom to send it.
2964 * we compute the length by looking at wct and bcc fields.
2966 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2976 ncbp = smb_GetNCB();
2980 memset((char *)ncbp, 0, sizeof(NCB));
2982 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2983 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2984 extra += tp[0] + (tp[1]<<8);
2985 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
2986 extra += 3; /* wct and length fields */
2988 ncbp->ncb_length = extra; /* bytes to send */
2989 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2990 ncbp->ncb_lana_num = vcp->lana;
2991 ncbp->ncb_command = NCBSEND; /* op means send data */
2992 ncbp->ncb_buffer = (char *) inp;/* packet */
2993 code = Netbios(ncbp);
2996 const char * s = ncb_error_string(code);
2997 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2998 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
3000 lock_ObtainMutex(&vcp->mx);
3001 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
3002 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
3004 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
3005 lock_ReleaseMutex(&vcp->mx);
3006 lock_ObtainWrite(&smb_globalLock);
3007 dead_sessions[vcp->session] = TRUE;
3008 lock_ReleaseWrite(&smb_globalLock);
3009 smb_CleanupDeadVC(vcp);
3011 lock_ReleaseMutex(&vcp->mx);
3019 void smb_MapNTError(long code, unsigned long *NTStatusp)
3021 unsigned long NTStatus;
3023 /* map CM_ERROR_* errors to NT 32-bit status codes */
3024 /* NT Status codes are listed in ntstatus.h not winerror.h */
3028 else if (code == CM_ERROR_NOSUCHCELL) {
3029 NTStatus = 0xC000000FL; /* No such file */
3031 else if (code == CM_ERROR_NOSUCHVOLUME) {
3032 NTStatus = 0xC000000FL; /* No such file */
3034 else if (code == CM_ERROR_TIMEDOUT) {
3036 NTStatus = 0xC00000CFL; /* Sharing Paused */
3038 NTStatus = 0x00000102L; /* Timeout */
3041 else if (code == CM_ERROR_RETRY) {
3042 NTStatus = 0xC000022DL; /* Retry */
3044 else if (code == CM_ERROR_NOACCESS) {
3045 NTStatus = 0xC0000022L; /* Access denied */
3047 else if (code == CM_ERROR_READONLY) {
3048 NTStatus = 0xC00000A2L; /* Write protected */
3050 else if (code == CM_ERROR_NOSUCHFILE ||
3051 code == CM_ERROR_BPLUS_NOMATCH) {
3052 NTStatus = 0xC000000FL; /* No such file */
3054 else if (code == CM_ERROR_NOSUCHPATH) {
3055 NTStatus = 0xC000003AL; /* Object path not found */
3057 else if (code == CM_ERROR_TOOBIG) {
3058 NTStatus = 0xC000007BL; /* Invalid image format */
3060 else if (code == CM_ERROR_INVAL) {
3061 NTStatus = 0xC000000DL; /* Invalid parameter */
3063 else if (code == CM_ERROR_BADFD) {
3064 NTStatus = 0xC0000008L; /* Invalid handle */
3066 else if (code == CM_ERROR_BADFDOP) {
3067 NTStatus = 0xC0000022L; /* Access denied */
3069 else if (code == CM_ERROR_EXISTS) {
3070 NTStatus = 0xC0000035L; /* Object name collision */
3072 else if (code == CM_ERROR_NOTEMPTY) {
3073 NTStatus = 0xC0000101L; /* Directory not empty */
3075 else if (code == CM_ERROR_CROSSDEVLINK) {
3076 NTStatus = 0xC00000D4L; /* Not same device */
3078 else if (code == CM_ERROR_NOTDIR) {
3079 NTStatus = 0xC0000103L; /* Not a directory */
3081 else if (code == CM_ERROR_ISDIR) {
3082 NTStatus = 0xC00000BAL; /* File is a directory */
3084 else if (code == CM_ERROR_BADOP) {
3086 /* I have no idea where this comes from */
3087 NTStatus = 0xC09820FFL; /* SMB no support */
3089 NTStatus = 0xC00000BBL; /* Not supported */
3090 #endif /* COMMENT */
3092 else if (code == CM_ERROR_BADSHARENAME) {
3093 NTStatus = 0xC00000CCL; /* Bad network name */
3095 else if (code == CM_ERROR_NOIPC) {
3097 NTStatus = 0xC0000022L; /* Access Denied */
3099 NTStatus = 0xC000013DL; /* Remote Resources */
3102 else if (code == CM_ERROR_CLOCKSKEW) {
3103 NTStatus = 0xC0000133L; /* Time difference at DC */
3105 else if (code == CM_ERROR_BADTID) {
3106 NTStatus = 0xC0982005L; /* SMB bad TID */
3108 else if (code == CM_ERROR_USESTD) {
3109 NTStatus = 0xC09820FBL; /* SMB use standard */
3111 else if (code == CM_ERROR_QUOTA) {
3112 NTStatus = 0xC0000044L; /* Quota exceeded */
3114 else if (code == CM_ERROR_SPACE) {
3115 NTStatus = 0xC000007FL; /* Disk full */
3117 else if (code == CM_ERROR_ATSYS) {
3118 NTStatus = 0xC0000033L; /* Object name invalid */
3120 else if (code == CM_ERROR_BADNTFILENAME) {
3121 NTStatus = 0xC0000033L; /* Object name invalid */
3123 else if (code == CM_ERROR_WOULDBLOCK) {
3124 NTStatus = 0xC00000D8L; /* Can't wait */
3126 else if (code == CM_ERROR_SHARING_VIOLATION) {
3127 NTStatus = 0xC0000043L; /* Sharing violation */
3129 else if (code == CM_ERROR_LOCK_CONFLICT) {
3130 NTStatus = 0xC0000054L; /* Lock conflict */
3132 else if (code == CM_ERROR_PARTIALWRITE) {
3133 NTStatus = 0xC000007FL; /* Disk full */
3135 else if (code == CM_ERROR_BUFFERTOOSMALL) {
3136 NTStatus = 0xC0000023L; /* Buffer too small */
3138 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3139 NTStatus = 0xC0000035L; /* Object name collision */
3141 else if (code == CM_ERROR_BADPASSWORD) {
3142 NTStatus = 0xC000006DL; /* unknown username or bad password */
3144 else if (code == CM_ERROR_BADLOGONTYPE) {
3145 NTStatus = 0xC000015BL; /* logon type not granted */
3147 else if (code == CM_ERROR_GSSCONTINUE) {
3148 NTStatus = 0xC0000016L; /* more processing required */
3150 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3152 NTStatus = 0xC0000280L; /* reparse point not resolved */
3154 NTStatus = 0xC0000022L; /* Access Denied */
3157 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3158 NTStatus = 0xC0000257L; /* Path Not Covered */
3160 else if (code == CM_ERROR_ALLBUSY) {
3161 NTStatus = 0xC000022DL; /* Retry */
3163 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3164 NTStatus = 0xC00000BEL; /* Bad Network Path */
3166 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3167 NTStatus = 0xC0000322L; /* No Kerberos key */
3169 else if (code == CM_ERROR_BAD_LEVEL) {
3170 NTStatus = 0xC0000148L; /* Invalid Level */
3172 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3173 NTStatus = 0xC000007EL; /* Range Not Locked */
3175 else if (code == CM_ERROR_NOSUCHDEVICE) {
3176 NTStatus = 0xC000000EL; /* No Such Device */
3178 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3179 NTStatus = 0xC0000055L; /* Lock Not Granted */
3180 } else if (code == ENOMEM) {
3181 NTStatus = 0xC0000017L; /* Out of Memory */
3183 NTStatus = 0xC0982001L; /* SMB non-specific error */
3186 *NTStatusp = NTStatus;
3187 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
3190 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
3191 unsigned char *classp)
3193 unsigned char class;
3194 unsigned short error;
3196 /* map CM_ERROR_* errors to SMB errors */
3197 if (code == CM_ERROR_NOSUCHCELL) {
3199 error = 3; /* bad path */
3201 else if (code == CM_ERROR_NOSUCHVOLUME) {
3203 error = 3; /* bad path */
3205 else if (code == CM_ERROR_TIMEDOUT) {
3207 error = 81; /* server is paused */
3209 else if (code == CM_ERROR_RETRY) {
3210 class = 2; /* shouldn't happen */
3213 else if (code == CM_ERROR_NOACCESS) {
3215 error = 4; /* bad access */
3217 else if (code == CM_ERROR_READONLY) {
3219 error = 19; /* read only */
3221 else if (code == CM_ERROR_NOSUCHFILE ||
3222 code == CM_ERROR_BPLUS_NOMATCH) {
3224 error = 2; /* ENOENT! */
3226 else if (code == CM_ERROR_NOSUCHPATH) {
3228 error = 3; /* Bad path */
3230 else if (code == CM_ERROR_TOOBIG) {
3232 error = 11; /* bad format */
3234 else if (code == CM_ERROR_INVAL) {
3235 class = 2; /* server non-specific error code */
3238 else if (code == CM_ERROR_BADFD) {
3240 error = 6; /* invalid file handle */
3242 else if (code == CM_ERROR_BADFDOP) {
3243 class = 1; /* invalid op on FD */
3246 else if (code == CM_ERROR_EXISTS) {
3248 error = 80; /* file already exists */
3250 else if (code == CM_ERROR_NOTEMPTY) {
3252 error = 5; /* delete directory not empty */
3254 else if (code == CM_ERROR_CROSSDEVLINK) {
3256 error = 17; /* EXDEV */
3258 else if (code == CM_ERROR_NOTDIR) {
3259 class = 1; /* bad path */
3262 else if (code == CM_ERROR_ISDIR) {
3263 class = 1; /* access denied; DOS doesn't have a good match */
3266 else if (code == CM_ERROR_BADOP) {
3270 else if (code == CM_ERROR_BADSHARENAME) {
3274 else if (code == CM_ERROR_NOIPC) {
3276 error = 4; /* bad access */
3278 else if (code == CM_ERROR_CLOCKSKEW) {
3279 class = 1; /* invalid function */
3282 else if (code == CM_ERROR_BADTID) {
3286 else if (code == CM_ERROR_USESTD) {
3290 else if (code == CM_ERROR_REMOTECONN) {
3294 else if (code == CM_ERROR_QUOTA) {
3295 if (vcp->flags & SMB_VCFLAG_USEV3) {
3297 error = 39; /* disk full */
3301 error = 5; /* access denied */
3304 else if (code == CM_ERROR_SPACE) {
3305 if (vcp->flags & SMB_VCFLAG_USEV3) {
3307 error = 39; /* disk full */
3311 error = 5; /* access denied */
3314 else if (code == CM_ERROR_PARTIALWRITE) {
3316 error = 39; /* disk full */
3318 else if (code == CM_ERROR_ATSYS) {
3320 error = 2; /* ENOENT */
3322 else if (code == CM_ERROR_WOULDBLOCK) {
3324 error = 33; /* lock conflict */
3326 else if (code == CM_ERROR_LOCK_CONFLICT) {
3328 error = 33; /* lock conflict */
3330 else if (code == CM_ERROR_SHARING_VIOLATION) {
3332 error = 33; /* lock conflict */
3334 else if (code == CM_ERROR_NOFILES) {
3336 error = 18; /* no files in search */
3338 else if (code == CM_ERROR_RENAME_IDENTICAL) {
3340 error = 183; /* Samba uses this */
3342 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
3343 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
3345 error = 2; /* bad password */
3347 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3349 error = 3; /* bad path */
3358 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
3361 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3363 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
3364 return CM_ERROR_BADOP;
3368 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3370 unsigned short EchoCount, i;
3371 char *data, *outdata;
3374 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
3376 for (i=1; i<=EchoCount; i++) {
3377 data = smb_GetSMBData(inp, &dataSize);
3378 smb_SetSMBParm(outp, 0, i);
3379 smb_SetSMBDataLength(outp, dataSize);
3380 outdata = smb_GetSMBData(outp, NULL);
3381 memcpy(outdata, data, dataSize);
3382 smb_SendPacket(vcp, outp);
3388 /* SMB_COM_READ_RAW */
3389 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3392 long count, minCount, finalCount;
3396 smb_t *smbp = (smb_t*) inp;
3398 cm_user_t *userp = NULL;
3401 char *rawBuf = NULL;
3406 fd = smb_GetSMBParm(inp, 0);
3407 count = smb_GetSMBParm(inp, 3);
3408 minCount = smb_GetSMBParm(inp, 4);
3409 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3411 if (*inp->wctp == 10) {
3412 /* we were sent a request with 64-bit file offsets */
3413 #ifdef AFS_LARGEFILES
3414 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
3416 if (LargeIntegerLessThanZero(offset)) {
3417 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
3421 if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
3422 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset. Dropping request.");
3425 offset.HighPart = 0;
3429 /* we were sent a request with 32-bit file offsets */
3430 offset.HighPart = 0;
3433 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
3434 fd, offset.HighPart, offset.LowPart, count);
3436 fidp = smb_FindFID(vcp, fd, 0);
3440 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3441 smb_CloseFID(vcp, fidp, NULL, 0);
3442 code = CM_ERROR_NOSUCHFILE;
3449 LARGE_INTEGER LOffset, LLength;
3452 key = cm_GenerateKey(vcp->vcID, pid, fd);
3454 LOffset.HighPart = offset.HighPart;
3455 LOffset.LowPart = offset.LowPart;
3456 LLength.HighPart = 0;
3457 LLength.LowPart = count;
3459 lock_ObtainWrite(&fidp->scp->rw);
3460 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
3461 lock_ReleaseWrite(&fidp->scp->rw);
3467 lock_ObtainMutex(&smb_RawBufLock);
3469 /* Get a raw buf, from head of list */
3470 rawBuf = smb_RawBufs;
3471 smb_RawBufs = *(char **)smb_RawBufs;
3473 lock_ReleaseMutex(&smb_RawBufLock);
3477 lock_ObtainMutex(&fidp->mx);
3478 if (fidp->flags & SMB_FID_IOCTL)
3480 lock_ReleaseMutex(&fidp->mx);
3481 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
3483 /* Give back raw buffer */
3484 lock_ObtainMutex(&smb_RawBufLock);
3485 *((char **) rawBuf) = smb_RawBufs;
3487 smb_RawBufs = rawBuf;
3488 lock_ReleaseMutex(&smb_RawBufLock);
3491 lock_ReleaseMutex(&fidp->mx);
3492 smb_ReleaseFID(fidp);
3495 lock_ReleaseMutex(&fidp->mx);
3497 userp = smb_GetUserFromVCP(vcp, inp);
3499 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
3505 cm_ReleaseUser(userp);
3508 smb_ReleaseFID(fidp);
3512 memset((char *)ncbp, 0, sizeof(NCB));
3514 ncbp->ncb_length = (unsigned short) finalCount;
3515 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
3516 ncbp->ncb_lana_num = vcp->lana;
3517 ncbp->ncb_command = NCBSEND;
3518 ncbp->ncb_buffer = rawBuf;
3520 code = Netbios(ncbp);
3522 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
3525 /* Give back raw buffer */
3526 lock_ObtainMutex(&smb_RawBufLock);
3527 *((char **) rawBuf) = smb_RawBufs;
3529 smb_RawBufs = rawBuf;
3530 lock_ReleaseMutex(&smb_RawBufLock);
3536 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3538 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3543 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3545 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3550 /* SMB_COM_NEGOTIATE */
3551 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3558 int VistaProtoIndex;
3559 int protoIndex; /* index we're using */
3564 char protocol_array[10][1024]; /* protocol signature of the client */
3565 int caps; /* capabilities */
3568 TIME_ZONE_INFORMATION tzi;
3570 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3573 namep = smb_GetSMBData(inp, &dbytes);
3576 coreProtoIndex = -1; /* not found */
3579 VistaProtoIndex = -1;
3580 while(namex < dbytes) {
3581 osi_Log1(smb_logp, "Protocol %s",
3582 osi_LogSaveString(smb_logp, namep+1));
3583 strcpy(protocol_array[tcounter], namep+1);
3585 /* namep points at the first protocol, or really, a 0x02
3586 * byte preceding the null-terminated ASCII name.
3588 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3589 coreProtoIndex = tcounter;
3591 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3592 v3ProtoIndex = tcounter;
3594 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3595 NTProtoIndex = tcounter;
3597 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3598 VistaProtoIndex = tcounter;
3601 /* compute size of protocol entry */
3602 entryLength = (int)strlen(namep+1);
3603 entryLength += 2; /* 0x02 bytes and null termination */
3605 /* advance over this protocol entry */
3606 namex += entryLength;
3607 namep += entryLength;
3608 tcounter++; /* which proto entry we're looking at */
3611 lock_ObtainMutex(&vcp->mx);
3613 if (VistaProtoIndex != -1) {
3614 protoIndex = VistaProtoIndex;
3615 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3618 if (NTProtoIndex != -1) {
3619 protoIndex = NTProtoIndex;
3620 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3622 else if (v3ProtoIndex != -1) {
3623 protoIndex = v3ProtoIndex;
3624 vcp->flags |= SMB_VCFLAG_USEV3;
3626 else if (coreProtoIndex != -1) {
3627 protoIndex = coreProtoIndex;
3628 vcp->flags |= SMB_VCFLAG_USECORE;
3630 else protoIndex = -1;
3631 lock_ReleaseMutex(&vcp->mx);
3633 if (protoIndex == -1)
3634 return CM_ERROR_INVAL;
3635 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3636 smb_SetSMBParm(outp, 0, protoIndex);
3637 if (smb_authType != SMB_AUTH_NONE) {
3638 smb_SetSMBParmByte(outp, 1,
3639 NEGOTIATE_SECURITY_USER_LEVEL |
3640 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3642 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3644 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3645 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3646 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3647 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3648 /* The session key is not a well documented field however most clients
3649 * will echo back the session key to the server. Currently we are using
3650 * the same value for all sessions. We should generate a random value
3651 * and store it into the vcp
3653 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3654 smb_SetSMBParm(outp, 8, 1);
3656 * Tried changing the capabilities to support for W2K - defect 117695
3657 * Maybe something else needs to be changed here?
3661 smb_SetSMBParmLong(outp, 9, 0x43fd);
3663 smb_SetSMBParmLong(outp, 9, 0x251);
3666 * 32-bit error codes *
3672 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3674 NTNEGOTIATE_CAPABILITY_DFS |
3676 #ifdef AFS_LARGEFILES
3677 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3679 NTNEGOTIATE_CAPABILITY_NTFIND |
3680 NTNEGOTIATE_CAPABILITY_RAWMODE |
3681 NTNEGOTIATE_CAPABILITY_NTSMB;
3683 if ( smb_authType == SMB_AUTH_EXTENDED )
3684 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3687 if ( smb_UseUnicode ) {
3688 caps |= NTNEGOTIATE_CAPABILITY_UNICODE;
3692 smb_SetSMBParmLong(outp, 9, caps);
3694 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3695 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3696 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3698 GetTimeZoneInformation(&tzi);
3699 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3701 if (smb_authType == SMB_AUTH_NTLM) {
3702 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3703 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3704 /* paste in encryption key */
3705 datap = smb_GetSMBData(outp, NULL);
3706 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3707 /* and the faux domain name */
3708 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3709 datap + MSV1_0_CHALLENGE_LENGTH,
3710 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3711 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3715 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3717 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3719 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3721 datap = smb_GetSMBData(outp, NULL);
3722 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3725 datap += sizeof(smb_ServerGUID);
3726 memcpy(datap, secBlob, secBlobLength);
3730 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3731 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3734 else if (v3ProtoIndex != -1) {
3735 smb_SetSMBParm(outp, 0, protoIndex);
3737 /* NOTE: Extended authentication cannot be negotiated with v3
3738 * therefore we fail over to NTLM
3740 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3741 smb_SetSMBParm(outp, 1,
3742 NEGOTIATE_SECURITY_USER_LEVEL |
3743 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3745 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3747 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3748 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3749 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3750 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3751 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3752 smb_SetSMBParm(outp, 7, 1);
3754 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3755 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3756 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3758 GetTimeZoneInformation(&tzi);
3759 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3761 /* NOTE: Extended authentication cannot be negotiated with v3
3762 * therefore we fail over to NTLM
3764 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3765 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3766 smb_SetSMBParm(outp, 12, 0); /* resvd */
3767 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3768 datap = smb_GetSMBData(outp, NULL);
3769 /* paste in a new encryption key */
3770 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3771 /* and the faux domain name */
3772 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3773 datap + MSV1_0_CHALLENGE_LENGTH,
3774 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3776 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3777 smb_SetSMBParm(outp, 12, 0); /* resvd */
3778 smb_SetSMBDataLength(outp, 0);
3781 else if (coreProtoIndex != -1) { /* not really supported anymore */
3782 smb_SetSMBParm(outp, 0, protoIndex);
3783 smb_SetSMBDataLength(outp, 0);
3788 void smb_CheckVCs(void)
3790 smb_vc_t * vcp, *nextp;
3791 smb_packet_t * outp = smb_GetPacket();
3794 lock_ObtainWrite(&smb_rctLock);
3795 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
3797 if (vcp->magic != SMB_VC_MAGIC)
3798 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
3799 __FILE__, __LINE__);
3801 /* on the first pass hold 'vcp' which was not held as 'nextp' */
3803 smb_HoldVCNoLock(vcp);
3806 * obtain a reference to 'nextp' now because we drop the
3807 * smb_rctLock later and the list contents could change
3808 * or 'vcp' could be destroyed when released.
3812 smb_HoldVCNoLock(nextp);
3814 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
3815 smb_ReleaseVCNoLock(vcp);
3819 smb_FormatResponsePacket(vcp, NULL, outp);
3820 smbp = (smb_t *)outp;
3821 outp->inCom = smbp->com = 0x2b /* Echo */;
3829 smb_SetSMBParm(outp, 0, 0);
3830 smb_SetSMBDataLength(outp, 0);
3831 lock_ReleaseWrite(&smb_rctLock);
3833 smb_SendPacket(vcp, outp);
3835 lock_ObtainWrite(&smb_rctLock);
3836 smb_ReleaseVCNoLock(vcp);
3838 lock_ReleaseWrite(&smb_rctLock);
3839 smb_FreePacket(outp);
3842 void smb_Daemon(void *parmp)
3844 afs_uint32 count = 0;
3845 smb_username_t **unpp;
3848 while(smbShutdownFlag == 0) {
3852 if (smbShutdownFlag == 1)
3855 if ((count % 72) == 0) { /* every five minutes */
3857 time_t old_localZero = smb_localZero;
3859 /* Initialize smb_localZero */
3860 myTime.tm_isdst = -1; /* compute whether on DST or not */
3861 myTime.tm_year = 70;
3867 smb_localZero = mktime(&myTime);
3869 #ifndef USE_NUMERIC_TIME_CONV
3870 smb_CalculateNowTZ();
3871 #endif /* USE_NUMERIC_TIME_CONV */
3872 #ifdef AFS_FREELANCE
3873 if ( smb_localZero != old_localZero )
3874 cm_noteLocalMountPointChange();
3880 /* GC smb_username_t objects that will no longer be used */
3882 lock_ObtainWrite(&smb_rctLock);
3883 for ( unpp=&usernamesp; *unpp; ) {
3885 smb_username_t *unp;
3887 lock_ObtainMutex(&(*unpp)->mx);
3888 if ( (*unpp)->refCount > 0 ||
3889 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
3890 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
3892 else if (!smb_LogoffTokenTransfer ||
3893 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
3895 lock_ReleaseMutex(&(*unpp)->mx);
3903 lock_FinalizeMutex(&unp->mx);
3909 cm_ReleaseUser(userp);
3911 unpp = &(*unpp)->nextp;
3914 lock_ReleaseWrite(&smb_rctLock);
3916 /* XXX GC dir search entries */
3920 void smb_WaitingLocksDaemon()
3922 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3923 smb_waitingLock_t *wl, *wlNext;
3926 smb_packet_t *inp, *outp;
3930 while (smbShutdownFlag == 0) {
3931 lock_ObtainWrite(&smb_globalLock);
3932 nwlRequest = smb_allWaitingLocks;
3933 if (nwlRequest == NULL) {
3934 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
3939 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
3946 lock_ObtainWrite(&smb_globalLock);
3948 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
3950 wlRequest = nwlRequest;
3951 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3952 lock_ReleaseWrite(&smb_globalLock);
3956 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3957 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3960 if (wl->state == SMB_WAITINGLOCKSTATE_CANCELLED) {
3961 code = CM_ERROR_LOCK_NOT_GRANTED;
3965 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
3967 /* wl->state is either _DONE or _WAITING. _ERROR
3968 would no longer be on the queue. */
3969 code = cm_RetryLock( wl->lockp,
3970 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3973 wl->state = SMB_WAITINGLOCKSTATE_DONE;
3974 } else if (code != CM_ERROR_WOULDBLOCK) {
3975 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3980 if (code == CM_ERROR_WOULDBLOCK) {
3983 if (wlRequest->msTimeout != 0xffffffff
3984 && ((osi_Time() - wlRequest->start_t) * 1000 > wlRequest->msTimeout))
3996 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
3999 scp = wlRequest->scp;
4000 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
4004 lock_ObtainWrite(&scp->rw);
4006 for (wl = wlRequest->locks; wl; wl = wlNext) {
4007 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4009 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4010 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
4011 wl->LLength, wl->key, NULL, &req);
4013 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4018 lock_ReleaseWrite(&scp->rw);
4022 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
4025 for (wl = wlRequest->locks; wl; wl = wlNext) {
4026 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4027 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4032 vcp = wlRequest->vcp;
4033 inp = wlRequest->inp;
4034 outp = wlRequest->outp;
4035 ncbp = smb_GetNCB();
4036 ncbp->ncb_length = inp->ncb_length;
4037 inp->spacep = cm_GetSpace();
4039 /* Remove waitingLock from list */
4040 lock_ObtainWrite(&smb_globalLock);
4041 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
4043 lock_ReleaseWrite(&smb_globalLock);
4045 /* Resume packet processing */
4047 smb_SetSMBDataLength(outp, 0);
4048 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
4049 outp->resumeCode = code;
4051 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
4054 cm_FreeSpace(inp->spacep);
4055 smb_FreePacket(inp);
4056 smb_FreePacket(outp);
4058 cm_ReleaseSCache(wlRequest->scp);
4061 } while (nwlRequest && smbShutdownFlag == 0);
4066 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4068 osi_Log0(smb_logp, "SMB receive get disk attributes");
4070 smb_SetSMBParm(outp, 0, 32000);
4071 smb_SetSMBParm(outp, 1, 64);
4072 smb_SetSMBParm(outp, 2, 1024);
4073 smb_SetSMBParm(outp, 3, 30000);
4074 smb_SetSMBParm(outp, 4, 0);
4075 smb_SetSMBDataLength(outp, 0);
4079 /* SMB_COM_TREE_CONNECT */
4080 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
4084 unsigned short newTid;
4085 clientchar_t shareName[AFSPATHMAX];
4086 clientchar_t *sharePath;
4089 clientchar_t *pathp;
4092 osi_Log0(smb_logp, "SMB receive tree connect");
4094 /* parse input parameters */
4097 tbp = smb_GetSMBData(inp, NULL);
4098 pathp = smb_ParseASCIIBlock(inp, tbp, &tbp, SMB_STRF_ANSIPATH);
4100 return CM_ERROR_BADSMB;
4102 tp = cm_ClientStrRChr(pathp, '\\');
4104 return CM_ERROR_BADSMB;
4105 cm_ClientStrCpy(shareName, lengthof(shareName), tp+1);
4107 lock_ObtainMutex(&vcp->mx);
4108 newTid = vcp->tidCounter++;
4109 lock_ReleaseMutex(&vcp->mx);
4111 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
4112 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
4114 return CM_ERROR_BADSMB;
4115 userp = smb_GetUserFromUID(uidp);
4116 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
4117 smb_ReleaseUID(uidp);
4119 smb_ReleaseTID(tidp, FALSE);
4120 return CM_ERROR_BADSHARENAME;
4122 lock_ObtainMutex(&tidp->mx);
4123 tidp->userp = userp;
4124 tidp->pathname = sharePath;
4125 lock_ReleaseMutex(&tidp->mx);
4126 smb_ReleaseTID(tidp, FALSE);
4128 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
4129 smb_SetSMBParm(rsp, 1, newTid);
4130 smb_SetSMBDataLength(rsp, 0);
4132 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
4136 /* set maskp to the mask part of the incoming path.
4137 * Mask is 11 bytes long (8.3 with the dot elided).
4138 * Returns true if succeeds with a valid name, otherwise it does
4139 * its best, but returns false.
4141 int smb_Get8Dot3MaskFromPath(clientchar_t *maskp, clientchar_t *pathp)
4149 /* starts off valid */
4152 /* mask starts out all blanks */
4153 memset(maskp, ' ', 11);
4156 /* find last backslash, or use whole thing if there is none */
4157 tp = cm_ClientStrRChr(pathp, '\\');
4161 tp++; /* skip slash */
4165 /* names starting with a dot are illegal */
4173 if (tc == '.' || tc == '"')
4181 /* if we get here, tp point after the dot */
4182 up = maskp+8; /* ext goes here */
4189 if (tc == '.' || tc == '"')
4192 /* copy extension if not too long */
4202 int smb_Match8Dot3Mask(clientchar_t *unixNamep, clientchar_t *maskp)
4204 clientchar_t umask[11];
4212 /* XXX redo this, calling cm_MatchMask with a converted mask */
4214 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
4218 /* otherwise, we have a valid 8.3 name; see if we have a match,
4219 * treating '?' as a wildcard in maskp (but not in the file name).
4221 tp1 = umask; /* real name, in mask format */
4222 tp2 = maskp; /* mask, in mask format */
4223 for(i=0; i<11; i++) {
4224 tc1 = *tp1++; /* clientchar_t from real name */
4225 tc2 = *tp2++; /* clientchar_t from mask */
4226 tc1 = (clientchar_t) cm_foldUpper[(clientchar_t)tc1];
4227 tc2 = (clientchar_t) cm_foldUpper[(clientchar_t)tc2];
4230 if (tc2 == '?' && tc1 != ' ')
4237 /* we got a match */
4241 clientchar_t *smb_FindMask(clientchar_t *pathp)
4245 tp = cm_ClientStrRChr(pathp, '\\'); /* find last slash */
4248 return tp+1; /* skip the slash */
4250 return pathp; /* no slash, return the entire path */
4253 /* SMB_COM_SEARCH for a volume label
4255 (This is called from smb_ReceiveCoreSearchDir() and not an actual
4256 dispatch function.) */
4257 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4259 clientchar_t *pathp;
4261 clientchar_t mask[12];
4262 unsigned char *statBlockp;
4263 unsigned char initStatBlock[21];
4266 osi_Log0(smb_logp, "SMB receive search volume");
4268 /* pull pathname and stat block out of request */
4269 tp = smb_GetSMBData(inp, NULL);
4270 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4271 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4273 return CM_ERROR_BADSMB;
4274 statBlockp = smb_ParseVblBlock(tp, &tp, &statLen);
4275 osi_assertx(statBlockp != NULL, "null statBlock");
4277 statBlockp = initStatBlock;
4281 /* for returning to caller */
4282 smb_Get8Dot3MaskFromPath(mask, pathp);
4284 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
4285 tp = smb_GetSMBData(outp, NULL);
4287 *tp++ = 43; /* bytes in a dir entry */
4288 *tp++ = 0; /* high byte in counter */
4290 /* now marshall the dir entry, starting with the search status */
4291 *tp++ = statBlockp[0]; /* Reserved */
4292 memcpy(tp, mask, 11); tp += 11; /* FileName */
4294 /* now pass back server use info, with 1st byte non-zero */
4296 memset(tp, 0, 4); tp += 4; /* reserved for server use */
4298 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
4300 *tp++ = 0x8; /* attribute: volume */
4310 /* 4 byte file size */
4316 /* The filename is a UCHAR buffer that is ASCII even if Unicode
4319 /* finally, null-terminated 8.3 pathname, which we set to AFS */
4320 memset(tp, ' ', 13);
4323 /* set the length of the data part of the packet to 43 + 3, for the dir
4324 * entry plus the 5 and the length fields.
4326 smb_SetSMBDataLength(outp, 46);
4331 smb_ApplyDirListPatches(cm_scache_t * dscp, smb_dirListPatch_t **dirPatchespp,
4332 clientchar_t * tidPathp, clientchar_t * relPathp,
4333 cm_user_t *userp, cm_req_t *reqp)
4341 smb_dirListPatch_t *patchp;
4342 smb_dirListPatch_t *npatchp;
4343 clientchar_t path[AFSPATHMAX];
4345 afs_int32 mustFake = 0;
4347 code = cm_FindACLCache(dscp, userp, &rights);
4349 lock_ObtainWrite(&dscp->rw);
4350 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4351 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4352 lock_ReleaseWrite(&dscp->rw);
4353 if (code == CM_ERROR_NOACCESS) {
4361 if (!mustFake) { /* Bulk Stat */
4363 cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4365 memset(bsp, 0, sizeof(cm_bulkStat_t));
4367 for (patchp = *dirPatchespp, count=0;
4369 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4370 cm_scache_t *tscp = cm_FindSCache(&patchp->fid);
4374 if (lock_TryWrite(&tscp->rw)) {
4375 /* we have an entry that we can look at */
4376 if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
4377 /* we have a callback on it. Don't bother
4378 * fetching this stat entry, since we're happy
4379 * with the info we have.
4381 lock_ReleaseWrite(&tscp->rw);
4382 cm_ReleaseSCache(tscp);
4385 lock_ReleaseWrite(&tscp->rw);
4387 cm_ReleaseSCache(tscp);
4391 bsp->fids[i].Volume = patchp->fid.volume;
4392 bsp->fids[i].Vnode = patchp->fid.vnode;
4393 bsp->fids[i].Unique = patchp->fid.unique;
4395 if (bsp->counter == AFSCBMAX) {
4396 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4397 memset(bsp, 0, sizeof(cm_bulkStat_t));
4401 if (bsp->counter > 0)
4402 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4407 for (patchp = *dirPatchespp; patchp; patchp =
4408 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4410 dptr = patchp->dptr;
4412 cm_ClientStrPrintfN(path, AFSPATHMAX, _C("%s\\%s"),
4413 relPathp ? relPathp : _C(""), patchp->dep->name);
4414 reqp->relPathp = path;
4415 reqp->tidPathp = tidPathp;
4417 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4418 reqp->relPathp = reqp->tidPathp = NULL;
4421 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
4422 *dptr++ = SMB_ATTR_HIDDEN;
4425 lock_ObtainWrite(&scp->rw);
4426 if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
4427 lock_ReleaseWrite(&scp->rw);
4429 /* set the attribute */
4430 switch (scp->fileType) {
4431 case CM_SCACHETYPE_DIRECTORY:
4432 case CM_SCACHETYPE_MOUNTPOINT:
4433 case CM_SCACHETYPE_INVALID:
4434 attr = SMB_ATTR_DIRECTORY;
4436 case CM_SCACHETYPE_SYMLINK:
4437 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4438 attr = SMB_ATTR_DIRECTORY;
4440 attr = SMB_ATTR_NORMAL;
4443 /* if we get here we either have a normal file
4444 * or we have a file for which we have never
4445 * received status info. In this case, we can
4446 * check the even/odd value of the entry's vnode.
4447 * odd means it is to be treated as a directory
4448 * and even means it is to be treated as a file.
4450 if (mustFake && (scp->fid.vnode & 0x1))
4451 attr = SMB_ATTR_DIRECTORY;
4453 attr = SMB_ATTR_NORMAL;
4457 /* 1969-12-31 23:59:58 +00*/
4458 dosTime = 0xEBBFBF7D;
4461 shortTemp = (unsigned short) (dosTime & 0xffff);
4462 *((u_short *)dptr) = shortTemp;
4465 /* and copy out date */
4466 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4467 *((u_short *)dptr) = shortTemp;
4470 /* copy out file length */
4471 *((u_long *)dptr) = 0;
4474 lock_ConvertWToR(&scp->rw);
4475 attr = smb_Attributes(scp);
4476 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
4477 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
4478 attr |= SMB_ATTR_HIDDEN;
4482 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4485 shortTemp = (unsigned short) (dosTime & 0xffff);
4486 *((u_short *)dptr) = shortTemp;
4489 /* and copy out date */
4490 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4491 *((u_short *)dptr) = shortTemp;
4494 /* copy out file length */
4495 *((u_long *)dptr) = scp->length.LowPart;
4497 lock_ReleaseRead(&scp->rw);
4499 cm_ReleaseSCache(scp);
4502 /* now free the patches */
4503 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4504 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4508 /* and mark the list as empty */
4509 *dirPatchespp = NULL;
4515 /* SMB_COM_SEARCH */
4516 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4522 clientchar_t *pathp;
4523 cm_dirEntry_t *dep = 0;
4525 smb_dirListPatch_t *dirListPatchesp;
4526 smb_dirListPatch_t *curPatchp;
4530 osi_hyper_t dirLength;
4531 osi_hyper_t bufferOffset;
4532 osi_hyper_t curOffset;
4534 unsigned char *inCookiep;
4535 smb_dirSearch_t *dsp;
4539 unsigned long clientCookie;
4540 cm_pageHeader_t *pageHeaderp;
4541 cm_user_t *userp = NULL;
4543 clientchar_t mask[12];
4545 long nextEntryCookie;
4546 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4547 char resByte; /* reserved byte from the cookie */
4548 char *op; /* output data ptr */
4549 char *origOp; /* original value of op */
4550 cm_space_t *spacep; /* for pathname buffer */
4554 clientchar_t *tidPathp = 0;
4561 maxCount = smb_GetSMBParm(inp, 0);
4563 dirListPatchesp = NULL;
4565 caseFold = CM_FLAG_CASEFOLD;
4567 tp = smb_GetSMBData(inp, NULL);
4568 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4569 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4571 return CM_ERROR_BADSMB;
4573 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
4575 return CM_ERROR_BADSMB;
4577 /* We can handle long names */
4578 if (vcp->flags & SMB_VCFLAG_USENT)
4579 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
4581 /* make sure we got a whole search status */
4582 if (dataLength < 21) {
4583 nextCookie = 0; /* start at the beginning of the dir */
4586 attribute = smb_GetSMBParm(inp, 1);
4588 /* handle volume info in another function */
4589 if (attribute & 0x8)
4590 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
4592 osi_Log2(smb_logp, "SMB receive search dir count %d [%S]",
4593 maxCount, osi_LogSaveClientString(smb_logp, pathp));
4595 if (*pathp == 0) { /* null pathp, treat as root dir */
4596 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
4597 return CM_ERROR_NOFILES;
4601 dsp = smb_NewDirSearch(0);
4602 dsp->attribute = attribute;
4603 smb_Get8Dot3MaskFromPath(mask, pathp);
4604 memcpy(dsp->mask, mask, 12);
4606 /* track if this is likely to match a lot of entries */
4607 if (smb_Is8Dot3StarMask(mask))
4612 /* pull the next cookie value out of the search status block */
4613 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
4614 + (inCookiep[16]<<24);
4615 dsp = smb_FindDirSearch(inCookiep[12]);
4617 /* can't find dir search status; fatal error */
4618 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%S]",
4619 inCookiep[12], nextCookie, osi_LogSaveClientString(smb_logp, pathp));
4620 return CM_ERROR_BADFD;
4622 attribute = dsp->attribute;
4623 resByte = inCookiep[0];
4625 /* copy out client cookie, in host byte order. Don't bother
4626 * interpreting it, since we're just passing it through, anyway.
4628 memcpy(&clientCookie, &inCookiep[17], 4);
4630 memcpy(mask, dsp->mask, 12);
4632 /* assume we're doing a star match if it has continued for more
4638 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
4639 nextCookie, dsp->cookie, attribute);
4641 userp = smb_GetUserFromVCP(vcp, inp);
4643 /* try to get the vnode for the path name next */
4644 lock_ObtainMutex(&dsp->mx);
4647 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
4651 spacep = inp->spacep;
4652 smb_StripLastComponent(spacep->wdata, NULL, pathp);
4653 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4655 lock_ReleaseMutex(&dsp->mx);
4656 cm_ReleaseUser(userp);
4657 smb_DeleteDirSearch(dsp);
4658 smb_ReleaseDirSearch(dsp);
4659 return CM_ERROR_NOFILES;
4661 cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
4662 cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
4664 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
4665 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
4668 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4671 pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->wdata);
4672 cm_ReleaseSCache(scp);
4673 lock_ReleaseMutex(&dsp->mx);
4674 cm_ReleaseUser(userp);
4675 smb_DeleteDirSearch(dsp);
4676 smb_ReleaseDirSearch(dsp);
4677 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4678 return CM_ERROR_PATH_NOT_COVERED;
4680 return CM_ERROR_BADSHARENAME;
4682 #endif /* DFS_SUPPORT */
4685 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
4686 /* we need one hold for the entry we just stored into,
4687 * and one for our own processing. When we're done with this
4688 * function, we'll drop the one for our own processing.
4689 * We held it once from the namei call, and so we do another hold
4693 lock_ObtainWrite(&scp->rw);
4694 dsp->flags |= SMB_DIRSEARCH_BULKST;
4695 lock_ReleaseWrite(&scp->rw);
4698 lock_ReleaseMutex(&dsp->mx);
4700 cm_ReleaseUser(userp);
4701 smb_DeleteDirSearch(dsp);
4702 smb_ReleaseDirSearch(dsp);
4706 /* reserves space for parameter; we'll adjust it again later to the
4707 * real count of the # of entries we returned once we've actually
4708 * assembled the directory listing.
4710 smb_SetSMBParm(outp, 0, 0);
4712 /* get the directory size */
4713 lock_ObtainWrite(&scp->rw);
4714 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4715 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4717 lock_ReleaseWrite(&scp->rw);
4718 cm_ReleaseSCache(scp);
4719 cm_ReleaseUser(userp);
4720 smb_DeleteDirSearch(dsp);
4721 smb_ReleaseDirSearch(dsp);
4725 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4727 dirLength = scp->length;
4729 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4730 curOffset.HighPart = 0;
4731 curOffset.LowPart = nextCookie;
4732 origOp = op = smb_GetSMBData(outp, NULL);
4733 /* and write out the basic header */
4734 *op++ = 5; /* variable block */
4735 op += 2; /* skip vbl block length; we'll fill it in later */
4739 clientchar_t *actualName = NULL;
4740 int free_actualName = 0;
4741 clientchar_t shortName[13];
4742 clientchar_t *shortNameEnd;
4744 /* make sure that curOffset.LowPart doesn't point to the first
4745 * 32 bytes in the 2nd through last dir page, and that it doesn't
4746 * point at the first 13 32-byte chunks in the first dir page,
4747 * since those are dir and page headers, and don't contain useful
4750 temp = curOffset.LowPart & (2048-1);
4751 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4752 /* we're in the first page */
4753 if (temp < 13*32) temp = 13*32;
4756 /* we're in a later dir page */
4757 if (temp < 32) temp = 32;
4760 /* make sure the low order 5 bits are zero */
4763 /* now put temp bits back ito curOffset.LowPart */
4764 curOffset.LowPart &= ~(2048-1);
4765 curOffset.LowPart |= temp;
4767 /* check if we've returned all the names that will fit in the
4770 if (returnedNames >= maxCount) {
4771 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
4772 returnedNames, maxCount);
4776 /* check if we've passed the dir's EOF */
4777 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
4779 /* see if we can use the bufferp we have now; compute in which page
4780 * the current offset would be, and check whether that's the offset
4781 * of the buffer we have. If not, get the buffer.
4783 thyper.HighPart = curOffset.HighPart;
4784 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4785 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4788 buf_Release(bufferp);
4791 lock_ReleaseWrite(&scp->rw);
4792 code = buf_Get(scp, &thyper, &bufferp);
4793 lock_ObtainMutex(&dsp->mx);
4795 /* now, if we're doing a star match, do bulk fetching of all of
4796 * the status info for files in the dir.
4799 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
4801 lock_ObtainWrite(&scp->rw);
4802 lock_ReleaseMutex(&dsp->mx);
4804 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
4808 bufferOffset = thyper;
4810 /* now get the data in the cache */
4812 code = cm_SyncOp(scp, bufferp, userp, &req,
4814 CM_SCACHESYNC_NEEDCALLBACK |
4815 CM_SCACHESYNC_READ);
4817 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
4821 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
4823 if (cm_HaveBuffer(scp, bufferp, 0)) {
4824 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4828 /* otherwise, load the buffer and try again */
4829 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
4831 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4832 scp, bufferp, code);
4837 buf_Release(bufferp);
4841 } /* if (wrong buffer) ... */
4843 /* now we have the buffer containing the entry we're interested in; copy
4844 * it out if it represents a non-deleted entry.
4846 entryInDir = curOffset.LowPart & (2048-1);
4847 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4849 /* page header will help tell us which entries are free. Page header
4850 * can change more often than once per buffer, since AFS 3 dir page size
4851 * may be less than (but not more than a buffer package buffer.
4853 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
4854 temp &= ~(2048 - 1); /* turn off intra-page bits */
4855 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4857 /* now determine which entry we're looking at in the page. If it is
4858 * free (there's a free bitmap at the start of the dir), we should
4859 * skip these 32 bytes.
4861 slotInPage = (entryInDir & 0x7e0) >> 5;
4862 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
4863 /* this entry is free */
4864 numDirChunks = 1; /* only skip this guy */
4868 tp = bufferp->datap + entryInBuffer;
4869 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4871 /* while we're here, compute the next entry's location, too,
4872 * since we'll need it when writing out the cookie into the dir
4875 * XXXX Probably should do more sanity checking.
4877 numDirChunks = cm_NameEntries(dep->name, NULL);
4879 /* compute the offset of the cookie representing the next entry */
4880 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4882 /* Compute 8.3 name if necessary */
4883 actualName = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
4884 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
4887 cm_Gen8Dot3NameInt(dep->name, &dep->fid, shortName, &shortNameEnd);
4888 actualName = shortName;
4889 free_actualName = 0;
4891 free_actualName = 1;
4894 if (actualName == NULL) {
4895 /* Couldn't convert the name for some reason */
4896 osi_Log1(smb_logp, "SMB search dir skipping entry :[%s]",
4897 osi_LogSaveString(smb_logp, dep->name));
4901 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%S)",
4902 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
4903 osi_LogSaveClientString(smb_logp, actualName));
4905 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
4906 /* this is one of the entries to use: it is not deleted
4907 * and it matches the star pattern we're looking for.
4910 /* Eliminate entries that don't match requested
4913 /* no hidden files */
4914 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
4915 osi_Log0(smb_logp, "SMB search dir skipping hidden");
4919 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4921 /* We have already done the cm_TryBulkStat above */
4922 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
4923 fileType = cm_FindFileType(&fid);
4924 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
4925 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
4927 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4928 fileType == CM_SCACHETYPE_MOUNTPOINT ||
4929 fileType == CM_SCACHETYPE_DFSLINK ||
4930 fileType == CM_SCACHETYPE_INVALID)
4931 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
4936 memcpy(op, mask, 11); op += 11;
4937 *op++ = (unsigned char) dsp->cookie; /* they say it must be non-zero */
4938 *op++ = (unsigned char)(nextEntryCookie & 0xff);
4939 *op++ = (unsigned char)((nextEntryCookie>>8) & 0xff);
4940 *op++ = (unsigned char)((nextEntryCookie>>16) & 0xff);
4941 *op++ = (unsigned char)((nextEntryCookie>>24) & 0xff);
4942 memcpy(op, &clientCookie, 4); op += 4;
4944 /* now we emit the attribute. This is sort of tricky,
4945 * since we need to really stat the file to find out
4946 * what type of entry we've got. Right now, we're
4947 * copying out data from a buffer, while holding the
4948 * scp locked, so it isn't really convenient to stat
4949 * something now. We'll put in a place holder now,
4950 * and make a second pass before returning this to get
4951 * the real attributes. So, we just skip the data for
4952 * now, and adjust it later. We allocate a patch
4953 * record to make it easy to find this point later.
4954 * The replay will happen at a time when it is safe to
4955 * unlock the directory.
4957 curPatchp = malloc(sizeof(*curPatchp));
4958 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
4959 curPatchp->dptr = op;
4960 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
4962 /* do hidden attribute here since name won't be around when applying
4966 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
4967 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4969 curPatchp->flags = 0;
4971 op += 9; /* skip attr, time, date and size */
4973 /* zero out name area. The spec says to pad with
4974 * spaces, but Samba doesn't, and neither do we.
4978 /* finally, we get to copy out the name; we know that
4979 * it fits in 8.3 or the pattern wouldn't match, but it
4980 * never hurts to be sure.
4982 cm_ClientStringToUtf8(actualName, -1, op, 13);
4983 if (smb_StoreAnsiFilenames)
4985 /* This is a UCHAR field, which is ASCII even if Unicode
4988 /* Uppercase if requested by client */
4989 if (!KNOWS_LONG_NAMES(inp))
4994 /* now, adjust the # of entries copied */
4996 } /* if we're including this name */
4999 if (free_actualName && actualName) {
5004 /* and adjust curOffset to be where the new cookie is */
5005 thyper.HighPart = 0;
5006 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5007 curOffset = LargeIntegerAdd(thyper, curOffset);
5008 } /* while copying data for dir listing */
5010 /* release the mutex */
5011 lock_ReleaseWrite(&scp->rw);
5013 buf_Release(bufferp);
5017 /* apply and free last set of patches; if not doing a star match, this
5018 * will be empty, but better safe (and freeing everything) than sorry.
5020 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
5022 /* special return code for unsuccessful search */
5023 if (code == 0 && dataLength < 21 && returnedNames == 0)
5024 code = CM_ERROR_NOFILES;
5026 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
5027 returnedNames, code);
5030 smb_DeleteDirSearch(dsp);
5031 smb_ReleaseDirSearch(dsp);
5032 cm_ReleaseSCache(scp);
5033 cm_ReleaseUser(userp);
5037 /* finalize the output buffer */
5038 smb_SetSMBParm(outp, 0, returnedNames);
5039 temp = (long) (op - origOp);
5040 smb_SetSMBDataLength(outp, temp);
5042 /* the data area is a variable block, which has a 5 (already there)
5043 * followed by the length of the # of data bytes. We now know this to
5044 * be "temp," although that includes the 3 bytes of vbl block header.
5045 * Deduct for them and fill in the length field.
5047 temp -= 3; /* deduct vbl block info */
5048 osi_assertx(temp == (43 * returnedNames), "unexpected data length");
5049 origOp[1] = (unsigned char)(temp & 0xff);
5050 origOp[2] = (unsigned char)((temp>>8) & 0xff);
5051 if (returnedNames == 0)
5052 smb_DeleteDirSearch(dsp);
5053 smb_ReleaseDirSearch(dsp);
5054 cm_ReleaseSCache(scp);
5055 cm_ReleaseUser(userp);
5060 /* verify that this is a valid path to a directory. I don't know why they
5061 * don't use the get file attributes call.
5063 * SMB_COM_CHECK_DIRECTORY
5065 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5067 clientchar_t *pathp;
5069 cm_scache_t *rootScp;
5070 cm_scache_t *newScp;
5074 clientchar_t *tidPathp;
5080 pdata = smb_GetSMBData(inp, NULL);
5081 pathp = smb_ParseASCIIBlock(inp, pdata, NULL, SMB_STRF_ANSIPATH);
5083 return CM_ERROR_BADSMB;
5084 osi_Log1(smb_logp, "SMB receive check path %S",
5085 osi_LogSaveClientString(smb_logp, pathp));
5087 rootScp = cm_data.rootSCachep;
5089 userp = smb_GetUserFromVCP(vcp, inp);
5091 caseFold = CM_FLAG_CASEFOLD;
5093 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5095 cm_ReleaseUser(userp);
5096 return CM_ERROR_NOSUCHPATH;
5098 code = cm_NameI(rootScp, pathp,
5099 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
5100 userp, tidPathp, &req, &newScp);
5103 cm_ReleaseUser(userp);
5108 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5109 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5110 cm_ReleaseSCache(newScp);
5111 cm_ReleaseUser(userp);
5112 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5113 return CM_ERROR_PATH_NOT_COVERED;
5115 return CM_ERROR_BADSHARENAME;
5117 #endif /* DFS_SUPPORT */
5119 /* now lock the vnode with a callback; returns with newScp locked */
5120 lock_ObtainWrite(&newScp->rw);
5121 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
5122 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5124 if (code != CM_ERROR_NOACCESS) {
5125 lock_ReleaseWrite(&newScp->rw);
5126 cm_ReleaseSCache(newScp);
5127 cm_ReleaseUser(userp);
5131 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5134 attrs = smb_Attributes(newScp);
5136 if (!(attrs & SMB_ATTR_DIRECTORY))
5137 code = CM_ERROR_NOTDIR;
5139 lock_ReleaseWrite(&newScp->rw);
5141 cm_ReleaseSCache(newScp);
5142 cm_ReleaseUser(userp);
5146 /* SMB_COM_SET_INFORMATION */
5147 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5149 clientchar_t *pathp;
5151 cm_scache_t *rootScp;
5152 unsigned short attribute;
5154 cm_scache_t *newScp;
5158 clientchar_t *tidPathp;
5164 /* decode basic attributes we're passed */
5165 attribute = smb_GetSMBParm(inp, 0);
5166 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5168 datap = smb_GetSMBData(inp, NULL);
5169 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5171 return CM_ERROR_BADSMB;
5173 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
5174 dosTime, attribute);
5176 rootScp = cm_data.rootSCachep;
5178 userp = smb_GetUserFromVCP(vcp, inp);
5180 caseFold = CM_FLAG_CASEFOLD;
5182 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5184 cm_ReleaseUser(userp);
5185 return CM_ERROR_NOSUCHFILE;
5187 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5188 tidPathp, &req, &newScp);
5191 cm_ReleaseUser(userp);
5196 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5197 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5198 cm_ReleaseSCache(newScp);
5199 cm_ReleaseUser(userp);
5200 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5201 return CM_ERROR_PATH_NOT_COVERED;
5203 return CM_ERROR_BADSHARENAME;
5205 #endif /* DFS_SUPPORT */
5207 /* now lock the vnode with a callback; returns with newScp locked; we
5208 * need the current status to determine what the new status is, in some
5211 lock_ObtainWrite(&newScp->rw);
5212 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5213 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5215 lock_ReleaseWrite(&newScp->rw);
5216 cm_ReleaseSCache(newScp);
5217 cm_ReleaseUser(userp);
5221 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5223 /* Check for RO volume */
5224 if (newScp->flags & CM_SCACHEFLAG_RO) {
5225 lock_ReleaseWrite(&newScp->rw);
5226 cm_ReleaseSCache(newScp);
5227 cm_ReleaseUser(userp);
5228 return CM_ERROR_READONLY;
5231 /* prepare for setattr call */
5234 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
5235 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
5237 if ((newScp->unixModeBits & 0222) && (attribute & SMB_ATTR_READONLY) != 0) {
5238 /* we're told to make a writable file read-only */
5239 attr.unixModeBits = newScp->unixModeBits & ~0222;
5240 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5242 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
5243 /* we're told to make a read-only file writable */
5244 attr.unixModeBits = newScp->unixModeBits | 0222;
5245 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5247 lock_ReleaseWrite(&newScp->rw);
5249 /* now call setattr */
5251 code = cm_SetAttr(newScp, &attr, userp, &req);
5255 cm_ReleaseSCache(newScp);
5256 cm_ReleaseUser(userp);
5262 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5264 clientchar_t *pathp;
5266 cm_scache_t *rootScp;
5267 cm_scache_t *newScp, *dscp;
5272 clientchar_t *tidPathp;
5274 clientchar_t *lastComp;
5280 datap = smb_GetSMBData(inp, NULL);
5281 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5283 return CM_ERROR_BADSMB;
5285 if (*pathp == 0) /* null path */
5288 osi_Log1(smb_logp, "SMB receive getfile attributes path %S",
5289 osi_LogSaveClientString(smb_logp, pathp));
5291 rootScp = cm_data.rootSCachep;
5293 userp = smb_GetUserFromVCP(vcp, inp);
5295 /* we shouldn't need this for V3 requests, but we seem to */
5296 caseFold = CM_FLAG_CASEFOLD;
5298 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5300 cm_ReleaseUser(userp);
5301 return CM_ERROR_NOSUCHFILE;
5305 * XXX Strange hack XXX
5307 * As of Patch 5 (16 July 97), we are having the following problem:
5308 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
5309 * requests to look up "desktop.ini" in all the subdirectories.
5310 * This can cause zillions of timeouts looking up non-existent cells
5311 * and volumes, especially in the top-level directory.
5313 * We have not found any way to avoid this or work around it except
5314 * to explicitly ignore the requests for mount points that haven't
5315 * yet been evaluated and for directories that haven't yet been
5318 * We should modify this hack to provide a fake desktop.ini file
5319 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
5321 spacep = inp->spacep;
5322 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
5323 #ifndef SPECIAL_FOLDERS
5324 if (lastComp && cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
5325 code = cm_NameI(rootScp, spacep->wdata,
5326 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
5327 userp, tidPathp, &req, &dscp);
5330 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5331 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
5333 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5334 return CM_ERROR_PATH_NOT_COVERED;
5336 return CM_ERROR_BADSHARENAME;
5338 #endif /* DFS_SUPPORT */
5339 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
5340 code = CM_ERROR_NOSUCHFILE;
5341 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
5342 cm_buf_t *bp = buf_Find(dscp, &hzero);
5347 code = CM_ERROR_NOSUCHFILE;
5349 cm_ReleaseSCache(dscp);
5351 cm_ReleaseUser(userp);
5356 #endif /* SPECIAL_FOLDERS */
5358 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5359 tidPathp, &req, &newScp);
5361 cm_ReleaseUser(userp);
5366 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5367 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5368 cm_ReleaseSCache(newScp);
5369 cm_ReleaseUser(userp);
5370 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5371 return CM_ERROR_PATH_NOT_COVERED;
5373 return CM_ERROR_BADSHARENAME;
5375 #endif /* DFS_SUPPORT */
5377 /* now lock the vnode with a callback; returns with newScp locked */
5378 lock_ObtainWrite(&newScp->rw);
5379 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5380 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5382 lock_ReleaseWrite(&newScp->rw);
5383 cm_ReleaseSCache(newScp);
5384 cm_ReleaseUser(userp);
5388 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5390 attrs = smb_Attributes(newScp);
5392 smb_SetSMBParm(outp, 0, attrs);
5394 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
5395 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
5396 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
5397 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
5398 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
5399 smb_SetSMBParm(outp, 5, 0);
5400 smb_SetSMBParm(outp, 6, 0);
5401 smb_SetSMBParm(outp, 7, 0);
5402 smb_SetSMBParm(outp, 8, 0);
5403 smb_SetSMBParm(outp, 9, 0);
5404 smb_SetSMBDataLength(outp, 0);
5405 lock_ReleaseWrite(&newScp->rw);
5407 cm_ReleaseSCache(newScp);
5408 cm_ReleaseUser(userp);
5413 /* SMB_COM_TREE_DISCONNECT */
5414 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5418 osi_Log0(smb_logp, "SMB receive tree disconnect");
5420 /* find the tree and free it */
5421 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
5423 lock_ObtainWrite(&smb_rctLock);
5425 smb_ReleaseTID(tidp, TRUE);
5426 lock_ReleaseWrite(&smb_rctLock);
5433 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5436 clientchar_t *pathp;
5437 clientchar_t *lastNamep;
5446 clientchar_t *tidPathp;
5452 datap = smb_GetSMBData(inp, NULL);
5453 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5455 return CM_ERROR_BADSMB;
5457 osi_Log1(smb_logp, "SMB receive open file [%S]", osi_LogSaveClientString(smb_logp, pathp));
5459 #ifdef DEBUG_VERBOSE
5463 hexpath = osi_HexifyString( pathp );
5464 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
5469 if (!cm_IsValidClientString(pathp)) {
5471 clientchar_t * hexp;
5473 hexp = cm_GetRawCharsAlloc(pathp, -1);
5474 osi_Log1(smb_logp, "CoreOpen rejecting invalid name. [%S]",
5475 osi_LogSaveClientString(smb_logp, hexp));
5479 osi_Log0(smb_logp, "CoreOpen rejecting invalid name");
5481 return CM_ERROR_BADNTFILENAME;
5484 share = smb_GetSMBParm(inp, 0);
5485 attribute = smb_GetSMBParm(inp, 1);
5487 spacep = inp->spacep;
5488 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5489 if (lastNamep && cm_ClientStrCmp(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0) {
5490 /* special case magic file name for receiving IOCTL requests
5491 * (since IOCTL calls themselves aren't getting through).
5493 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5494 smb_SetupIoctlFid(fidp, spacep);
5495 smb_SetSMBParm(outp, 0, fidp->fid);
5496 smb_SetSMBParm(outp, 1, 0); /* attrs */
5497 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
5498 smb_SetSMBParm(outp, 3, 0);
5499 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
5500 smb_SetSMBParm(outp, 5, 0x7fff);
5501 /* pass the open mode back */
5502 smb_SetSMBParm(outp, 6, (share & 0xf));
5503 smb_SetSMBDataLength(outp, 0);
5504 smb_ReleaseFID(fidp);
5508 userp = smb_GetUserFromVCP(vcp, inp);
5510 caseFold = CM_FLAG_CASEFOLD;
5512 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5514 cm_ReleaseUser(userp);
5515 return CM_ERROR_NOSUCHPATH;
5517 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5518 tidPathp, &req, &scp);
5521 cm_ReleaseUser(userp);
5526 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5527 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
5528 cm_ReleaseSCache(scp);
5529 cm_ReleaseUser(userp);
5530 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5531 return CM_ERROR_PATH_NOT_COVERED;
5533 return CM_ERROR_BADSHARENAME;
5535 #endif /* DFS_SUPPORT */
5537 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
5539 cm_ReleaseSCache(scp);
5540 cm_ReleaseUser(userp);
5544 /* don't need callback to check file type, since file types never
5545 * change, and namei and cm_Lookup all stat the object at least once on
5546 * a successful return.
5548 if (scp->fileType != CM_SCACHETYPE_FILE) {
5549 cm_ReleaseSCache(scp);
5550 cm_ReleaseUser(userp);
5551 return CM_ERROR_ISDIR;
5554 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5555 osi_assertx(fidp, "null smb_fid_t");
5557 /* save a pointer to the vnode */
5559 osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
5560 lock_ObtainWrite(&scp->rw);
5561 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5562 lock_ReleaseWrite(&scp->rw);
5566 fidp->userp = userp;
5568 lock_ObtainMutex(&fidp->mx);
5569 if ((share & 0xf) == 0)
5570 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5571 else if ((share & 0xf) == 1)
5572 fidp->flags |= SMB_FID_OPENWRITE;
5574 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
5575 lock_ReleaseMutex(&fidp->mx);
5577 lock_ObtainRead(&scp->rw);
5578 smb_SetSMBParm(outp, 0, fidp->fid);
5579 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
5580 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5581 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
5582 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
5583 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
5584 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
5585 /* pass the open mode back; XXXX add access checks */
5586 smb_SetSMBParm(outp, 6, (share & 0xf));
5587 smb_SetSMBDataLength(outp, 0);
5588 lock_ReleaseRead(&scp->rw);
5591 cm_Open(scp, 0, userp);
5593 /* send and free packet */
5594 smb_ReleaseFID(fidp);
5595 cm_ReleaseUser(userp);
5596 /* don't release scp, since we've squirreled away the pointer in the fid struct */
5600 typedef struct smb_unlinkRock {
5605 clientchar_t *maskp; /* pointer to the star pattern */
5608 cm_dirEntryList_t * matches;
5611 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5614 smb_unlinkRock_t *rockp;
5617 normchar_t matchName[MAX_PATH];
5621 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5622 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5623 caseFold |= CM_FLAG_8DOT3;
5625 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
5626 /* Can't convert name */
5627 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string.",
5628 osi_LogSaveString(smb_logp, dep->name));
5632 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5634 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5635 !cm_Is8Dot3(matchName)) {
5636 cm_Gen8Dot3Name(dep, matchName, NULL);
5637 /* 8.3 matches are always case insensitive */
5638 match = cm_MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
5641 osi_Log1(smb_logp, "Found match %S",
5642 osi_LogSaveClientString(smb_logp, matchName));
5644 cm_DirEntryListAdd(dep->name, &rockp->matches);
5648 /* If we made a case sensitive exact match, we might as well quit now. */
5649 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !cm_ClientStrCmp(matchName, rockp->maskp))
5650 code = CM_ERROR_STOPNOW;
5659 /* SMB_COM_DELETE */
5660 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5664 clientchar_t *pathp;
5668 clientchar_t *lastNamep;
5669 smb_unlinkRock_t rock;
5673 clientchar_t *tidPathp;
5677 memset(&rock, 0, sizeof(rock));
5679 attribute = smb_GetSMBParm(inp, 0);
5681 tp = smb_GetSMBData(inp, NULL);
5682 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
5684 return CM_ERROR_BADSMB;
5686 osi_Log1(smb_logp, "SMB receive unlink %S",
5687 osi_LogSaveClientString(smb_logp, pathp));
5689 spacep = inp->spacep;
5690 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5692 userp = smb_GetUserFromVCP(vcp, inp);
5694 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5696 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5698 cm_ReleaseUser(userp);
5699 return CM_ERROR_NOSUCHPATH;
5701 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold, userp, tidPathp,
5704 cm_ReleaseUser(userp);
5709 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5710 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
5711 cm_ReleaseSCache(dscp);
5712 cm_ReleaseUser(userp);
5713 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5714 return CM_ERROR_PATH_NOT_COVERED;
5716 return CM_ERROR_BADSHARENAME;
5718 #endif /* DFS_SUPPORT */
5720 /* otherwise, scp points to the parent directory. */
5727 rock.maskp = cm_ClientStringToNormStringAlloc(smb_FindMask(pathp), -1, NULL);
5729 code = CM_ERROR_NOSUCHFILE;
5732 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5735 thyper.HighPart = 0;
5740 rock.matches = NULL;
5742 /* Now, if we aren't dealing with a wildcard match, we first try an exact
5743 * match. If that fails, we do a case insensitve match.
5745 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
5746 !smb_IsStarMask(rock.maskp)) {
5747 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5750 thyper.HighPart = 0;
5751 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5756 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5758 if (code == CM_ERROR_STOPNOW)
5761 if (code == 0 && rock.matches) {
5762 cm_dirEntryList_t * entry;
5764 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
5765 normchar_t normalizedName[MAX_PATH];
5767 /* Note: entry->name is a non-normalized name */
5769 osi_Log1(smb_logp, "Unlinking %s",
5770 osi_LogSaveString(smb_logp, entry->name));
5772 /* We assume this works because entry->name was
5773 successfully converted in smb_UnlinkProc() once. */
5774 cm_FsStringToNormString(entry->name, -1,
5775 normalizedName, lengthof(normalizedName));
5777 code = cm_Unlink(dscp, entry->name, normalizedName, userp, &req);
5779 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5780 smb_NotifyChange(FILE_ACTION_REMOVED,
5781 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5782 dscp, normalizedName, NULL, TRUE);
5786 cm_DirEntryListFree(&rock.matches);
5790 cm_ReleaseUser(userp);
5793 cm_ReleaseSCache(dscp);
5798 if (code == 0 && !rock.any)
5799 code = CM_ERROR_NOSUCHFILE;
5803 typedef struct smb_renameRock {
5804 cm_scache_t *odscp; /* old dir */
5805 cm_scache_t *ndscp; /* new dir */
5806 cm_user_t *userp; /* user */
5807 cm_req_t *reqp; /* request struct */
5808 smb_vc_t *vcp; /* virtual circuit */
5809 normchar_t *maskp; /* pointer to star pattern of old file name */
5810 int flags; /* tilde, casefold, etc */
5811 clientchar_t *newNamep; /* ptr to the new file's name */
5812 fschar_t fsOldName[MAX_PATH]; /* raw FS name */
5813 clientchar_t clOldName[MAX_PATH]; /* client name */
5817 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5820 smb_renameRock_t *rockp;
5823 normchar_t matchName[MAX_PATH];
5825 rockp = (smb_renameRock_t *) vrockp;
5827 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
5828 /* Can't convert string */
5829 osi_Log1(smb_logp, "Skpping entry [%s]. Can't normalize FS string",
5830 osi_LogSaveString(smb_logp, dep->name));
5834 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5835 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5836 caseFold |= CM_FLAG_8DOT3;
5838 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5840 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5841 !cm_Is8Dot3(matchName)) {
5842 cm_Gen8Dot3Name(dep, matchName, NULL);
5843 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5848 StringCbCopyA(rockp->fsOldName, sizeof(rockp->fsOldName), dep->name);
5849 cm_ClientStrCpy(rockp->clOldName, lengthof(rockp->clOldName),
5851 code = CM_ERROR_STOPNOW;
5861 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp, int attrs)
5864 cm_space_t *spacep = NULL;
5865 smb_renameRock_t rock;
5866 cm_scache_t *oldDscp = NULL;
5867 cm_scache_t *newDscp = NULL;
5868 cm_scache_t *tmpscp= NULL;
5869 cm_scache_t *tmpscp2 = NULL;
5870 clientchar_t *oldLastNamep;
5871 clientchar_t *newLastNamep;
5875 clientchar_t *tidPathp;
5879 userp = smb_GetUserFromVCP(vcp, inp);
5880 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5882 cm_ReleaseUser(userp);
5883 return CM_ERROR_NOSUCHPATH;
5887 memset(&rock, 0, sizeof(rock));
5889 spacep = inp->spacep;
5890 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
5892 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5893 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
5894 userp, tidPathp, &req, &oldDscp);
5896 cm_ReleaseUser(userp);
5901 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5902 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
5903 cm_ReleaseSCache(oldDscp);
5904 cm_ReleaseUser(userp);
5905 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5906 return CM_ERROR_PATH_NOT_COVERED;
5908 return CM_ERROR_BADSHARENAME;
5910 #endif /* DFS_SUPPORT */
5912 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
5913 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
5914 userp, tidPathp, &req, &newDscp);
5917 cm_ReleaseSCache(oldDscp);
5918 cm_ReleaseUser(userp);
5923 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5924 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
5925 cm_ReleaseSCache(oldDscp);
5926 cm_ReleaseSCache(newDscp);
5927 cm_ReleaseUser(userp);
5928 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5929 return CM_ERROR_PATH_NOT_COVERED;
5931 return CM_ERROR_BADSHARENAME;
5933 #endif /* DFS_SUPPORT */
5936 /* otherwise, oldDscp and newDscp point to the corresponding directories.
5937 * next, get the component names, and lower case them.
5940 /* handle the old name first */
5942 oldLastNamep = oldPathp;
5946 /* and handle the new name, too */
5948 newLastNamep = newPathp;
5952 /* TODO: The old name could be a wildcard. The new name must not be */
5954 /* Check if the file already exists; if so return error */
5955 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5956 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
5957 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
5959 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
5960 osi_LogSaveClientString(smb_logp, newLastNamep));
5962 /* Check if the old and the new names differ only in case. If so return
5963 * success, else return CM_ERROR_EXISTS
5965 if (!code && oldDscp == newDscp && !cm_ClientStrCmpI(oldLastNamep, newLastNamep)) {
5967 /* This would be a success only if the old file is *as same as* the new file */
5968 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
5970 if (tmpscp == tmpscp2)
5973 code = CM_ERROR_EXISTS;
5974 cm_ReleaseSCache(tmpscp2);
5977 code = CM_ERROR_NOSUCHFILE;
5980 /* file exist, do not rename, also fixes move */
5981 osi_Log0(smb_logp, "Can't rename. Target already exists");
5982 code = CM_ERROR_EXISTS;
5987 /* do the vnode call */
5988 rock.odscp = oldDscp;
5989 rock.ndscp = newDscp;
5993 rock.maskp = cm_ClientStringToNormStringAlloc(oldLastNamep, -1, NULL);
5995 code = CM_ERROR_NOSUCHFILE;
5998 rock.flags = ((cm_ClientStrChr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5999 rock.newNamep = newLastNamep;
6000 rock.fsOldName[0] = '\0';
6001 rock.clOldName[0] = '\0';
6004 /* Now search the directory for the pattern, and do the appropriate rename when found */
6005 thyper.LowPart = 0; /* search dir from here */
6006 thyper.HighPart = 0;
6008 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6009 if (code == 0 && !rock.any) {
6011 thyper.HighPart = 0;
6012 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6013 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6015 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
6017 if (code == CM_ERROR_STOPNOW && rock.fsOldName[0] != '\0') {
6018 code = cm_Rename(rock.odscp, rock.fsOldName, rock.clOldName,
6019 rock.ndscp, rock.newNamep, rock.userp,
6021 /* if the call worked, stop doing the search now, since we
6022 * really only want to rename one file.
6025 osi_Log0(smb_logp, "cm_Rename failure");
6026 osi_Log1(smb_logp, "cm_Rename returns %ld", code);
6027 } else if (code == 0) {
6028 code = CM_ERROR_NOSUCHFILE;
6031 /* Handle Change Notification */
6033 * Being lazy, not distinguishing between files and dirs in this
6034 * filter, since we'd have to do a lookup.
6037 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
6038 if (oldDscp == newDscp) {
6039 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6040 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6041 filter, oldDscp, rock.clOldName,
6042 newLastNamep, TRUE);
6044 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6045 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6046 filter, oldDscp, rock.clOldName,
6048 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6049 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
6050 filter, newDscp, newLastNamep,
6057 cm_ReleaseSCache(tmpscp);
6059 cm_ReleaseUser(userp);
6061 cm_ReleaseSCache(oldDscp);
6063 cm_ReleaseSCache(newDscp);
6071 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp)
6074 cm_space_t *spacep = NULL;
6075 cm_scache_t *oldDscp = NULL;
6076 cm_scache_t *newDscp = NULL;
6077 cm_scache_t *tmpscp= NULL;
6078 cm_scache_t *tmpscp2 = NULL;
6079 cm_scache_t *sscp = NULL;
6080 clientchar_t *oldLastNamep;
6081 clientchar_t *newLastNamep;
6084 clientchar_t *tidPathp;
6088 userp = smb_GetUserFromVCP(vcp, inp);
6090 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6092 cm_ReleaseUser(userp);
6093 return CM_ERROR_NOSUCHPATH;
6098 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6100 spacep = inp->spacep;
6101 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6103 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6104 userp, tidPathp, &req, &oldDscp);
6106 cm_ReleaseUser(userp);
6111 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6112 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6113 cm_ReleaseSCache(oldDscp);
6114 cm_ReleaseUser(userp);
6115 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6116 return CM_ERROR_PATH_NOT_COVERED;
6118 return CM_ERROR_BADSHARENAME;
6120 #endif /* DFS_SUPPORT */
6122 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6123 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6124 userp, tidPathp, &req, &newDscp);
6126 cm_ReleaseSCache(oldDscp);
6127 cm_ReleaseUser(userp);
6132 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6133 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6134 cm_ReleaseSCache(newDscp);
6135 cm_ReleaseSCache(oldDscp);
6136 cm_ReleaseUser(userp);
6137 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6138 return CM_ERROR_PATH_NOT_COVERED;
6140 return CM_ERROR_BADSHARENAME;
6142 #endif /* DFS_SUPPORT */
6144 /* Now, although we did two lookups for the two directories (because the same
6145 * directory can be referenced through different paths), we only allow hard links
6146 * within the same directory. */
6147 if (oldDscp != newDscp) {
6148 cm_ReleaseSCache(oldDscp);
6149 cm_ReleaseSCache(newDscp);
6150 cm_ReleaseUser(userp);
6151 return CM_ERROR_CROSSDEVLINK;
6154 /* handle the old name first */
6156 oldLastNamep = oldPathp;
6160 /* and handle the new name, too */
6162 newLastNamep = newPathp;
6166 /* now lookup the old name */
6167 osi_Log1(smb_logp," looking up [%S]", osi_LogSaveClientString(smb_logp,oldLastNamep));
6168 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
6170 cm_ReleaseSCache(oldDscp);
6171 cm_ReleaseSCache(newDscp);
6172 cm_ReleaseUser(userp);
6176 /* Check if the file already exists; if so return error */
6177 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6178 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6179 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6181 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6182 osi_LogSaveClientString(smb_logp, newLastNamep));
6184 /* if the existing link is to the same file, then we return success */
6186 if(sscp == tmpscp) {
6189 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
6190 code = CM_ERROR_EXISTS;
6195 cm_ReleaseSCache(tmpscp);
6196 cm_ReleaseSCache(sscp);
6197 cm_ReleaseSCache(newDscp);
6198 cm_ReleaseSCache(oldDscp);
6199 cm_ReleaseUser(userp);
6203 /* now create the hardlink */
6204 osi_Log1(smb_logp," Attempting to create new link [%S]", osi_LogSaveClientString(smb_logp, newLastNamep));
6205 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
6206 osi_Log1(smb_logp," Link returns 0x%x", code);
6208 /* Handle Change Notification */
6210 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
6211 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6212 smb_NotifyChange(FILE_ACTION_ADDED,
6213 filter, newDscp, newLastNamep,
6218 cm_ReleaseSCache(tmpscp);
6219 cm_ReleaseUser(userp);
6220 cm_ReleaseSCache(sscp);
6221 cm_ReleaseSCache(oldDscp);
6222 cm_ReleaseSCache(newDscp);
6226 /* SMB_COM_RENAME */
6228 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6230 clientchar_t *oldPathp;
6231 clientchar_t *newPathp;
6235 tp = smb_GetSMBData(inp, NULL);
6236 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6238 return CM_ERROR_BADSMB;
6239 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6241 return CM_ERROR_BADSMB;
6243 osi_Log2(smb_logp, "smb rename [%S] to [%S]",
6244 osi_LogSaveClientString(smb_logp, oldPathp),
6245 osi_LogSaveClientString(smb_logp, newPathp));
6247 if (!cm_IsValidClientString(newPathp)) {
6249 clientchar_t * hexp;
6251 hexp = cm_GetRawCharsAlloc(newPathp, -1);
6252 osi_Log1(smb_logp, "CoreRename rejecting invalid name. [%S]",
6253 osi_LogSaveClientString(smb_logp, hexp));
6257 osi_Log0(smb_logp, "CoreRename rejecting invalid name");
6259 return CM_ERROR_BADNTFILENAME;
6262 code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
6264 osi_Log1(smb_logp, "smb rename returns 0x%x", code);
6270 typedef struct smb_rmdirRock {
6274 normchar_t *maskp; /* pointer to the star pattern */
6277 cm_dirEntryList_t * matches;
6280 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6283 smb_rmdirRock_t *rockp;
6285 normchar_t matchName[MAX_PATH];
6287 rockp = (smb_rmdirRock_t *) vrockp;
6289 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6290 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6291 osi_LogSaveString(smb_logp, dep->name));
6295 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
6296 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6298 match = (cm_ClientStrCmp(matchName, rockp->maskp) == 0);
6300 (rockp->flags & SMB_MASKFLAG_TILDE) &&
6301 !cm_Is8Dot3(matchName)) {
6302 cm_Gen8Dot3Name(dep, matchName, NULL);
6303 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6308 cm_DirEntryListAdd(dep->name, &rockp->matches);
6315 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6318 clientchar_t *pathp;
6322 clientchar_t *lastNamep;
6323 smb_rmdirRock_t rock;
6327 clientchar_t *tidPathp;
6331 memset(&rock, 0, sizeof(rock));
6333 tp = smb_GetSMBData(inp, NULL);
6334 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6336 return CM_ERROR_BADSMB;
6338 spacep = inp->spacep;
6339 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
6341 userp = smb_GetUserFromVCP(vcp, inp);
6343 caseFold = CM_FLAG_CASEFOLD;
6345 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6347 cm_ReleaseUser(userp);
6348 return CM_ERROR_NOSUCHPATH;
6350 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
6351 userp, tidPathp, &req, &dscp);
6354 cm_ReleaseUser(userp);
6359 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6360 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
6361 cm_ReleaseSCache(dscp);
6362 cm_ReleaseUser(userp);
6363 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6364 return CM_ERROR_PATH_NOT_COVERED;
6366 return CM_ERROR_BADSHARENAME;
6368 #endif /* DFS_SUPPORT */
6370 /* otherwise, scp points to the parent directory. */
6377 rock.maskp = cm_ClientStringToNormStringAlloc(lastNamep, -1, NULL);
6379 code = CM_ERROR_NOSUCHFILE;
6382 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6385 thyper.HighPart = 0;
6389 rock.matches = NULL;
6391 /* First do a case sensitive match, and if that fails, do a case insensitive match */
6392 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6393 if (code == 0 && !rock.any) {
6395 thyper.HighPart = 0;
6396 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6397 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6400 if (code == 0 && rock.matches) {
6401 cm_dirEntryList_t * entry;
6403 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
6404 clientchar_t clientName[MAX_PATH];
6406 /* We assume this will succeed because smb_RmdirProc()
6407 successfully converted entry->name once above. */
6408 cm_FsStringToClientString(entry->name, -1, clientName, lengthof(clientName));
6410 osi_Log1(smb_logp, "Removing directory %s",
6411 osi_LogSaveString(smb_logp, entry->name));
6413 code = cm_RemoveDir(dscp, entry->name, clientName, userp, &req);
6415 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6416 smb_NotifyChange(FILE_ACTION_REMOVED,
6417 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6418 dscp, clientName, NULL, TRUE);
6424 cm_DirEntryListFree(&rock.matches);
6427 cm_ReleaseUser(userp);
6430 cm_ReleaseSCache(dscp);
6432 if (code == 0 && !rock.any)
6433 code = CM_ERROR_NOSUCHFILE;
6442 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6452 fid = smb_GetSMBParm(inp, 0);
6454 osi_Log1(smb_logp, "SMB flush fid %d", fid);
6456 fid = smb_ChainFID(fid, inp);
6457 fidp = smb_FindFID(vcp, fid, 0);
6459 return CM_ERROR_BADFD;
6461 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6462 smb_CloseFID(vcp, fidp, NULL, 0);
6463 smb_ReleaseFID(fidp);
6464 return CM_ERROR_NOSUCHFILE;
6467 lock_ObtainMutex(&fidp->mx);
6468 if (fidp->flags & SMB_FID_IOCTL) {
6469 lock_ReleaseMutex(&fidp->mx);
6470 smb_ReleaseFID(fidp);
6471 return CM_ERROR_BADFD;
6473 lock_ReleaseMutex(&fidp->mx);
6475 userp = smb_GetUserFromVCP(vcp, inp);
6477 lock_ObtainMutex(&fidp->mx);
6478 if ((fidp->flags & SMB_FID_OPENWRITE) && smb_AsyncStore != 2) {
6479 cm_scache_t * scp = fidp->scp;
6481 lock_ReleaseMutex(&fidp->mx);
6482 code = cm_FSync(scp, userp, &req);
6483 cm_ReleaseSCache(scp);
6486 lock_ReleaseMutex(&fidp->mx);
6489 smb_ReleaseFID(fidp);
6491 cm_ReleaseUser(userp);
6496 struct smb_FullNameRock {
6499 clientchar_t *fullName;
6500 fschar_t *originalName;
6503 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
6506 normchar_t matchName[MAX_PATH];
6507 struct smb_FullNameRock *vrockp;
6509 vrockp = (struct smb_FullNameRock *)rockp;
6511 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6512 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6513 osi_LogSaveString(smb_logp, dep->name));
6517 if (!cm_Is8Dot3(matchName)) {
6518 clientchar_t shortName[13];
6520 cm_Gen8Dot3Name(dep, shortName, NULL);
6522 if (cm_ClientStrCmpIA(shortName, vrockp->name) == 0) {
6523 vrockp->fullName = cm_ClientStrDup(matchName);
6524 vrockp->originalName = cm_FsStrDup(dep->name);
6525 return CM_ERROR_STOPNOW;
6528 if (cm_ClientStrCmpI(matchName, vrockp->name) == 0 &&
6529 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
6530 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
6531 vrockp->fullName = cm_ClientStrDup(matchName);
6532 vrockp->originalName = cm_FsStrDup(dep->name);
6533 return CM_ERROR_STOPNOW;
6538 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, clientchar_t *pathp,
6539 clientchar_t **newPathp, fschar_t ** originalPathp,
6540 cm_user_t *userp, cm_req_t *reqp)
6542 struct smb_FullNameRock rock;
6545 memset(&rock, 0, sizeof(rock));
6549 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
6550 if (code == CM_ERROR_STOPNOW) {
6551 *newPathp = rock.fullName;
6552 *originalPathp = rock.originalName;
6554 *newPathp = cm_ClientStrDup(pathp);
6555 *originalPathp = cm_ClientStringToFsStringAlloc(pathp, -1, NULL);
6559 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
6560 afs_uint32 dosTime) {
6563 cm_scache_t *dscp = NULL;
6564 clientchar_t *pathp = NULL;
6565 cm_scache_t * scp = NULL;
6566 cm_scache_t *delscp = NULL;
6567 int nullcreator = 0;
6569 osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
6570 fidp, fidp->fid, scp, vcp);
6573 lock_ObtainMutex(&fidp->mx);
6574 if (!fidp->userp && !(fidp->flags & SMB_FID_IOCTL)) {
6575 lock_ReleaseMutex(&fidp->mx);
6576 osi_Log0(smb_logp, " No user specified. Not closing fid");
6577 return CM_ERROR_BADFD;
6580 userp = fidp->userp; /* no hold required since fidp is held
6581 throughout the function */
6582 lock_ReleaseMutex(&fidp->mx);
6587 lock_ObtainWrite(&smb_rctLock);
6588 if (fidp->deleteOk) {
6589 osi_Log0(smb_logp, " Fid already closed.");
6590 lock_ReleaseWrite(&smb_rctLock);
6591 return CM_ERROR_BADFD;
6594 lock_ReleaseWrite(&smb_rctLock);
6596 lock_ObtainMutex(&fidp->mx);
6597 if (fidp->NTopen_dscp) {
6598 dscp = fidp->NTopen_dscp;
6599 cm_HoldSCache(dscp);
6602 if (fidp->NTopen_pathp) {
6603 pathp = cm_ClientStrDup(fidp->NTopen_pathp);
6611 /* Don't jump the gun on an async raw write */
6612 while (fidp->raw_writers) {
6613 lock_ReleaseMutex(&fidp->mx);
6614 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
6615 lock_ObtainMutex(&fidp->mx);
6618 /* watch for ioctl closes, and read-only opens */
6620 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
6621 == SMB_FID_OPENWRITE) {
6622 if (dosTime != 0 && dosTime != -1) {
6623 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6624 /* This fixes defect 10958 */
6625 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
6626 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
6628 if (smb_AsyncStore != 2) {
6629 lock_ReleaseMutex(&fidp->mx);
6630 code = cm_FSync(scp, userp, &req);
6631 lock_ObtainMutex(&fidp->mx);
6637 /* unlock any pending locks */
6638 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
6639 scp->fileType == CM_SCACHETYPE_FILE) {
6643 lock_ReleaseMutex(&fidp->mx);
6645 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
6647 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
6648 lock_ObtainWrite(&scp->rw);
6650 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
6651 CM_SCACHESYNC_NEEDCALLBACK
6652 | CM_SCACHESYNC_GETSTATUS
6653 | CM_SCACHESYNC_LOCK);
6657 "smb CoreClose SyncOp failure code 0x%x", tcode);
6658 goto post_syncopdone;
6661 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
6663 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
6667 lock_ReleaseWrite(&scp->rw);
6668 lock_ObtainMutex(&fidp->mx);
6671 if (fidp->flags & SMB_FID_DELONCLOSE) {
6672 clientchar_t *fullPathp = NULL;
6673 fschar_t *originalNamep = NULL;
6675 lock_ReleaseMutex(&fidp->mx);
6677 code = cm_Lookup(dscp, pathp, CM_FLAG_NOMOUNTCHASE, userp, &req, &delscp);
6682 smb_FullName(dscp, delscp, pathp, &fullPathp, &originalNamep, userp, &req);
6683 if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
6684 code = cm_RemoveDir(dscp, originalNamep, fullPathp, userp, &req);
6686 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6687 smb_NotifyChange(FILE_ACTION_REMOVED,
6688 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6689 dscp, fullPathp, NULL, TRUE);
6692 code = cm_Unlink(dscp, originalNamep, fullPathp, userp, &req);
6694 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6695 smb_NotifyChange(FILE_ACTION_REMOVED,
6696 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6697 dscp, fullPathp, NULL, TRUE);
6704 free(originalNamep);
6706 lock_ObtainMutex(&fidp->mx);
6707 fidp->flags &= ~SMB_FID_DELONCLOSE;
6710 /* if this was a newly created file, then clear the creator
6711 * in the stat cache entry. */
6712 if (fidp->flags & SMB_FID_CREATED) {
6714 fidp->flags &= ~SMB_FID_CREATED;
6717 if (fidp->flags & SMB_FID_NTOPEN) {
6718 cm_ReleaseSCache(fidp->NTopen_dscp);
6719 fidp->NTopen_dscp = NULL;
6720 free(fidp->NTopen_pathp);
6721 fidp->NTopen_pathp = NULL;
6722 fidp->flags &= ~SMB_FID_NTOPEN;
6724 osi_assertx(fidp->NTopen_dscp == NULL, "null NTopen_dsc");
6725 osi_assertx(fidp->NTopen_pathp == NULL, "null NTopen_path");
6728 if (fidp->NTopen_wholepathp) {
6729 free(fidp->NTopen_wholepathp);
6730 fidp->NTopen_wholepathp = NULL;
6734 cm_ReleaseSCache(fidp->scp);
6737 lock_ReleaseMutex(&fidp->mx);
6740 cm_ReleaseSCache(dscp);
6743 cm_ReleaseSCache(delscp);
6747 lock_ObtainWrite(&scp->rw);
6748 if (nullcreator && scp->creator == userp)
6749 scp->creator = NULL;
6750 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
6751 lock_ReleaseWrite(&scp->rw);
6752 cm_ReleaseSCache(scp);
6762 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6770 fid = smb_GetSMBParm(inp, 0);
6771 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6773 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
6775 fid = smb_ChainFID(fid, inp);
6776 fidp = smb_FindFID(vcp, fid, 0);
6778 return CM_ERROR_BADFD;
6781 userp = smb_GetUserFromVCP(vcp, inp);
6783 code = smb_CloseFID(vcp, fidp, userp, dosTime);
6785 smb_ReleaseFID(fidp);
6786 cm_ReleaseUser(userp);
6791 * smb_ReadData -- common code for Read, Read And X, and Raw Read
6793 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
6794 cm_user_t *userp, long *readp)
6800 osi_hyper_t fileLength;
6802 osi_hyper_t lastByte;
6803 osi_hyper_t bufferOffset;
6807 int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
6810 osi_Log3(smb_logp, "smb_ReadData fid %d, off 0x%x, size 0x%x",
6811 fidp->fid, offsetp->LowPart, count);
6815 lock_ObtainMutex(&fidp->mx);
6816 /* make sure we have a readable FD */
6817 if (!(fidp->flags & SMB_FID_OPENREAD_LISTDIR)) {
6818 osi_Log2(smb_logp, "smb_ReadData fid %d not OPENREAD_LISTDIR flags 0x%x",
6819 fidp->fid, fidp->flags);
6820 lock_ReleaseMutex(&fidp->mx);
6821 code = CM_ERROR_BADFDOP;
6832 lock_ObtainWrite(&scp->rw);
6834 if (offset.HighPart == 0) {
6835 chunk = offset.LowPart >> cm_logChunkSize;
6836 if (chunk != fidp->curr_chunk) {
6837 fidp->prev_chunk = fidp->curr_chunk;
6838 fidp->curr_chunk = chunk;
6840 if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
6843 lock_ReleaseMutex(&fidp->mx);
6845 /* start by looking up the file's end */
6846 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6847 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6851 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6853 /* now we have the entry locked, look up the length */
6854 fileLength = scp->length;
6856 /* adjust count down so that it won't go past EOF */
6857 thyper.LowPart = count;
6858 thyper.HighPart = 0;
6859 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
6861 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6862 /* we'd read past EOF, so just stop at fileLength bytes.
6863 * Start by computing how many bytes remain in the file.
6865 thyper = LargeIntegerSubtract(fileLength, offset);
6867 /* if we are past EOF, read 0 bytes */
6868 if (LargeIntegerLessThanZero(thyper))
6871 count = thyper.LowPart;
6876 /* now, copy the data one buffer at a time,
6877 * until we've filled the request packet
6880 /* if we've copied all the data requested, we're done */
6881 if (count <= 0) break;
6883 /* otherwise, load up a buffer of data */
6884 thyper.HighPart = offset.HighPart;
6885 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6886 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6889 buf_Release(bufferp);
6892 lock_ReleaseWrite(&scp->rw);
6894 code = buf_Get(scp, &thyper, &bufferp);
6896 lock_ObtainWrite(&scp->rw);
6897 if (code) goto done;
6898 bufferOffset = thyper;
6900 /* now get the data in the cache */
6902 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6903 CM_SCACHESYNC_NEEDCALLBACK |
6904 CM_SCACHESYNC_READ);
6908 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
6910 if (cm_HaveBuffer(scp, bufferp, 0)) break;
6912 /* otherwise, load the buffer and try again */
6913 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
6917 buf_Release(bufferp);
6921 } /* if (wrong buffer) ... */
6923 /* now we have the right buffer loaded. Copy out the
6924 * data from here to the user's buffer.
6926 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6928 /* and figure out how many bytes we want from this buffer */
6929 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6930 if (nbytes > count) nbytes = count; /* don't go past EOF */
6932 /* now copy the data */
6933 memcpy(op, bufferp->datap + bufIndex, nbytes);
6935 /* adjust counters, pointers, etc. */
6938 thyper.LowPart = nbytes;
6939 thyper.HighPart = 0;
6940 offset = LargeIntegerAdd(thyper, offset);
6944 lock_ReleaseWrite(&scp->rw);
6946 buf_Release(bufferp);
6948 if (code == 0 && sequential)
6949 cm_ConsiderPrefetch(scp, &lastByte, *readp, userp, &req);
6951 cm_ReleaseSCache(scp);
6954 osi_Log3(smb_logp, "smb_ReadData fid %d returns 0x%x read %d bytes",
6955 fidp->fid, code, *readp);
6960 * smb_WriteData -- common code for Write and Raw Write
6962 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
6963 cm_user_t *userp, long *writtenp)
6965 osi_hyper_t offset = *offsetp;
6968 cm_scache_t *scp = NULL;
6969 osi_hyper_t fileLength; /* file's length at start of write */
6970 osi_hyper_t minLength; /* don't read past this */
6971 afs_uint32 nbytes; /* # of bytes to transfer this iteration */
6972 cm_buf_t *bufferp = NULL;
6973 osi_hyper_t thyper; /* hyper tmp variable */
6974 osi_hyper_t bufferOffset;
6975 afs_uint32 bufIndex; /* index in buffer where our data is */
6976 int doWriteBack = 0;
6977 osi_hyper_t writeBackOffset;/* offset of region to write back when I/O is done */
6981 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
6982 fidp->fid, offsetp->LowPart, count);
6986 lock_ObtainMutex(&fidp->mx);
6987 /* make sure we have a writable FD */
6988 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
6989 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
6990 fidp->fid, fidp->flags);
6991 lock_ReleaseMutex(&fidp->mx);
6992 code = CM_ERROR_BADFDOP;
7000 lock_ReleaseMutex(&fidp->mx);
7002 lock_ObtainWrite(&scp->rw);
7003 /* start by looking up the file's end */
7004 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7005 CM_SCACHESYNC_NEEDCALLBACK
7006 | CM_SCACHESYNC_SETSTATUS
7007 | CM_SCACHESYNC_GETSTATUS);
7011 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
7013 /* now we have the entry locked, look up the length */
7014 fileLength = scp->length;
7015 minLength = fileLength;
7016 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
7017 minLength = scp->serverLength;
7019 /* adjust file length if we extend past EOF */
7020 thyper.LowPart = count;
7021 thyper.HighPart = 0;
7022 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
7023 if (LargeIntegerGreaterThan(thyper, fileLength)) {
7024 /* we'd write past EOF, so extend the file */
7025 scp->mask |= CM_SCACHEMASK_LENGTH;
7026 scp->length = thyper;
7027 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
7029 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
7031 /* now, if the new position (thyper) and the old (offset) are in
7032 * different storeback windows, remember to store back the previous
7033 * storeback window when we're done with the write.
7035 * the purpose of this logic is to slow down the CIFS client
7036 * in order to avoid the client disconnecting during the CLOSE
7037 * operation if there are too many dirty buffers left to write
7038 * than can be accomplished during 45 seconds. This used to be
7039 * based upon cm_chunkSize but we desire cm_chunkSize to be large
7040 * so that we can read larger amounts of data at a time.
7042 if (smb_AsyncStore == 1 &&
7043 (thyper.LowPart & ~(smb_AsyncStoreSize-1)) !=
7044 (offset.LowPart & ~(smb_AsyncStoreSize-1))) {
7045 /* they're different */
7047 writeBackOffset.HighPart = offset.HighPart;
7048 writeBackOffset.LowPart = offset.LowPart & ~(smb_AsyncStoreSize-1);
7053 /* now, copy the data one buffer at a time, until we've filled the
7056 /* if we've copied all the data requested, we're done */
7060 /* handle over quota or out of space */
7061 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
7062 *writtenp = written;
7063 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
7067 /* otherwise, load up a buffer of data */
7068 thyper.HighPart = offset.HighPart;
7069 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7070 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7073 lock_ReleaseMutex(&bufferp->mx);
7074 buf_Release(bufferp);
7077 lock_ReleaseWrite(&scp->rw);
7079 code = buf_Get(scp, &thyper, &bufferp);
7081 lock_ObtainMutex(&bufferp->mx);
7082 lock_ObtainWrite(&scp->rw);
7083 if (code) goto done;
7085 bufferOffset = thyper;
7087 /* now get the data in the cache */
7089 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7090 CM_SCACHESYNC_NEEDCALLBACK
7091 | CM_SCACHESYNC_WRITE
7092 | CM_SCACHESYNC_BUFLOCKED);
7096 cm_SyncOpDone(scp, bufferp,
7097 CM_SCACHESYNC_NEEDCALLBACK
7098 | CM_SCACHESYNC_WRITE
7099 | CM_SCACHESYNC_BUFLOCKED);
7101 /* If we're overwriting the entire buffer, or
7102 * if we're writing at or past EOF, mark the
7103 * buffer as current so we don't call
7104 * cm_GetBuffer. This skips the fetch from the
7105 * server in those cases where we're going to
7106 * obliterate all the data in the buffer anyway,
7107 * or in those cases where there is no useful
7108 * data at the server to start with.
7110 * Use minLength instead of scp->length, since
7111 * the latter has already been updated by this
7114 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
7115 || LargeIntegerEqualTo(offset, bufferp->offset)
7116 && (count >= cm_data.buf_blockSize
7117 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
7118 ConvertLongToLargeInteger(count)),
7120 if (count < cm_data.buf_blockSize
7121 && bufferp->dataVersion == CM_BUF_VERSION_BAD)
7122 memset(bufferp->datap, 0,
7123 cm_data.buf_blockSize);
7124 bufferp->dataVersion = scp->dataVersion;
7127 if (cm_HaveBuffer(scp, bufferp, 1)) break;
7129 /* otherwise, load the buffer and try again */
7130 lock_ReleaseMutex(&bufferp->mx);
7131 code = cm_GetBuffer(scp, bufferp, NULL, userp,
7133 lock_ReleaseWrite(&scp->rw);
7134 lock_ObtainMutex(&bufferp->mx);
7135 lock_ObtainWrite(&scp->rw);
7139 lock_ReleaseMutex(&bufferp->mx);
7140 buf_Release(bufferp);
7144 } /* if (wrong buffer) ... */
7146 /* now we have the right buffer loaded. Copy out the
7147 * data from here to the user's buffer.
7149 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7151 /* and figure out how many bytes we want from this buffer */
7152 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
7154 nbytes = count; /* don't go past end of request */
7156 /* now copy the data */
7157 memcpy(bufferp->datap + bufIndex, op, nbytes);
7158 buf_SetDirty(bufferp, bufIndex, nbytes, userp);
7160 /* adjust counters, pointers, etc. */
7164 thyper.LowPart = nbytes;
7165 thyper.HighPart = 0;
7166 offset = LargeIntegerAdd(thyper, offset);
7170 lock_ReleaseWrite(&scp->rw);
7173 lock_ReleaseMutex(&bufferp->mx);
7174 buf_Release(bufferp);
7177 lock_ObtainMutex(&fidp->mx);
7178 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
7179 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7181 lock_ReleaseMutex(&fidp->mx);
7182 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
7183 fidp->NTopen_dscp, fidp->NTopen_pathp,
7186 lock_ReleaseMutex(&fidp->mx);
7190 if (smb_AsyncStore > 0) {
7194 lock_ObtainWrite(&scp->rw);
7195 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
7197 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
7198 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
7200 lock_ReleaseWrite(&scp->rw);
7201 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
7202 writeBackOffset.HighPart,
7203 smb_AsyncStoreSize, 0, userp);
7204 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
7207 cm_BufWrite(scp, offsetp, *writtenp, 0, userp, &req);
7211 cm_ReleaseSCache(scp);
7214 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
7215 fidp->fid, code, *writtenp);
7220 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7223 unsigned short count;
7225 unsigned short hint;
7226 long written = 0, total_written = 0;
7229 smb_t* smbp = (smb_t*) inp;
7232 cm_attr_t truncAttr; /* attribute struct used for truncating file */
7234 int inDataBlockCount;
7236 fd = smb_GetSMBParm(inp, 0);
7237 count = smb_GetSMBParm(inp, 1);
7238 offset.HighPart = 0; /* too bad */
7239 offset.LowPart = smb_GetSMBParmLong(inp, 2);
7240 hint = smb_GetSMBParm(inp, 4);
7242 op = smb_GetSMBData(inp, NULL);
7243 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
7245 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
7246 fd, offset.LowPart, count);
7248 fd = smb_ChainFID(fd, inp);
7249 fidp = smb_FindFID(vcp, fd, 0);
7251 osi_Log0(smb_logp, "smb_ReceiveCoreWrite fid not found");
7252 return CM_ERROR_BADFD;
7255 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7256 smb_CloseFID(vcp, fidp, NULL, 0);
7257 smb_ReleaseFID(fidp);
7258 return CM_ERROR_NOSUCHFILE;
7261 lock_ObtainMutex(&fidp->mx);
7262 if (fidp->flags & SMB_FID_IOCTL) {
7263 lock_ReleaseMutex(&fidp->mx);
7264 code = smb_IoctlWrite(fidp, vcp, inp, outp);
7265 smb_ReleaseFID(fidp);
7266 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
7269 lock_ReleaseMutex(&fidp->mx);
7270 userp = smb_GetUserFromVCP(vcp, inp);
7274 LARGE_INTEGER LOffset;
7275 LARGE_INTEGER LLength;
7278 key = cm_GenerateKey(vcp->vcID, pid, fd);
7280 LOffset.HighPart = offset.HighPart;
7281 LOffset.LowPart = offset.LowPart;
7282 LLength.HighPart = 0;
7283 LLength.LowPart = count;
7285 lock_ObtainWrite(&fidp->scp->rw);
7286 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
7287 lock_ReleaseWrite(&fidp->scp->rw);
7290 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
7295 /* special case: 0 bytes transferred means truncate to this position */
7299 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
7303 truncAttr.mask = CM_ATTRMASK_LENGTH;
7304 truncAttr.length.LowPart = offset.LowPart;
7305 truncAttr.length.HighPart = 0;
7306 lock_ObtainMutex(&fidp->mx);
7307 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
7308 fidp->flags |= SMB_FID_LENGTHSETDONE;
7309 lock_ReleaseMutex(&fidp->mx);
7310 smb_SetSMBParm(outp, 0, 0 /* count */);
7311 smb_SetSMBDataLength(outp, 0);
7316 * Work around bug in NT client
7318 * When copying a file, the NT client should first copy the data,
7319 * then copy the last write time. But sometimes the NT client does
7320 * these in the wrong order, so the data copies would inadvertently
7321 * cause the last write time to be overwritten. We try to detect this,
7322 * and don't set client mod time if we think that would go against the
7325 lock_ObtainMutex(&fidp->mx);
7326 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
7327 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7328 fidp->scp->clientModTime = time(NULL);
7330 lock_ReleaseMutex(&fidp->mx);
7333 while ( code == 0 && count > 0 ) {
7334 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7335 if (code == 0 && written == 0)
7336 code = CM_ERROR_PARTIALWRITE;
7338 offset = LargeIntegerAdd(offset,
7339 ConvertLongToLargeInteger(written));
7340 count -= (unsigned short)written;
7341 total_written += written;
7345 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
7346 total_written, code);
7348 /* set the packet data length to 3 bytes for the data block header,
7349 * plus the size of the data.
7351 smb_SetSMBParm(outp, 0, total_written);
7352 smb_SetSMBParmLong(outp, 1, offset.LowPart);
7353 smb_SetSMBParm(outp, 3, hint);
7354 smb_SetSMBDataLength(outp, 0);
7357 smb_ReleaseFID(fidp);
7358 cm_ReleaseUser(userp);
7363 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7364 NCB *ncbp, raw_write_cont_t *rwcp)
7373 fd = smb_GetSMBParm(inp, 0);
7374 fidp = smb_FindFID(vcp, fd, 0);
7376 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7377 smb_CloseFID(vcp, fidp, NULL, 0);
7378 smb_ReleaseFID(fidp);
7382 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
7383 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
7385 userp = smb_GetUserFromVCP(vcp, inp);
7388 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
7390 if (rwcp->writeMode & 0x1) { /* synchronous */
7393 smb_FormatResponsePacket(vcp, inp, outp);
7394 op = (smb_t *) outp;
7395 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7396 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
7397 smb_SetSMBDataLength(outp, 0);
7398 smb_SendPacket(vcp, outp);
7399 smb_FreePacket(outp);
7401 else { /* asynchronous */
7402 lock_ObtainMutex(&fidp->mx);
7403 fidp->raw_writers--;
7404 if (fidp->raw_writers == 0)
7405 thrd_SetEvent(fidp->raw_write_event);
7406 lock_ReleaseMutex(&fidp->mx);
7409 /* Give back raw buffer */
7410 lock_ObtainMutex(&smb_RawBufLock);
7411 *((char **)rawBuf) = smb_RawBufs;
7412 smb_RawBufs = rawBuf;
7413 lock_ReleaseMutex(&smb_RawBufLock);
7415 smb_ReleaseFID(fidp);
7416 cm_ReleaseUser(userp);
7419 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7424 /* SMB_COM_WRITE_RAW */
7425 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
7428 long count, written = 0, total_written = 0;
7432 smb_t *smbp = (smb_t*) inp;
7436 unsigned short writeMode;
7438 fd = smb_GetSMBParm(inp, 0);
7439 totalCount = smb_GetSMBParm(inp, 1);
7440 count = smb_GetSMBParm(inp, 10);
7441 writeMode = smb_GetSMBParm(inp, 7);
7443 op = (char *) inp->data;
7444 op += smb_GetSMBParm(inp, 11);
7446 offset.HighPart = 0;
7447 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
7449 if (*inp->wctp == 14) {
7450 /* we received a 64-bit file offset */
7451 #ifdef AFS_LARGEFILES
7452 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
7454 if (LargeIntegerLessThanZero(offset)) {
7456 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
7457 offset.HighPart, offset.LowPart);
7458 return CM_ERROR_BADSMB;
7461 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
7463 "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files");
7464 return CM_ERROR_BADSMB;
7467 offset.HighPart = 0;
7470 offset.HighPart = 0; /* 32-bit file offset */
7474 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
7475 fd, offset.HighPart, offset.LowPart, count);
7477 " WriteRaw WriteMode 0x%x",
7480 fd = smb_ChainFID(fd, inp);
7481 fidp = smb_FindFID(vcp, fd, 0);
7483 return CM_ERROR_BADFD;
7486 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7487 smb_CloseFID(vcp, fidp, NULL, 0);
7488 smb_ReleaseFID(fidp);
7489 return CM_ERROR_NOSUCHFILE;
7495 LARGE_INTEGER LOffset;
7496 LARGE_INTEGER LLength;
7499 key = cm_GenerateKey(vcp->vcID, pid, fd);
7501 LOffset.HighPart = offset.HighPart;
7502 LOffset.LowPart = offset.LowPart;
7503 LLength.HighPart = 0;
7504 LLength.LowPart = count;
7506 lock_ObtainWrite(&fidp->scp->rw);
7507 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
7508 lock_ReleaseWrite(&fidp->scp->rw);
7511 smb_ReleaseFID(fidp);
7516 userp = smb_GetUserFromVCP(vcp, inp);
7519 * Work around bug in NT client
7521 * When copying a file, the NT client should first copy the data,
7522 * then copy the last write time. But sometimes the NT client does
7523 * these in the wrong order, so the data copies would inadvertently
7524 * cause the last write time to be overwritten. We try to detect this,
7525 * and don't set client mod time if we think that would go against the
7528 lock_ObtainMutex(&fidp->mx);
7529 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
7530 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7531 fidp->scp->clientModTime = time(NULL);
7533 lock_ReleaseMutex(&fidp->mx);
7536 while ( code == 0 && count > 0 ) {
7537 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7538 if (code == 0 && written == 0)
7539 code = CM_ERROR_PARTIALWRITE;
7541 offset = LargeIntegerAdd(offset,
7542 ConvertLongToLargeInteger(written));
7545 total_written += written;
7549 /* Get a raw buffer */
7552 lock_ObtainMutex(&smb_RawBufLock);
7554 /* Get a raw buf, from head of list */
7555 rawBuf = smb_RawBufs;
7556 smb_RawBufs = *(char **)smb_RawBufs;
7559 code = CM_ERROR_USESTD;
7561 lock_ReleaseMutex(&smb_RawBufLock);
7564 /* Don't allow a premature Close */
7565 if (code == 0 && (writeMode & 1) == 0) {
7566 lock_ObtainMutex(&fidp->mx);
7567 fidp->raw_writers++;
7568 thrd_ResetEvent(fidp->raw_write_event);
7569 lock_ReleaseMutex(&fidp->mx);
7572 smb_ReleaseFID(fidp);
7573 cm_ReleaseUser(userp);
7576 smb_SetSMBParm(outp, 0, total_written);
7577 smb_SetSMBDataLength(outp, 0);
7578 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7583 offset = LargeIntegerAdd(offset,
7584 ConvertLongToLargeInteger(count));
7588 rwcp->offset.HighPart = offset.HighPart;
7589 rwcp->offset.LowPart = offset.LowPart;
7590 rwcp->count = totalCount - count;
7591 rwcp->writeMode = writeMode;
7592 rwcp->alreadyWritten = total_written;
7594 /* set the packet data length to 3 bytes for the data block header,
7595 * plus the size of the data.
7597 smb_SetSMBParm(outp, 0, 0xffff);
7598 smb_SetSMBDataLength(outp, 0);
7604 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7607 long count, finalCount;
7611 smb_t *smbp = (smb_t*) inp;
7616 fd = smb_GetSMBParm(inp, 0);
7617 count = smb_GetSMBParm(inp, 1);
7618 offset.HighPart = 0; /* too bad */
7619 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7621 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
7622 fd, offset.LowPart, count);
7624 fd = smb_ChainFID(fd, inp);
7625 fidp = smb_FindFID(vcp, fd, 0);
7627 return CM_ERROR_BADFD;
7629 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7630 smb_CloseFID(vcp, fidp, NULL, 0);
7631 smb_ReleaseFID(fidp);
7632 return CM_ERROR_NOSUCHFILE;
7635 lock_ObtainMutex(&fidp->mx);
7636 if (fidp->flags & SMB_FID_IOCTL) {
7637 lock_ReleaseMutex(&fidp->mx);
7638 code = smb_IoctlRead(fidp, vcp, inp, outp);
7639 smb_ReleaseFID(fidp);
7642 lock_ReleaseMutex(&fidp->mx);
7645 LARGE_INTEGER LOffset, LLength;
7649 key = cm_GenerateKey(vcp->vcID, pid, fd);
7651 LOffset.HighPart = 0;
7652 LOffset.LowPart = offset.LowPart;
7653 LLength.HighPart = 0;
7654 LLength.LowPart = count;
7656 lock_ObtainWrite(&fidp->scp->rw);
7657 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
7658 lock_ReleaseWrite(&fidp->scp->rw);
7661 smb_ReleaseFID(fidp);
7665 userp = smb_GetUserFromVCP(vcp, inp);
7667 /* remember this for final results */
7668 smb_SetSMBParm(outp, 0, count);
7669 smb_SetSMBParm(outp, 1, 0);
7670 smb_SetSMBParm(outp, 2, 0);
7671 smb_SetSMBParm(outp, 3, 0);
7672 smb_SetSMBParm(outp, 4, 0);
7674 /* set the packet data length to 3 bytes for the data block header,
7675 * plus the size of the data.
7677 smb_SetSMBDataLength(outp, count+3);
7679 /* get op ptr after putting in the parms, since otherwise we don't
7680 * know where the data really is.
7682 op = smb_GetSMBData(outp, NULL);
7684 /* now emit the data block header: 1 byte of type and 2 bytes of length */
7685 *op++ = 1; /* data block marker */
7686 *op++ = (unsigned char) (count & 0xff);
7687 *op++ = (unsigned char) ((count >> 8) & 0xff);
7689 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
7691 /* fix some things up */
7692 smb_SetSMBParm(outp, 0, finalCount);
7693 smb_SetSMBDataLength(outp, finalCount+3);
7695 smb_ReleaseFID(fidp);
7697 cm_ReleaseUser(userp);
7701 /* SMB_COM_CREATE_DIRECTORY */
7702 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7704 clientchar_t *pathp;
7709 cm_scache_t *dscp; /* dir we're dealing with */
7710 cm_scache_t *scp; /* file we're creating */
7712 int initialModeBits;
7713 clientchar_t *lastNamep;
7715 clientchar_t *tidPathp;
7722 /* compute initial mode bits based on read-only flag in attributes */
7723 initialModeBits = 0777;
7725 tp = smb_GetSMBData(inp, NULL);
7726 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
7728 return CM_ERROR_BADSMB;
7730 spacep = inp->spacep;
7731 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
7733 if (cm_ClientStrCmp(pathp, _C("\\")) == 0)
7734 return CM_ERROR_EXISTS;
7736 userp = smb_GetUserFromVCP(vcp, inp);
7738 caseFold = CM_FLAG_CASEFOLD;
7740 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7742 cm_ReleaseUser(userp);
7743 return CM_ERROR_NOSUCHPATH;
7746 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
7747 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
7748 userp, tidPathp, &req, &dscp);
7751 cm_ReleaseUser(userp);
7756 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7757 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
7758 cm_ReleaseSCache(dscp);
7759 cm_ReleaseUser(userp);
7760 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7761 return CM_ERROR_PATH_NOT_COVERED;
7763 return CM_ERROR_BADSHARENAME;
7765 #endif /* DFS_SUPPORT */
7767 /* otherwise, scp points to the parent directory. Do a lookup, and
7768 * fail if we find it. Otherwise, we do the create.
7774 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
7775 if (scp) cm_ReleaseSCache(scp);
7776 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7777 if (code == 0) code = CM_ERROR_EXISTS;
7778 cm_ReleaseSCache(dscp);
7779 cm_ReleaseUser(userp);
7783 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7784 setAttr.clientModTime = time(NULL);
7785 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
7786 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7787 smb_NotifyChange(FILE_ACTION_ADDED,
7788 FILE_NOTIFY_CHANGE_DIR_NAME,
7789 dscp, lastNamep, NULL, TRUE);
7791 /* we don't need this any longer */
7792 cm_ReleaseSCache(dscp);
7795 /* something went wrong creating or truncating the file */
7796 cm_ReleaseUser(userp);
7800 /* otherwise we succeeded */
7801 smb_SetSMBDataLength(outp, 0);
7802 cm_ReleaseUser(userp);
7807 BOOL smb_IsLegalFilename(clientchar_t *filename)
7810 * Find the longest substring of filename that does not contain
7811 * any of the chars in illegalChars. If that substring is less
7812 * than the length of the whole string, then one or more of the
7813 * illegal chars is in filename.
7815 if (cm_ClientStrCSpn(filename, illegalChars) < cm_ClientStrLen(filename))
7821 /* SMB_COM_CREATE and SMB_COM_CREATE_NEW */
7822 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7824 clientchar_t *pathp;
7830 cm_scache_t *dscp; /* dir we're dealing with */
7831 cm_scache_t *scp; /* file we're creating */
7833 int initialModeBits;
7836 clientchar_t *lastNamep;
7839 clientchar_t *tidPathp;
7841 int created = 0; /* the file was new */
7846 excl = (inp->inCom == 0x03)? 0 : 1;
7848 attributes = smb_GetSMBParm(inp, 0);
7849 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
7851 /* compute initial mode bits based on read-only flag in attributes */
7852 initialModeBits = 0666;
7853 if (attributes & SMB_ATTR_READONLY)
7854 initialModeBits &= ~0222;
7856 tp = smb_GetSMBData(inp, NULL);
7857 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
7859 return CM_ERROR_BADSMB;
7861 if (!cm_IsValidClientString(pathp)) {
7863 clientchar_t * hexp;
7865 hexp = cm_GetRawCharsAlloc(pathp, -1);
7866 osi_Log1(smb_logp, "CoreCreate rejecting invalid name. [%S]",
7867 osi_LogSaveClientString(smb_logp, hexp));
7871 osi_Log0(smb_logp, "CoreCreate rejecting invalid name");
7873 return CM_ERROR_BADNTFILENAME;
7876 spacep = inp->spacep;
7877 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
7879 userp = smb_GetUserFromVCP(vcp, inp);
7881 caseFold = CM_FLAG_CASEFOLD;
7883 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7885 cm_ReleaseUser(userp);
7886 return CM_ERROR_NOSUCHPATH;
7888 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
7889 userp, tidPathp, &req, &dscp);
7892 cm_ReleaseUser(userp);
7897 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7898 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
7899 cm_ReleaseSCache(dscp);
7900 cm_ReleaseUser(userp);
7901 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7902 return CM_ERROR_PATH_NOT_COVERED;
7904 return CM_ERROR_BADSHARENAME;
7906 #endif /* DFS_SUPPORT */
7908 /* otherwise, scp points to the parent directory. Do a lookup, and
7909 * truncate the file if we find it, otherwise we create the file.
7916 if (!smb_IsLegalFilename(lastNamep))
7917 return CM_ERROR_BADNTFILENAME;
7919 osi_Log1(smb_logp, "SMB receive create [%S]", osi_LogSaveClientString( smb_logp, pathp ));
7920 #ifdef DEBUG_VERBOSE
7923 hexp = osi_HexifyString( lastNamep );
7924 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
7929 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
7930 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7931 cm_ReleaseSCache(dscp);
7932 cm_ReleaseUser(userp);
7936 /* if we get here, if code is 0, the file exists and is represented by
7937 * scp. Otherwise, we have to create it.
7941 /* oops, file shouldn't be there */
7942 cm_ReleaseSCache(dscp);
7943 cm_ReleaseSCache(scp);
7944 cm_ReleaseUser(userp);
7945 return CM_ERROR_EXISTS;
7948 setAttr.mask = CM_ATTRMASK_LENGTH;
7949 setAttr.length.LowPart = 0;
7950 setAttr.length.HighPart = 0;
7951 code = cm_SetAttr(scp, &setAttr, userp, &req);
7954 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7955 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
7956 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7960 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7961 smb_NotifyChange(FILE_ACTION_ADDED,
7962 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7963 dscp, lastNamep, NULL, TRUE);
7964 } else if (!excl && code == CM_ERROR_EXISTS) {
7965 /* not an exclusive create, and someone else tried
7966 * creating it already, then we open it anyway. We
7967 * don't bother retrying after this, since if this next
7968 * fails, that means that the file was deleted after
7969 * we started this call.
7971 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
7974 setAttr.mask = CM_ATTRMASK_LENGTH;
7975 setAttr.length.LowPart = 0;
7976 setAttr.length.HighPart = 0;
7977 code = cm_SetAttr(scp, &setAttr, userp, &req);
7982 /* we don't need this any longer */
7983 cm_ReleaseSCache(dscp);
7986 /* something went wrong creating or truncating the file */
7987 if (scp) cm_ReleaseSCache(scp);
7988 cm_ReleaseUser(userp);
7992 /* make sure we only open files */
7993 if (scp->fileType != CM_SCACHETYPE_FILE) {
7994 cm_ReleaseSCache(scp);
7995 cm_ReleaseUser(userp);
7996 return CM_ERROR_ISDIR;
7999 /* now all we have to do is open the file itself */
8000 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8001 osi_assertx(fidp, "null smb_fid_t");
8005 lock_ObtainMutex(&fidp->mx);
8006 /* always create it open for read/write */
8007 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
8009 /* remember that the file was newly created */
8011 fidp->flags |= SMB_FID_CREATED;
8013 osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
8015 /* save a pointer to the vnode */
8017 lock_ObtainWrite(&scp->rw);
8018 scp->flags |= CM_SCACHEFLAG_SMB_FID;
8019 lock_ReleaseWrite(&scp->rw);
8022 fidp->userp = userp;
8023 lock_ReleaseMutex(&fidp->mx);
8025 smb_SetSMBParm(outp, 0, fidp->fid);
8026 smb_SetSMBDataLength(outp, 0);
8028 cm_Open(scp, 0, userp);
8030 smb_ReleaseFID(fidp);
8031 cm_ReleaseUser(userp);
8032 /* leave scp held since we put it in fidp->scp */
8037 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8040 osi_hyper_t new_offset;
8051 fd = smb_GetSMBParm(inp, 0);
8052 whence = smb_GetSMBParm(inp, 1);
8053 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
8055 /* try to find the file descriptor */
8056 fd = smb_ChainFID(fd, inp);
8057 fidp = smb_FindFID(vcp, fd, 0);
8059 return CM_ERROR_BADFD;
8061 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
8062 smb_CloseFID(vcp, fidp, NULL, 0);
8063 smb_ReleaseFID(fidp);
8064 return CM_ERROR_NOSUCHFILE;
8067 lock_ObtainMutex(&fidp->mx);
8068 if (fidp->flags & SMB_FID_IOCTL) {
8069 lock_ReleaseMutex(&fidp->mx);
8070 smb_ReleaseFID(fidp);
8071 return CM_ERROR_BADFD;
8073 lock_ReleaseMutex(&fidp->mx);
8075 userp = smb_GetUserFromVCP(vcp, inp);
8077 lock_ObtainMutex(&fidp->mx);
8080 lock_ReleaseMutex(&fidp->mx);
8081 lock_ObtainWrite(&scp->rw);
8082 code = cm_SyncOp(scp, NULL, userp, &req, 0,
8083 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8085 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8087 /* offset from current offset */
8088 new_offset = LargeIntegerAdd(fidp->offset,
8089 ConvertLongToLargeInteger(offset));
8091 else if (whence == 2) {
8092 /* offset from current EOF */
8093 new_offset = LargeIntegerAdd(scp->length,
8094 ConvertLongToLargeInteger(offset));
8096 new_offset = ConvertLongToLargeInteger(offset);
8099 fidp->offset = new_offset;
8100 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
8101 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
8102 smb_SetSMBDataLength(outp, 0);
8104 lock_ReleaseWrite(&scp->rw);
8105 smb_ReleaseFID(fidp);
8106 cm_ReleaseSCache(scp);
8107 cm_ReleaseUser(userp);
8111 /* dispatch all of the requests received in a packet. Due to chaining, this may
8112 * be more than one request.
8114 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
8115 NCB *ncbp, raw_write_cont_t *rwcp)
8119 unsigned long code = 0;
8120 unsigned char *outWctp;
8121 int nparms; /* # of bytes of parameters */
8123 int nbytes; /* bytes of data, excluding count */
8126 unsigned short errCode;
8127 unsigned long NTStatus;
8129 unsigned char errClass;
8130 unsigned int oldGen;
8131 DWORD oldTime, newTime;
8133 /* get easy pointer to the data */
8134 smbp = (smb_t *) inp->data;
8136 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
8137 /* setup the basic parms for the initial request in the packet */
8138 inp->inCom = smbp->com;
8139 inp->wctp = &smbp->wct;
8141 inp->ncb_length = ncbp->ncb_length;
8146 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
8147 /* log it and discard it */
8148 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
8149 __FILE__, __LINE__, ncbp->ncb_length);
8150 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
8154 /* We are an ongoing op */
8155 thrd_Increment(&ongoingOps);
8157 /* set up response packet for receiving output */
8158 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
8159 smb_FormatResponsePacket(vcp, inp, outp);
8160 outWctp = outp->wctp;
8162 /* Remember session generation number and time */
8163 oldGen = sessionGen;
8164 oldTime = GetTickCount();
8166 while (inp->inCom != 0xff) {
8167 dp = &smb_dispatchTable[inp->inCom];
8169 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
8170 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
8171 code = outp->resumeCode;
8175 /* process each request in the packet; inCom, wctp and inCount
8176 * are already set up.
8178 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
8181 /* now do the dispatch */
8182 /* start by formatting the response record a little, as a default */
8183 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
8185 outWctp[1] = 0xff; /* no operation */
8186 outWctp[2] = 0; /* padding */
8191 /* not a chained request, this is a more reasonable default */
8192 outWctp[0] = 0; /* wct of zero */
8193 outWctp[1] = 0; /* and bcc (word) of zero */
8197 /* once set, stays set. Doesn't matter, since we never chain
8198 * "no response" calls.
8200 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
8204 /* we have a recognized operation */
8205 char * opName = myCrt_Dispatch(inp->inCom);
8207 if (inp->inCom == 0x1d)
8209 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
8211 osi_Log4(smb_logp,"Dispatch %s vcp 0x%p lana %d lsn %d",
8212 opName,vcp,vcp->lana,vcp->lsn);
8213 code = (*(dp->procp)) (vcp, inp, outp);
8214 osi_Log4(smb_logp,"Dispatch return code 0x%x vcp 0x%p lana %d lsn %d",
8215 code,vcp,vcp->lana,vcp->lsn);
8217 if ( code == CM_ERROR_BADSMB ||
8218 code == CM_ERROR_BADOP )
8220 #endif /* LOG_PACKET */
8223 newTime = GetTickCount();
8224 osi_Log2(smb_logp, "Dispatch %s duration %d ms", opName, newTime - oldTime);
8226 /* ReceiveV3Tran2A handles its own logging */
8227 if (inp->inCom != 0x32 && newTime - oldTime > 45000) {
8230 clientchar_t *treepath = NULL; /* do not free */
8231 clientchar_t *pathname = NULL;
8232 cm_fid_t afid = {0,0,0,0,0};
8234 uidp = smb_FindUID(vcp, smbp->uid, 0);
8235 smb_LookupTIDPath(vcp,((smb_t *)inp)->tid, &treepath);
8236 fidp = smb_FindFID(vcp, inp->fid, 0);
8238 if (fidp && fidp->NTopen_pathp)
8239 pathname = fidp->NTopen_pathp;
8240 else if (inp->stringsp->wdata)
8241 pathname = inp->stringsp->wdata;
8243 if (fidp && fidp->scp)
8244 afid = fidp->scp->fid;
8246 afsi_log("Request %s duration %d ms user %S tid \"%S\" path? \"%S\" afid (%d.%d.%d.%d)",
8247 opName, newTime - oldTime,
8248 uidp ? uidp->unp->name : NULL,
8251 afid.cell, afid.volume, afid.vnode, afid.unique);
8254 smb_ReleaseUID(uidp);
8256 smb_ReleaseFID(fidp);
8259 if (oldGen != sessionGen) {
8260 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
8261 newTime - oldTime, ncbp->ncb_length);
8262 osi_Log3(smb_logp, "Request %s straddled session startup, "
8263 "took %d ms, ncb length %d", opName, newTime - oldTime, ncbp->ncb_length);
8266 FreeSMBStrings(inp);
8268 /* bad opcode, fail the request, after displaying it */
8269 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
8272 #endif /* LOG_PACKET */
8275 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
8276 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
8277 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
8278 if (code == IDCANCEL)
8281 code = CM_ERROR_BADOP;
8284 /* catastrophic failure: log as much as possible */
8285 if (code == CM_ERROR_BADSMB) {
8286 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
8290 #endif /* LOG_PACKET */
8291 osi_Log1(smb_logp, "Invalid SMB message, length %d",
8294 code = CM_ERROR_INVAL;
8297 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
8298 thrd_Decrement(&ongoingOps);
8303 /* now, if we failed, turn the current response into an empty
8304 * one, and fill in the response packet's error code.
8307 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8308 smb_MapNTError(code, &NTStatus);
8309 outWctp = outp->wctp;
8310 smbp = (smb_t *) &outp->data;
8311 if (code != CM_ERROR_PARTIALWRITE
8312 && code != CM_ERROR_BUFFERTOOSMALL
8313 && code != CM_ERROR_GSSCONTINUE) {
8314 /* nuke wct and bcc. For a partial
8315 * write or an in-process authentication handshake,
8316 * assume they're OK.
8322 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8323 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8324 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8325 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8326 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8330 smb_MapCoreError(code, vcp, &errCode, &errClass);
8331 outWctp = outp->wctp;
8332 smbp = (smb_t *) &outp->data;
8333 if (code != CM_ERROR_PARTIALWRITE) {
8334 /* nuke wct and bcc. For a partial
8335 * write, assume they're OK.
8341 smbp->errLow = (unsigned char) (errCode & 0xff);
8342 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8343 smbp->rcls = errClass;
8346 } /* error occurred */
8348 /* if we're here, we've finished one request. Look to see if
8349 * this is a chained opcode. If it is, setup things to process
8350 * the chained request, and setup the output buffer to hold the
8351 * chained response. Start by finding the next input record.
8353 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
8354 break; /* not a chained req */
8355 tp = inp->wctp; /* points to start of last request */
8356 /* in a chained request, the first two
8357 * parm fields are required, and are
8358 * AndXCommand/AndXReserved and
8360 if (tp[0] < 2) break;
8361 if (tp[1] == 0xff) break; /* no more chained opcodes */
8363 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
8366 /* and now append the next output request to the end of this
8367 * last request. Begin by finding out where the last response
8368 * ends, since that's where we'll put our new response.
8370 outWctp = outp->wctp; /* ptr to out parameters */
8371 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
8372 nparms = outWctp[0] << 1;
8373 tp = outWctp + nparms + 1; /* now points to bcc field */
8374 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
8375 tp += 2 /* for the count itself */ + nbytes;
8376 /* tp now points to the new output record; go back and patch the
8377 * second parameter (off2) to point to the new record.
8379 temp = (unsigned int)(tp - outp->data);
8380 outWctp[3] = (unsigned char) (temp & 0xff);
8381 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
8382 outWctp[2] = 0; /* padding */
8383 outWctp[1] = inp->inCom; /* next opcode */
8385 /* finally, setup for the next iteration */
8388 } /* while loop over all requests in the packet */
8390 /* now send the output packet, and return */
8392 smb_SendPacket(vcp, outp);
8393 thrd_Decrement(&ongoingOps);
8398 /* Wait for Netbios() calls to return, and make the results available to server
8399 * threads. Note that server threads can't wait on the NCBevents array
8400 * themselves, because NCB events are manual-reset, and the servers would race
8401 * each other to reset them.
8403 void smb_ClientWaiter(void *parmp)
8408 while (smbShutdownFlag == 0) {
8409 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
8411 if (code == WAIT_OBJECT_0)
8414 /* error checking */
8415 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8417 int abandonIdx = code - WAIT_ABANDONED_0;
8418 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8421 if (code == WAIT_IO_COMPLETION)
8423 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
8427 if (code == WAIT_TIMEOUT)
8429 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
8432 if (code == WAIT_FAILED)
8434 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
8437 idx = code - WAIT_OBJECT_0;
8439 /* check idx range! */
8440 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
8442 /* this is fatal - log as much as possible */
8443 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
8444 osi_assertx(0, "invalid index");
8447 thrd_ResetEvent(NCBevents[idx]);
8448 thrd_SetEvent(NCBreturns[0][idx]);
8453 * Try to have one NCBRECV request waiting for every live session. Not more
8454 * than one, because if there is more than one, it's hard to handle Write Raw.
8456 void smb_ServerWaiter(void *parmp)
8459 int idx_session, idx_NCB;
8462 while (smbShutdownFlag == 0) {
8464 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
8466 if (code == WAIT_OBJECT_0)
8469 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
8471 int abandonIdx = code - WAIT_ABANDONED_0;
8472 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8475 if (code == WAIT_IO_COMPLETION)
8477 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
8481 if (code == WAIT_TIMEOUT)
8483 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
8486 if (code == WAIT_FAILED)
8488 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
8491 idx_session = code - WAIT_OBJECT_0;
8493 /* check idx range! */
8494 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
8496 /* this is fatal - log as much as possible */
8497 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
8498 osi_assertx(0, "invalid index");
8503 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
8505 if (code == WAIT_OBJECT_0) {
8506 if (smbShutdownFlag == 1)
8512 /* error checking */
8513 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8515 int abandonIdx = code - WAIT_ABANDONED_0;
8516 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8519 if (code == WAIT_IO_COMPLETION)
8521 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
8525 if (code == WAIT_TIMEOUT)
8527 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
8530 if (code == WAIT_FAILED)
8532 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
8535 idx_NCB = code - WAIT_OBJECT_0;
8537 /* check idx range! */
8538 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
8540 /* this is fatal - log as much as possible */
8541 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
8542 osi_assertx(0, "invalid index");
8545 /* Link them together */
8546 NCBsessions[idx_NCB] = idx_session;
8549 ncbp = NCBs[idx_NCB];
8550 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
8551 ncbp->ncb_command = NCBRECV | ASYNCH;
8552 ncbp->ncb_lana_num = lanas[idx_session];
8553 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
8554 ncbp->ncb_event = NCBevents[idx_NCB];
8555 ncbp->ncb_length = SMB_PACKETSIZE;
8561 * The top level loop for handling SMB request messages. Each server thread
8562 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
8563 * NCB and buffer for the incoming request are loaned to us.
8565 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
8566 * to immediately send a request for the rest of the data. This must come
8567 * before any other traffic for that session, so we delay setting the session
8568 * event until that data has come in.
8570 void smb_Server(VOID *parmp)
8572 INT_PTR myIdx = (INT_PTR) parmp;
8576 smb_packet_t *outbufp;
8578 int idx_NCB, idx_session;
8580 smb_vc_t *vcp = NULL;
8582 extern void rx_StartClientThread(void);
8584 rx_StartClientThread();
8586 outncbp = smb_GetNCB();
8587 outbufp = smb_GetPacket();
8588 outbufp->ncbp = outncbp;
8596 smb_ResetServerPriority();
8598 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
8601 /* terminate silently if shutdown flag is set */
8602 if (code == WAIT_OBJECT_0) {
8603 if (smbShutdownFlag == 1) {
8604 thrd_SetEvent(smb_ServerShutdown[myIdx]);
8610 /* error checking */
8611 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8613 int abandonIdx = code - WAIT_ABANDONED_0;
8614 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
8617 if (code == WAIT_IO_COMPLETION)
8619 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
8623 if (code == WAIT_TIMEOUT)
8625 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
8628 if (code == WAIT_FAILED)
8630 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
8633 idx_NCB = code - WAIT_OBJECT_0;
8635 /* check idx range! */
8636 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
8638 /* this is fatal - log as much as possible */
8639 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
8640 osi_assertx(0, "invalid index");
8643 ncbp = NCBs[idx_NCB];
8644 idx_session = NCBsessions[idx_NCB];
8645 rc = ncbp->ncb_retcode;
8647 if (rc != NRC_PENDING && rc != NRC_GOODRET)
8648 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
8652 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8656 /* Can this happen? Or is it just my UNIX paranoia? */
8657 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
8662 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
8665 /* Client closed session */
8666 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8668 lock_ObtainMutex(&vcp->mx);
8669 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8670 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8672 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8673 lock_ReleaseMutex(&vcp->mx);
8674 lock_ObtainWrite(&smb_globalLock);
8675 dead_sessions[vcp->session] = TRUE;
8676 lock_ReleaseWrite(&smb_globalLock);
8678 lock_ReleaseMutex(&vcp->mx);
8680 smb_CleanupDeadVC(vcp);
8687 /* Treat as transient error */
8688 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
8691 "dispatch smb recv failed, message incomplete, ncb_length %d",
8694 "SMB message incomplete, "
8695 "length %d", ncbp->ncb_length);
8698 * We used to discard the packet.
8699 * Instead, try handling it normally.
8703 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8707 /* A weird error code. Log it, sleep, and continue. */
8708 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8710 lock_ObtainMutex(&vcp->mx);
8711 if (vcp->errorCount++ > 3) {
8712 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
8713 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8714 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8716 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8717 lock_ReleaseMutex(&vcp->mx);
8718 lock_ObtainWrite(&smb_globalLock);
8719 dead_sessions[vcp->session] = TRUE;
8720 lock_ReleaseWrite(&smb_globalLock);
8722 lock_ReleaseMutex(&vcp->mx);
8724 smb_CleanupDeadVC(vcp);
8730 lock_ReleaseMutex(&vcp->mx);
8734 thrd_SetEvent(SessionEvents[idx_session]);
8740 /* Success, so now dispatch on all the data in the packet */
8742 smb_concurrentCalls++;
8743 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
8744 smb_maxObsConcurrentCalls = smb_concurrentCalls;
8747 * If at this point vcp is NULL (implies that packet was invalid)
8748 * then we are in big trouble. This means either :
8749 * a) we have the wrong NCB.
8750 * b) Netbios screwed up the call.
8751 * c) The VC was already marked dead before we were able to
8753 * Obviously this implies that
8754 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
8755 * lanas[idx_session] != ncbp->ncb_lana_num )
8756 * Either way, we can't do anything with this packet.
8757 * Log, sleep and resume.
8760 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
8764 ncbp->ncb_lana_num);
8766 /* Also log in the trace log. */
8767 osi_Log4(smb_logp, "Server: VCP does not exist!"
8768 "LSNs[idx_session]=[%d],"
8769 "lanas[idx_session]=[%d],"
8770 "ncbp->ncb_lsn=[%d],"
8771 "ncbp->ncb_lana_num=[%d]",
8775 ncbp->ncb_lana_num);
8777 /* thrd_Sleep(1000); Don't bother sleeping */
8778 thrd_SetEvent(SessionEvents[idx_session]);
8779 smb_concurrentCalls--;
8783 smb_SetRequestStartTime();
8785 vcp->errorCount = 0;
8786 bufp = (struct smb_packet *) ncbp->ncb_buffer;
8787 smbp = (smb_t *)bufp->data;
8794 if (smbp->com == 0x1d) {
8795 /* Special handling for Write Raw */
8796 raw_write_cont_t rwc;
8797 EVENT_HANDLE rwevent;
8798 char eventName[MAX_PATH];
8800 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
8801 if (rwc.code == 0) {
8802 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
8803 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8804 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8805 ncbp->ncb_command = NCBRECV | ASYNCH;
8806 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
8807 ncbp->ncb_lana_num = vcp->lana;
8808 ncbp->ncb_buffer = rwc.buf;
8809 ncbp->ncb_length = 65535;
8810 ncbp->ncb_event = rwevent;
8812 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
8813 thrd_CloseHandle(rwevent);
8815 thrd_SetEvent(SessionEvents[idx_session]);
8817 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
8819 else if (smbp->com == 0xa0) {
8821 * Serialize the handling for NT Transact
8824 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
8825 thrd_SetEvent(SessionEvents[idx_session]);
8827 thrd_SetEvent(SessionEvents[idx_session]);
8828 /* TODO: what else needs to be serialized? */
8829 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
8833 __except( smb_ServerExceptionFilter() ) {
8837 smb_concurrentCalls--;
8840 thrd_SetEvent(NCBavails[idx_NCB]);
8845 smb_FreePacket(outbufp);
8847 smb_FreeNCB(outncbp);
8851 * Exception filter for the server threads. If an exception occurs in the
8852 * dispatch routines, which is where exceptions are most common, then do a
8853 * force trace and give control to upstream exception handlers. Useful for
8856 DWORD smb_ServerExceptionFilter(void) {
8857 /* While this is not the best time to do a trace, if it succeeds, then
8858 * we have a trace (assuming tracing was enabled). Otherwise, this should
8859 * throw a second exception.
8861 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
8862 afsd_ForceTrace(TRUE);
8863 buf_ForceTrace(TRUE);
8864 return EXCEPTION_CONTINUE_SEARCH;
8868 * Create a new NCB and associated events, packet buffer, and "space" buffer.
8869 * If the number of server threads is M, and the number of live sessions is
8870 * N, then the number of NCB's in use at any time either waiting for, or
8871 * holding, received messages is M + N, so that is how many NCB's get created.
8873 void InitNCBslot(int idx)
8875 struct smb_packet *bufp;
8876 EVENT_HANDLE retHandle;
8878 char eventName[MAX_PATH];
8880 osi_assertx( idx < (sizeof(NCBs) / sizeof(NCBs[0])), "invalid index" );
8882 NCBs[idx] = smb_GetNCB();
8883 sprintf(eventName,"NCBavails[%d]", idx);
8884 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8885 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8886 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8887 sprintf(eventName,"NCBevents[%d]", idx);
8888 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
8889 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8890 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8891 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
8892 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8893 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8894 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8895 for (i=0; i<smb_NumServerThreads; i++)
8896 NCBreturns[i][idx] = retHandle;
8897 bufp = smb_GetPacket();
8898 bufp->spacep = cm_GetSpace();
8902 /* listen for new connections */
8903 void smb_Listener(void *parmp)
8909 afs_uint32 session, thread;
8910 smb_vc_t *vcp = NULL;
8912 char rname[NCBNAMSZ+1];
8913 char cname[MAX_COMPUTERNAME_LENGTH+1];
8914 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
8915 INT_PTR lana = (INT_PTR) parmp;
8916 char eventName[MAX_PATH];
8917 int bridgeCount = 0;
8918 int nowildCount = 0;
8920 sprintf(eventName,"smb_Listener_lana_%d", (unsigned char)lana);
8921 ListenerShutdown[lana] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8922 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8923 thrd_ResetEvent(ListenerShutdown[lana]);
8925 ncbp = smb_GetNCB();
8927 /* retrieve computer name */
8928 GetComputerName(cname, &cnamelen);
8931 while (smb_ListenerState == SMB_LISTENER_STARTED) {
8932 memset(ncbp, 0, sizeof(NCB));
8935 ncbp->ncb_command = NCBLISTEN;
8936 ncbp->ncb_rto = 0; /* No receive timeout */
8937 ncbp->ncb_sto = 0; /* No send timeout */
8939 /* pad out with spaces instead of null termination */
8940 len = (long)strlen(smb_localNamep);
8941 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
8942 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
8944 strcpy(ncbp->ncb_callname, "*");
8945 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
8947 ncbp->ncb_lana_num = (UCHAR)lana;
8949 code = Netbios(ncbp);
8951 if (code == NRC_NAMERR) {
8952 /* An smb shutdown or Vista resume must have taken place */
8954 "NCBLISTEN lana=%d failed with NRC_NAMERR.",
8955 ncbp->ncb_lana_num);
8956 afsi_log("NCBLISTEN lana=%d failed with NRC_NAMERR.", ncbp->ncb_lana_num);
8958 if (lock_TryMutex(&smb_StartedLock)) {
8959 lana_list.lana[i] = LANA_INVALID;
8960 lock_ReleaseMutex(&smb_StartedLock);
8963 } else if (code == NRC_BRIDGE || code != 0) {
8964 int lanaRemaining = 0;
8966 if (code == NRC_BRIDGE) {
8967 if (++bridgeCount <= 5) {
8968 afsi_log("NCBLISTEN lana=%d failed with NRC_BRIDGE, retrying ...", ncbp->ncb_lana_num);
8971 } else if (code == NRC_NOWILD) {
8972 if (++nowildCount <= 5) {
8973 afsi_log("NCBLISTEN lana=%d failed with NRC_NOWILD, retrying ...", ncbp->ncb_lana_num);
8975 if (bridgeCount > 0) {
8976 memset(ncbp, 0, sizeof(*ncbp));
8977 ncbp->ncb_command = NCBADDNAME;
8978 ncbp->ncb_lana_num = (UCHAR)lana;
8979 /* pad out with spaces instead of null termination */
8980 len = (long)strlen(smb_localNamep);
8981 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
8982 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
8983 code = Netbios(ncbp);
8989 while (!lock_TryMutex(&smb_StartedLock)) {
8990 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
8996 "NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
8997 ncbp->ncb_lana_num, ncb_error_string(code));
8998 afsi_log("NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
8999 ncbp->ncb_lana_num, ncb_error_string(code));
9001 for (i = 0; i < lana_list.length; i++) {
9002 if (lana_list.lana[i] == lana) {
9003 smb_StopListener(ncbp, lana_list.lana[i], FALSE);
9004 lana_list.lana[i] = LANA_INVALID;
9006 if (lana_list.lana[i] != LANA_INVALID)
9010 if (lanaRemaining == 0) {
9011 cm_VolStatus_Network_Stopped(cm_NetbiosName
9016 smb_ListenerState = SMB_LISTENER_STOPPED;
9017 smb_LANadapter = LANA_INVALID;
9018 lana_list.length = 0;
9020 lock_ReleaseMutex(&smb_StartedLock);
9024 else if (code != 0) {
9025 char tbuffer[AFSPATHMAX];
9027 /* terminate silently if shutdown flag is set */
9028 while (!lock_TryMutex(&smb_StartedLock)) {
9029 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9035 "NCBLISTEN lana=%d failed with code %d [%s]",
9036 ncbp->ncb_lana_num, code, ncb_error_string(code));
9038 "Client exiting due to network failure. Please restart client.\n");
9041 "Client exiting due to network failure. Please restart client.\n"
9042 "NCBLISTEN lana=%d failed with code %d [%s]",
9043 ncbp->ncb_lana_num, code, ncb_error_string(code));
9045 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
9046 MB_OK|MB_SERVICE_NOTIFICATION);
9047 osi_panic(tbuffer, __FILE__, __LINE__);
9049 lock_ReleaseMutex(&smb_StartedLock);
9054 /* a successful packet received. clear bridge error count */
9058 /* check for remote conns */
9059 /* first get remote name and insert null terminator */
9060 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
9061 for (i=NCBNAMSZ; i>0; i--) {
9062 if (rname[i-1] != ' ' && rname[i-1] != 0) {
9068 /* compare with local name */
9070 if (strncmp(rname, cname, NCBNAMSZ) != 0)
9071 flags |= SMB_VCFLAG_REMOTECONN;
9074 lock_ObtainMutex(&smb_ListenerLock);
9076 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
9077 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
9079 /* now ncbp->ncb_lsn is the connection ID */
9080 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
9081 if (vcp->session == 0) {
9082 /* New generation */
9083 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
9086 /* Log session startup */
9088 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9089 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9090 #endif /* NOTSERVICE */
9091 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9092 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9094 if (reportSessionStartups) {
9095 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9098 lock_ObtainMutex(&vcp->mx);
9099 cm_Utf8ToUtf16(rname, -1, vcp->rname, lengthof(vcp->rname));
9100 vcp->flags |= flags;
9101 lock_ReleaseMutex(&vcp->mx);
9103 /* Allocate slot in session arrays */
9104 /* Re-use dead session if possible, otherwise add one more */
9105 /* But don't look at session[0], it is reserved */
9106 lock_ObtainWrite(&smb_globalLock);
9107 for (session = 1; session < numSessions; session++) {
9108 if (dead_sessions[session]) {
9109 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
9110 dead_sessions[session] = FALSE;
9114 lock_ReleaseWrite(&smb_globalLock);
9116 /* We are re-using an existing VC because the lsn and lana
9118 session = vcp->session;
9120 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
9122 /* Log session startup */
9124 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9125 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9126 #endif /* NOTSERVICE */
9127 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9128 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9130 if (reportSessionStartups) {
9131 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9135 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
9136 unsigned long code = CM_ERROR_ALLBUSY;
9137 smb_packet_t * outp = smb_GetPacket();
9138 unsigned char *outWctp;
9141 smb_FormatResponsePacket(vcp, NULL, outp);
9144 if (vcp->flags & SMB_VCFLAG_STATUS32) {
9145 unsigned long NTStatus;
9146 smb_MapNTError(code, &NTStatus);
9147 outWctp = outp->wctp;
9148 smbp = (smb_t *) &outp->data;
9152 smbp->rcls = (unsigned char) (NTStatus & 0xff);
9153 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
9154 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
9155 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
9156 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9158 unsigned short errCode;
9159 unsigned char errClass;
9160 smb_MapCoreError(code, vcp, &errCode, &errClass);
9161 outWctp = outp->wctp;
9162 smbp = (smb_t *) &outp->data;
9166 smbp->errLow = (unsigned char) (errCode & 0xff);
9167 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
9168 smbp->rcls = errClass;
9171 smb_SendPacket(vcp, outp);
9172 smb_FreePacket(outp);
9174 lock_ObtainMutex(&vcp->mx);
9175 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9176 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9178 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9179 lock_ReleaseMutex(&vcp->mx);
9180 lock_ObtainWrite(&smb_globalLock);
9181 dead_sessions[vcp->session] = TRUE;
9182 lock_ReleaseWrite(&smb_globalLock);
9183 smb_CleanupDeadVC(vcp);
9185 lock_ReleaseMutex(&vcp->mx);
9188 /* assert that we do not exceed the maximum number of sessions or NCBs.
9189 * we should probably want to wait for a session to be freed in case
9192 osi_assertx(session < SESSION_MAX - 1, "invalid session");
9193 osi_assertx(numNCBs < NCB_MAX - 1, "invalid numNCBs"); /* if we pass this test we can allocate one more */
9195 lock_ObtainMutex(&vcp->mx);
9196 vcp->session = session;
9197 lock_ReleaseMutex(&vcp->mx);
9198 lock_ObtainWrite(&smb_globalLock);
9199 LSNs[session] = ncbp->ncb_lsn;
9200 lanas[session] = ncbp->ncb_lana_num;
9201 lock_ReleaseWrite(&smb_globalLock);
9203 if (session == numSessions) {
9204 /* Add new NCB for new session */
9205 char eventName[MAX_PATH];
9207 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
9209 InitNCBslot(numNCBs);
9210 lock_ObtainWrite(&smb_globalLock);
9212 lock_ReleaseWrite(&smb_globalLock);
9213 thrd_SetEvent(NCBavails[0]);
9214 thrd_SetEvent(NCBevents[0]);
9215 for (thread = 0; thread < smb_NumServerThreads; thread++)
9216 thrd_SetEvent(NCBreturns[thread][0]);
9217 /* Also add new session event */
9218 sprintf(eventName, "SessionEvents[%d]", session);
9219 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9220 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9221 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9222 lock_ObtainWrite(&smb_globalLock);
9224 lock_ReleaseWrite(&smb_globalLock);
9225 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
9226 thrd_SetEvent(SessionEvents[0]);
9228 thrd_SetEvent(SessionEvents[session]);
9234 lock_ReleaseMutex(&smb_ListenerLock);
9235 } /* dispatch while loop */
9239 thrd_SetEvent(ListenerShutdown[lana]);
9244 smb_LanAdapterChangeThread(void *param)
9247 * Give the IPAddrDaemon thread a chance
9248 * to block before we trigger.
9251 smb_LanAdapterChange(0);
9254 void smb_SetLanAdapterChangeDetected(void)
9259 lock_ObtainMutex(&smb_StartedLock);
9261 if (!powerStateSuspended) {
9262 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_LanAdapterChangeThread,
9263 NULL, 0, &lpid, "smb_LanAdapterChange");
9264 osi_assertx(phandle != NULL, "smb_LanAdapterChangeThread thread creation failure");
9265 thrd_CloseHandle(phandle);
9268 smb_LanAdapterChangeDetected = 1;
9269 lock_ReleaseMutex(&smb_StartedLock);
9272 void smb_LanAdapterChange(int locked) {
9273 lana_number_t lanaNum;
9275 char NetbiosName[MAX_NB_NAME_LENGTH] = "";
9277 LANA_ENUM temp_list;
9282 afsi_log("smb_LanAdapterChange");
9285 lock_ObtainMutex(&smb_StartedLock);
9287 smb_LanAdapterChangeDetected = 0;
9289 if (!powerStateSuspended &&
9290 SUCCEEDED(lana_GetUncServerNameEx(NetbiosName, &lanaNum, &bGateway,
9291 LANA_NETBIOS_NAME_FULL)) &&
9292 lanaNum != LANA_INVALID && smb_LANadapter != lanaNum) {
9293 if ( isGateway != bGateway ) {
9294 afsi_log("Lan Adapter Change detected (%d != %d): gateway %d != %d",
9295 smb_LANadapter, lanaNum, isGateway, bGateway);
9297 } else if (strcmp(cm_NetbiosName, NetbiosName) ) {
9298 afsi_log("Lan Adapter Change detected (%d != %d): name %s != %s",
9299 smb_LANadapter, lanaNum, cm_NetbiosName, NetbiosName);
9302 NCB *ncbp = smb_GetNCB();
9303 ncbp->ncb_command = NCBENUM;
9304 ncbp->ncb_buffer = (PUCHAR)&temp_list;
9305 ncbp->ncb_length = sizeof(temp_list);
9306 code = Netbios(ncbp);
9308 if (temp_list.length != lana_list.length) {
9309 afsi_log("Lan Adapter Change detected (%d != %d): lan list length changed %d != %d",
9310 smb_LANadapter, lanaNum, temp_list.length, lana_list.length);
9313 for (i=0; i<lana_list.length; i++) {
9314 if ( temp_list.lana[i] != lana_list.lana[i] ) {
9315 afsi_log("Lan Adapter Change detected (%d != %d): lana[%d] %d != %d",
9316 smb_LANadapter, lanaNum, i, temp_list.lana[i], lana_list.lana[i]);
9328 smb_StopListeners(1);
9329 smb_RestartListeners(1);
9332 lock_ReleaseMutex(&smb_StartedLock);
9335 /* initialize Netbios */
9336 int smb_NetbiosInit(int locked)
9339 int i, lana, code, l;
9341 int delname_tried=0;
9344 lana_number_t lanaNum;
9347 lock_ObtainMutex(&smb_StartedLock);
9349 if (smb_ListenerState != SMB_LISTENER_UNINITIALIZED &&
9350 smb_ListenerState != SMB_LISTENER_STOPPED) {
9353 lock_ReleaseMutex(&smb_StartedLock);
9356 /* setup the NCB system */
9357 ncbp = smb_GetNCB();
9359 /* Call lanahelper to get Netbios name, lan adapter number and gateway flag */
9360 if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
9361 smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
9363 if (smb_LANadapter != LANA_INVALID)
9364 afsi_log("LAN adapter number %d", smb_LANadapter);
9366 afsi_log("LAN adapter number not determined");
9369 afsi_log("Set for gateway service");
9371 afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
9373 /* something went horribly wrong. We can't proceed without a netbios name */
9375 StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
9376 osi_panic(buf, __FILE__, __LINE__);
9379 /* remember the name */
9380 len = (int)strlen(cm_NetbiosName);
9382 free(smb_localNamep);
9383 smb_localNamep = malloc(len+1);
9384 strcpy(smb_localNamep, cm_NetbiosName);
9385 afsi_log("smb_localNamep is >%s<", smb_localNamep);
9387 /* Also copy the value to the client character encoded string */
9388 cm_Utf8ToClientString(cm_NetbiosName, -1, cm_NetbiosNameC, MAX_NB_NAME_LENGTH);
9390 if (smb_LANadapter == LANA_INVALID) {
9391 ncbp->ncb_command = NCBENUM;
9392 ncbp->ncb_buffer = (PUCHAR)&lana_list;
9393 ncbp->ncb_length = sizeof(lana_list);
9394 code = Netbios(ncbp);
9396 afsi_log("Netbios NCBENUM error code %d", code);
9397 osi_panic(s, __FILE__, __LINE__);
9401 lana_list.length = 1;
9402 lana_list.lana[0] = smb_LANadapter;
9405 for (i = 0; i < lana_list.length; i++) {
9406 /* reset the adaptor: in Win32, this is required for every process, and
9407 * acts as an init call, not as a real hardware reset.
9409 ncbp->ncb_command = NCBRESET;
9410 ncbp->ncb_callname[0] = 100;
9411 ncbp->ncb_callname[2] = 100;
9412 ncbp->ncb_lana_num = lana_list.lana[i];
9413 code = Netbios(ncbp);
9415 code = ncbp->ncb_retcode;
9417 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
9418 lana_list.lana[i] = LANA_INVALID; /* invalid lana */
9420 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
9424 /* and declare our name so we can receive connections */
9425 memset(ncbp, 0, sizeof(*ncbp));
9426 len=lstrlen(smb_localNamep);
9427 memset(smb_sharename,' ',NCBNAMSZ);
9428 memcpy(smb_sharename,smb_localNamep,len);
9429 afsi_log("lana_list.length %d", lana_list.length);
9431 /* Keep the name so we can unregister it later */
9432 for (l = 0; l < lana_list.length; l++) {
9433 lana = lana_list.lana[l];
9435 ncbp->ncb_command = NCBADDNAME;
9436 ncbp->ncb_lana_num = lana;
9437 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9438 code = Netbios(ncbp);
9440 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
9441 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
9443 char name[NCBNAMSZ+1];
9445 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
9446 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
9450 code = ncbp->ncb_retcode;
9453 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
9456 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
9457 if (code == NRC_BRIDGE) { /* invalid LANA num */
9458 lana_list.lana[l] = LANA_INVALID;
9461 else if (code == NRC_DUPNAME) {
9462 afsi_log("Name already exists; try to delete it");
9463 memset(ncbp, 0, sizeof(*ncbp));
9464 ncbp->ncb_command = NCBDELNAME;
9465 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9466 ncbp->ncb_lana_num = lana;
9467 code = Netbios(ncbp);
9469 code = ncbp->ncb_retcode;
9471 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
9473 if (code != 0 || delname_tried) {
9474 lana_list.lana[l] = LANA_INVALID;
9476 else if (code == 0) {
9477 if (!delname_tried) {
9485 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
9486 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
9490 smb_LANadapter = lana;
9491 lana_found = 1; /* at least one worked */
9495 osi_assertx(lana_list.length >= 0, "empty lana list");
9497 afsi_log("No valid LANA numbers found!");
9498 lana_list.length = 0;
9499 smb_LANadapter = LANA_INVALID;
9500 smb_ListenerState = SMB_LISTENER_STOPPED;
9501 cm_VolStatus_Network_Stopped(cm_NetbiosName
9508 /* we're done with the NCB now */
9511 afsi_log("smb_NetbiosInit smb_LANadapter=%d",smb_LANadapter);
9512 if (lana_list.length > 0)
9513 osi_assert(smb_LANadapter != LANA_INVALID);
9516 lock_ReleaseMutex(&smb_StartedLock);
9518 return (lana_list.length > 0 ? 1 : 0);
9521 void smb_StartListeners(int locked)
9528 lock_ObtainMutex(&smb_StartedLock);
9530 if (smb_ListenerState == SMB_LISTENER_STARTED) {
9532 lock_ReleaseMutex(&smb_StartedLock);
9536 afsi_log("smb_StartListeners");
9537 smb_ListenerState = SMB_LISTENER_STARTED;
9538 cm_VolStatus_Network_Started(cm_NetbiosName
9544 for (i = 0; i < lana_list.length; i++) {
9545 if (lana_list.lana[i] == LANA_INVALID)
9547 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
9548 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
9549 osi_assertx(phandle != NULL, "smb_Listener thread creation failure");
9550 thrd_CloseHandle(phandle);
9553 lock_ReleaseMutex(&smb_StartedLock);
9556 void smb_RestartListeners(int locked)
9559 lock_ObtainMutex(&smb_StartedLock);
9561 if (powerStateSuspended)
9562 afsi_log("smb_RestartListeners called while suspended");
9564 if (!powerStateSuspended && smb_ListenerState != SMB_LISTENER_UNINITIALIZED) {
9565 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
9566 if (smb_NetbiosInit(1))
9567 smb_StartListeners(1);
9568 } else if (smb_LanAdapterChangeDetected) {
9569 smb_LanAdapterChange(1);
9573 lock_ReleaseMutex(&smb_StartedLock);
9576 void smb_StopListener(NCB *ncbp, int lana, int wait)
9580 memset(ncbp, 0, sizeof(*ncbp));
9581 ncbp->ncb_command = NCBDELNAME;
9582 ncbp->ncb_lana_num = lana;
9583 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9584 code = Netbios(ncbp);
9586 afsi_log("StopListener: Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
9587 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
9589 /* and then reset the LANA; this will cause the listener threads to exit */
9590 ncbp->ncb_command = NCBRESET;
9591 ncbp->ncb_callname[0] = 100;
9592 ncbp->ncb_callname[2] = 100;
9593 ncbp->ncb_lana_num = lana;
9594 code = Netbios(ncbp);
9596 code = ncbp->ncb_retcode;
9598 afsi_log("StopListener: Netbios NCBRESET lana %d error code %d", lana, code);
9600 afsi_log("StopListener: Netbios NCBRESET lana %d succeeded", lana);
9604 thrd_WaitForSingleObject_Event(ListenerShutdown[lana], INFINITE);
9607 void smb_StopListeners(int locked)
9613 lock_ObtainMutex(&smb_StartedLock);
9615 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
9617 lock_ReleaseMutex(&smb_StartedLock);
9621 afsi_log("smb_StopListeners");
9622 smb_ListenerState = SMB_LISTENER_STOPPED;
9623 cm_VolStatus_Network_Stopped(cm_NetbiosName
9629 ncbp = smb_GetNCB();
9631 /* Unregister the SMB name */
9632 for (l = 0; l < lana_list.length; l++) {
9633 lana = lana_list.lana[l];
9635 if (lana != LANA_INVALID) {
9636 smb_StopListener(ncbp, lana, TRUE);
9638 /* mark the adapter invalid */
9639 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
9643 /* force a re-evaluation of the network adapters */
9644 lana_list.length = 0;
9645 smb_LANadapter = LANA_INVALID;
9648 lock_ReleaseMutex(&smb_StartedLock);
9651 void smb_Init(osi_log_t *logp, int useV3,
9661 EVENT_HANDLE retHandle;
9662 char eventName[MAX_PATH];
9663 int startListeners = 0;
9665 smb_TlsRequestSlot = TlsAlloc();
9667 smb_MBfunc = aMBfunc;
9671 /* Initialize smb_localZero */
9672 myTime.tm_isdst = -1; /* compute whether on DST or not */
9673 myTime.tm_year = 70;
9679 smb_localZero = mktime(&myTime);
9681 #ifndef USE_NUMERIC_TIME_CONV
9682 /* Initialize kludge-GMT */
9683 smb_CalculateNowTZ();
9684 #endif /* USE_NUMERIC_TIME_CONV */
9685 #ifdef AFS_FREELANCE_CLIENT
9686 /* Make sure the root.afs volume has the correct time */
9687 cm_noteLocalMountPointChange();
9690 /* initialize the remote debugging log */
9693 /* and the global lock */
9694 lock_InitializeRWLock(&smb_globalLock, "smb global lock", LOCK_HIERARCHY_SMB_GLOBAL);
9695 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock", LOCK_HIERARCHY_SMB_RCT_GLOBAL);
9697 /* Raw I/O data structures */
9698 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock", LOCK_HIERARCHY_SMB_RAWBUF);
9700 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock", LOCK_HIERARCHY_SMB_LISTENER);
9701 lock_InitializeMutex(&smb_StartedLock, "smb started lock", LOCK_HIERARCHY_SMB_STARTED);
9703 /* 4 Raw I/O buffers */
9704 smb_RawBufs = calloc(65536,1);
9705 *((char **)smb_RawBufs) = NULL;
9706 for (i=0; i<3; i++) {
9707 char *rawBuf = calloc(65536,1);
9708 *((char **)rawBuf) = smb_RawBufs;
9709 smb_RawBufs = rawBuf;
9712 /* global free lists */
9713 smb_ncbFreeListp = NULL;
9714 smb_packetFreeListp = NULL;
9716 lock_ObtainMutex(&smb_StartedLock);
9717 startListeners = smb_NetbiosInit(1);
9719 /* Initialize listener and server structures */
9721 memset(dead_sessions, 0, sizeof(dead_sessions));
9722 sprintf(eventName, "SessionEvents[0]");
9723 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9724 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9725 afsi_log("Event Object Already Exists: %s", eventName);
9727 smb_NumServerThreads = nThreads;
9728 sprintf(eventName, "NCBavails[0]");
9729 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9730 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9731 afsi_log("Event Object Already Exists: %s", eventName);
9732 sprintf(eventName, "NCBevents[0]");
9733 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9734 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9735 afsi_log("Event Object Already Exists: %s", eventName);
9736 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
9737 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
9738 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9739 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9740 afsi_log("Event Object Already Exists: %s", eventName);
9741 for (i = 0; i < smb_NumServerThreads; i++) {
9742 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
9743 NCBreturns[i][0] = retHandle;
9746 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
9747 for (i = 0; i < smb_NumServerThreads; i++) {
9748 sprintf(eventName, "smb_ServerShutdown[%d]", i);
9749 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9750 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9751 afsi_log("Event Object Already Exists: %s", eventName);
9752 InitNCBslot((int)(i+1));
9754 numNCBs = smb_NumServerThreads + 1;
9756 /* Initialize dispatch table */
9757 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
9758 /* Prepare the table for unknown operations */
9759 for(i=0; i<= SMB_NOPCODES; i++) {
9760 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
9762 /* Fill in the ones we do know */
9763 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
9764 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
9765 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
9766 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
9767 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
9768 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
9769 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
9770 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
9771 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
9772 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
9773 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
9774 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
9775 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
9776 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
9777 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
9778 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
9779 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
9780 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
9781 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
9782 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
9783 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
9784 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9785 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
9786 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
9787 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
9788 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
9789 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
9790 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
9791 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9792 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
9793 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9794 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
9795 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
9796 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
9797 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9798 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
9799 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
9800 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
9801 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
9802 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
9803 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
9804 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
9805 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9806 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
9807 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9808 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
9809 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
9810 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
9811 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
9812 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
9813 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
9814 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
9815 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
9816 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
9817 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
9818 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
9819 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
9820 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
9821 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
9822 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
9823 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
9824 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
9825 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
9826 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
9827 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
9828 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9829 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
9830 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
9831 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
9832 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
9833 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
9834 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
9835 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
9836 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
9838 /* setup tran 2 dispatch table */
9839 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
9840 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
9841 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
9842 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
9843 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
9844 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
9845 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
9846 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
9847 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
9848 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
9849 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
9850 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
9851 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
9852 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
9853 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
9854 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
9855 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
9856 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
9858 /* setup the rap dispatch table */
9859 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
9860 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
9861 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
9862 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
9863 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
9867 /* if we are doing SMB authentication we have register outselves as a logon process */
9868 if (smb_authType != SMB_AUTH_NONE) {
9869 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
9870 LSA_STRING afsProcessName;
9871 LSA_OPERATIONAL_MODE dummy; /*junk*/
9873 afsProcessName.Buffer = "OpenAFSClientDaemon";
9874 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
9875 afsProcessName.MaximumLength = afsProcessName.Length + 1;
9877 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
9879 if (nts == STATUS_SUCCESS) {
9880 LSA_STRING packageName;
9881 /* we are registered. Find out the security package id */
9882 packageName.Buffer = MSV1_0_PACKAGE_NAME;
9883 packageName.Length = (USHORT)strlen(packageName.Buffer);
9884 packageName.MaximumLength = packageName.Length + 1;
9885 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
9886 if (nts == STATUS_SUCCESS) {
9888 * This code forces Windows to authenticate against the Logon Cache
9889 * first instead of attempting to authenticate against the Domain
9890 * Controller. When the Windows logon cache is enabled this improves
9891 * performance by removing the network access and works around a bug
9892 * seen at sites which are using a MIT Kerberos principal to login
9893 * to machines joined to a non-root domain in a multi-domain forest.
9894 * MsV1_0SetProcessOption was added in Windows XP.
9896 PVOID pResponse = NULL;
9897 ULONG cbResponse = 0;
9898 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
9900 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
9901 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
9902 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
9903 OptionsRequest.DisableOptions = FALSE;
9905 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
9908 sizeof(OptionsRequest),
9914 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
9915 char message[AFSPATHMAX];
9916 sprintf(message,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
9918 OutputDebugString(message);
9921 OutputDebugString("MsV1_0SetProcessOption success");
9922 afsi_log("MsV1_0SetProcessOption success");
9924 /* END - code from Larry */
9926 smb_lsaLogonOrigin.Buffer = "OpenAFS";
9927 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
9928 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
9930 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
9932 /* something went wrong. We report the error and revert back to no authentication
9933 because we can't perform any auth requests without a successful lsa handle
9934 or sec package id. */
9935 afsi_log("Reverting to NO SMB AUTH");
9936 smb_authType = SMB_AUTH_NONE;
9939 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
9941 /* something went wrong. We report the error and revert back to no authentication
9942 because we can't perform any auth requests without a successful lsa handle
9943 or sec package id. */
9944 afsi_log("Reverting to NO SMB AUTH");
9945 smb_authType = SMB_AUTH_NONE;
9949 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
9950 * time prevents the failure of authentication when logged into Windows with an
9951 * external Kerberos principal mapped to a local account.
9953 else if ( smb_authType == SMB_AUTH_EXTENDED) {
9954 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
9955 * then the only option is NTLMSSP anyway; so just fallback.
9960 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
9961 if (secBlobLength == 0) {
9962 smb_authType = SMB_AUTH_NTLM;
9963 afsi_log("Reverting to SMB AUTH NTLM");
9972 /* Now get ourselves a domain name. */
9973 /* For now we are using the local computer name as the domain name.
9974 * It is actually the domain for local logins, and we are acting as
9975 * a local SMB server.
9977 bufsize = lengthof(smb_ServerDomainName) - 1;
9978 GetComputerNameW(smb_ServerDomainName, &bufsize);
9979 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
9980 afsi_log("Setting SMB server domain name to [%S]", smb_ServerDomainName);
9983 /* Start listeners, waiters, servers, and daemons */
9985 smb_StartListeners(1);
9987 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
9988 NULL, 0, &lpid, "smb_ClientWaiter");
9989 osi_assertx(phandle != NULL, "smb_ClientWaiter thread creation failure");
9990 thrd_CloseHandle(phandle);
9992 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
9993 NULL, 0, &lpid, "smb_ServerWaiter");
9994 osi_assertx(phandle != NULL, "smb_ServerWaiter thread creation failure");
9995 thrd_CloseHandle(phandle);
9997 for (i=0; i<smb_NumServerThreads; i++) {
9998 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
9999 (void *) i, 0, &lpid, "smb_Server");
10000 osi_assertx(phandle != NULL, "smb_Server thread creation failure");
10001 thrd_CloseHandle(phandle);
10004 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
10005 NULL, 0, &lpid, "smb_Daemon");
10006 osi_assertx(phandle != NULL, "smb_Daemon thread creation failure");
10007 thrd_CloseHandle(phandle);
10009 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
10010 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
10011 osi_assertx(phandle != NULL, "smb_WaitingLocksDaemon thread creation failure");
10012 thrd_CloseHandle(phandle);
10014 lock_ReleaseMutex(&smb_StartedLock);
10018 void smb_Shutdown(void)
10025 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
10027 /* setup the NCB system */
10028 ncbp = smb_GetNCB();
10030 /* Block new sessions by setting shutdown flag */
10031 smbShutdownFlag = 1;
10033 /* Hang up all sessions */
10034 memset((char *)ncbp, 0, sizeof(NCB));
10035 for (i = 1; i < numSessions; i++)
10037 if (dead_sessions[i])
10040 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
10041 ncbp->ncb_command = NCBHANGUP;
10042 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
10043 ncbp->ncb_lsn = (UCHAR)LSNs[i];
10044 code = Netbios(ncbp);
10045 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
10046 if (code == 0) code = ncbp->ncb_retcode;
10048 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
10049 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
10053 /* Trigger the shutdown of all SMB threads */
10054 for (i = 0; i < smb_NumServerThreads; i++)
10055 thrd_SetEvent(NCBreturns[i][0]);
10057 thrd_SetEvent(NCBevents[0]);
10058 thrd_SetEvent(SessionEvents[0]);
10059 thrd_SetEvent(NCBavails[0]);
10061 for (i = 0;i < smb_NumServerThreads; i++) {
10062 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
10063 if (code == WAIT_OBJECT_0) {
10066 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
10067 thrd_SetEvent(NCBreturns[i--][0]);
10071 /* Delete Netbios name */
10072 memset((char *)ncbp, 0, sizeof(NCB));
10073 for (i = 0; i < lana_list.length; i++) {
10074 if (lana_list.lana[i] == LANA_INVALID) continue;
10075 ncbp->ncb_command = NCBDELNAME;
10076 ncbp->ncb_lana_num = lana_list.lana[i];
10077 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10078 code = Netbios(ncbp);
10080 code = ncbp->ncb_retcode;
10082 fprintf(stderr, "Shutdown: Netbios NCBDELNAME lana %d error code %d",
10083 ncbp->ncb_lana_num, code);
10088 /* Release the reference counts held by the VCs */
10089 lock_ObtainWrite(&smb_rctLock);
10090 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
10095 if (vcp->magic != SMB_VC_MAGIC)
10096 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
10097 __FILE__, __LINE__);
10099 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10101 if (fidp->scp != NULL) {
10104 lock_ReleaseWrite(&smb_rctLock);
10105 lock_ObtainMutex(&fidp->mx);
10106 if (fidp->scp != NULL) {
10109 lock_ObtainWrite(&scp->rw);
10110 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
10111 lock_ReleaseWrite(&scp->rw);
10112 osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
10113 cm_ReleaseSCache(scp);
10115 lock_ReleaseMutex(&fidp->mx);
10116 lock_ObtainWrite(&smb_rctLock);
10120 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10122 smb_ReleaseVCNoLock(tidp->vcp);
10124 cm_user_t *userp = tidp->userp;
10125 tidp->userp = NULL;
10126 cm_ReleaseUser(userp);
10130 lock_ReleaseWrite(&smb_rctLock);
10132 TlsFree(smb_TlsRequestSlot);
10135 /* Get the UNC \\<servername>\<sharename> prefix. */
10136 char *smb_GetSharename()
10141 /* Make sure we have been properly initialized. */
10142 if (smb_localNamep == NULL)
10145 /* Allocate space for \\<servername>\<sharename>, plus the
10148 len = (strlen(smb_localNamep) + strlen("ALL") + 4) * sizeof(char);
10149 name = malloc(len);
10150 snprintf(name, len, "\\\\%s\\%s", smb_localNamep, "ALL");
10156 void smb_LogPacket(smb_packet_t *packet)
10160 unsigned length, paramlen, datalen, i, j;
10162 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
10164 if (!packet) return;
10166 osi_Log0(smb_logp, "*** SMB packet dump ***");
10168 smbp = (smb_t *) packet->data;
10169 vp = (BYTE *) packet->data;
10171 paramlen = smbp->wct * 2;
10172 datalen = *((WORD *) (smbp->vdata + paramlen));
10173 length = sizeof(*smbp) + paramlen + 1 + datalen;
10175 for (i=0;i < length; i+=16)
10177 memset( buf, ' ', 80 );
10180 itoa( i, buf, 16 );
10182 buf[strlen(buf)] = ' ';
10184 cp = (BYTE*) buf + 7;
10186 for (j=0;j < 16 && (i+j)<length; j++)
10188 *(cp++) = hex[vp[i+j] >> 4];
10189 *(cp++) = hex[vp[i+j] & 0xf];
10199 for (j=0;j < 16 && (i+j)<length;j++)
10201 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
10212 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
10215 osi_Log0(smb_logp, "*** End SMB packet dump ***");
10217 #endif /* LOG_PACKET */
10220 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
10226 smb_username_t *unp;
10227 smb_waitingLockRequest_t *wlrp;
10230 lock_ObtainRead(&smb_rctLock);
10232 sprintf(output, "begin dumping smb_username_t\r\n");
10233 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10234 for (unp = usernamesp; unp; unp=unp->nextp)
10236 cm_ucell_t *ucellp;
10238 sprintf(output, "%s -- smb_unp=0x%p, refCount=%d, cm_userp=0x%p, flags=0x%x, logoff=%u, name=%S, machine=%S\r\n",
10239 cookie, unp, unp->refCount, unp->userp, unp->flags, unp->last_logoff_t,
10240 unp->name ? unp->name : _C("NULL"),
10241 unp->machine ? unp->machine : _C("NULL"));
10242 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10244 sprintf(output, " begin dumping cm_ucell_t\r\n");
10245 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10247 for ( ucellp = unp->userp->cellInfop; ucellp; ucellp = ucellp->nextp ) {
10248 sprintf(output, " %s -- ucellp=0x%p, cellp=0x%p, flags=0x%x, tktLen=%04u, kvno=%03u, expires=%I64u, gen=%d, name=%s, cellname=%s\r\n",
10249 cookie, ucellp, ucellp->cellp, ucellp->flags, ucellp->ticketLen, ucellp->kvno,
10250 ucellp->expirationTime, ucellp->gen,
10252 ucellp->cellp->name);
10253 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10256 sprintf(output, " done dumping cm_ucell_t\r\n");
10257 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10260 sprintf(output, "done dumping smb_username_t\r\n");
10261 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10264 sprintf(output, "begin dumping smb_waitingLockRequest_t\r\n");
10265 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10268 for ( wlrp = smb_allWaitingLocks; wlrp; wlrp = (smb_waitingLockRequest_t *) osi_QNext(&wlrp->q)) {
10269 smb_waitingLock_t *lockp;
10271 sprintf(output, "%s wlrp=0x%p vcp=0x%p, scp=0x%p, type=0x%x, start_t=0x%I64u msTimeout=0x%x\r\n",
10272 cookie, wlrp, wlrp->vcp, wlrp->scp, wlrp->lockType, wlrp->start_t, wlrp->msTimeout);
10273 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10275 sprintf(output, " begin dumping smb_waitingLock_t\r\n");
10276 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10277 for (lockp = wlrp->locks; lockp; lockp = (smb_waitingLock_t *) osi_QNext(&lockp->q)) {
10278 sprintf(output, " %s -- waitlockp=0x%p lockp=0x%p key=0x%I64x offset=0x%I64x length=0x%I64x state=0x%x\r\n",
10279 cookie, lockp, lockp->lockp, lockp->key, lockp->LOffset.QuadPart, lockp->LLength.QuadPart, lockp->state);
10280 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10282 sprintf(output, " done dumping smb_waitingLock_t\r\n");
10283 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10286 sprintf(output, "done dumping smb_waitingLockRequest_t\r\n");
10287 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10289 sprintf(output, "begin dumping smb_vc_t\r\n");
10290 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10292 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
10298 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
10299 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
10300 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10302 sprintf(output, " begin dumping smb_user_t\r\n");
10303 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10304 for (userp = vcp->usersp; userp; userp = userp->nextp) {
10305 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
10306 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
10307 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10309 sprintf(output, " done dumping smb_user_t\r\n");
10310 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10312 sprintf(output, " begin dumping smb_tid_t\r\n");
10313 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10314 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10315 sprintf(output, " %s -- smb_tidp=0x%p, refCount=%d, tid=%d, vcp=0x%p, cm_userp=0x%p, flags=0x%x, delOk=%d, path=%S\r\n",
10316 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
10317 tidp->pathname ? tidp->pathname : _C("NULL"));
10318 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10320 sprintf(output, " done dumping smb_tid_t\r\n");
10321 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10323 sprintf(output, " begin dumping smb_fid_t\r\n");
10324 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10326 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10328 sprintf(output, " %s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, userp=0x%p, ioctlp=0x%p, flags=0x%x, delOk=%d, NTopen_pathp=%S, NTopen_wholepathp=%S\r\n",
10329 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
10330 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
10331 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
10332 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10335 sprintf(output, " done dumping smb_fid_t\r\n");
10336 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10339 sprintf(output, "done dumping smb_vc_t\r\n");
10340 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10342 sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
10343 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10345 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
10351 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
10352 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
10353 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10355 sprintf(output, " begin dumping smb_user_t\r\n");
10356 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10357 for (userp = vcp->usersp; userp; userp = userp->nextp) {
10358 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
10359 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
10360 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10362 sprintf(output, " done dumping smb_user_t\r\n");
10363 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10365 sprintf(output, " begin dumping smb_tid_t\r\n");
10366 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10367 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10368 sprintf(output, " %s -- smb_tidp=0x%p, refCount=%d, tid=%d, vcp=0x%p, cm_userp=0x%p, flags=0x%x, delOk=%d, path=%S\r\n",
10369 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
10370 tidp->pathname ? tidp->pathname : _C("NULL"));
10371 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10373 sprintf(output, " done dumping smb_tid_t\r\n");
10374 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10376 sprintf(output, " begin dumping smb_fid_t\r\n");
10377 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10379 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10381 sprintf(output, " %s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, userp=0x%p, ioctlp=0x%p, flags=0x%x, delOk=%d, NTopen_pathp=%S, NTopen_wholepathp=%S\r\n",
10382 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
10383 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
10384 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
10385 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10388 sprintf(output, " done dumping smb_fid_t\r\n");
10389 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10392 sprintf(output, "done dumping DEAD smb_vc_t\r\n");
10393 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10396 lock_ReleaseRead(&smb_rctLock);
10400 long smb_IsNetworkStarted(void)
10403 lock_ObtainWrite(&smb_globalLock);
10404 rc = (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);
10405 lock_ReleaseWrite(&smb_globalLock);