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 int smb_IsStarMask(clientchar_t *maskp)
922 for(i=0; i<11; i++) {
924 if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
930 #ifdef DEBUG_SMB_REFCOUNT
931 void smb_ReleaseVCInternalDbg(smb_vc_t *vcp, char * file, long line)
932 #define smb_ReleaseVCInternal(a) smb_ReleaseVCInternalDbg(a, file, line)
934 void smb_ReleaseVCInternal(smb_vc_t *vcp)
940 lock_AssertWrite(&smb_rctLock);
943 if (vcp->refCount == 0) {
944 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
945 #ifdef DEBUG_SMB_REFCOUNT
946 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
947 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
949 /* remove VCP from smb_deadVCsp */
950 for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
956 lock_FinalizeMutex(&vcp->mx);
957 memset(vcp,0,sizeof(smb_vc_t));
960 #ifdef DEBUG_SMB_REFCOUNT
961 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is alive ref %d", file, line, vcp, vcp->refCount);
963 for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
967 osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
968 avcp?"":"not ",vcp, vcp->refCount);
970 /* This is a wrong. However, I suspect that there is an undercount
971 * and I don't want to release 1.4.1 in a state that will allow
972 * smb_vc_t objects to be deallocated while still in the
973 * smb_allVCsp list. The list is supposed to keep a reference
974 * to the smb_vc_t. Put it back.
978 #ifdef DEBUG_SMB_REFCOUNT
979 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
980 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
984 } else if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
985 /* The reference count is non-zero but the VC is dead.
986 * This implies that some FIDs, TIDs, etc on the VC have yet to
987 * be cleaned up. If we were not called by smb_CleanupDeadVC(),
988 * add a reference that will be dropped by
989 * smb_CleanupDeadVC() and try to cleanup the VC again.
990 * Eventually the refCount will drop to zero when all of the
991 * active threads working with the VC end their task.
993 if (!(vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS)) {
994 vcp->refCount++; /* put the refCount back */
995 lock_ReleaseWrite(&smb_rctLock);
996 smb_CleanupDeadVC(vcp);
997 #ifdef DEBUG_SMB_REFCOUNT
998 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
999 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
1001 lock_ObtainWrite(&smb_rctLock);
1004 #ifdef DEBUG_SMB_REFCOUNT
1005 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1006 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1011 #ifdef DEBUG_SMB_REFCOUNT
1012 void smb_ReleaseVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
1014 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
1017 lock_AssertWrite(&smb_rctLock);
1018 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
1019 smb_ReleaseVCInternal(vcp);
1022 #ifdef DEBUG_SMB_REFCOUNT
1023 void smb_ReleaseVCDbg(smb_vc_t *vcp, char * file, long line)
1025 void smb_ReleaseVC(smb_vc_t *vcp)
1028 lock_ObtainWrite(&smb_rctLock);
1029 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
1030 smb_ReleaseVCInternal(vcp);
1031 lock_ReleaseWrite(&smb_rctLock);
1034 #ifdef DEBUG_SMB_REFCOUNT
1035 void smb_HoldVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
1037 void smb_HoldVCNoLock(smb_vc_t *vcp)
1040 lock_AssertWrite(&smb_rctLock);
1042 #ifdef DEBUG_SMB_REFCOUNT
1043 afsi_log("%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1044 osi_Log4(smb_logp,"%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1046 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
1050 #ifdef DEBUG_SMB_REFCOUNT
1051 void smb_HoldVCDbg(smb_vc_t *vcp, char * file, long line)
1053 void smb_HoldVC(smb_vc_t *vcp)
1056 lock_ObtainWrite(&smb_rctLock);
1058 #ifdef DEBUG_SMB_REFCOUNT
1059 afsi_log("%s:%d smb_HoldVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1060 osi_Log4(smb_logp,"%s:%d smb_HoldVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1062 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
1064 lock_ReleaseWrite(&smb_rctLock);
1067 void smb_CleanupDeadVC(smb_vc_t *vcp)
1069 smb_fid_t *fidpIter;
1070 smb_fid_t *fidpNext;
1072 smb_tid_t *tidpIter;
1073 smb_tid_t *tidpNext;
1075 smb_user_t *uidpIter;
1076 smb_user_t *uidpNext;
1078 afs_uint32 refCount = 0;
1080 lock_ObtainMutex(&vcp->mx);
1081 if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
1082 lock_ReleaseMutex(&vcp->mx);
1083 osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
1086 vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
1087 lock_ReleaseMutex(&vcp->mx);
1088 osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
1090 lock_ObtainWrite(&smb_rctLock);
1091 /* remove VCP from smb_allVCsp */
1092 for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
1093 if ((*vcpp)->magic != SMB_VC_MAGIC)
1094 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
1095 __FILE__, __LINE__);
1098 vcp->nextp = smb_deadVCsp;
1100 /* Hold onto the reference until we are done with this function */
1105 for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
1106 fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
1108 if (fidpIter->deleteOk)
1111 fid = fidpIter->fid;
1112 osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1114 smb_HoldFIDNoLock(fidpIter);
1115 lock_ReleaseWrite(&smb_rctLock);
1117 smb_CloseFID(vcp, fidpIter, NULL, 0);
1118 smb_ReleaseFID(fidpIter);
1120 lock_ObtainWrite(&smb_rctLock);
1121 fidpNext = vcp->fidsp;
1124 for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1125 tidpNext = tidpIter->nextp;
1126 if (tidpIter->deleteOk)
1128 tidpIter->deleteOk = 1;
1130 tid = tidpIter->tid;
1131 osi_Log2(smb_logp, " Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1133 smb_HoldTIDNoLock(tidpIter);
1134 smb_ReleaseTID(tidpIter, TRUE);
1135 tidpNext = vcp->tidsp;
1138 for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1139 uidpNext = uidpIter->nextp;
1140 if (uidpIter->deleteOk)
1142 uidpIter->deleteOk = 1;
1144 /* do not add an additional reference count for the smb_user_t
1145 * as the smb_vc_t already is holding a reference */
1146 lock_ReleaseWrite(&smb_rctLock);
1148 smb_ReleaseUID(uidpIter);
1150 lock_ObtainWrite(&smb_rctLock);
1151 uidpNext = vcp->usersp;
1154 /* The vcp is now on the deadVCsp list. We intentionally drop the
1155 * reference so that the refcount can reach 0 and we can delete it
1157 * If the refCount == 1 going into the ReleaseVCNoLock call
1158 * the object will be freed and it won't be safe to clear
1161 refCount = vcp->refCount;
1162 smb_ReleaseVCNoLock(vcp);
1164 lock_ObtainMutex(&vcp->mx);
1165 vcp->flags &= ~SMB_VCFLAG_CLEAN_IN_PROGRESS;
1166 lock_ReleaseMutex(&vcp->mx);
1169 lock_ReleaseWrite(&smb_rctLock);
1170 osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1173 #ifdef DEBUG_SMB_REFCOUNT
1174 smb_tid_t *smb_FindTIDDbg(smb_vc_t *vcp, unsigned short tid, int flags, char * file, long line)
1176 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1181 lock_ObtainWrite(&smb_rctLock);
1183 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1184 if (tidp->refCount == 0 && tidp->deleteOk) {
1186 smb_ReleaseTID(tidp, TRUE);
1190 if (tid == tidp->tid) {
1195 if (!tidp && (flags & SMB_FLAG_CREATE)) {
1196 tidp = malloc(sizeof(*tidp));
1197 memset(tidp, 0, sizeof(*tidp));
1198 tidp->nextp = vcp->tidsp;
1201 smb_HoldVCNoLock(vcp);
1203 lock_InitializeMutex(&tidp->mx, "tid_t mutex", LOCK_HIERARCHY_SMB_TID);
1206 #ifdef DEBUG_SMB_REFCOUNT
1208 afsi_log("%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1209 osi_Log4(smb_logp,"%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1212 lock_ReleaseWrite(&smb_rctLock);
1216 #ifdef DEBUG_SMB_REFCOUNT
1217 void smb_HoldTIDNoLockDbg(smb_tid_t *tidp, char * file, long line)
1219 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1222 lock_AssertWrite(&smb_rctLock);
1224 #ifdef DEBUG_SMB_REFCOUNT
1225 afsi_log("%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1226 osi_Log4(smb_logp,"%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1230 #ifdef DEBUG_SMB_REFCOUNT
1231 void smb_ReleaseTIDDbg(smb_tid_t *tidp, afs_uint32 locked, char *file, long line)
1233 void smb_ReleaseTID(smb_tid_t *tidp, afs_uint32 locked)
1238 cm_user_t *userp = NULL;
1239 smb_vc_t *vcp = NULL;
1242 lock_ObtainWrite(&smb_rctLock);
1244 lock_AssertWrite(&smb_rctLock);
1246 osi_assertx(tidp->refCount-- > 0, "smb_tid_t refCount 0");
1247 #ifdef DEBUG_SMB_REFCOUNT
1248 afsi_log("%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1249 osi_Log5(smb_logp,"%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1251 if (tidp->refCount == 0) {
1252 if (tidp->deleteOk) {
1253 ltpp = &tidp->vcp->tidsp;
1254 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1258 osi_assertx(tp != NULL, "null smb_tid_t");
1260 lock_FinalizeMutex(&tidp->mx);
1261 userp = tidp->userp; /* remember to drop ref later */
1269 lock_ReleaseWrite(&smb_rctLock);
1271 cm_ReleaseUser(userp);
1273 smb_ReleaseVCNoLock(vcp);
1276 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1278 smb_user_t *uidp = NULL;
1280 lock_ObtainWrite(&smb_rctLock);
1281 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1282 if (uid == uidp->userID) {
1284 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%S]",
1286 ((uidp->unp)? osi_LogSaveClientString(smb_logp, uidp->unp->name):_C("")));
1290 if (!uidp && (flags & SMB_FLAG_CREATE)) {
1291 uidp = malloc(sizeof(*uidp));
1292 memset(uidp, 0, sizeof(*uidp));
1293 uidp->nextp = vcp->usersp;
1294 uidp->refCount = 2; /* one for the vcp and one for the caller */
1296 smb_HoldVCNoLock(vcp);
1298 lock_InitializeMutex(&uidp->mx, "user_t mutex", LOCK_HIERARCHY_SMB_UID);
1300 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%S]",
1302 ((uidp->unp)?osi_LogSaveClientString(smb_logp,uidp->unp->name):_C("")));
1304 lock_ReleaseWrite(&smb_rctLock);
1308 smb_username_t *smb_FindUserByName(clientchar_t *usern, clientchar_t *machine,
1311 smb_username_t *unp= NULL;
1313 lock_ObtainWrite(&smb_rctLock);
1314 for(unp = usernamesp; unp; unp = unp->nextp) {
1315 if (cm_ClientStrCmpI(unp->name, usern) == 0 &&
1316 cm_ClientStrCmpI(unp->machine, machine) == 0) {
1321 if (!unp && (flags & SMB_FLAG_CREATE)) {
1322 unp = malloc(sizeof(*unp));
1323 memset(unp, 0, sizeof(*unp));
1325 unp->nextp = usernamesp;
1326 unp->name = cm_ClientStrDup(usern);
1327 unp->machine = cm_ClientStrDup(machine);
1329 lock_InitializeMutex(&unp->mx, "username_t mutex", LOCK_HIERARCHY_SMB_USERNAME);
1330 if (flags & SMB_FLAG_AFSLOGON)
1331 unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1334 lock_ReleaseWrite(&smb_rctLock);
1338 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, clientchar_t *usern)
1340 smb_user_t *uidp= NULL;
1342 lock_ObtainWrite(&smb_rctLock);
1343 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1346 if (cm_stricmp_utf16(uidp->unp->name, usern) == 0) {
1348 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%S]",
1349 vcp,uidp->userID,osi_LogSaveClientString(smb_logp,usern));
1354 lock_ReleaseWrite(&smb_rctLock);
1358 void smb_ReleaseUsername(smb_username_t *unp)
1361 smb_username_t **lupp;
1362 cm_user_t *userp = NULL;
1363 time_t now = osi_Time();
1365 lock_ObtainWrite(&smb_rctLock);
1366 osi_assertx(unp->refCount-- > 0, "smb_username_t refCount 0");
1367 if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1368 (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1370 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1374 osi_assertx(up != NULL, "null smb_username_t");
1376 up->nextp = NULL; /* do not remove this */
1377 lock_FinalizeMutex(&unp->mx);
1383 lock_ReleaseWrite(&smb_rctLock);
1385 cm_ReleaseUser(userp);
1388 void smb_HoldUIDNoLock(smb_user_t *uidp)
1390 lock_AssertWrite(&smb_rctLock);
1394 void smb_ReleaseUID(smb_user_t *uidp)
1398 smb_username_t *unp = NULL;
1400 lock_ObtainWrite(&smb_rctLock);
1401 osi_assertx(uidp->refCount-- > 0, "smb_user_t refCount 0");
1402 if (uidp->refCount == 0) {
1403 lupp = &uidp->vcp->usersp;
1404 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1408 osi_assertx(up != NULL, "null smb_user_t");
1410 lock_FinalizeMutex(&uidp->mx);
1412 smb_ReleaseVCNoLock(uidp->vcp);
1416 lock_ReleaseWrite(&smb_rctLock);
1420 cm_ReleaseUserVCRef(unp->userp);
1421 smb_ReleaseUsername(unp);
1425 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1427 cm_user_t *up = NULL;
1432 lock_ObtainMutex(&uidp->mx);
1434 up = uidp->unp->userp;
1437 lock_ReleaseMutex(&uidp->mx);
1443 /* retrieve a held reference to a user structure corresponding to an incoming
1445 * corresponding release function is cm_ReleaseUser.
1447 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1450 cm_user_t *up = NULL;
1453 smbp = (smb_t *) inp;
1454 uidp = smb_FindUID(vcp, smbp->uid, 0);
1458 up = smb_GetUserFromUID(uidp);
1460 smb_ReleaseUID(uidp);
1465 * Return a pointer to a pathname extracted from a TID structure. The
1466 * TID structure is not held; assume it won't go away.
1468 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, clientchar_t ** treepath)
1473 tidp = smb_FindTID(vcp, tid, 0);
1477 if (tidp->flags & SMB_TIDFLAG_IPC) {
1478 code = CM_ERROR_TIDIPC;
1479 /* tidp->pathname would be NULL, but that's fine */
1481 *treepath = tidp->pathname;
1482 smb_ReleaseTID(tidp, FALSE);
1487 /* check to see if we have a chained fid, that is, a fid that comes from an
1488 * OpenAndX message that ran earlier in this packet. In this case, the fid
1489 * field in a read, for example, request, isn't set, since the value is
1490 * supposed to be inherited from the openAndX call.
1492 int smb_ChainFID(int fid, smb_packet_t *inp)
1494 if (inp->fid == 0 || inp->inCount == 0)
1500 /* are we a priv'd user? What does this mean on NT? */
1501 int smb_SUser(cm_user_t *userp)
1506 /* find a file ID. If we pass in 0 we select an unused File ID.
1507 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1508 * smb_fid_t data structure if desired File ID cannot be found.
1510 #ifdef DEBUG_SMB_REFCOUNT
1511 smb_fid_t *smb_FindFIDDbg(smb_vc_t *vcp, unsigned short fid, int flags, char *file, long line)
1513 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1519 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1522 lock_ObtainWrite(&smb_rctLock);
1523 /* figure out if we need to allocate a new file ID */
1526 fid = vcp->fidCounter;
1530 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1531 if (fidp->refCount == 0 && fidp->deleteOk) {
1533 lock_ReleaseWrite(&smb_rctLock);
1534 smb_ReleaseFID(fidp);
1535 lock_ObtainWrite(&smb_rctLock);
1538 if (fid == fidp->fid) {
1541 if (fid == 0xFFFF) {
1543 "New FID number wraps on vcp 0x%x", vcp);
1553 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1554 char eventName[MAX_PATH];
1556 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1557 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1558 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1559 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1560 thrd_CloseHandle(event);
1562 if (fid == 0xFFFF) {
1563 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1569 fidp = malloc(sizeof(*fidp));
1570 memset(fidp, 0, sizeof(*fidp));
1571 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1574 smb_HoldVCNoLock(vcp);
1575 lock_InitializeMutex(&fidp->mx, "fid_t mutex", LOCK_HIERARCHY_SMB_FID);
1577 fidp->curr_chunk = fidp->prev_chunk = -2;
1578 fidp->raw_write_event = event;
1580 vcp->fidCounter = fid+1;
1581 if (vcp->fidCounter == 0xFFFF) {
1582 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1584 vcp->fidCounter = 1;
1589 #ifdef DEBUG_SMB_REFCOUNT
1591 afsi_log("%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1592 osi_Log4(smb_logp,"%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1595 lock_ReleaseWrite(&smb_rctLock);
1599 #ifdef DEBUG_SMB_REFCOUNT
1600 smb_fid_t *smb_FindFIDByScacheDbg(smb_vc_t *vcp, cm_scache_t * scp, char *file, long line)
1602 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1605 smb_fid_t *fidp = NULL;
1611 lock_ObtainWrite(&smb_rctLock);
1612 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1613 if (scp == fidp->scp) {
1618 #ifdef DEBUG_SMB_REFCOUNT
1620 afsi_log("%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1621 osi_Log4(smb_logp,"%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1624 lock_ReleaseWrite(&smb_rctLock);
1628 #ifdef DEBUG_SMB_REFCOUNT
1629 void smb_HoldFIDNoLockDbg(smb_fid_t *fidp, char *file, long line)
1631 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1634 lock_AssertWrite(&smb_rctLock);
1636 #ifdef DEBUG_SMB_REFCOUNT
1637 afsi_log("%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1638 osi_Log4(smb_logp,"%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1643 /* smb_ReleaseFID cannot be called while an cm_scache_t mutex lock is held */
1644 /* the sm_fid_t->mx and smb_rctLock must not be held */
1645 #ifdef DEBUG_SMB_REFCOUNT
1646 void smb_ReleaseFIDDbg(smb_fid_t *fidp, char *file, long line)
1648 void smb_ReleaseFID(smb_fid_t *fidp)
1651 cm_scache_t *scp = NULL;
1652 cm_user_t *userp = NULL;
1653 smb_vc_t *vcp = NULL;
1654 smb_ioctl_t *ioctlp;
1656 lock_ObtainMutex(&fidp->mx);
1657 lock_ObtainWrite(&smb_rctLock);
1658 osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
1659 #ifdef DEBUG_SMB_REFCOUNT
1660 afsi_log("%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1661 osi_Log5(smb_logp,"%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1663 if (fidp->refCount == 0) {
1664 if (fidp->deleteOk) {
1667 scp = fidp->scp; /* release after lock is released */
1669 lock_ObtainWrite(&scp->rw);
1670 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1671 lock_ReleaseWrite(&scp->rw);
1672 osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1675 userp = fidp->userp;
1679 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1680 thrd_CloseHandle(fidp->raw_write_event);
1682 /* and see if there is ioctl stuff to free */
1683 ioctlp = fidp->ioctlp;
1686 cm_FreeSpace(ioctlp->prefix);
1687 if (ioctlp->ioctl.inAllocp)
1688 free(ioctlp->ioctl.inAllocp);
1689 if (ioctlp->ioctl.outAllocp)
1690 free(ioctlp->ioctl.outAllocp);
1693 lock_ReleaseMutex(&fidp->mx);
1694 lock_FinalizeMutex(&fidp->mx);
1699 smb_ReleaseVCNoLock(vcp);
1703 lock_ReleaseMutex(&fidp->mx);
1705 lock_ReleaseWrite(&smb_rctLock);
1707 /* now release the scache structure */
1709 cm_ReleaseSCache(scp);
1712 cm_ReleaseUser(userp);
1716 * Case-insensitive search for one string in another;
1717 * used to find variable names in submount pathnames.
1719 static clientchar_t *smb_stristr(clientchar_t *str1, clientchar_t *str2)
1721 clientchar_t *cursor;
1723 for (cursor = str1; *cursor; cursor++)
1724 if (cm_ClientStrCmpI(cursor, str2) == 0)
1731 * Substitute a variable value for its name in a submount pathname. Variable
1732 * name has been identified by smb_stristr() and is in substr. Variable name
1733 * length (plus one) is in substr_size. Variable value is in newstr.
1735 static void smb_subst(clientchar_t *str1, int cchstr1, clientchar_t *substr,
1736 unsigned int substr_size, clientchar_t *newstr)
1738 clientchar_t temp[1024];
1740 cm_ClientStrCpy(temp, lengthof(temp), substr + substr_size - 1);
1741 cm_ClientStrCpy(substr, cchstr1 - (substr - str1), newstr);
1742 cm_ClientStrCat(str1, cchstr1, temp);
1745 clientchar_t VNUserName[] = _C("%USERNAME%");
1746 clientchar_t VNLCUserName[] = _C("%LCUSERNAME%");
1747 clientchar_t VNComputerName[] = _C("%COMPUTERNAME%");
1748 clientchar_t VNLCComputerName[] = _C("%LCCOMPUTERNAME%");
1750 typedef struct smb_findShare_rock {
1751 clientchar_t * shareName;
1752 clientchar_t * match;
1754 } smb_findShare_rock_t;
1756 #define SMB_FINDSHARE_EXACT_MATCH 1
1757 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1759 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1763 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1764 normchar_t normName[MAX_PATH];
1766 if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(normName[0])) == 0) {
1767 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
1768 osi_LogSaveString(smb_logp, dep->name));
1772 if (!cm_ClientStrCmpNI(normName, vrock->shareName, 12)) {
1773 if(!cm_ClientStrCmpI(normName, vrock->shareName))
1774 matchType = SMB_FINDSHARE_EXACT_MATCH;
1776 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1777 if(vrock->match) free(vrock->match);
1778 vrock->match = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
1779 vrock->matchType = matchType;
1781 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1782 return CM_ERROR_STOPNOW;
1788 /* find a shareName in the table of submounts */
1789 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp,
1790 clientchar_t *shareName,
1791 clientchar_t **pathNamep)
1795 clientchar_t pathName[1024];
1798 clientchar_t *p, *q;
1799 fschar_t *cellname = NULL;
1802 DWORD allSubmount = 1;
1804 /* if allSubmounts == 0, only return the //mountRoot/all share
1805 * if in fact it has been been created in the subMounts table.
1806 * This is to allow sites that want to restrict access to the
1809 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1810 0, KEY_QUERY_VALUE, &parmKey);
1811 if (code == ERROR_SUCCESS) {
1812 cblen = sizeof(allSubmount);
1813 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1814 (BYTE *) &allSubmount, &cblen);
1815 if (code != ERROR_SUCCESS) {
1818 RegCloseKey (parmKey);
1821 if (allSubmount && cm_ClientStrCmpI(shareName, _C("all")) == 0) {
1826 /* In case, the all share is disabled we need to still be able
1827 * to handle ioctl requests
1829 if (cm_ClientStrCmpI(shareName, _C("ioctl$")) == 0) {
1830 *pathNamep = cm_ClientStrDup(_C("/.__ioctl__"));
1834 if (cm_ClientStrCmpIA(shareName, _C("IPC$")) == 0 ||
1835 cm_ClientStrCmpIA(shareName, _C("srvsvc")) == 0 ||
1836 cm_ClientStrCmpIA(shareName, _C("wkssvc")) == 0 ||
1837 cm_ClientStrCmpIA(shareName, _C(SMB_IOCTL_FILENAME_NOSLASH)) == 0 ||
1838 cm_ClientStrCmpIA(shareName, _C("DESKTOP.INI")) == 0
1844 /* Check for volume references
1846 * They look like <cell>{%,#}<volume>
1848 if (cm_ClientStrChr(shareName, '%') != NULL ||
1849 cm_ClientStrChr(shareName, '#') != NULL) {
1850 clientchar_t pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
1851 /* make room for '/@vol:' + mountchar + NULL terminator*/
1853 osi_Log1(smb_logp, "smb_FindShare found volume reference [%S]",
1854 osi_LogSaveClientString(smb_logp, shareName));
1856 cm_ClientStrPrintfN(pathstr, lengthof(pathstr),
1857 _C("/") _C(CM_PREFIX_VOL) _C("%s"), shareName);
1858 cchlen = (DWORD)(cm_ClientStrLen(pathstr) + 1);
1860 *pathNamep = malloc(cchlen * sizeof(clientchar_t));
1862 cm_ClientStrCpy(*pathNamep, cchlen, pathstr);
1863 cm_ClientStrLwr(*pathNamep);
1864 osi_Log1(smb_logp, " returning pathname [%S]",
1865 osi_LogSaveClientString(smb_logp, *pathNamep));
1873 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1874 0, KEY_QUERY_VALUE, &parmKey);
1875 if (code == ERROR_SUCCESS) {
1876 cblen = sizeof(pathName);
1877 code = RegQueryValueExW(parmKey, shareName, NULL, NULL,
1878 (BYTE *) pathName, &cblen);
1879 if (code != ERROR_SUCCESS)
1881 RegCloseKey (parmKey);
1885 cchlen = cblen / sizeof(clientchar_t);
1886 if (cchlen != 0 && cchlen != lengthof(pathName) - 1) {
1887 /* We can accept either unix or PC style AFS pathnames. Convert
1888 * Unix-style to PC style here for internal use.
1891 cchlen = lengthof(pathName);
1893 /* within this code block, we maintain, cchlen = writeable
1894 buffer length of p */
1896 if (cm_ClientStrCmpN(p, cm_mountRootC, cm_mountRootCLen) == 0) {
1897 p += cm_mountRootCLen; /* skip mount path */
1898 cchlen -= (DWORD)(p - pathName);
1903 if (*q == _C('/')) *q = _C('\\'); /* change to \ */
1909 clientchar_t temp[1024];
1911 if (var = smb_stristr(p, VNUserName)) {
1912 if (uidp && uidp->unp)
1913 smb_subst(p, cchlen, var, lengthof(VNUserName),uidp->unp->name);
1915 smb_subst(p, cchlen, var, lengthof(VNUserName), _C(" "));
1917 else if (var = smb_stristr(p, VNLCUserName))
1919 if (uidp && uidp->unp)
1920 cm_ClientStrCpy(temp, lengthof(temp), uidp->unp->name);
1922 cm_ClientStrCpy(temp, lengthof(temp), _C(" "));
1923 cm_ClientStrLwr(temp);
1924 smb_subst(p, cchlen, var, lengthof(VNLCUserName), temp);
1926 else if (var = smb_stristr(p, VNComputerName))
1928 sizeTemp = lengthof(temp);
1929 GetComputerNameW(temp, &sizeTemp);
1930 smb_subst(p, cchlen, var, lengthof(VNComputerName), temp);
1932 else if (var = smb_stristr(p, VNLCComputerName))
1934 sizeTemp = lengthof(temp);
1935 GetComputerName((LPTSTR)temp, &sizeTemp);
1936 cm_ClientStrLwr(temp);
1937 smb_subst(p, cchlen, var, lengthof(VNLCComputerName), temp);
1942 *pathNamep = cm_ClientStrDup(p);
1947 /* First lookup shareName in root.afs */
1949 smb_findShare_rock_t vrock;
1951 fschar_t ftemp[1024];
1952 clientchar_t * p = shareName;
1955 /* attempt to locate a partial match in root.afs. This is because
1956 when using the ANSI RAP calls, the share name is limited to 13 chars
1957 and hence is truncated. Of course we prefer exact matches. */
1959 thyper.HighPart = 0;
1962 vrock.shareName = cm_ClientStringToNormStringAlloc(shareName, -1, NULL);
1963 if (vrock.shareName == NULL)
1966 vrock.matchType = 0;
1968 cm_HoldSCache(cm_data.rootSCachep);
1969 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1970 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1971 cm_ReleaseSCache(cm_data.rootSCachep);
1973 free(vrock.shareName);
1974 vrock.shareName = NULL;
1976 if (vrock.matchType) {
1977 cm_ClientStrPrintfN(pathName, lengthof(pathName), _C("/%s/"), vrock.match);
1978 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
1983 /* if we get here, there was no match for the share in root.afs */
1984 /* so try to create \\<netbiosName>\<cellname> */
1989 /* Get the full name for this cell */
1990 cellname = cm_ClientStringToFsStringAlloc(p, -1, NULL);
1991 code = cm_SearchCellFile(cellname, ftemp, 0, 0);
1992 #ifdef AFS_AFSDB_ENV
1993 if (code && cm_dnsEnabled) {
1995 code = cm_SearchCellByDNS(cellname, ftemp, &ttl, 0, 0);
2001 /* construct the path */
2003 clientchar_t temp[1024];
2005 if (cm_FsStringToClientString(ftemp, -1, temp, 1024) != 0) {
2006 cm_ClientStrPrintfN(pathName, (int)lengthof(pathName),
2007 rw ? _C("/.%S/") : _C("/%S/"), temp);
2008 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
2018 /* Client-side offline caching policy types */
2019 #define CSC_POLICY_MANUAL 0
2020 #define CSC_POLICY_DOCUMENTS 1
2021 #define CSC_POLICY_PROGRAMS 2
2022 #define CSC_POLICY_DISABLE 3
2024 int smb_FindShareCSCPolicy(clientchar_t *shareName)
2027 clientchar_t policy[1024];
2030 int retval = CSC_POLICY_MANUAL;
2032 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
2033 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
2036 REG_OPTION_NON_VOLATILE,
2042 len = sizeof(policy);
2043 if ( RegQueryValueExW( hkCSCPolicy, shareName, 0, &dwType, (LPBYTE) policy, &len ) ||
2045 retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
2047 else if (cm_ClientStrCmpIA(policy, _C("documents")) == 0)
2049 retval = CSC_POLICY_DOCUMENTS;
2051 else if (cm_ClientStrCmpIA(policy, _C("programs")) == 0)
2053 retval = CSC_POLICY_PROGRAMS;
2055 else if (cm_ClientStrCmpIA(policy, _C("disable")) == 0)
2057 retval = CSC_POLICY_DISABLE;
2060 RegCloseKey(hkCSCPolicy);
2064 /* find a dir search structure by cookie value, and return it held.
2065 * Must be called with smb_globalLock held.
2067 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
2069 smb_dirSearch_t *dsp;
2071 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2072 if (dsp->cookie == cookie) {
2073 if (dsp != smb_firstDirSearchp) {
2074 /* move to head of LRU queue, too, if we're not already there */
2075 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
2076 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2077 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2078 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2079 if (!smb_lastDirSearchp)
2080 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2088 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
2089 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2090 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
2096 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
2098 lock_ObtainMutex(&dsp->mx);
2099 osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p",
2100 dsp->cookie, dsp, dsp->scp);
2101 dsp->flags |= SMB_DIRSEARCH_DELETE;
2102 if (dsp->scp != NULL) {
2103 lock_ObtainWrite(&dsp->scp->rw);
2104 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
2105 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2106 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2107 dsp->scp->bulkStatProgress = hzero;
2109 lock_ReleaseWrite(&dsp->scp->rw);
2111 lock_ReleaseMutex(&dsp->mx);
2114 /* Must be called with the smb_globalLock held */
2115 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
2117 cm_scache_t *scp = NULL;
2119 osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
2120 if (dsp->refCount == 0) {
2121 lock_ObtainMutex(&dsp->mx);
2122 if (dsp->flags & SMB_DIRSEARCH_DELETE) {
2123 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
2124 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
2125 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2126 lock_ReleaseMutex(&dsp->mx);
2127 lock_FinalizeMutex(&dsp->mx);
2129 osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p",
2130 dsp->cookie, dsp, scp);
2133 lock_ReleaseMutex(&dsp->mx);
2136 /* do this now to avoid spurious locking hierarchy creation */
2138 cm_ReleaseSCache(scp);
2141 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
2143 lock_ObtainWrite(&smb_globalLock);
2144 smb_ReleaseDirSearchNoLock(dsp);
2145 lock_ReleaseWrite(&smb_globalLock);
2148 /* find a dir search structure by cookie value, and return it held */
2149 smb_dirSearch_t *smb_FindDirSearch(long cookie)
2151 smb_dirSearch_t *dsp;
2153 lock_ObtainWrite(&smb_globalLock);
2154 dsp = smb_FindDirSearchNoLock(cookie);
2155 lock_ReleaseWrite(&smb_globalLock);
2159 /* GC some dir search entries, in the address space expected by the specific protocol.
2160 * Must be called with smb_globalLock held; release the lock temporarily.
2162 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
2163 void smb_GCDirSearches(int isV3)
2165 smb_dirSearch_t *prevp;
2166 smb_dirSearch_t *dsp;
2167 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
2171 victimCount = 0; /* how many have we got so far */
2172 for (dsp = smb_lastDirSearchp; dsp; dsp=prevp) {
2173 /* we'll move tp from queue, so
2176 prevp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2177 /* if no one is using this guy, and we're either in the new protocol,
2178 * or we're in the old one and this is a small enough ID to be useful
2179 * to the old protocol, GC this guy.
2181 if (dsp->refCount == 0 && (isV3 || dsp->cookie <= 255)) {
2182 /* hold and delete */
2183 lock_ObtainMutex(&dsp->mx);
2184 dsp->flags |= SMB_DIRSEARCH_DELETE;
2185 lock_ReleaseMutex(&dsp->mx);
2186 victimsp[victimCount++] = dsp;
2190 /* don't do more than this */
2191 if (victimCount >= SMB_DIRSEARCH_GCMAX)
2195 /* now release them */
2196 for (i = 0; i < victimCount; i++) {
2197 smb_ReleaseDirSearchNoLock(victimsp[i]);
2201 /* function for allocating a dir search entry. We need these to remember enough context
2202 * since we don't get passed the path from call to call during a directory search.
2204 * Returns a held dir search structure, and bumps the reference count on the vnode,
2205 * since it saves a pointer to the vnode.
2207 smb_dirSearch_t *smb_NewDirSearch(int isV3)
2209 smb_dirSearch_t *dsp;
2215 lock_ObtainWrite(&smb_globalLock);
2218 /* what's the biggest ID allowed in this version of the protocol */
2219 /* TODO: do we really want a non v3 dir search request to wrap
2220 smb_dirSearchCounter? */
2221 maxAllowed = isV3 ? 65535 : 255;
2222 if (smb_dirSearchCounter > maxAllowed)
2223 smb_dirSearchCounter = 1;
2225 start = smb_dirSearchCounter;
2228 /* twice so we have enough tries to find guys we GC after one pass;
2229 * 10 extra is just in case I mis-counted.
2231 if (++counter > 2*maxAllowed+10)
2232 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2234 if (smb_dirSearchCounter > maxAllowed) {
2235 smb_dirSearchCounter = 1;
2237 if (smb_dirSearchCounter == start) {
2239 smb_GCDirSearches(isV3);
2242 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2244 /* don't need to watch for refcount zero and deleted, since
2245 * we haven't dropped the global lock.
2248 ++smb_dirSearchCounter;
2252 dsp = malloc(sizeof(*dsp));
2253 memset(dsp, 0, sizeof(*dsp));
2254 dsp->cookie = smb_dirSearchCounter;
2255 ++smb_dirSearchCounter;
2257 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t", LOCK_HIERARCHY_SMB_DIRSEARCH);
2258 dsp->lastTime = osi_Time();
2259 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2260 if (!smb_lastDirSearchp)
2261 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2263 osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p",
2267 lock_ReleaseWrite(&smb_globalLock);
2271 static smb_packet_t *smb_GetPacket(void)
2275 lock_ObtainWrite(&smb_globalLock);
2276 tbp = smb_packetFreeListp;
2278 smb_packetFreeListp = tbp->nextp;
2279 lock_ReleaseWrite(&smb_globalLock);
2281 tbp = calloc(sizeof(*tbp),1);
2282 tbp->magic = SMB_PACKETMAGIC;
2285 tbp->resumeCode = 0;
2291 tbp->ncb_length = 0;
2294 tbp->stringsp = NULL;
2296 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2301 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2304 tbp = smb_GetPacket();
2305 memcpy(tbp, pkt, sizeof(smb_packet_t));
2306 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2307 tbp->stringsp = NULL;
2309 smb_HoldVC(tbp->vcp);
2313 static NCB *smb_GetNCB(void)
2318 lock_ObtainWrite(&smb_globalLock);
2319 tbp = smb_ncbFreeListp;
2321 smb_ncbFreeListp = tbp->nextp;
2322 lock_ReleaseWrite(&smb_globalLock);
2324 tbp = calloc(sizeof(*tbp),1);
2325 tbp->magic = SMB_NCBMAGIC;
2328 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2330 memset(&tbp->ncb, 0, sizeof(NCB));
2335 static void FreeSMBStrings(smb_packet_t * pkt)
2340 for (s = pkt->stringsp; s; s = ns) {
2344 pkt->stringsp = NULL;
2347 void smb_FreePacket(smb_packet_t *tbp)
2349 smb_vc_t * vcp = NULL;
2350 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2352 lock_ObtainWrite(&smb_globalLock);
2353 tbp->nextp = smb_packetFreeListp;
2354 smb_packetFreeListp = tbp;
2355 tbp->magic = SMB_PACKETMAGIC;
2359 tbp->resumeCode = 0;
2365 tbp->ncb_length = 0;
2367 FreeSMBStrings(tbp);
2368 lock_ReleaseWrite(&smb_globalLock);
2374 static void smb_FreeNCB(NCB *bufferp)
2378 tbp = (smb_ncb_t *) bufferp;
2379 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2381 lock_ObtainWrite(&smb_globalLock);
2382 tbp->nextp = smb_ncbFreeListp;
2383 smb_ncbFreeListp = tbp;
2384 lock_ReleaseWrite(&smb_globalLock);
2387 /* get a ptr to the data part of a packet, and its count */
2388 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2392 unsigned char *afterParmsp;
2394 parmBytes = *smbp->wctp << 1;
2395 afterParmsp = smbp->wctp + parmBytes + 1;
2397 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2398 if (nbytesp) *nbytesp = dataBytes;
2400 /* don't forget to skip the data byte count, since it follows
2401 * the parameters; that's where the "2" comes from below.
2403 return (unsigned char *) (afterParmsp + 2);
2406 /* must set all the returned parameters before playing around with the
2407 * data region, since the data region is located past the end of the
2408 * variable number of parameters.
2410 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2412 unsigned char *afterParmsp;
2414 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2416 *afterParmsp++ = dsize & 0xff;
2417 *afterParmsp = (dsize>>8) & 0xff;
2420 /* return the parm'th parameter in the smbp packet */
2421 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2424 unsigned char *parmDatap;
2426 parmCount = *smbp->wctp;
2428 if (parm >= parmCount) {
2431 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2432 parm, parmCount, smbp->ncb_length);
2433 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2434 parm, parmCount, smbp->ncb_length);
2435 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2436 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2437 osi_panic(s, __FILE__, __LINE__);
2439 parmDatap = smbp->wctp + (2*parm) + 1;
2441 return parmDatap[0] + (parmDatap[1] << 8);
2444 /* return the parm'th parameter in the smbp packet */
2445 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2448 unsigned char *parmDatap;
2450 parmCount = *smbp->wctp;
2452 if (parm >= parmCount) {
2455 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2456 parm, parmCount, smbp->ncb_length);
2457 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2458 parm, parmCount, smbp->ncb_length);
2459 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2460 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2461 osi_panic(s, __FILE__, __LINE__);
2463 parmDatap = smbp->wctp + (2*parm) + 1;
2465 return parmDatap[0];
2468 /* return the parm'th parameter in the smbp packet */
2469 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2472 unsigned char *parmDatap;
2474 parmCount = *smbp->wctp;
2476 if (parm + 1 >= parmCount) {
2479 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2480 parm, parmCount, smbp->ncb_length);
2481 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2482 parm, parmCount, smbp->ncb_length);
2483 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2484 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2485 osi_panic(s, __FILE__, __LINE__);
2487 parmDatap = smbp->wctp + (2*parm) + 1;
2489 return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2492 /* return the parm'th parameter in the smbp packet */
2493 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2496 unsigned char *parmDatap;
2498 parmCount = *smbp->wctp;
2500 if (parm * 2 + offset >= parmCount * 2) {
2503 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2504 parm, offset, parmCount, smbp->ncb_length);
2505 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2506 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2507 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2508 parm, offset, parmCount, smbp->ncb_length);
2509 osi_panic(s, __FILE__, __LINE__);
2511 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2513 return parmDatap[0] + (parmDatap[1] << 8);
2516 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2518 unsigned char *parmDatap;
2520 /* make sure we have enough slots */
2521 if (*smbp->wctp <= slot)
2522 *smbp->wctp = slot+1;
2524 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2525 *parmDatap++ = parmValue & 0xff;
2526 *parmDatap = (parmValue>>8) & 0xff;
2529 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2531 unsigned char *parmDatap;
2533 /* make sure we have enough slots */
2534 if (*smbp->wctp <= slot)
2535 *smbp->wctp = slot+2;
2537 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2538 *parmDatap++ = parmValue & 0xff;
2539 *parmDatap++ = (parmValue>>8) & 0xff;
2540 *parmDatap++ = (parmValue>>16) & 0xff;
2541 *parmDatap = (parmValue>>24) & 0xff;
2544 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2546 unsigned char *parmDatap;
2549 /* make sure we have enough slots */
2550 if (*smbp->wctp <= slot)
2551 *smbp->wctp = slot+4;
2553 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2555 *parmDatap++ = *parmValuep++;
2558 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2560 unsigned char *parmDatap;
2562 /* make sure we have enough slots */
2563 if (*smbp->wctp <= slot) {
2564 if (smbp->oddByte) {
2566 *smbp->wctp = slot+1;
2571 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2572 *parmDatap++ = parmValue & 0xff;
2577 void smb_StripLastComponent(clientchar_t *outPathp, clientchar_t **lastComponentp,
2578 clientchar_t *inPathp)
2580 clientchar_t *lastSlashp;
2582 lastSlashp = cm_ClientStrRChr(inPathp, '\\');
2584 *lastComponentp = lastSlashp;
2587 if (inPathp == lastSlashp)
2589 *outPathp++ = *inPathp++;
2598 clientchar_t *smb_ParseASCIIBlock(smb_packet_t * pktp, unsigned char *inp,
2599 char **chainpp, int flags)
2607 if (!WANTS_UNICODE(pktp))
2608 flags |= SMB_STRF_FORCEASCII;
2611 cb = sizeof(pktp->data) - (inp - pktp->data);
2612 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2613 #ifdef DEBUG_UNICODE
2616 cb = sizeof(pktp->data);
2618 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2621 clientchar_t *smb_ParseString(smb_packet_t * pktp, unsigned char * inp,
2622 char ** chainpp, int flags)
2627 if (!WANTS_UNICODE(pktp))
2628 flags |= SMB_STRF_FORCEASCII;
2631 cb = sizeof(pktp->data) - (inp - pktp->data);
2632 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2633 #ifdef DEBUG_UNICODE
2636 cb = sizeof(pktp->data);
2638 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp,
2639 flags | SMB_STRF_SRCNULTERM);
2642 clientchar_t *smb_ParseStringCb(smb_packet_t * pktp, unsigned char * inp,
2643 size_t cb, char ** chainpp, int flags)
2646 if (!WANTS_UNICODE(pktp))
2647 flags |= SMB_STRF_FORCEASCII;
2650 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2653 clientchar_t *smb_ParseStringCch(smb_packet_t * pktp, unsigned char * inp,
2654 size_t cch, char ** chainpp, int flags)
2659 if (!WANTS_UNICODE(pktp))
2660 flags |= SMB_STRF_FORCEASCII;
2662 cb = cch * sizeof(wchar_t);
2665 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2669 smb_ParseStringBuf(const unsigned char * bufbase,
2670 cm_space_t ** stringspp,
2671 unsigned char *inp, size_t *pcb_max,
2672 char **chainpp, int flags)
2675 if (!(flags & SMB_STRF_FORCEASCII)) {
2677 cm_space_t * spacep;
2680 if (bufbase && ((inp - bufbase) % 2) != 0) {
2681 inp++; /* unicode strings are always word aligned */
2685 if (FAILED(StringCchLengthW((const wchar_t *) inp, *pcb_max / sizeof(wchar_t),
2687 cch_src = *pcb_max / sizeof(wchar_t);
2691 *pcb_max -= (cch_src + 1) * sizeof(wchar_t);
2698 spacep = cm_GetSpace();
2699 spacep->nextp = *stringspp;
2700 *stringspp = spacep;
2704 *chainpp = inp + sizeof(wchar_t);
2707 *(spacep->wdata) = 0;
2708 return spacep->wdata;
2711 StringCchCopyNW(spacep->wdata,
2712 lengthof(spacep->wdata),
2713 (const clientchar_t *) inp, cch_src);
2716 *chainpp = inp + (cch_src + null_terms)*sizeof(wchar_t);
2718 return spacep->wdata;
2722 cm_space_t * spacep;
2725 /* Not using Unicode */
2727 *chainpp = inp + strlen(inp) + 1;
2730 spacep = cm_GetSpace();
2731 spacep->nextp = *stringspp;
2732 *stringspp = spacep;
2734 cchdest = lengthof(spacep->wdata);
2735 cm_Utf8ToUtf16(inp, (int)((flags & SMB_STRF_SRCNULTERM)? -1 : *pcb_max),
2736 spacep->wdata, cchdest);
2738 return spacep->wdata;
2744 unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
2746 size_t * plen, int flags)
2752 /* we are only calculating the required size */
2759 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2761 StringCbLengthW(str, SMB_STRINGBUFSIZE * sizeof(wchar_t), plen);
2762 if (!(flags & SMB_STRF_IGNORENUL))
2763 *plen += sizeof(wchar_t);
2765 return (unsigned char *) 1; /* return TRUE if we are using unicode */
2775 cch_str = cm_ClientStrLen(str);
2776 cch_dest = cm_ClientStringToUtf8(str, (int)cch_str, NULL, 0);
2779 *plen = ((flags & SMB_STRF_IGNORENUL)? cch_dest: cch_dest+1);
2787 /* if outp != NULL ... */
2789 /* Number of bytes left in the buffer.
2791 If outp lies inside the packet data buffer, we assume that the
2792 buffer is the packet data buffer. Otherwise we assume that the
2793 buffer is sizeof(packet->data).
2796 if (outp >= pktp->data && outp < pktp->data + sizeof(pktp->data)) {
2797 align = (int)((outp - pktp->data) % 2);
2798 buffersize = (pktp->data + sizeof(pktp->data)) - ((char *) outp);
2800 align = (int)(((size_t) outp) % 2);
2801 buffersize = (int)sizeof(pktp->data);
2806 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2812 if (*str == _C('\0')) {
2814 if (buffersize < sizeof(wchar_t))
2817 *((wchar_t *) outp) = L'\0';
2818 if (plen && !(flags & SMB_STRF_IGNORENUL))
2819 *plen += sizeof(wchar_t);
2820 return outp + sizeof(wchar_t);
2823 nchars = cm_ClientStringToUtf16(str, -1, (wchar_t *) outp, (int)(buffersize / sizeof(wchar_t)));
2825 osi_Log2(smb_logp, "UnparseString: Can't convert string to Unicode [%S], GLE=%d",
2826 osi_LogSaveClientString(smb_logp, str),
2832 *plen += sizeof(wchar_t) * ((flags & SMB_STRF_IGNORENUL)? nchars - 1: nchars);
2834 return outp + sizeof(wchar_t) * nchars;
2842 cch_dest = cm_ClientStringToUtf8(str, -1, outp, (int)buffersize);
2845 *plen += ((flags & SMB_STRF_IGNORENUL)? cch_dest - 1: cch_dest);
2847 return outp + cch_dest;
2851 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2857 tlen = inp[0] + (inp[1]<<8);
2858 inp += 2; /* skip length field */
2861 *chainpp = inp + tlen;
2870 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2874 if (*inp++ != 0x1) return NULL;
2875 tlen = inp[0] + (inp[1]<<8);
2876 inp += 2; /* skip length field */
2879 *chainpp = inp + tlen;
2882 if (lengthp) *lengthp = tlen;
2887 /* format a packet as a response */
2888 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2893 outp = (smb_t *) op;
2895 /* zero the basic structure through the smb_wct field, and zero the data
2896 * size field, assuming that wct stays zero; otherwise, you have to
2897 * explicitly set the data size field, too.
2899 inSmbp = (smb_t *) inp;
2900 memset(outp, 0, sizeof(smb_t)+2);
2906 outp->com = inSmbp->com;
2907 outp->tid = inSmbp->tid;
2908 outp->pid = inSmbp->pid;
2909 outp->uid = inSmbp->uid;
2910 outp->mid = inSmbp->mid;
2911 outp->res[0] = inSmbp->res[0];
2912 outp->res[1] = inSmbp->res[1];
2913 op->inCom = inSmbp->com;
2915 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
2916 #ifdef SEND_CANONICAL_PATHNAMES
2917 outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
2919 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2921 if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
2922 outp->flg2 |= SMB_FLAGS2_UNICODE;
2925 /* copy fields in generic packet area */
2926 op->wctp = &outp->wct;
2929 /* send a (probably response) packet; vcp tells us to whom to send it.
2930 * we compute the length by looking at wct and bcc fields.
2932 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2942 ncbp = smb_GetNCB();
2946 memset((char *)ncbp, 0, sizeof(NCB));
2948 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2949 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2950 extra += tp[0] + (tp[1]<<8);
2951 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
2952 extra += 3; /* wct and length fields */
2954 ncbp->ncb_length = extra; /* bytes to send */
2955 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2956 ncbp->ncb_lana_num = vcp->lana;
2957 ncbp->ncb_command = NCBSEND; /* op means send data */
2958 ncbp->ncb_buffer = (char *) inp;/* packet */
2959 code = Netbios(ncbp);
2962 const char * s = ncb_error_string(code);
2963 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2964 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
2966 lock_ObtainMutex(&vcp->mx);
2967 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
2968 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
2970 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2971 lock_ReleaseMutex(&vcp->mx);
2972 lock_ObtainWrite(&smb_globalLock);
2973 dead_sessions[vcp->session] = TRUE;
2974 lock_ReleaseWrite(&smb_globalLock);
2975 smb_CleanupDeadVC(vcp);
2977 lock_ReleaseMutex(&vcp->mx);
2985 void smb_MapNTError(long code, unsigned long *NTStatusp)
2987 unsigned long NTStatus;
2989 /* map CM_ERROR_* errors to NT 32-bit status codes */
2990 /* NT Status codes are listed in ntstatus.h not winerror.h */
2991 if (code == CM_ERROR_NOSUCHCELL) {
2992 NTStatus = 0xC000000FL; /* No such file */
2994 else if (code == CM_ERROR_NOSUCHVOLUME) {
2995 NTStatus = 0xC000000FL; /* No such file */
2997 else if (code == CM_ERROR_TIMEDOUT) {
2999 NTStatus = 0xC00000CFL; /* Sharing Paused */
3001 NTStatus = 0x00000102L; /* Timeout */
3004 else if (code == CM_ERROR_RETRY) {
3005 NTStatus = 0xC000022DL; /* Retry */
3007 else if (code == CM_ERROR_NOACCESS) {
3008 NTStatus = 0xC0000022L; /* Access denied */
3010 else if (code == CM_ERROR_READONLY) {
3011 NTStatus = 0xC00000A2L; /* Write protected */
3013 else if (code == CM_ERROR_NOSUCHFILE ||
3014 code == CM_ERROR_BPLUS_NOMATCH) {
3015 NTStatus = 0xC000000FL; /* No such file */
3017 else if (code == CM_ERROR_NOSUCHPATH) {
3018 NTStatus = 0xC000003AL; /* Object path not found */
3020 else if (code == CM_ERROR_TOOBIG) {
3021 NTStatus = 0xC000007BL; /* Invalid image format */
3023 else if (code == CM_ERROR_INVAL) {
3024 NTStatus = 0xC000000DL; /* Invalid parameter */
3026 else if (code == CM_ERROR_BADFD) {
3027 NTStatus = 0xC0000008L; /* Invalid handle */
3029 else if (code == CM_ERROR_BADFDOP) {
3030 NTStatus = 0xC0000022L; /* Access denied */
3032 else if (code == CM_ERROR_EXISTS) {
3033 NTStatus = 0xC0000035L; /* Object name collision */
3035 else if (code == CM_ERROR_NOTEMPTY) {
3036 NTStatus = 0xC0000101L; /* Directory not empty */
3038 else if (code == CM_ERROR_CROSSDEVLINK) {
3039 NTStatus = 0xC00000D4L; /* Not same device */
3041 else if (code == CM_ERROR_NOTDIR) {
3042 NTStatus = 0xC0000103L; /* Not a directory */
3044 else if (code == CM_ERROR_ISDIR) {
3045 NTStatus = 0xC00000BAL; /* File is a directory */
3047 else if (code == CM_ERROR_BADOP) {
3049 /* I have no idea where this comes from */
3050 NTStatus = 0xC09820FFL; /* SMB no support */
3052 NTStatus = 0xC00000BBL; /* Not supported */
3053 #endif /* COMMENT */
3055 else if (code == CM_ERROR_BADSHARENAME) {
3056 NTStatus = 0xC00000CCL; /* Bad network name */
3058 else if (code == CM_ERROR_NOIPC) {
3060 NTStatus = 0xC0000022L; /* Access Denied */
3062 NTStatus = 0xC000013DL; /* Remote Resources */
3065 else if (code == CM_ERROR_CLOCKSKEW) {
3066 NTStatus = 0xC0000133L; /* Time difference at DC */
3068 else if (code == CM_ERROR_BADTID) {
3069 NTStatus = 0xC0982005L; /* SMB bad TID */
3071 else if (code == CM_ERROR_USESTD) {
3072 NTStatus = 0xC09820FBL; /* SMB use standard */
3074 else if (code == CM_ERROR_QUOTA) {
3075 NTStatus = 0xC0000044L; /* Quota exceeded */
3077 else if (code == CM_ERROR_SPACE) {
3078 NTStatus = 0xC000007FL; /* Disk full */
3080 else if (code == CM_ERROR_ATSYS) {
3081 NTStatus = 0xC0000033L; /* Object name invalid */
3083 else if (code == CM_ERROR_BADNTFILENAME) {
3084 NTStatus = 0xC0000033L; /* Object name invalid */
3086 else if (code == CM_ERROR_WOULDBLOCK) {
3087 NTStatus = 0xC0000055L; /* Lock not granted */
3089 else if (code == CM_ERROR_SHARING_VIOLATION) {
3090 NTStatus = 0xC0000043L; /* Sharing violation */
3092 else if (code == CM_ERROR_LOCK_CONFLICT) {
3093 NTStatus = 0xC0000054L; /* Lock conflict */
3095 else if (code == CM_ERROR_PARTIALWRITE) {
3096 NTStatus = 0xC000007FL; /* Disk full */
3098 else if (code == CM_ERROR_BUFFERTOOSMALL) {
3099 NTStatus = 0xC0000023L; /* Buffer too small */
3101 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3102 NTStatus = 0xC0000035L; /* Object name collision */
3104 else if (code == CM_ERROR_BADPASSWORD) {
3105 NTStatus = 0xC000006DL; /* unknown username or bad password */
3107 else if (code == CM_ERROR_BADLOGONTYPE) {
3108 NTStatus = 0xC000015BL; /* logon type not granted */
3110 else if (code == CM_ERROR_GSSCONTINUE) {
3111 NTStatus = 0xC0000016L; /* more processing required */
3113 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3115 NTStatus = 0xC0000280L; /* reparse point not resolved */
3117 NTStatus = 0xC0000022L; /* Access Denied */
3120 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3121 NTStatus = 0xC0000257L; /* Path Not Covered */
3123 else if (code == CM_ERROR_ALLBUSY) {
3124 NTStatus = 0xC000022DL; /* Retry */
3126 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3127 NTStatus = 0xC00000BEL; /* Bad Network Path */
3129 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3130 NTStatus = 0xC0000322L; /* No Kerberos key */
3132 else if (code == CM_ERROR_BAD_LEVEL) {
3133 NTStatus = 0xC0000148L; /* Invalid Level */
3135 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3136 NTStatus = 0xC000007EL; /* Range Not Locked */
3138 else if (code == CM_ERROR_NOSUCHDEVICE) {
3139 NTStatus = 0xC000000EL; /* No Such Device */
3141 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3142 NTStatus = 0xC0000055L; /* Lock Not Granted */
3144 NTStatus = 0xC0982001L; /* SMB non-specific error */
3147 *NTStatusp = NTStatus;
3148 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
3151 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
3152 unsigned char *classp)
3154 unsigned char class;
3155 unsigned short error;
3157 /* map CM_ERROR_* errors to SMB errors */
3158 if (code == CM_ERROR_NOSUCHCELL) {
3160 error = 3; /* bad path */
3162 else if (code == CM_ERROR_NOSUCHVOLUME) {
3164 error = 3; /* bad path */
3166 else if (code == CM_ERROR_TIMEDOUT) {
3168 error = 81; /* server is paused */
3170 else if (code == CM_ERROR_RETRY) {
3171 class = 2; /* shouldn't happen */
3174 else if (code == CM_ERROR_NOACCESS) {
3176 error = 4; /* bad access */
3178 else if (code == CM_ERROR_READONLY) {
3180 error = 19; /* read only */
3182 else if (code == CM_ERROR_NOSUCHFILE ||
3183 code == CM_ERROR_BPLUS_NOMATCH) {
3185 error = 2; /* ENOENT! */
3187 else if (code == CM_ERROR_NOSUCHPATH) {
3189 error = 3; /* Bad path */
3191 else if (code == CM_ERROR_TOOBIG) {
3193 error = 11; /* bad format */
3195 else if (code == CM_ERROR_INVAL) {
3196 class = 2; /* server non-specific error code */
3199 else if (code == CM_ERROR_BADFD) {
3201 error = 6; /* invalid file handle */
3203 else if (code == CM_ERROR_BADFDOP) {
3204 class = 1; /* invalid op on FD */
3207 else if (code == CM_ERROR_EXISTS) {
3209 error = 80; /* file already exists */
3211 else if (code == CM_ERROR_NOTEMPTY) {
3213 error = 5; /* delete directory not empty */
3215 else if (code == CM_ERROR_CROSSDEVLINK) {
3217 error = 17; /* EXDEV */
3219 else if (code == CM_ERROR_NOTDIR) {
3220 class = 1; /* bad path */
3223 else if (code == CM_ERROR_ISDIR) {
3224 class = 1; /* access denied; DOS doesn't have a good match */
3227 else if (code == CM_ERROR_BADOP) {
3231 else if (code == CM_ERROR_BADSHARENAME) {
3235 else if (code == CM_ERROR_NOIPC) {
3237 error = 4; /* bad access */
3239 else if (code == CM_ERROR_CLOCKSKEW) {
3240 class = 1; /* invalid function */
3243 else if (code == CM_ERROR_BADTID) {
3247 else if (code == CM_ERROR_USESTD) {
3251 else if (code == CM_ERROR_REMOTECONN) {
3255 else if (code == CM_ERROR_QUOTA) {
3256 if (vcp->flags & SMB_VCFLAG_USEV3) {
3258 error = 39; /* disk full */
3262 error = 5; /* access denied */
3265 else if (code == CM_ERROR_SPACE) {
3266 if (vcp->flags & SMB_VCFLAG_USEV3) {
3268 error = 39; /* disk full */
3272 error = 5; /* access denied */
3275 else if (code == CM_ERROR_PARTIALWRITE) {
3277 error = 39; /* disk full */
3279 else if (code == CM_ERROR_ATSYS) {
3281 error = 2; /* ENOENT */
3283 else if (code == CM_ERROR_WOULDBLOCK) {
3285 error = 33; /* lock conflict */
3287 else if (code == CM_ERROR_LOCK_CONFLICT) {
3289 error = 33; /* lock conflict */
3291 else if (code == CM_ERROR_SHARING_VIOLATION) {
3293 error = 33; /* lock conflict */
3295 else if (code == CM_ERROR_NOFILES) {
3297 error = 18; /* no files in search */
3299 else if (code == CM_ERROR_RENAME_IDENTICAL) {
3301 error = 183; /* Samba uses this */
3303 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
3304 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
3306 error = 2; /* bad password */
3308 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3310 error = 3; /* bad path */
3319 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
3322 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3324 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
3325 return CM_ERROR_BADOP;
3329 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3331 unsigned short EchoCount, i;
3332 char *data, *outdata;
3335 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
3337 for (i=1; i<=EchoCount; i++) {
3338 data = smb_GetSMBData(inp, &dataSize);
3339 smb_SetSMBParm(outp, 0, i);
3340 smb_SetSMBDataLength(outp, dataSize);
3341 outdata = smb_GetSMBData(outp, NULL);
3342 memcpy(outdata, data, dataSize);
3343 smb_SendPacket(vcp, outp);
3349 /* SMB_COM_READ_RAW */
3350 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3353 long count, minCount, finalCount;
3357 smb_t *smbp = (smb_t*) inp;
3359 cm_user_t *userp = NULL;
3362 char *rawBuf = NULL;
3367 fd = smb_GetSMBParm(inp, 0);
3368 count = smb_GetSMBParm(inp, 3);
3369 minCount = smb_GetSMBParm(inp, 4);
3370 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3372 if (*inp->wctp == 10) {
3373 /* we were sent a request with 64-bit file offsets */
3374 #ifdef AFS_LARGEFILES
3375 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
3377 if (LargeIntegerLessThanZero(offset)) {
3378 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
3382 if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
3383 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset. Dropping request.");
3386 offset.HighPart = 0;
3390 /* we were sent a request with 32-bit file offsets */
3391 offset.HighPart = 0;
3394 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
3395 fd, offset.HighPart, offset.LowPart, count);
3397 fidp = smb_FindFID(vcp, fd, 0);
3401 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3402 smb_CloseFID(vcp, fidp, NULL, 0);
3403 code = CM_ERROR_NOSUCHFILE;
3410 LARGE_INTEGER LOffset, LLength;
3413 key = cm_GenerateKey(vcp->vcID, pid, fd);
3415 LOffset.HighPart = offset.HighPart;
3416 LOffset.LowPart = offset.LowPart;
3417 LLength.HighPart = 0;
3418 LLength.LowPart = count;
3420 lock_ObtainWrite(&fidp->scp->rw);
3421 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
3422 lock_ReleaseWrite(&fidp->scp->rw);
3428 lock_ObtainMutex(&smb_RawBufLock);
3430 /* Get a raw buf, from head of list */
3431 rawBuf = smb_RawBufs;
3432 smb_RawBufs = *(char **)smb_RawBufs;
3434 lock_ReleaseMutex(&smb_RawBufLock);
3438 lock_ObtainMutex(&fidp->mx);
3439 if (fidp->flags & SMB_FID_IOCTL)
3441 lock_ReleaseMutex(&fidp->mx);
3442 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
3444 /* Give back raw buffer */
3445 lock_ObtainMutex(&smb_RawBufLock);
3446 *((char **) rawBuf) = smb_RawBufs;
3448 smb_RawBufs = rawBuf;
3449 lock_ReleaseMutex(&smb_RawBufLock);
3452 lock_ReleaseMutex(&fidp->mx);
3453 smb_ReleaseFID(fidp);
3456 lock_ReleaseMutex(&fidp->mx);
3458 userp = smb_GetUserFromVCP(vcp, inp);
3460 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
3466 cm_ReleaseUser(userp);
3469 smb_ReleaseFID(fidp);
3473 memset((char *)ncbp, 0, sizeof(NCB));
3475 ncbp->ncb_length = (unsigned short) finalCount;
3476 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
3477 ncbp->ncb_lana_num = vcp->lana;
3478 ncbp->ncb_command = NCBSEND;
3479 ncbp->ncb_buffer = rawBuf;
3481 code = Netbios(ncbp);
3483 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
3486 /* Give back raw buffer */
3487 lock_ObtainMutex(&smb_RawBufLock);
3488 *((char **) rawBuf) = smb_RawBufs;
3490 smb_RawBufs = rawBuf;
3491 lock_ReleaseMutex(&smb_RawBufLock);
3497 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3499 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3504 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3506 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3511 /* SMB_COM_NEGOTIATE */
3512 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3519 int VistaProtoIndex;
3520 int protoIndex; /* index we're using */
3525 char protocol_array[10][1024]; /* protocol signature of the client */
3526 int caps; /* capabilities */
3529 TIME_ZONE_INFORMATION tzi;
3531 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3534 namep = smb_GetSMBData(inp, &dbytes);
3537 coreProtoIndex = -1; /* not found */
3540 VistaProtoIndex = -1;
3541 while(namex < dbytes) {
3542 osi_Log1(smb_logp, "Protocol %s",
3543 osi_LogSaveString(smb_logp, namep+1));
3544 strcpy(protocol_array[tcounter], namep+1);
3546 /* namep points at the first protocol, or really, a 0x02
3547 * byte preceding the null-terminated ASCII name.
3549 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3550 coreProtoIndex = tcounter;
3552 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3553 v3ProtoIndex = tcounter;
3555 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3556 NTProtoIndex = tcounter;
3558 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3559 VistaProtoIndex = tcounter;
3562 /* compute size of protocol entry */
3563 entryLength = (int)strlen(namep+1);
3564 entryLength += 2; /* 0x02 bytes and null termination */
3566 /* advance over this protocol entry */
3567 namex += entryLength;
3568 namep += entryLength;
3569 tcounter++; /* which proto entry we're looking at */
3572 lock_ObtainMutex(&vcp->mx);
3574 if (VistaProtoIndex != -1) {
3575 protoIndex = VistaProtoIndex;
3576 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3579 if (NTProtoIndex != -1) {
3580 protoIndex = NTProtoIndex;
3581 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3583 else if (v3ProtoIndex != -1) {
3584 protoIndex = v3ProtoIndex;
3585 vcp->flags |= SMB_VCFLAG_USEV3;
3587 else if (coreProtoIndex != -1) {
3588 protoIndex = coreProtoIndex;
3589 vcp->flags |= SMB_VCFLAG_USECORE;
3591 else protoIndex = -1;
3592 lock_ReleaseMutex(&vcp->mx);
3594 if (protoIndex == -1)
3595 return CM_ERROR_INVAL;
3596 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3597 smb_SetSMBParm(outp, 0, protoIndex);
3598 if (smb_authType != SMB_AUTH_NONE) {
3599 smb_SetSMBParmByte(outp, 1,
3600 NEGOTIATE_SECURITY_USER_LEVEL |
3601 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3603 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3605 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3606 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3607 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3608 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3609 /* The session key is not a well documented field however most clients
3610 * will echo back the session key to the server. Currently we are using
3611 * the same value for all sessions. We should generate a random value
3612 * and store it into the vcp
3614 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3615 smb_SetSMBParm(outp, 8, 1);
3617 * Tried changing the capabilities to support for W2K - defect 117695
3618 * Maybe something else needs to be changed here?
3622 smb_SetSMBParmLong(outp, 9, 0x43fd);
3624 smb_SetSMBParmLong(outp, 9, 0x251);
3627 * 32-bit error codes *
3633 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3635 NTNEGOTIATE_CAPABILITY_DFS |
3637 #ifdef AFS_LARGEFILES
3638 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3640 NTNEGOTIATE_CAPABILITY_NTFIND |
3641 NTNEGOTIATE_CAPABILITY_RAWMODE |
3642 NTNEGOTIATE_CAPABILITY_NTSMB;
3644 if ( smb_authType == SMB_AUTH_EXTENDED )
3645 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3648 if ( smb_UseUnicode ) {
3649 caps |= NTNEGOTIATE_CAPABILITY_UNICODE;
3653 smb_SetSMBParmLong(outp, 9, caps);
3655 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3656 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3657 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3659 GetTimeZoneInformation(&tzi);
3660 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3662 if (smb_authType == SMB_AUTH_NTLM) {
3663 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3664 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3665 /* paste in encryption key */
3666 datap = smb_GetSMBData(outp, NULL);
3667 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3668 /* and the faux domain name */
3669 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3670 datap + MSV1_0_CHALLENGE_LENGTH,
3671 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3672 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3676 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3678 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3680 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3682 datap = smb_GetSMBData(outp, NULL);
3683 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3686 datap += sizeof(smb_ServerGUID);
3687 memcpy(datap, secBlob, secBlobLength);
3691 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3692 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3695 else if (v3ProtoIndex != -1) {
3696 smb_SetSMBParm(outp, 0, protoIndex);
3698 /* NOTE: Extended authentication cannot be negotiated with v3
3699 * therefore we fail over to NTLM
3701 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3702 smb_SetSMBParm(outp, 1,
3703 NEGOTIATE_SECURITY_USER_LEVEL |
3704 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3706 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3708 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3709 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3710 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3711 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3712 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3713 smb_SetSMBParm(outp, 7, 1);
3715 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3716 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3717 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3719 GetTimeZoneInformation(&tzi);
3720 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3722 /* NOTE: Extended authentication cannot be negotiated with v3
3723 * therefore we fail over to NTLM
3725 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3726 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3727 smb_SetSMBParm(outp, 12, 0); /* resvd */
3728 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3729 datap = smb_GetSMBData(outp, NULL);
3730 /* paste in a new encryption key */
3731 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3732 /* and the faux domain name */
3733 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3734 datap + MSV1_0_CHALLENGE_LENGTH,
3735 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3737 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3738 smb_SetSMBParm(outp, 12, 0); /* resvd */
3739 smb_SetSMBDataLength(outp, 0);
3742 else if (coreProtoIndex != -1) { /* not really supported anymore */
3743 smb_SetSMBParm(outp, 0, protoIndex);
3744 smb_SetSMBDataLength(outp, 0);
3749 void smb_CheckVCs(void)
3751 smb_vc_t * vcp, *nextp;
3752 smb_packet_t * outp = smb_GetPacket();
3755 lock_ObtainWrite(&smb_rctLock);
3756 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
3758 if (vcp->magic != SMB_VC_MAGIC)
3759 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
3760 __FILE__, __LINE__);
3762 /* on the first pass hold 'vcp' which was not held as 'nextp' */
3764 smb_HoldVCNoLock(vcp);
3767 * obtain a reference to 'nextp' now because we drop the
3768 * smb_rctLock later and the list contents could change
3769 * or 'vcp' could be destroyed when released.
3773 smb_HoldVCNoLock(nextp);
3775 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
3776 smb_ReleaseVCNoLock(vcp);
3780 smb_FormatResponsePacket(vcp, NULL, outp);
3781 smbp = (smb_t *)outp;
3782 outp->inCom = smbp->com = 0x2b /* Echo */;
3790 smb_SetSMBParm(outp, 0, 0);
3791 smb_SetSMBDataLength(outp, 0);
3792 lock_ReleaseWrite(&smb_rctLock);
3794 smb_SendPacket(vcp, outp);
3796 lock_ObtainWrite(&smb_rctLock);
3797 smb_ReleaseVCNoLock(vcp);
3799 lock_ReleaseWrite(&smb_rctLock);
3800 smb_FreePacket(outp);
3803 void smb_Daemon(void *parmp)
3805 afs_uint32 count = 0;
3806 smb_username_t **unpp;
3809 while(smbShutdownFlag == 0) {
3813 if (smbShutdownFlag == 1)
3816 if ((count % 72) == 0) { /* every five minutes */
3818 time_t old_localZero = smb_localZero;
3820 /* Initialize smb_localZero */
3821 myTime.tm_isdst = -1; /* compute whether on DST or not */
3822 myTime.tm_year = 70;
3828 smb_localZero = mktime(&myTime);
3830 #ifndef USE_NUMERIC_TIME_CONV
3831 smb_CalculateNowTZ();
3832 #endif /* USE_NUMERIC_TIME_CONV */
3833 #ifdef AFS_FREELANCE
3834 if ( smb_localZero != old_localZero )
3835 cm_noteLocalMountPointChange();
3841 /* GC smb_username_t objects that will no longer be used */
3843 lock_ObtainWrite(&smb_rctLock);
3844 for ( unpp=&usernamesp; *unpp; ) {
3846 smb_username_t *unp;
3848 lock_ObtainMutex(&(*unpp)->mx);
3849 if ( (*unpp)->refCount > 0 ||
3850 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
3851 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
3853 else if (!smb_LogoffTokenTransfer ||
3854 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
3856 lock_ReleaseMutex(&(*unpp)->mx);
3864 lock_FinalizeMutex(&unp->mx);
3870 cm_ReleaseUser(userp);
3872 unpp = &(*unpp)->nextp;
3875 lock_ReleaseWrite(&smb_rctLock);
3877 /* XXX GC dir search entries */
3881 void smb_WaitingLocksDaemon()
3883 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3884 smb_waitingLock_t *wl, *wlNext;
3887 smb_packet_t *inp, *outp;
3891 while (smbShutdownFlag == 0) {
3892 lock_ObtainWrite(&smb_globalLock);
3893 nwlRequest = smb_allWaitingLocks;
3894 if (nwlRequest == NULL) {
3895 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
3900 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
3907 lock_ObtainWrite(&smb_globalLock);
3909 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
3911 wlRequest = nwlRequest;
3912 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3913 lock_ReleaseWrite(&smb_globalLock);
3917 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3918 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3921 if (wl->state == SMB_WAITINGLOCKSTATE_CANCELLED) {
3922 code = CM_ERROR_LOCK_NOT_GRANTED;
3926 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
3928 /* wl->state is either _DONE or _WAITING. _ERROR
3929 would no longer be on the queue. */
3930 code = cm_RetryLock( wl->lockp,
3931 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3934 wl->state = SMB_WAITINGLOCKSTATE_DONE;
3935 } else if (code != CM_ERROR_WOULDBLOCK) {
3936 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3941 if (code == CM_ERROR_WOULDBLOCK) {
3944 if (wlRequest->msTimeout != 0xffffffff
3945 && ((osi_Time() - wlRequest->start_t) * 1000 > wlRequest->msTimeout))
3957 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
3960 scp = wlRequest->scp;
3961 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
3965 lock_ObtainWrite(&scp->rw);
3967 for (wl = wlRequest->locks; wl; wl = wlNext) {
3968 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3970 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3971 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
3972 wl->LLength, wl->key, NULL, &req);
3974 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3979 lock_ReleaseWrite(&scp->rw);
3983 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
3986 for (wl = wlRequest->locks; wl; wl = wlNext) {
3987 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3988 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3993 vcp = wlRequest->vcp;
3994 inp = wlRequest->inp;
3995 outp = wlRequest->outp;
3996 ncbp = smb_GetNCB();
3997 ncbp->ncb_length = inp->ncb_length;
3998 inp->spacep = cm_GetSpace();
4000 /* Remove waitingLock from list */
4001 lock_ObtainWrite(&smb_globalLock);
4002 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
4004 lock_ReleaseWrite(&smb_globalLock);
4006 /* Resume packet processing */
4008 smb_SetSMBDataLength(outp, 0);
4009 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
4010 outp->resumeCode = code;
4012 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
4015 cm_FreeSpace(inp->spacep);
4016 smb_FreePacket(inp);
4017 smb_FreePacket(outp);
4019 cm_ReleaseSCache(wlRequest->scp);
4022 } while (nwlRequest && smbShutdownFlag == 0);
4027 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4029 osi_Log0(smb_logp, "SMB receive get disk attributes");
4031 smb_SetSMBParm(outp, 0, 32000);
4032 smb_SetSMBParm(outp, 1, 64);
4033 smb_SetSMBParm(outp, 2, 1024);
4034 smb_SetSMBParm(outp, 3, 30000);
4035 smb_SetSMBParm(outp, 4, 0);
4036 smb_SetSMBDataLength(outp, 0);
4040 /* SMB_COM_TREE_CONNECT */
4041 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
4045 unsigned short newTid;
4046 clientchar_t shareName[AFSPATHMAX];
4047 clientchar_t *sharePath;
4050 clientchar_t *pathp;
4053 osi_Log0(smb_logp, "SMB receive tree connect");
4055 /* parse input parameters */
4058 tbp = smb_GetSMBData(inp, NULL);
4059 pathp = smb_ParseASCIIBlock(inp, tbp, &tbp, SMB_STRF_ANSIPATH);
4061 tp = cm_ClientStrRChr(pathp, '\\');
4063 return CM_ERROR_BADSMB;
4064 cm_ClientStrCpy(shareName, lengthof(shareName), tp+1);
4066 lock_ObtainMutex(&vcp->mx);
4067 newTid = vcp->tidCounter++;
4068 lock_ReleaseMutex(&vcp->mx);
4070 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
4071 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
4072 userp = smb_GetUserFromUID(uidp);
4073 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
4075 smb_ReleaseUID(uidp);
4077 smb_ReleaseTID(tidp, FALSE);
4078 return CM_ERROR_BADSHARENAME;
4080 lock_ObtainMutex(&tidp->mx);
4081 tidp->userp = userp;
4082 tidp->pathname = sharePath;
4083 lock_ReleaseMutex(&tidp->mx);
4084 smb_ReleaseTID(tidp, FALSE);
4086 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
4087 smb_SetSMBParm(rsp, 1, newTid);
4088 smb_SetSMBDataLength(rsp, 0);
4090 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
4094 /* set maskp to the mask part of the incoming path.
4095 * Mask is 11 bytes long (8.3 with the dot elided).
4096 * Returns true if succeeds with a valid name, otherwise it does
4097 * its best, but returns false.
4099 int smb_Get8Dot3MaskFromPath(clientchar_t *maskp, clientchar_t *pathp)
4107 /* starts off valid */
4110 /* mask starts out all blanks */
4111 memset(maskp, ' ', 11);
4114 /* find last backslash, or use whole thing if there is none */
4115 tp = cm_ClientStrRChr(pathp, '\\');
4119 tp++; /* skip slash */
4123 /* names starting with a dot are illegal */
4131 if (tc == '.' || tc == '"')
4139 /* if we get here, tp point after the dot */
4140 up = maskp+8; /* ext goes here */
4147 if (tc == '.' || tc == '"')
4150 /* copy extension if not too long */
4160 int smb_Match8Dot3Mask(clientchar_t *unixNamep, clientchar_t *maskp)
4162 clientchar_t umask[11];
4170 /* XXX redo this, calling cm_MatchMask with a converted mask */
4172 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
4176 /* otherwise, we have a valid 8.3 name; see if we have a match,
4177 * treating '?' as a wildcard in maskp (but not in the file name).
4179 tp1 = umask; /* real name, in mask format */
4180 tp2 = maskp; /* mask, in mask format */
4181 for(i=0; i<11; i++) {
4182 tc1 = *tp1++; /* clientchar_t from real name */
4183 tc2 = *tp2++; /* clientchar_t from mask */
4184 tc1 = (clientchar_t) cm_foldUpper[(clientchar_t)tc1];
4185 tc2 = (clientchar_t) cm_foldUpper[(clientchar_t)tc2];
4188 if (tc2 == '?' && tc1 != ' ')
4195 /* we got a match */
4199 clientchar_t *smb_FindMask(clientchar_t *pathp)
4203 tp = cm_ClientStrRChr(pathp, '\\'); /* find last slash */
4206 return tp+1; /* skip the slash */
4208 return pathp; /* no slash, return the entire path */
4211 /* SMB_COM_SEARCH for a volume label
4213 (This is called from smb_ReceiveCoreSearchDir() and not an actual
4214 dispatch function.) */
4215 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4217 clientchar_t *pathp;
4219 clientchar_t mask[12];
4220 unsigned char *statBlockp;
4221 unsigned char initStatBlock[21];
4224 osi_Log0(smb_logp, "SMB receive search volume");
4226 /* pull pathname and stat block out of request */
4227 tp = smb_GetSMBData(inp, NULL);
4228 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4229 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4230 osi_assertx(pathp != NULL, "null path");
4231 statBlockp = smb_ParseVblBlock(tp, &tp, &statLen);
4232 osi_assertx(statBlockp != NULL, "null statBlock");
4234 statBlockp = initStatBlock;
4238 /* for returning to caller */
4239 smb_Get8Dot3MaskFromPath(mask, pathp);
4241 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
4242 tp = smb_GetSMBData(outp, NULL);
4244 *tp++ = 43; /* bytes in a dir entry */
4245 *tp++ = 0; /* high byte in counter */
4247 /* now marshall the dir entry, starting with the search status */
4248 *tp++ = statBlockp[0]; /* Reserved */
4249 memcpy(tp, mask, 11); tp += 11; /* FileName */
4251 /* now pass back server use info, with 1st byte non-zero */
4253 memset(tp, 0, 4); tp += 4; /* reserved for server use */
4255 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
4257 *tp++ = 0x8; /* attribute: volume */
4267 /* 4 byte file size */
4273 /* The filename is a UCHAR buffer that is ASCII even if Unicode
4276 /* finally, null-terminated 8.3 pathname, which we set to AFS */
4277 memset(tp, ' ', 13);
4280 /* set the length of the data part of the packet to 43 + 3, for the dir
4281 * entry plus the 5 and the length fields.
4283 smb_SetSMBDataLength(outp, 46);
4288 smb_ApplyDirListPatches(cm_scache_t * dscp, smb_dirListPatch_t **dirPatchespp,
4289 clientchar_t * tidPathp, clientchar_t * relPathp,
4290 cm_user_t *userp, cm_req_t *reqp)
4298 smb_dirListPatch_t *patchp;
4299 smb_dirListPatch_t *npatchp;
4300 clientchar_t path[AFSPATHMAX];
4302 afs_int32 mustFake = 0;
4304 code = cm_FindACLCache(dscp, userp, &rights);
4306 lock_ObtainWrite(&dscp->rw);
4307 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4308 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4309 lock_ReleaseWrite(&dscp->rw);
4310 if (code == CM_ERROR_NOACCESS) {
4318 if (!mustFake) { /* Bulk Stat */
4320 cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4322 memset(bsp, 0, sizeof(cm_bulkStat_t));
4324 for (patchp = *dirPatchespp, count=0;
4326 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4327 cm_scache_t *tscp = cm_FindSCache(&patchp->fid);
4331 if (lock_TryWrite(&tscp->rw)) {
4332 /* we have an entry that we can look at */
4333 if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
4334 /* we have a callback on it. Don't bother
4335 * fetching this stat entry, since we're happy
4336 * with the info we have.
4338 lock_ReleaseWrite(&tscp->rw);
4339 cm_ReleaseSCache(tscp);
4342 lock_ReleaseWrite(&tscp->rw);
4344 cm_ReleaseSCache(tscp);
4348 bsp->fids[i].Volume = patchp->fid.volume;
4349 bsp->fids[i].Vnode = patchp->fid.vnode;
4350 bsp->fids[i].Unique = patchp->fid.unique;
4352 if (bsp->counter == AFSCBMAX) {
4353 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4354 memset(bsp, 0, sizeof(cm_bulkStat_t));
4358 if (bsp->counter > 0)
4359 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4364 for (patchp = *dirPatchespp; patchp; patchp =
4365 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4367 dptr = patchp->dptr;
4369 cm_ClientStrPrintfN(path, AFSPATHMAX, _C("%s\\%s"),
4370 relPathp ? relPathp : _C(""), patchp->dep->name);
4371 reqp->relPathp = path;
4372 reqp->tidPathp = tidPathp;
4374 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4375 reqp->relPathp = reqp->tidPathp = NULL;
4378 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
4379 *dptr++ = SMB_ATTR_HIDDEN;
4382 lock_ObtainWrite(&scp->rw);
4383 if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
4384 lock_ReleaseWrite(&scp->rw);
4386 /* set the attribute */
4387 switch (scp->fileType) {
4388 case CM_SCACHETYPE_DIRECTORY:
4389 case CM_SCACHETYPE_MOUNTPOINT:
4390 case CM_SCACHETYPE_INVALID:
4391 attr = SMB_ATTR_DIRECTORY;
4393 case CM_SCACHETYPE_SYMLINK:
4394 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4395 attr = SMB_ATTR_DIRECTORY;
4397 attr = SMB_ATTR_NORMAL;
4400 /* if we get here we either have a normal file
4401 * or we have a file for which we have never
4402 * received status info. In this case, we can
4403 * check the even/odd value of the entry's vnode.
4404 * odd means it is to be treated as a directory
4405 * and even means it is to be treated as a file.
4407 if (mustFake && (scp->fid.vnode & 0x1))
4408 attr = SMB_ATTR_DIRECTORY;
4410 attr = SMB_ATTR_NORMAL;
4414 /* 1969-12-31 23:59:58 +00*/
4415 dosTime = 0xEBBFBF7D;
4418 shortTemp = (unsigned short) (dosTime & 0xffff);
4419 *((u_short *)dptr) = shortTemp;
4422 /* and copy out date */
4423 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4424 *((u_short *)dptr) = shortTemp;
4427 /* copy out file length */
4428 *((u_long *)dptr) = 0;
4431 lock_ConvertWToR(&scp->rw);
4432 attr = smb_Attributes(scp);
4433 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
4434 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
4435 attr |= SMB_ATTR_HIDDEN;
4439 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4442 shortTemp = (unsigned short) (dosTime & 0xffff);
4443 *((u_short *)dptr) = shortTemp;
4446 /* and copy out date */
4447 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4448 *((u_short *)dptr) = shortTemp;
4451 /* copy out file length */
4452 *((u_long *)dptr) = scp->length.LowPart;
4454 lock_ReleaseRead(&scp->rw);
4456 cm_ReleaseSCache(scp);
4459 /* now free the patches */
4460 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4461 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4465 /* and mark the list as empty */
4466 *dirPatchespp = NULL;
4472 /* SMB_COM_SEARCH */
4473 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4479 clientchar_t *pathp;
4480 cm_dirEntry_t *dep = 0;
4482 smb_dirListPatch_t *dirListPatchesp;
4483 smb_dirListPatch_t *curPatchp;
4487 osi_hyper_t dirLength;
4488 osi_hyper_t bufferOffset;
4489 osi_hyper_t curOffset;
4491 unsigned char *inCookiep;
4492 smb_dirSearch_t *dsp;
4496 unsigned long clientCookie;
4497 cm_pageHeader_t *pageHeaderp;
4498 cm_user_t *userp = NULL;
4500 clientchar_t mask[12];
4502 long nextEntryCookie;
4503 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4504 char resByte; /* reserved byte from the cookie */
4505 char *op; /* output data ptr */
4506 char *origOp; /* original value of op */
4507 cm_space_t *spacep; /* for pathname buffer */
4511 clientchar_t *tidPathp = 0;
4518 maxCount = smb_GetSMBParm(inp, 0);
4520 dirListPatchesp = NULL;
4522 caseFold = CM_FLAG_CASEFOLD;
4524 tp = smb_GetSMBData(inp, NULL);
4525 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4526 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4527 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
4529 /* bail out if request looks bad */
4530 if (!tp || !pathp) {
4531 return CM_ERROR_BADSMB;
4534 /* We can handle long names */
4535 if (vcp->flags & SMB_VCFLAG_USENT)
4536 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
4538 /* make sure we got a whole search status */
4539 if (dataLength < 21) {
4540 nextCookie = 0; /* start at the beginning of the dir */
4543 attribute = smb_GetSMBParm(inp, 1);
4545 /* handle volume info in another function */
4546 if (attribute & 0x8)
4547 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
4549 osi_Log2(smb_logp, "SMB receive search dir count %d [%S]",
4550 maxCount, osi_LogSaveClientString(smb_logp, pathp));
4552 if (*pathp == 0) { /* null pathp, treat as root dir */
4553 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
4554 return CM_ERROR_NOFILES;
4558 dsp = smb_NewDirSearch(0);
4559 dsp->attribute = attribute;
4560 smb_Get8Dot3MaskFromPath(mask, pathp);
4561 memcpy(dsp->mask, mask, 12);
4563 /* track if this is likely to match a lot of entries */
4564 if (smb_IsStarMask(mask))
4569 /* pull the next cookie value out of the search status block */
4570 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
4571 + (inCookiep[16]<<24);
4572 dsp = smb_FindDirSearch(inCookiep[12]);
4574 /* can't find dir search status; fatal error */
4575 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%S]",
4576 inCookiep[12], nextCookie, osi_LogSaveClientString(smb_logp, pathp));
4577 return CM_ERROR_BADFD;
4579 attribute = dsp->attribute;
4580 resByte = inCookiep[0];
4582 /* copy out client cookie, in host byte order. Don't bother
4583 * interpreting it, since we're just passing it through, anyway.
4585 memcpy(&clientCookie, &inCookiep[17], 4);
4587 memcpy(mask, dsp->mask, 12);
4589 /* assume we're doing a star match if it has continued for more
4595 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
4596 nextCookie, dsp->cookie, attribute);
4598 userp = smb_GetUserFromVCP(vcp, inp);
4600 /* try to get the vnode for the path name next */
4601 lock_ObtainMutex(&dsp->mx);
4604 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
4608 spacep = inp->spacep;
4609 smb_StripLastComponent(spacep->wdata, NULL, pathp);
4610 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4612 lock_ReleaseMutex(&dsp->mx);
4613 cm_ReleaseUser(userp);
4614 smb_DeleteDirSearch(dsp);
4615 smb_ReleaseDirSearch(dsp);
4616 return CM_ERROR_NOFILES;
4618 cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
4619 cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
4621 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
4622 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
4625 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4628 pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->wdata);
4629 cm_ReleaseSCache(scp);
4630 lock_ReleaseMutex(&dsp->mx);
4631 cm_ReleaseUser(userp);
4632 smb_DeleteDirSearch(dsp);
4633 smb_ReleaseDirSearch(dsp);
4634 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4635 return CM_ERROR_PATH_NOT_COVERED;
4637 return CM_ERROR_BADSHARENAME;
4639 #endif /* DFS_SUPPORT */
4642 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
4643 /* we need one hold for the entry we just stored into,
4644 * and one for our own processing. When we're done with this
4645 * function, we'll drop the one for our own processing.
4646 * We held it once from the namei call, and so we do another hold
4650 lock_ObtainWrite(&scp->rw);
4651 dsp->flags |= SMB_DIRSEARCH_BULKST;
4652 lock_ReleaseWrite(&scp->rw);
4655 lock_ReleaseMutex(&dsp->mx);
4657 cm_ReleaseUser(userp);
4658 smb_DeleteDirSearch(dsp);
4659 smb_ReleaseDirSearch(dsp);
4663 /* reserves space for parameter; we'll adjust it again later to the
4664 * real count of the # of entries we returned once we've actually
4665 * assembled the directory listing.
4667 smb_SetSMBParm(outp, 0, 0);
4669 /* get the directory size */
4670 lock_ObtainWrite(&scp->rw);
4671 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4672 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4674 lock_ReleaseWrite(&scp->rw);
4675 cm_ReleaseSCache(scp);
4676 cm_ReleaseUser(userp);
4677 smb_DeleteDirSearch(dsp);
4678 smb_ReleaseDirSearch(dsp);
4682 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4684 dirLength = scp->length;
4686 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4687 curOffset.HighPart = 0;
4688 curOffset.LowPart = nextCookie;
4689 origOp = op = smb_GetSMBData(outp, NULL);
4690 /* and write out the basic header */
4691 *op++ = 5; /* variable block */
4692 op += 2; /* skip vbl block length; we'll fill it in later */
4696 clientchar_t *actualName = NULL;
4697 int free_actualName = 0;
4698 clientchar_t shortName[13];
4699 clientchar_t *shortNameEnd;
4701 /* make sure that curOffset.LowPart doesn't point to the first
4702 * 32 bytes in the 2nd through last dir page, and that it doesn't
4703 * point at the first 13 32-byte chunks in the first dir page,
4704 * since those are dir and page headers, and don't contain useful
4707 temp = curOffset.LowPart & (2048-1);
4708 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4709 /* we're in the first page */
4710 if (temp < 13*32) temp = 13*32;
4713 /* we're in a later dir page */
4714 if (temp < 32) temp = 32;
4717 /* make sure the low order 5 bits are zero */
4720 /* now put temp bits back ito curOffset.LowPart */
4721 curOffset.LowPart &= ~(2048-1);
4722 curOffset.LowPart |= temp;
4724 /* check if we've returned all the names that will fit in the
4727 if (returnedNames >= maxCount) {
4728 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
4729 returnedNames, maxCount);
4733 /* check if we've passed the dir's EOF */
4734 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
4736 /* see if we can use the bufferp we have now; compute in which page
4737 * the current offset would be, and check whether that's the offset
4738 * of the buffer we have. If not, get the buffer.
4740 thyper.HighPart = curOffset.HighPart;
4741 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4742 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4745 buf_Release(bufferp);
4748 lock_ReleaseWrite(&scp->rw);
4749 code = buf_Get(scp, &thyper, &bufferp);
4750 lock_ObtainMutex(&dsp->mx);
4752 /* now, if we're doing a star match, do bulk fetching of all of
4753 * the status info for files in the dir.
4756 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
4758 lock_ObtainWrite(&scp->rw);
4759 lock_ReleaseMutex(&dsp->mx);
4761 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
4765 bufferOffset = thyper;
4767 /* now get the data in the cache */
4769 code = cm_SyncOp(scp, bufferp, userp, &req,
4771 CM_SCACHESYNC_NEEDCALLBACK |
4772 CM_SCACHESYNC_READ);
4774 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
4778 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
4780 if (cm_HaveBuffer(scp, bufferp, 0)) {
4781 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4785 /* otherwise, load the buffer and try again */
4786 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
4788 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4789 scp, bufferp, code);
4794 buf_Release(bufferp);
4798 } /* if (wrong buffer) ... */
4800 /* now we have the buffer containing the entry we're interested in; copy
4801 * it out if it represents a non-deleted entry.
4803 entryInDir = curOffset.LowPart & (2048-1);
4804 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4806 /* page header will help tell us which entries are free. Page header
4807 * can change more often than once per buffer, since AFS 3 dir page size
4808 * may be less than (but not more than a buffer package buffer.
4810 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
4811 temp &= ~(2048 - 1); /* turn off intra-page bits */
4812 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4814 /* now determine which entry we're looking at in the page. If it is
4815 * free (there's a free bitmap at the start of the dir), we should
4816 * skip these 32 bytes.
4818 slotInPage = (entryInDir & 0x7e0) >> 5;
4819 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
4820 /* this entry is free */
4821 numDirChunks = 1; /* only skip this guy */
4825 tp = bufferp->datap + entryInBuffer;
4826 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4828 /* while we're here, compute the next entry's location, too,
4829 * since we'll need it when writing out the cookie into the dir
4832 * XXXX Probably should do more sanity checking.
4834 numDirChunks = cm_NameEntries(dep->name, NULL);
4836 /* compute the offset of the cookie representing the next entry */
4837 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4839 /* Compute 8.3 name if necessary */
4840 actualName = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
4841 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
4843 cm_Gen8Dot3NameInt(dep->name, &dep->fid, shortName, &shortNameEnd);
4844 actualName = shortName;
4845 free_actualName = 0;
4847 free_actualName = 1;
4850 if (actualName == NULL) {
4851 /* Couldn't convert the name for some reason */
4852 osi_Log1(smb_logp, "SMB search dir skipping entry :[%s]",
4853 osi_LogSaveString(smb_logp, dep->name));
4857 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%S)",
4858 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
4859 osi_LogSaveClientString(smb_logp, actualName));
4861 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
4862 /* this is one of the entries to use: it is not deleted
4863 * and it matches the star pattern we're looking for.
4866 /* Eliminate entries that don't match requested
4869 /* no hidden files */
4870 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
4871 osi_Log0(smb_logp, "SMB search dir skipping hidden");
4875 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4877 /* We have already done the cm_TryBulkStat above */
4878 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
4879 fileType = cm_FindFileType(&fid);
4880 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
4881 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
4883 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4884 fileType == CM_SCACHETYPE_MOUNTPOINT ||
4885 fileType == CM_SCACHETYPE_DFSLINK ||
4886 fileType == CM_SCACHETYPE_INVALID)
4887 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
4892 memcpy(op, mask, 11); op += 11;
4893 *op++ = (unsigned char) dsp->cookie; /* they say it must be non-zero */
4894 *op++ = (unsigned char)(nextEntryCookie & 0xff);
4895 *op++ = (unsigned char)((nextEntryCookie>>8) & 0xff);
4896 *op++ = (unsigned char)((nextEntryCookie>>16) & 0xff);
4897 *op++ = (unsigned char)((nextEntryCookie>>24) & 0xff);
4898 memcpy(op, &clientCookie, 4); op += 4;
4900 /* now we emit the attribute. This is sort of tricky,
4901 * since we need to really stat the file to find out
4902 * what type of entry we've got. Right now, we're
4903 * copying out data from a buffer, while holding the
4904 * scp locked, so it isn't really convenient to stat
4905 * something now. We'll put in a place holder now,
4906 * and make a second pass before returning this to get
4907 * the real attributes. So, we just skip the data for
4908 * now, and adjust it later. We allocate a patch
4909 * record to make it easy to find this point later.
4910 * The replay will happen at a time when it is safe to
4911 * unlock the directory.
4913 curPatchp = malloc(sizeof(*curPatchp));
4914 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
4915 curPatchp->dptr = op;
4916 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
4918 /* do hidden attribute here since name won't be around when applying
4922 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
4923 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4925 curPatchp->flags = 0;
4927 op += 9; /* skip attr, time, date and size */
4929 /* zero out name area. The spec says to pad with
4930 * spaces, but Samba doesn't, and neither do we.
4934 /* finally, we get to copy out the name; we know that
4935 * it fits in 8.3 or the pattern wouldn't match, but it
4936 * never hurts to be sure.
4938 cm_ClientStringToUtf8(actualName, -1, op, 13);
4939 if (smb_StoreAnsiFilenames)
4941 /* This is a UCHAR field, which is ASCII even if Unicode
4944 /* Uppercase if requested by client */
4945 if (!KNOWS_LONG_NAMES(inp))
4950 /* now, adjust the # of entries copied */
4952 } /* if we're including this name */
4955 if (free_actualName && actualName) {
4960 /* and adjust curOffset to be where the new cookie is */
4961 thyper.HighPart = 0;
4962 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4963 curOffset = LargeIntegerAdd(thyper, curOffset);
4964 } /* while copying data for dir listing */
4966 /* release the mutex */
4967 lock_ReleaseWrite(&scp->rw);
4969 buf_Release(bufferp);
4973 /* apply and free last set of patches; if not doing a star match, this
4974 * will be empty, but better safe (and freeing everything) than sorry.
4976 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
4978 /* special return code for unsuccessful search */
4979 if (code == 0 && dataLength < 21 && returnedNames == 0)
4980 code = CM_ERROR_NOFILES;
4982 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
4983 returnedNames, code);
4986 smb_DeleteDirSearch(dsp);
4987 smb_ReleaseDirSearch(dsp);
4988 cm_ReleaseSCache(scp);
4989 cm_ReleaseUser(userp);
4993 /* finalize the output buffer */
4994 smb_SetSMBParm(outp, 0, returnedNames);
4995 temp = (long) (op - origOp);
4996 smb_SetSMBDataLength(outp, temp);
4998 /* the data area is a variable block, which has a 5 (already there)
4999 * followed by the length of the # of data bytes. We now know this to
5000 * be "temp," although that includes the 3 bytes of vbl block header.
5001 * Deduct for them and fill in the length field.
5003 temp -= 3; /* deduct vbl block info */
5004 osi_assertx(temp == (43 * returnedNames), "unexpected data length");
5005 origOp[1] = (unsigned char)(temp & 0xff);
5006 origOp[2] = (unsigned char)((temp>>8) & 0xff);
5007 if (returnedNames == 0)
5008 smb_DeleteDirSearch(dsp);
5009 smb_ReleaseDirSearch(dsp);
5010 cm_ReleaseSCache(scp);
5011 cm_ReleaseUser(userp);
5016 /* verify that this is a valid path to a directory. I don't know why they
5017 * don't use the get file attributes call.
5019 * SMB_COM_CHECK_DIRECTORY
5021 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5023 clientchar_t *pathp;
5025 cm_scache_t *rootScp;
5026 cm_scache_t *newScp;
5030 clientchar_t *tidPathp;
5036 pdata = smb_GetSMBData(inp, NULL);
5037 pathp = smb_ParseASCIIBlock(inp, pdata, NULL, SMB_STRF_ANSIPATH);
5039 return CM_ERROR_BADFD;
5040 osi_Log1(smb_logp, "SMB receive check path %S",
5041 osi_LogSaveClientString(smb_logp, pathp));
5043 rootScp = cm_data.rootSCachep;
5045 userp = smb_GetUserFromVCP(vcp, inp);
5047 caseFold = CM_FLAG_CASEFOLD;
5049 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5051 cm_ReleaseUser(userp);
5052 return CM_ERROR_NOSUCHPATH;
5054 code = cm_NameI(rootScp, pathp,
5055 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
5056 userp, tidPathp, &req, &newScp);
5059 cm_ReleaseUser(userp);
5064 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5065 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5066 cm_ReleaseSCache(newScp);
5067 cm_ReleaseUser(userp);
5068 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5069 return CM_ERROR_PATH_NOT_COVERED;
5071 return CM_ERROR_BADSHARENAME;
5073 #endif /* DFS_SUPPORT */
5075 /* now lock the vnode with a callback; returns with newScp locked */
5076 lock_ObtainWrite(&newScp->rw);
5077 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
5078 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5080 if (code != CM_ERROR_NOACCESS) {
5081 lock_ReleaseWrite(&newScp->rw);
5082 cm_ReleaseSCache(newScp);
5083 cm_ReleaseUser(userp);
5087 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5090 attrs = smb_Attributes(newScp);
5092 if (!(attrs & SMB_ATTR_DIRECTORY))
5093 code = CM_ERROR_NOTDIR;
5095 lock_ReleaseWrite(&newScp->rw);
5097 cm_ReleaseSCache(newScp);
5098 cm_ReleaseUser(userp);
5102 /* SMB_COM_SET_INFORMATION */
5103 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5105 clientchar_t *pathp;
5107 cm_scache_t *rootScp;
5108 unsigned short attribute;
5110 cm_scache_t *newScp;
5114 clientchar_t *tidPathp;
5120 /* decode basic attributes we're passed */
5121 attribute = smb_GetSMBParm(inp, 0);
5122 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5124 datap = smb_GetSMBData(inp, NULL);
5125 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5127 return CM_ERROR_BADSMB;
5129 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
5130 dosTime, attribute);
5132 rootScp = cm_data.rootSCachep;
5134 userp = smb_GetUserFromVCP(vcp, inp);
5136 caseFold = CM_FLAG_CASEFOLD;
5138 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5140 cm_ReleaseUser(userp);
5141 return CM_ERROR_NOSUCHFILE;
5143 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5144 tidPathp, &req, &newScp);
5147 cm_ReleaseUser(userp);
5152 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5153 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5154 cm_ReleaseSCache(newScp);
5155 cm_ReleaseUser(userp);
5156 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5157 return CM_ERROR_PATH_NOT_COVERED;
5159 return CM_ERROR_BADSHARENAME;
5161 #endif /* DFS_SUPPORT */
5163 /* now lock the vnode with a callback; returns with newScp locked; we
5164 * need the current status to determine what the new status is, in some
5167 lock_ObtainWrite(&newScp->rw);
5168 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5169 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5171 lock_ReleaseWrite(&newScp->rw);
5172 cm_ReleaseSCache(newScp);
5173 cm_ReleaseUser(userp);
5177 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5179 /* Check for RO volume */
5180 if (newScp->flags & CM_SCACHEFLAG_RO) {
5181 lock_ReleaseWrite(&newScp->rw);
5182 cm_ReleaseSCache(newScp);
5183 cm_ReleaseUser(userp);
5184 return CM_ERROR_READONLY;
5187 /* prepare for setattr call */
5190 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
5191 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
5193 if ((newScp->unixModeBits & 0222) && (attribute & SMB_ATTR_READONLY) != 0) {
5194 /* we're told to make a writable file read-only */
5195 attr.unixModeBits = newScp->unixModeBits & ~0222;
5196 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5198 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
5199 /* we're told to make a read-only file writable */
5200 attr.unixModeBits = newScp->unixModeBits | 0222;
5201 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5203 lock_ReleaseWrite(&newScp->rw);
5205 /* now call setattr */
5207 code = cm_SetAttr(newScp, &attr, userp, &req);
5211 cm_ReleaseSCache(newScp);
5212 cm_ReleaseUser(userp);
5218 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5220 clientchar_t *pathp;
5222 cm_scache_t *rootScp;
5223 cm_scache_t *newScp, *dscp;
5228 clientchar_t *tidPathp;
5230 clientchar_t *lastComp;
5236 datap = smb_GetSMBData(inp, NULL);
5237 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5239 return CM_ERROR_BADSMB;
5241 if (*pathp == 0) /* null path */
5244 osi_Log1(smb_logp, "SMB receive getfile attributes path %S",
5245 osi_LogSaveClientString(smb_logp, pathp));
5247 rootScp = cm_data.rootSCachep;
5249 userp = smb_GetUserFromVCP(vcp, inp);
5251 /* we shouldn't need this for V3 requests, but we seem to */
5252 caseFold = CM_FLAG_CASEFOLD;
5254 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5256 cm_ReleaseUser(userp);
5257 return CM_ERROR_NOSUCHFILE;
5261 * XXX Strange hack XXX
5263 * As of Patch 5 (16 July 97), we are having the following problem:
5264 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
5265 * requests to look up "desktop.ini" in all the subdirectories.
5266 * This can cause zillions of timeouts looking up non-existent cells
5267 * and volumes, especially in the top-level directory.
5269 * We have not found any way to avoid this or work around it except
5270 * to explicitly ignore the requests for mount points that haven't
5271 * yet been evaluated and for directories that haven't yet been
5274 * We should modify this hack to provide a fake desktop.ini file
5275 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
5277 spacep = inp->spacep;
5278 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
5279 #ifndef SPECIAL_FOLDERS
5280 if (lastComp && cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
5281 code = cm_NameI(rootScp, spacep->wdata,
5282 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
5283 userp, tidPathp, &req, &dscp);
5286 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5287 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
5289 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5290 return CM_ERROR_PATH_NOT_COVERED;
5292 return CM_ERROR_BADSHARENAME;
5294 #endif /* DFS_SUPPORT */
5295 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
5296 code = CM_ERROR_NOSUCHFILE;
5297 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
5298 cm_buf_t *bp = buf_Find(dscp, &hzero);
5303 code = CM_ERROR_NOSUCHFILE;
5305 cm_ReleaseSCache(dscp);
5307 cm_ReleaseUser(userp);
5312 #endif /* SPECIAL_FOLDERS */
5314 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5315 tidPathp, &req, &newScp);
5317 cm_ReleaseUser(userp);
5322 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5323 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5324 cm_ReleaseSCache(newScp);
5325 cm_ReleaseUser(userp);
5326 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5327 return CM_ERROR_PATH_NOT_COVERED;
5329 return CM_ERROR_BADSHARENAME;
5331 #endif /* DFS_SUPPORT */
5333 /* now lock the vnode with a callback; returns with newScp locked */
5334 lock_ObtainWrite(&newScp->rw);
5335 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5336 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5338 lock_ReleaseWrite(&newScp->rw);
5339 cm_ReleaseSCache(newScp);
5340 cm_ReleaseUser(userp);
5344 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5346 attrs = smb_Attributes(newScp);
5348 smb_SetSMBParm(outp, 0, attrs);
5350 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
5351 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
5352 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
5353 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
5354 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
5355 smb_SetSMBParm(outp, 5, 0);
5356 smb_SetSMBParm(outp, 6, 0);
5357 smb_SetSMBParm(outp, 7, 0);
5358 smb_SetSMBParm(outp, 8, 0);
5359 smb_SetSMBParm(outp, 9, 0);
5360 smb_SetSMBDataLength(outp, 0);
5361 lock_ReleaseWrite(&newScp->rw);
5363 cm_ReleaseSCache(newScp);
5364 cm_ReleaseUser(userp);
5369 /* SMB_COM_TREE_DISCONNECT */
5370 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5374 osi_Log0(smb_logp, "SMB receive tree disconnect");
5376 /* find the tree and free it */
5377 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
5379 lock_ObtainWrite(&smb_rctLock);
5381 smb_ReleaseTID(tidp, TRUE);
5382 lock_ReleaseWrite(&smb_rctLock);
5389 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5392 clientchar_t *pathp;
5393 clientchar_t *lastNamep;
5402 clientchar_t *tidPathp;
5408 datap = smb_GetSMBData(inp, NULL);
5409 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5411 osi_Log1(smb_logp, "SMB receive open file [%S]", osi_LogSaveClientString(smb_logp, pathp));
5413 #ifdef DEBUG_VERBOSE
5417 hexpath = osi_HexifyString( pathp );
5418 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
5423 if (!cm_IsValidClientString(pathp)) {
5425 clientchar_t * hexp;
5427 hexp = cm_GetRawCharsAlloc(pathp, -1);
5428 osi_Log1(smb_logp, "CoreOpen rejecting invalid name. [%S]",
5429 osi_LogSaveClientString(smb_logp, hexp));
5433 osi_Log0(smb_logp, "CoreOpen rejecting invalid name");
5435 return CM_ERROR_BADNTFILENAME;
5438 share = smb_GetSMBParm(inp, 0);
5439 attribute = smb_GetSMBParm(inp, 1);
5441 spacep = inp->spacep;
5442 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5443 if (lastNamep && cm_ClientStrCmp(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0) {
5444 /* special case magic file name for receiving IOCTL requests
5445 * (since IOCTL calls themselves aren't getting through).
5447 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5448 smb_SetupIoctlFid(fidp, spacep);
5449 smb_SetSMBParm(outp, 0, fidp->fid);
5450 smb_SetSMBParm(outp, 1, 0); /* attrs */
5451 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
5452 smb_SetSMBParm(outp, 3, 0);
5453 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
5454 smb_SetSMBParm(outp, 5, 0x7fff);
5455 /* pass the open mode back */
5456 smb_SetSMBParm(outp, 6, (share & 0xf));
5457 smb_SetSMBDataLength(outp, 0);
5458 smb_ReleaseFID(fidp);
5462 userp = smb_GetUserFromVCP(vcp, inp);
5464 caseFold = CM_FLAG_CASEFOLD;
5466 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5468 cm_ReleaseUser(userp);
5469 return CM_ERROR_NOSUCHPATH;
5471 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5472 tidPathp, &req, &scp);
5475 cm_ReleaseUser(userp);
5480 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5481 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
5482 cm_ReleaseSCache(scp);
5483 cm_ReleaseUser(userp);
5484 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5485 return CM_ERROR_PATH_NOT_COVERED;
5487 return CM_ERROR_BADSHARENAME;
5489 #endif /* DFS_SUPPORT */
5491 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
5493 cm_ReleaseSCache(scp);
5494 cm_ReleaseUser(userp);
5498 /* don't need callback to check file type, since file types never
5499 * change, and namei and cm_Lookup all stat the object at least once on
5500 * a successful return.
5502 if (scp->fileType != CM_SCACHETYPE_FILE) {
5503 cm_ReleaseSCache(scp);
5504 cm_ReleaseUser(userp);
5505 return CM_ERROR_ISDIR;
5508 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5509 osi_assertx(fidp, "null smb_fid_t");
5511 /* save a pointer to the vnode */
5513 osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
5514 lock_ObtainWrite(&scp->rw);
5515 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5516 lock_ReleaseWrite(&scp->rw);
5520 fidp->userp = userp;
5522 lock_ObtainMutex(&fidp->mx);
5523 if ((share & 0xf) == 0)
5524 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5525 else if ((share & 0xf) == 1)
5526 fidp->flags |= SMB_FID_OPENWRITE;
5528 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
5529 lock_ReleaseMutex(&fidp->mx);
5531 lock_ObtainRead(&scp->rw);
5532 smb_SetSMBParm(outp, 0, fidp->fid);
5533 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
5534 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5535 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
5536 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
5537 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
5538 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
5539 /* pass the open mode back; XXXX add access checks */
5540 smb_SetSMBParm(outp, 6, (share & 0xf));
5541 smb_SetSMBDataLength(outp, 0);
5542 lock_ReleaseRead(&scp->rw);
5545 cm_Open(scp, 0, userp);
5547 /* send and free packet */
5548 smb_ReleaseFID(fidp);
5549 cm_ReleaseUser(userp);
5550 /* don't release scp, since we've squirreled away the pointer in the fid struct */
5554 typedef struct smb_unlinkRock {
5559 clientchar_t *maskp; /* pointer to the star pattern */
5562 cm_dirEntryList_t * matches;
5565 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5568 smb_unlinkRock_t *rockp;
5571 normchar_t matchName[MAX_PATH];
5575 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5576 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5577 caseFold |= CM_FLAG_8DOT3;
5579 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
5580 /* Can't convert name */
5581 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string.",
5582 osi_LogSaveString(smb_logp, dep->name));
5586 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5588 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5589 !cm_Is8Dot3(matchName)) {
5590 cm_Gen8Dot3Name(dep, matchName, NULL);
5591 /* 8.3 matches are always case insensitive */
5592 match = cm_MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
5595 osi_Log1(smb_logp, "Found match %S",
5596 osi_LogSaveClientString(smb_logp, matchName));
5598 cm_DirEntryListAdd(dep->name, &rockp->matches);
5602 /* If we made a case sensitive exact match, we might as well quit now. */
5603 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !cm_ClientStrCmp(matchName, rockp->maskp))
5604 code = CM_ERROR_STOPNOW;
5613 /* SMB_COM_DELETE */
5614 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5618 clientchar_t *pathp;
5622 clientchar_t *lastNamep;
5623 smb_unlinkRock_t rock;
5627 clientchar_t *tidPathp;
5631 memset(&rock, 0, sizeof(rock));
5633 attribute = smb_GetSMBParm(inp, 0);
5635 tp = smb_GetSMBData(inp, NULL);
5636 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
5638 osi_Log1(smb_logp, "SMB receive unlink %S",
5639 osi_LogSaveClientString(smb_logp, pathp));
5641 spacep = inp->spacep;
5642 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5644 userp = smb_GetUserFromVCP(vcp, inp);
5646 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5648 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5650 cm_ReleaseUser(userp);
5651 return CM_ERROR_NOSUCHPATH;
5653 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold, userp, tidPathp,
5656 cm_ReleaseUser(userp);
5661 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5662 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
5663 cm_ReleaseSCache(dscp);
5664 cm_ReleaseUser(userp);
5665 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5666 return CM_ERROR_PATH_NOT_COVERED;
5668 return CM_ERROR_BADSHARENAME;
5670 #endif /* DFS_SUPPORT */
5672 /* otherwise, scp points to the parent directory. */
5679 rock.maskp = cm_ClientStringToNormStringAlloc(smb_FindMask(pathp), -1, NULL);
5681 code = CM_ERROR_NOSUCHFILE;
5684 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5687 thyper.HighPart = 0;
5692 rock.matches = NULL;
5694 /* Now, if we aren't dealing with a wildcard match, we first try an exact
5695 * match. If that fails, we do a case insensitve match.
5697 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
5698 !smb_IsStarMask(rock.maskp)) {
5699 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5702 thyper.HighPart = 0;
5703 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5708 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5710 if (code == CM_ERROR_STOPNOW)
5713 if (code == 0 && rock.matches) {
5714 cm_dirEntryList_t * entry;
5716 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
5717 normchar_t normalizedName[MAX_PATH];
5719 /* Note: entry->name is a non-normalized name */
5721 osi_Log1(smb_logp, "Unlinking %s",
5722 osi_LogSaveString(smb_logp, entry->name));
5724 /* We assume this works because entry->name was
5725 successfully converted in smb_UnlinkProc() once. */
5726 cm_FsStringToNormString(entry->name, -1,
5727 normalizedName, lengthof(normalizedName));
5729 code = cm_Unlink(dscp, entry->name, normalizedName, userp, &req);
5731 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5732 smb_NotifyChange(FILE_ACTION_REMOVED,
5733 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5734 dscp, normalizedName, NULL, TRUE);
5738 cm_DirEntryListFree(&rock.matches);
5742 cm_ReleaseUser(userp);
5745 cm_ReleaseSCache(dscp);
5750 if (code == 0 && !rock.any)
5751 code = CM_ERROR_NOSUCHFILE;
5755 typedef struct smb_renameRock {
5756 cm_scache_t *odscp; /* old dir */
5757 cm_scache_t *ndscp; /* new dir */
5758 cm_user_t *userp; /* user */
5759 cm_req_t *reqp; /* request struct */
5760 smb_vc_t *vcp; /* virtual circuit */
5761 normchar_t *maskp; /* pointer to star pattern of old file name */
5762 int flags; /* tilde, casefold, etc */
5763 clientchar_t *newNamep; /* ptr to the new file's name */
5764 fschar_t fsOldName[MAX_PATH]; /* raw FS name */
5765 clientchar_t clOldName[MAX_PATH]; /* client name */
5769 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5772 smb_renameRock_t *rockp;
5775 normchar_t matchName[MAX_PATH];
5777 rockp = (smb_renameRock_t *) vrockp;
5779 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
5780 /* Can't convert string */
5781 osi_Log1(smb_logp, "Skpping entry [%s]. Can't normalize FS string",
5782 osi_LogSaveString(smb_logp, dep->name));
5786 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5787 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5788 caseFold |= CM_FLAG_8DOT3;
5790 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5792 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5793 !cm_Is8Dot3(matchName)) {
5794 cm_Gen8Dot3Name(dep, matchName, NULL);
5795 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5800 StringCbCopyA(rockp->fsOldName, sizeof(rockp->fsOldName), dep->name);
5801 cm_ClientStrCpy(rockp->clOldName, lengthof(rockp->clOldName),
5803 code = CM_ERROR_STOPNOW;
5813 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp, int attrs)
5816 cm_space_t *spacep = NULL;
5817 smb_renameRock_t rock;
5818 cm_scache_t *oldDscp = NULL;
5819 cm_scache_t *newDscp = NULL;
5820 cm_scache_t *tmpscp= NULL;
5821 cm_scache_t *tmpscp2 = NULL;
5822 clientchar_t *oldLastNamep;
5823 clientchar_t *newLastNamep;
5827 clientchar_t *tidPathp;
5831 userp = smb_GetUserFromVCP(vcp, inp);
5832 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5834 cm_ReleaseUser(userp);
5835 return CM_ERROR_NOSUCHPATH;
5839 memset(&rock, 0, sizeof(rock));
5841 spacep = inp->spacep;
5842 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
5844 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5845 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
5846 userp, tidPathp, &req, &oldDscp);
5848 cm_ReleaseUser(userp);
5853 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5854 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
5855 cm_ReleaseSCache(oldDscp);
5856 cm_ReleaseUser(userp);
5857 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5858 return CM_ERROR_PATH_NOT_COVERED;
5860 return CM_ERROR_BADSHARENAME;
5862 #endif /* DFS_SUPPORT */
5864 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
5865 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
5866 userp, tidPathp, &req, &newDscp);
5869 cm_ReleaseSCache(oldDscp);
5870 cm_ReleaseUser(userp);
5875 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5876 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
5877 cm_ReleaseSCache(oldDscp);
5878 cm_ReleaseSCache(newDscp);
5879 cm_ReleaseUser(userp);
5880 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5881 return CM_ERROR_PATH_NOT_COVERED;
5883 return CM_ERROR_BADSHARENAME;
5885 #endif /* DFS_SUPPORT */
5888 /* otherwise, oldDscp and newDscp point to the corresponding directories.
5889 * next, get the component names, and lower case them.
5892 /* handle the old name first */
5894 oldLastNamep = oldPathp;
5898 /* and handle the new name, too */
5900 newLastNamep = newPathp;
5904 /* TODO: The old name could be a wildcard. The new name must not be */
5906 /* Check if the file already exists; if so return error */
5907 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5908 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
5909 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
5911 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
5912 osi_LogSaveClientString(smb_logp, newLastNamep));
5914 /* Check if the old and the new names differ only in case. If so return
5915 * success, else return CM_ERROR_EXISTS
5917 if (!code && oldDscp == newDscp && !cm_ClientStrCmpI(oldLastNamep, newLastNamep)) {
5919 /* This would be a success only if the old file is *as same as* the new file */
5920 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
5922 if (tmpscp == tmpscp2)
5925 code = CM_ERROR_EXISTS;
5926 cm_ReleaseSCache(tmpscp2);
5929 code = CM_ERROR_NOSUCHFILE;
5932 /* file exist, do not rename, also fixes move */
5933 osi_Log0(smb_logp, "Can't rename. Target already exists");
5934 code = CM_ERROR_EXISTS;
5938 cm_ReleaseSCache(tmpscp);
5943 /* do the vnode call */
5944 rock.odscp = oldDscp;
5945 rock.ndscp = newDscp;
5949 rock.maskp = cm_ClientStringToNormStringAlloc(oldLastNamep, -1, NULL);
5951 code = CM_ERROR_NOSUCHFILE;
5954 rock.flags = ((cm_ClientStrChr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5955 rock.newNamep = newLastNamep;
5956 rock.fsOldName[0] = '\0';
5957 rock.clOldName[0] = '\0';
5960 /* Now search the directory for the pattern, and do the appropriate rename when found */
5961 thyper.LowPart = 0; /* search dir from here */
5962 thyper.HighPart = 0;
5964 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5965 if (code == 0 && !rock.any) {
5967 thyper.HighPart = 0;
5968 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5969 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5971 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
5973 if (code == CM_ERROR_STOPNOW && rock.fsOldName[0] != '\0') {
5974 code = cm_Rename(rock.odscp, rock.fsOldName, rock.clOldName,
5975 rock.ndscp, rock.newNamep, rock.userp,
5977 /* if the call worked, stop doing the search now, since we
5978 * really only want to rename one file.
5981 osi_Log0(smb_logp, "cm_Rename failure");
5982 osi_Log1(smb_logp, "cm_Rename returns %ld", code);
5983 } else if (code == 0) {
5984 code = CM_ERROR_NOSUCHFILE;
5987 /* Handle Change Notification */
5989 * Being lazy, not distinguishing between files and dirs in this
5990 * filter, since we'd have to do a lookup.
5993 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
5994 if (oldDscp == newDscp) {
5995 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5996 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5997 filter, oldDscp, rock.clOldName,
5998 newLastNamep, TRUE);
6000 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6001 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6002 filter, oldDscp, rock.clOldName,
6004 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6005 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
6006 filter, newDscp, newLastNamep,
6013 cm_ReleaseSCache(tmpscp);
6015 cm_ReleaseUser(userp);
6017 cm_ReleaseSCache(oldDscp);
6019 cm_ReleaseSCache(newDscp);
6027 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp)
6030 cm_space_t *spacep = NULL;
6031 cm_scache_t *oldDscp = NULL;
6032 cm_scache_t *newDscp = NULL;
6033 cm_scache_t *tmpscp= NULL;
6034 cm_scache_t *tmpscp2 = NULL;
6035 cm_scache_t *sscp = NULL;
6036 clientchar_t *oldLastNamep;
6037 clientchar_t *newLastNamep;
6040 clientchar_t *tidPathp;
6044 userp = smb_GetUserFromVCP(vcp, inp);
6046 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6048 cm_ReleaseUser(userp);
6049 return CM_ERROR_NOSUCHPATH;
6054 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6056 spacep = inp->spacep;
6057 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6059 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6060 userp, tidPathp, &req, &oldDscp);
6062 cm_ReleaseUser(userp);
6067 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6068 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6069 cm_ReleaseSCache(oldDscp);
6070 cm_ReleaseUser(userp);
6071 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6072 return CM_ERROR_PATH_NOT_COVERED;
6074 return CM_ERROR_BADSHARENAME;
6076 #endif /* DFS_SUPPORT */
6078 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6079 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6080 userp, tidPathp, &req, &newDscp);
6082 cm_ReleaseSCache(oldDscp);
6083 cm_ReleaseUser(userp);
6088 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6089 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6090 cm_ReleaseSCache(newDscp);
6091 cm_ReleaseSCache(oldDscp);
6092 cm_ReleaseUser(userp);
6093 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6094 return CM_ERROR_PATH_NOT_COVERED;
6096 return CM_ERROR_BADSHARENAME;
6098 #endif /* DFS_SUPPORT */
6100 /* Now, although we did two lookups for the two directories (because the same
6101 * directory can be referenced through different paths), we only allow hard links
6102 * within the same directory. */
6103 if (oldDscp != newDscp) {
6104 cm_ReleaseSCache(oldDscp);
6105 cm_ReleaseSCache(newDscp);
6106 cm_ReleaseUser(userp);
6107 return CM_ERROR_CROSSDEVLINK;
6110 /* handle the old name first */
6112 oldLastNamep = oldPathp;
6116 /* and handle the new name, too */
6118 newLastNamep = newPathp;
6122 /* now lookup the old name */
6123 osi_Log1(smb_logp," looking up [%S]", osi_LogSaveClientString(smb_logp,oldLastNamep));
6124 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
6126 cm_ReleaseSCache(oldDscp);
6127 cm_ReleaseSCache(newDscp);
6128 cm_ReleaseUser(userp);
6132 /* Check if the file already exists; if so return error */
6133 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6134 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6135 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6137 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6138 osi_LogSaveClientString(smb_logp, newLastNamep));
6140 /* if the existing link is to the same file, then we return success */
6142 if(sscp == tmpscp) {
6145 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
6146 code = CM_ERROR_EXISTS;
6151 cm_ReleaseSCache(tmpscp);
6152 cm_ReleaseSCache(sscp);
6153 cm_ReleaseSCache(newDscp);
6154 cm_ReleaseSCache(oldDscp);
6155 cm_ReleaseUser(userp);
6159 /* now create the hardlink */
6160 osi_Log1(smb_logp," Attempting to create new link [%S]", osi_LogSaveClientString(smb_logp, newLastNamep));
6161 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
6162 osi_Log1(smb_logp," Link returns 0x%x", code);
6164 /* Handle Change Notification */
6166 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
6167 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6168 smb_NotifyChange(FILE_ACTION_ADDED,
6169 filter, newDscp, newLastNamep,
6174 cm_ReleaseSCache(tmpscp);
6175 cm_ReleaseUser(userp);
6176 cm_ReleaseSCache(sscp);
6177 cm_ReleaseSCache(oldDscp);
6178 cm_ReleaseSCache(newDscp);
6182 /* SMB_COM_RENAME */
6184 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6186 clientchar_t *oldPathp;
6187 clientchar_t *newPathp;
6191 tp = smb_GetSMBData(inp, NULL);
6192 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6193 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6195 osi_Log2(smb_logp, "smb rename [%S] to [%S]",
6196 osi_LogSaveClientString(smb_logp, oldPathp),
6197 osi_LogSaveClientString(smb_logp, newPathp));
6199 if (!cm_IsValidClientString(newPathp)) {
6201 clientchar_t * hexp;
6203 hexp = cm_GetRawCharsAlloc(newPathp, -1);
6204 osi_Log1(smb_logp, "CoreRename rejecting invalid name. [%S]",
6205 osi_LogSaveClientString(smb_logp, hexp));
6209 osi_Log0(smb_logp, "CoreRename rejecting invalid name");
6211 return CM_ERROR_BADNTFILENAME;
6214 code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
6216 osi_Log1(smb_logp, "smb rename returns 0x%x", code);
6222 typedef struct smb_rmdirRock {
6226 normchar_t *maskp; /* pointer to the star pattern */
6229 cm_dirEntryList_t * matches;
6232 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6235 smb_rmdirRock_t *rockp;
6237 normchar_t matchName[MAX_PATH];
6239 rockp = (smb_rmdirRock_t *) vrockp;
6241 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6242 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6243 osi_LogSaveString(smb_logp, dep->name));
6247 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
6248 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6250 match = (cm_ClientStrCmp(matchName, rockp->maskp) == 0);
6252 (rockp->flags & SMB_MASKFLAG_TILDE) &&
6253 !cm_Is8Dot3(matchName)) {
6254 cm_Gen8Dot3Name(dep, matchName, NULL);
6255 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6260 cm_DirEntryListAdd(dep->name, &rockp->matches);
6267 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6270 clientchar_t *pathp;
6274 clientchar_t *lastNamep;
6275 smb_rmdirRock_t rock;
6279 clientchar_t *tidPathp;
6283 memset(&rock, 0, sizeof(rock));
6285 tp = smb_GetSMBData(inp, NULL);
6286 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6288 spacep = inp->spacep;
6289 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
6291 userp = smb_GetUserFromVCP(vcp, inp);
6293 caseFold = CM_FLAG_CASEFOLD;
6295 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6297 cm_ReleaseUser(userp);
6298 return CM_ERROR_NOSUCHPATH;
6300 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
6301 userp, tidPathp, &req, &dscp);
6304 cm_ReleaseUser(userp);
6309 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6310 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
6311 cm_ReleaseSCache(dscp);
6312 cm_ReleaseUser(userp);
6313 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6314 return CM_ERROR_PATH_NOT_COVERED;
6316 return CM_ERROR_BADSHARENAME;
6318 #endif /* DFS_SUPPORT */
6320 /* otherwise, scp points to the parent directory. */
6327 rock.maskp = cm_ClientStringToNormStringAlloc(lastNamep, -1, NULL);
6329 code = CM_ERROR_NOSUCHFILE;
6332 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6335 thyper.HighPart = 0;
6339 rock.matches = NULL;
6341 /* First do a case sensitive match, and if that fails, do a case insensitive match */
6342 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6343 if (code == 0 && !rock.any) {
6345 thyper.HighPart = 0;
6346 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6347 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6350 if (code == 0 && rock.matches) {
6351 cm_dirEntryList_t * entry;
6353 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
6354 clientchar_t clientName[MAX_PATH];
6356 /* We assume this will succeed because smb_RmdirProc()
6357 successfully converted entry->name once above. */
6358 cm_FsStringToClientString(entry->name, -1, clientName, lengthof(clientName));
6360 osi_Log1(smb_logp, "Removing directory %s",
6361 osi_LogSaveString(smb_logp, entry->name));
6363 code = cm_RemoveDir(dscp, entry->name, clientName, userp, &req);
6365 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6366 smb_NotifyChange(FILE_ACTION_REMOVED,
6367 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6368 dscp, clientName, NULL, TRUE);
6374 cm_DirEntryListFree(&rock.matches);
6377 cm_ReleaseUser(userp);
6380 cm_ReleaseSCache(dscp);
6382 if (code == 0 && !rock.any)
6383 code = CM_ERROR_NOSUCHFILE;
6392 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6402 fid = smb_GetSMBParm(inp, 0);
6404 osi_Log1(smb_logp, "SMB flush fid %d", fid);
6406 fid = smb_ChainFID(fid, inp);
6407 fidp = smb_FindFID(vcp, fid, 0);
6409 return CM_ERROR_BADFD;
6411 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6412 smb_CloseFID(vcp, fidp, NULL, 0);
6413 smb_ReleaseFID(fidp);
6414 return CM_ERROR_NOSUCHFILE;
6417 lock_ObtainMutex(&fidp->mx);
6418 if (fidp->flags & SMB_FID_IOCTL) {
6419 lock_ReleaseMutex(&fidp->mx);
6420 smb_ReleaseFID(fidp);
6421 return CM_ERROR_BADFD;
6423 lock_ReleaseMutex(&fidp->mx);
6425 userp = smb_GetUserFromVCP(vcp, inp);
6427 lock_ObtainMutex(&fidp->mx);
6428 if ((fidp->flags & SMB_FID_OPENWRITE) && smb_AsyncStore != 2) {
6429 cm_scache_t * scp = fidp->scp;
6431 lock_ReleaseMutex(&fidp->mx);
6432 code = cm_FSync(scp, userp, &req);
6433 cm_ReleaseSCache(scp);
6436 lock_ReleaseMutex(&fidp->mx);
6439 smb_ReleaseFID(fidp);
6441 cm_ReleaseUser(userp);
6446 struct smb_FullNameRock {
6449 clientchar_t *fullName;
6450 fschar_t *originalName;
6453 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
6456 normchar_t matchName[MAX_PATH];
6457 struct smb_FullNameRock *vrockp;
6459 vrockp = (struct smb_FullNameRock *)rockp;
6461 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6462 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6463 osi_LogSaveString(smb_logp, dep->name));
6467 if (!cm_Is8Dot3(matchName)) {
6468 clientchar_t shortName[13];
6470 cm_Gen8Dot3Name(dep, shortName, NULL);
6472 if (cm_ClientStrCmpIA(shortName, vrockp->name) == 0) {
6473 vrockp->fullName = cm_ClientStrDup(matchName);
6474 vrockp->originalName = cm_FsStrDup(dep->name);
6475 return CM_ERROR_STOPNOW;
6478 if (cm_ClientStrCmpI(matchName, vrockp->name) == 0 &&
6479 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
6480 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
6481 vrockp->fullName = cm_ClientStrDup(matchName);
6482 vrockp->originalName = cm_FsStrDup(dep->name);
6483 return CM_ERROR_STOPNOW;
6488 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, clientchar_t *pathp,
6489 clientchar_t **newPathp, fschar_t ** originalPathp,
6490 cm_user_t *userp, cm_req_t *reqp)
6492 struct smb_FullNameRock rock;
6495 memset(&rock, 0, sizeof(rock));
6499 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
6500 if (code == CM_ERROR_STOPNOW) {
6501 *newPathp = rock.fullName;
6502 *originalPathp = rock.originalName;
6504 *newPathp = cm_ClientStrDup(pathp);
6505 *originalPathp = cm_ClientStringToFsStringAlloc(pathp, -1, NULL);
6509 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
6510 afs_uint32 dosTime) {
6513 cm_scache_t *dscp = NULL;
6514 clientchar_t *pathp = NULL;
6515 cm_scache_t * scp = NULL;
6516 cm_scache_t *delscp = NULL;
6517 int nullcreator = 0;
6519 osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
6520 fidp, fidp->fid, scp, vcp);
6523 lock_ObtainMutex(&fidp->mx);
6524 if (!fidp->userp && !(fidp->flags & SMB_FID_IOCTL)) {
6525 lock_ReleaseMutex(&fidp->mx);
6526 osi_Log0(smb_logp, " No user specified. Not closing fid");
6527 return CM_ERROR_BADFD;
6530 userp = fidp->userp; /* no hold required since fidp is held
6531 throughout the function */
6532 lock_ReleaseMutex(&fidp->mx);
6537 lock_ObtainWrite(&smb_rctLock);
6538 if (fidp->deleteOk) {
6539 osi_Log0(smb_logp, " Fid already closed.");
6540 lock_ReleaseWrite(&smb_rctLock);
6541 return CM_ERROR_BADFD;
6544 lock_ReleaseWrite(&smb_rctLock);
6546 lock_ObtainMutex(&fidp->mx);
6547 if (fidp->NTopen_dscp) {
6548 dscp = fidp->NTopen_dscp;
6549 cm_HoldSCache(dscp);
6552 if (fidp->NTopen_pathp) {
6553 pathp = cm_ClientStrDup(fidp->NTopen_pathp);
6561 /* Don't jump the gun on an async raw write */
6562 while (fidp->raw_writers) {
6563 lock_ReleaseMutex(&fidp->mx);
6564 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
6565 lock_ObtainMutex(&fidp->mx);
6568 /* watch for ioctl closes, and read-only opens */
6570 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
6571 == SMB_FID_OPENWRITE) {
6572 if (dosTime != 0 && dosTime != -1) {
6573 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6574 /* This fixes defect 10958 */
6575 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
6576 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
6578 if (smb_AsyncStore != 2) {
6579 lock_ReleaseMutex(&fidp->mx);
6580 code = cm_FSync(scp, userp, &req);
6581 lock_ObtainMutex(&fidp->mx);
6587 /* unlock any pending locks */
6588 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
6589 scp->fileType == CM_SCACHETYPE_FILE) {
6593 lock_ReleaseMutex(&fidp->mx);
6595 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
6597 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
6598 lock_ObtainWrite(&scp->rw);
6600 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
6601 CM_SCACHESYNC_NEEDCALLBACK
6602 | CM_SCACHESYNC_GETSTATUS
6603 | CM_SCACHESYNC_LOCK);
6607 "smb CoreClose SyncOp failure code 0x%x", tcode);
6608 goto post_syncopdone;
6611 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
6613 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
6617 lock_ReleaseWrite(&scp->rw);
6618 lock_ObtainMutex(&fidp->mx);
6621 if (fidp->flags & SMB_FID_DELONCLOSE) {
6622 clientchar_t *fullPathp = NULL;
6623 fschar_t *originalNamep = NULL;
6625 lock_ReleaseMutex(&fidp->mx);
6627 code = cm_Lookup(dscp, pathp, CM_FLAG_NOMOUNTCHASE, userp, &req, &delscp);
6632 smb_FullName(dscp, delscp, pathp, &fullPathp, &originalNamep, userp, &req);
6633 if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
6634 code = cm_RemoveDir(dscp, originalNamep, fullPathp, userp, &req);
6636 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6637 smb_NotifyChange(FILE_ACTION_REMOVED,
6638 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6639 dscp, fullPathp, NULL, TRUE);
6642 code = cm_Unlink(dscp, originalNamep, fullPathp, userp, &req);
6644 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6645 smb_NotifyChange(FILE_ACTION_REMOVED,
6646 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6647 dscp, fullPathp, NULL, TRUE);
6654 free(originalNamep);
6656 lock_ObtainMutex(&fidp->mx);
6657 fidp->flags &= ~SMB_FID_DELONCLOSE;
6660 /* if this was a newly created file, then clear the creator
6661 * in the stat cache entry. */
6662 if (fidp->flags & SMB_FID_CREATED) {
6664 fidp->flags &= ~SMB_FID_CREATED;
6667 if (fidp->flags & SMB_FID_NTOPEN) {
6668 cm_ReleaseSCache(fidp->NTopen_dscp);
6669 fidp->NTopen_dscp = NULL;
6670 free(fidp->NTopen_pathp);
6671 fidp->NTopen_pathp = NULL;
6672 fidp->flags &= ~SMB_FID_NTOPEN;
6674 osi_assertx(fidp->NTopen_dscp == NULL, "null NTopen_dsc");
6675 osi_assertx(fidp->NTopen_pathp == NULL, "null NTopen_path");
6678 if (fidp->NTopen_wholepathp) {
6679 free(fidp->NTopen_wholepathp);
6680 fidp->NTopen_wholepathp = NULL;
6684 cm_ReleaseSCache(fidp->scp);
6687 lock_ReleaseMutex(&fidp->mx);
6690 cm_ReleaseSCache(dscp);
6693 cm_ReleaseSCache(delscp);
6697 lock_ObtainWrite(&scp->rw);
6698 if (nullcreator && scp->creator == userp)
6699 scp->creator = NULL;
6700 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
6701 lock_ReleaseWrite(&scp->rw);
6702 cm_ReleaseSCache(scp);
6712 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6720 fid = smb_GetSMBParm(inp, 0);
6721 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6723 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
6725 fid = smb_ChainFID(fid, inp);
6726 fidp = smb_FindFID(vcp, fid, 0);
6728 return CM_ERROR_BADFD;
6731 userp = smb_GetUserFromVCP(vcp, inp);
6733 code = smb_CloseFID(vcp, fidp, userp, dosTime);
6735 smb_ReleaseFID(fidp);
6736 cm_ReleaseUser(userp);
6741 * smb_ReadData -- common code for Read, Read And X, and Raw Read
6743 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
6744 cm_user_t *userp, long *readp)
6750 osi_hyper_t fileLength;
6752 osi_hyper_t lastByte;
6753 osi_hyper_t bufferOffset;
6757 int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
6760 osi_Log3(smb_logp, "smb_ReadData fid %d, off 0x%x, size 0x%x",
6761 fidp->fid, offsetp->LowPart, count);
6765 lock_ObtainMutex(&fidp->mx);
6766 /* make sure we have a readable FD */
6767 if (!(fidp->flags & SMB_FID_OPENREAD_LISTDIR)) {
6768 osi_Log2(smb_logp, "smb_ReadData fid %d not OPENREAD_LISTDIR flags 0x%x",
6769 fidp->fid, fidp->flags);
6770 lock_ReleaseMutex(&fidp->mx);
6771 code = CM_ERROR_BADFDOP;
6782 lock_ObtainWrite(&scp->rw);
6784 if (offset.HighPart == 0) {
6785 chunk = offset.LowPart >> cm_logChunkSize;
6786 if (chunk != fidp->curr_chunk) {
6787 fidp->prev_chunk = fidp->curr_chunk;
6788 fidp->curr_chunk = chunk;
6790 if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
6793 lock_ReleaseMutex(&fidp->mx);
6795 /* start by looking up the file's end */
6796 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6797 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6801 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6803 /* now we have the entry locked, look up the length */
6804 fileLength = scp->length;
6806 /* adjust count down so that it won't go past EOF */
6807 thyper.LowPart = count;
6808 thyper.HighPart = 0;
6809 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
6811 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6812 /* we'd read past EOF, so just stop at fileLength bytes.
6813 * Start by computing how many bytes remain in the file.
6815 thyper = LargeIntegerSubtract(fileLength, offset);
6817 /* if we are past EOF, read 0 bytes */
6818 if (LargeIntegerLessThanZero(thyper))
6821 count = thyper.LowPart;
6826 /* now, copy the data one buffer at a time,
6827 * until we've filled the request packet
6830 /* if we've copied all the data requested, we're done */
6831 if (count <= 0) break;
6833 /* otherwise, load up a buffer of data */
6834 thyper.HighPart = offset.HighPart;
6835 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6836 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6839 buf_Release(bufferp);
6842 lock_ReleaseWrite(&scp->rw);
6844 code = buf_Get(scp, &thyper, &bufferp);
6846 lock_ObtainWrite(&scp->rw);
6847 if (code) goto done;
6848 bufferOffset = thyper;
6850 /* now get the data in the cache */
6852 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6853 CM_SCACHESYNC_NEEDCALLBACK |
6854 CM_SCACHESYNC_READ);
6858 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
6860 if (cm_HaveBuffer(scp, bufferp, 0)) break;
6862 /* otherwise, load the buffer and try again */
6863 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
6867 buf_Release(bufferp);
6871 } /* if (wrong buffer) ... */
6873 /* now we have the right buffer loaded. Copy out the
6874 * data from here to the user's buffer.
6876 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6878 /* and figure out how many bytes we want from this buffer */
6879 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6880 if (nbytes > count) nbytes = count; /* don't go past EOF */
6882 /* now copy the data */
6883 memcpy(op, bufferp->datap + bufIndex, nbytes);
6885 /* adjust counters, pointers, etc. */
6888 thyper.LowPart = nbytes;
6889 thyper.HighPart = 0;
6890 offset = LargeIntegerAdd(thyper, offset);
6894 lock_ReleaseWrite(&scp->rw);
6896 buf_Release(bufferp);
6898 if (code == 0 && sequential)
6899 cm_ConsiderPrefetch(scp, &lastByte, *readp, userp, &req);
6901 cm_ReleaseSCache(scp);
6904 osi_Log3(smb_logp, "smb_ReadData fid %d returns 0x%x read %d bytes",
6905 fidp->fid, code, *readp);
6910 * smb_WriteData -- common code for Write and Raw Write
6912 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
6913 cm_user_t *userp, long *writtenp)
6915 osi_hyper_t offset = *offsetp;
6918 cm_scache_t *scp = NULL;
6919 osi_hyper_t fileLength; /* file's length at start of write */
6920 osi_hyper_t minLength; /* don't read past this */
6921 afs_uint32 nbytes; /* # of bytes to transfer this iteration */
6922 cm_buf_t *bufferp = NULL;
6923 osi_hyper_t thyper; /* hyper tmp variable */
6924 osi_hyper_t bufferOffset;
6925 afs_uint32 bufIndex; /* index in buffer where our data is */
6926 int doWriteBack = 0;
6927 osi_hyper_t writeBackOffset;/* offset of region to write back when I/O is done */
6931 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
6932 fidp->fid, offsetp->LowPart, count);
6936 lock_ObtainMutex(&fidp->mx);
6937 /* make sure we have a writable FD */
6938 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
6939 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
6940 fidp->fid, fidp->flags);
6941 lock_ReleaseMutex(&fidp->mx);
6942 code = CM_ERROR_BADFDOP;
6950 lock_ReleaseMutex(&fidp->mx);
6952 lock_ObtainWrite(&scp->rw);
6953 /* start by looking up the file's end */
6954 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6955 CM_SCACHESYNC_NEEDCALLBACK
6956 | CM_SCACHESYNC_SETSTATUS
6957 | CM_SCACHESYNC_GETSTATUS);
6961 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
6963 /* now we have the entry locked, look up the length */
6964 fileLength = scp->length;
6965 minLength = fileLength;
6966 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
6967 minLength = scp->serverLength;
6969 /* adjust file length if we extend past EOF */
6970 thyper.LowPart = count;
6971 thyper.HighPart = 0;
6972 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
6973 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6974 /* we'd write past EOF, so extend the file */
6975 scp->mask |= CM_SCACHEMASK_LENGTH;
6976 scp->length = thyper;
6977 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
6979 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
6981 /* now, if the new position (thyper) and the old (offset) are in
6982 * different storeback windows, remember to store back the previous
6983 * storeback window when we're done with the write.
6985 * the purpose of this logic is to slow down the CIFS client
6986 * in order to avoid the client disconnecting during the CLOSE
6987 * operation if there are too many dirty buffers left to write
6988 * than can be accomplished during 45 seconds. This used to be
6989 * based upon cm_chunkSize but we desire cm_chunkSize to be large
6990 * so that we can read larger amounts of data at a time.
6992 if (smb_AsyncStore == 1 &&
6993 (thyper.LowPart & ~(smb_AsyncStoreSize-1)) !=
6994 (offset.LowPart & ~(smb_AsyncStoreSize-1))) {
6995 /* they're different */
6997 writeBackOffset.HighPart = offset.HighPart;
6998 writeBackOffset.LowPart = offset.LowPart & ~(smb_AsyncStoreSize-1);
7003 /* now, copy the data one buffer at a time, until we've filled the
7006 /* if we've copied all the data requested, we're done */
7010 /* handle over quota or out of space */
7011 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
7012 *writtenp = written;
7013 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
7017 /* otherwise, load up a buffer of data */
7018 thyper.HighPart = offset.HighPart;
7019 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7020 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7023 lock_ReleaseMutex(&bufferp->mx);
7024 buf_Release(bufferp);
7027 lock_ReleaseWrite(&scp->rw);
7029 code = buf_Get(scp, &thyper, &bufferp);
7031 lock_ObtainMutex(&bufferp->mx);
7032 lock_ObtainWrite(&scp->rw);
7033 if (code) goto done;
7035 bufferOffset = thyper;
7037 /* now get the data in the cache */
7039 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7040 CM_SCACHESYNC_NEEDCALLBACK
7041 | CM_SCACHESYNC_WRITE
7042 | CM_SCACHESYNC_BUFLOCKED);
7046 cm_SyncOpDone(scp, bufferp,
7047 CM_SCACHESYNC_NEEDCALLBACK
7048 | CM_SCACHESYNC_WRITE
7049 | CM_SCACHESYNC_BUFLOCKED);
7051 /* If we're overwriting the entire buffer, or
7052 * if we're writing at or past EOF, mark the
7053 * buffer as current so we don't call
7054 * cm_GetBuffer. This skips the fetch from the
7055 * server in those cases where we're going to
7056 * obliterate all the data in the buffer anyway,
7057 * or in those cases where there is no useful
7058 * data at the server to start with.
7060 * Use minLength instead of scp->length, since
7061 * the latter has already been updated by this
7064 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
7065 || LargeIntegerEqualTo(offset, bufferp->offset)
7066 && (count >= cm_data.buf_blockSize
7067 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
7068 ConvertLongToLargeInteger(count)),
7070 if (count < cm_data.buf_blockSize
7071 && bufferp->dataVersion == CM_BUF_VERSION_BAD)
7072 memset(bufferp->datap, 0,
7073 cm_data.buf_blockSize);
7074 bufferp->dataVersion = scp->dataVersion;
7077 if (cm_HaveBuffer(scp, bufferp, 1)) break;
7079 /* otherwise, load the buffer and try again */
7080 lock_ReleaseMutex(&bufferp->mx);
7081 code = cm_GetBuffer(scp, bufferp, NULL, userp,
7083 lock_ReleaseWrite(&scp->rw);
7084 lock_ObtainMutex(&bufferp->mx);
7085 lock_ObtainWrite(&scp->rw);
7089 lock_ReleaseMutex(&bufferp->mx);
7090 buf_Release(bufferp);
7094 } /* if (wrong buffer) ... */
7096 /* now we have the right buffer loaded. Copy out the
7097 * data from here to the user's buffer.
7099 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7101 /* and figure out how many bytes we want from this buffer */
7102 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
7104 nbytes = count; /* don't go past end of request */
7106 /* now copy the data */
7107 memcpy(bufferp->datap + bufIndex, op, nbytes);
7108 buf_SetDirty(bufferp, bufIndex, nbytes, userp);
7110 /* adjust counters, pointers, etc. */
7114 thyper.LowPart = nbytes;
7115 thyper.HighPart = 0;
7116 offset = LargeIntegerAdd(thyper, offset);
7120 lock_ReleaseWrite(&scp->rw);
7123 lock_ReleaseMutex(&bufferp->mx);
7124 buf_Release(bufferp);
7127 lock_ObtainMutex(&fidp->mx);
7128 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
7129 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7131 lock_ReleaseMutex(&fidp->mx);
7132 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
7133 fidp->NTopen_dscp, fidp->NTopen_pathp,
7136 lock_ReleaseMutex(&fidp->mx);
7140 if (smb_AsyncStore > 0) {
7144 lock_ObtainWrite(&scp->rw);
7145 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
7147 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
7148 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
7150 lock_ReleaseWrite(&scp->rw);
7151 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
7152 writeBackOffset.HighPart,
7153 smb_AsyncStoreSize, 0, userp);
7154 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
7157 cm_BufWrite(scp, offsetp, *writtenp, 0, userp, &req);
7161 cm_ReleaseSCache(scp);
7164 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
7165 fidp->fid, code, *writtenp);
7170 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7173 unsigned short count;
7175 unsigned short hint;
7176 long written = 0, total_written = 0;
7179 smb_t* smbp = (smb_t*) inp;
7182 cm_attr_t truncAttr; /* attribute struct used for truncating file */
7184 int inDataBlockCount;
7186 fd = smb_GetSMBParm(inp, 0);
7187 count = smb_GetSMBParm(inp, 1);
7188 offset.HighPart = 0; /* too bad */
7189 offset.LowPart = smb_GetSMBParmLong(inp, 2);
7190 hint = smb_GetSMBParm(inp, 4);
7192 op = smb_GetSMBData(inp, NULL);
7193 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
7195 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
7196 fd, offset.LowPart, count);
7198 fd = smb_ChainFID(fd, inp);
7199 fidp = smb_FindFID(vcp, fd, 0);
7201 osi_Log0(smb_logp, "smb_ReceiveCoreWrite fid not found");
7202 return CM_ERROR_BADFD;
7205 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7206 smb_CloseFID(vcp, fidp, NULL, 0);
7207 smb_ReleaseFID(fidp);
7208 return CM_ERROR_NOSUCHFILE;
7211 lock_ObtainMutex(&fidp->mx);
7212 if (fidp->flags & SMB_FID_IOCTL) {
7213 lock_ReleaseMutex(&fidp->mx);
7214 code = smb_IoctlWrite(fidp, vcp, inp, outp);
7215 smb_ReleaseFID(fidp);
7216 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
7219 lock_ReleaseMutex(&fidp->mx);
7220 userp = smb_GetUserFromVCP(vcp, inp);
7224 LARGE_INTEGER LOffset;
7225 LARGE_INTEGER LLength;
7228 key = cm_GenerateKey(vcp->vcID, pid, fd);
7230 LOffset.HighPart = offset.HighPart;
7231 LOffset.LowPart = offset.LowPart;
7232 LLength.HighPart = 0;
7233 LLength.LowPart = count;
7235 lock_ObtainWrite(&fidp->scp->rw);
7236 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
7237 lock_ReleaseWrite(&fidp->scp->rw);
7240 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
7245 /* special case: 0 bytes transferred means truncate to this position */
7249 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
7253 truncAttr.mask = CM_ATTRMASK_LENGTH;
7254 truncAttr.length.LowPart = offset.LowPart;
7255 truncAttr.length.HighPart = 0;
7256 lock_ObtainMutex(&fidp->mx);
7257 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
7258 fidp->flags |= SMB_FID_LENGTHSETDONE;
7259 lock_ReleaseMutex(&fidp->mx);
7260 smb_SetSMBParm(outp, 0, 0 /* count */);
7261 smb_SetSMBDataLength(outp, 0);
7266 * Work around bug in NT client
7268 * When copying a file, the NT client should first copy the data,
7269 * then copy the last write time. But sometimes the NT client does
7270 * these in the wrong order, so the data copies would inadvertently
7271 * cause the last write time to be overwritten. We try to detect this,
7272 * and don't set client mod time if we think that would go against the
7275 lock_ObtainMutex(&fidp->mx);
7276 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
7277 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7278 fidp->scp->clientModTime = time(NULL);
7280 lock_ReleaseMutex(&fidp->mx);
7283 while ( code == 0 && count > 0 ) {
7284 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7285 if (code == 0 && written == 0)
7286 code = CM_ERROR_PARTIALWRITE;
7288 offset = LargeIntegerAdd(offset,
7289 ConvertLongToLargeInteger(written));
7290 count -= (unsigned short)written;
7291 total_written += written;
7295 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
7296 total_written, code);
7298 /* set the packet data length to 3 bytes for the data block header,
7299 * plus the size of the data.
7301 smb_SetSMBParm(outp, 0, total_written);
7302 smb_SetSMBParmLong(outp, 1, offset.LowPart);
7303 smb_SetSMBParm(outp, 3, hint);
7304 smb_SetSMBDataLength(outp, 0);
7307 smb_ReleaseFID(fidp);
7308 cm_ReleaseUser(userp);
7313 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7314 NCB *ncbp, raw_write_cont_t *rwcp)
7323 fd = smb_GetSMBParm(inp, 0);
7324 fidp = smb_FindFID(vcp, fd, 0);
7326 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7327 smb_CloseFID(vcp, fidp, NULL, 0);
7328 smb_ReleaseFID(fidp);
7332 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
7333 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
7335 userp = smb_GetUserFromVCP(vcp, inp);
7338 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
7340 if (rwcp->writeMode & 0x1) { /* synchronous */
7343 smb_FormatResponsePacket(vcp, inp, outp);
7344 op = (smb_t *) outp;
7345 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7346 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
7347 smb_SetSMBDataLength(outp, 0);
7348 smb_SendPacket(vcp, outp);
7349 smb_FreePacket(outp);
7351 else { /* asynchronous */
7352 lock_ObtainMutex(&fidp->mx);
7353 fidp->raw_writers--;
7354 if (fidp->raw_writers == 0)
7355 thrd_SetEvent(fidp->raw_write_event);
7356 lock_ReleaseMutex(&fidp->mx);
7359 /* Give back raw buffer */
7360 lock_ObtainMutex(&smb_RawBufLock);
7361 *((char **)rawBuf) = smb_RawBufs;
7362 smb_RawBufs = rawBuf;
7363 lock_ReleaseMutex(&smb_RawBufLock);
7365 smb_ReleaseFID(fidp);
7366 cm_ReleaseUser(userp);
7369 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7374 /* SMB_COM_WRITE_RAW */
7375 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
7378 long count, written = 0, total_written = 0;
7382 smb_t *smbp = (smb_t*) inp;
7386 unsigned short writeMode;
7388 fd = smb_GetSMBParm(inp, 0);
7389 totalCount = smb_GetSMBParm(inp, 1);
7390 count = smb_GetSMBParm(inp, 10);
7391 writeMode = smb_GetSMBParm(inp, 7);
7393 op = (char *) inp->data;
7394 op += smb_GetSMBParm(inp, 11);
7396 offset.HighPart = 0;
7397 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
7399 if (*inp->wctp == 14) {
7400 /* we received a 64-bit file offset */
7401 #ifdef AFS_LARGEFILES
7402 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
7404 if (LargeIntegerLessThanZero(offset)) {
7406 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
7407 offset.HighPart, offset.LowPart);
7408 return CM_ERROR_BADSMB;
7411 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
7413 "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files");
7414 return CM_ERROR_BADSMB;
7417 offset.HighPart = 0;
7420 offset.HighPart = 0; /* 32-bit file offset */
7424 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
7425 fd, offset.HighPart, offset.LowPart, count);
7427 " WriteRaw WriteMode 0x%x",
7430 fd = smb_ChainFID(fd, inp);
7431 fidp = smb_FindFID(vcp, fd, 0);
7433 return CM_ERROR_BADFD;
7436 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7437 smb_CloseFID(vcp, fidp, NULL, 0);
7438 smb_ReleaseFID(fidp);
7439 return CM_ERROR_NOSUCHFILE;
7445 LARGE_INTEGER LOffset;
7446 LARGE_INTEGER LLength;
7449 key = cm_GenerateKey(vcp->vcID, pid, fd);
7451 LOffset.HighPart = offset.HighPart;
7452 LOffset.LowPart = offset.LowPart;
7453 LLength.HighPart = 0;
7454 LLength.LowPart = count;
7456 lock_ObtainWrite(&fidp->scp->rw);
7457 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
7458 lock_ReleaseWrite(&fidp->scp->rw);
7461 smb_ReleaseFID(fidp);
7466 userp = smb_GetUserFromVCP(vcp, inp);
7469 * Work around bug in NT client
7471 * When copying a file, the NT client should first copy the data,
7472 * then copy the last write time. But sometimes the NT client does
7473 * these in the wrong order, so the data copies would inadvertently
7474 * cause the last write time to be overwritten. We try to detect this,
7475 * and don't set client mod time if we think that would go against the
7478 lock_ObtainMutex(&fidp->mx);
7479 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
7480 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7481 fidp->scp->clientModTime = time(NULL);
7483 lock_ReleaseMutex(&fidp->mx);
7486 while ( code == 0 && count > 0 ) {
7487 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7488 if (code == 0 && written == 0)
7489 code = CM_ERROR_PARTIALWRITE;
7491 offset = LargeIntegerAdd(offset,
7492 ConvertLongToLargeInteger(written));
7495 total_written += written;
7499 /* Get a raw buffer */
7502 lock_ObtainMutex(&smb_RawBufLock);
7504 /* Get a raw buf, from head of list */
7505 rawBuf = smb_RawBufs;
7506 smb_RawBufs = *(char **)smb_RawBufs;
7509 code = CM_ERROR_USESTD;
7511 lock_ReleaseMutex(&smb_RawBufLock);
7514 /* Don't allow a premature Close */
7515 if (code == 0 && (writeMode & 1) == 0) {
7516 lock_ObtainMutex(&fidp->mx);
7517 fidp->raw_writers++;
7518 thrd_ResetEvent(fidp->raw_write_event);
7519 lock_ReleaseMutex(&fidp->mx);
7522 smb_ReleaseFID(fidp);
7523 cm_ReleaseUser(userp);
7526 smb_SetSMBParm(outp, 0, total_written);
7527 smb_SetSMBDataLength(outp, 0);
7528 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7533 offset = LargeIntegerAdd(offset,
7534 ConvertLongToLargeInteger(count));
7538 rwcp->offset.HighPart = offset.HighPart;
7539 rwcp->offset.LowPart = offset.LowPart;
7540 rwcp->count = totalCount - count;
7541 rwcp->writeMode = writeMode;
7542 rwcp->alreadyWritten = total_written;
7544 /* set the packet data length to 3 bytes for the data block header,
7545 * plus the size of the data.
7547 smb_SetSMBParm(outp, 0, 0xffff);
7548 smb_SetSMBDataLength(outp, 0);
7554 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7557 long count, finalCount;
7561 smb_t *smbp = (smb_t*) inp;
7566 fd = smb_GetSMBParm(inp, 0);
7567 count = smb_GetSMBParm(inp, 1);
7568 offset.HighPart = 0; /* too bad */
7569 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7571 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
7572 fd, offset.LowPart, count);
7574 fd = smb_ChainFID(fd, inp);
7575 fidp = smb_FindFID(vcp, fd, 0);
7577 return CM_ERROR_BADFD;
7579 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7580 smb_CloseFID(vcp, fidp, NULL, 0);
7581 smb_ReleaseFID(fidp);
7582 return CM_ERROR_NOSUCHFILE;
7585 lock_ObtainMutex(&fidp->mx);
7586 if (fidp->flags & SMB_FID_IOCTL) {
7587 lock_ReleaseMutex(&fidp->mx);
7588 code = smb_IoctlRead(fidp, vcp, inp, outp);
7589 smb_ReleaseFID(fidp);
7592 lock_ReleaseMutex(&fidp->mx);
7595 LARGE_INTEGER LOffset, LLength;
7599 key = cm_GenerateKey(vcp->vcID, pid, fd);
7601 LOffset.HighPart = 0;
7602 LOffset.LowPart = offset.LowPart;
7603 LLength.HighPart = 0;
7604 LLength.LowPart = count;
7606 lock_ObtainWrite(&fidp->scp->rw);
7607 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
7608 lock_ReleaseWrite(&fidp->scp->rw);
7611 smb_ReleaseFID(fidp);
7615 userp = smb_GetUserFromVCP(vcp, inp);
7617 /* remember this for final results */
7618 smb_SetSMBParm(outp, 0, count);
7619 smb_SetSMBParm(outp, 1, 0);
7620 smb_SetSMBParm(outp, 2, 0);
7621 smb_SetSMBParm(outp, 3, 0);
7622 smb_SetSMBParm(outp, 4, 0);
7624 /* set the packet data length to 3 bytes for the data block header,
7625 * plus the size of the data.
7627 smb_SetSMBDataLength(outp, count+3);
7629 /* get op ptr after putting in the parms, since otherwise we don't
7630 * know where the data really is.
7632 op = smb_GetSMBData(outp, NULL);
7634 /* now emit the data block header: 1 byte of type and 2 bytes of length */
7635 *op++ = 1; /* data block marker */
7636 *op++ = (unsigned char) (count & 0xff);
7637 *op++ = (unsigned char) ((count >> 8) & 0xff);
7639 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
7641 /* fix some things up */
7642 smb_SetSMBParm(outp, 0, finalCount);
7643 smb_SetSMBDataLength(outp, finalCount+3);
7645 smb_ReleaseFID(fidp);
7647 cm_ReleaseUser(userp);
7651 /* SMB_COM_CREATE_DIRECTORY */
7652 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7654 clientchar_t *pathp;
7659 cm_scache_t *dscp; /* dir we're dealing with */
7660 cm_scache_t *scp; /* file we're creating */
7662 int initialModeBits;
7663 clientchar_t *lastNamep;
7665 clientchar_t *tidPathp;
7672 /* compute initial mode bits based on read-only flag in attributes */
7673 initialModeBits = 0777;
7675 tp = smb_GetSMBData(inp, NULL);
7676 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
7678 if (cm_ClientStrCmp(pathp, _C("\\")) == 0)
7679 return CM_ERROR_EXISTS;
7681 spacep = inp->spacep;
7682 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
7684 userp = smb_GetUserFromVCP(vcp, inp);
7686 caseFold = CM_FLAG_CASEFOLD;
7688 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7690 cm_ReleaseUser(userp);
7691 return CM_ERROR_NOSUCHPATH;
7694 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
7695 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
7696 userp, tidPathp, &req, &dscp);
7699 cm_ReleaseUser(userp);
7704 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7705 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
7706 cm_ReleaseSCache(dscp);
7707 cm_ReleaseUser(userp);
7708 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7709 return CM_ERROR_PATH_NOT_COVERED;
7711 return CM_ERROR_BADSHARENAME;
7713 #endif /* DFS_SUPPORT */
7715 /* otherwise, scp points to the parent directory. Do a lookup, and
7716 * fail if we find it. Otherwise, we do the create.
7722 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
7723 if (scp) cm_ReleaseSCache(scp);
7724 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7725 if (code == 0) code = CM_ERROR_EXISTS;
7726 cm_ReleaseSCache(dscp);
7727 cm_ReleaseUser(userp);
7731 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7732 setAttr.clientModTime = time(NULL);
7733 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
7734 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7735 smb_NotifyChange(FILE_ACTION_ADDED,
7736 FILE_NOTIFY_CHANGE_DIR_NAME,
7737 dscp, lastNamep, NULL, TRUE);
7739 /* we don't need this any longer */
7740 cm_ReleaseSCache(dscp);
7743 /* something went wrong creating or truncating the file */
7744 cm_ReleaseUser(userp);
7748 /* otherwise we succeeded */
7749 smb_SetSMBDataLength(outp, 0);
7750 cm_ReleaseUser(userp);
7755 BOOL smb_IsLegalFilename(clientchar_t *filename)
7758 * Find the longest substring of filename that does not contain
7759 * any of the chars in illegalChars. If that substring is less
7760 * than the length of the whole string, then one or more of the
7761 * illegal chars is in filename.
7763 if (cm_ClientStrCSpn(filename, illegalChars) < cm_ClientStrLen(filename))
7769 /* SMB_COM_CREATE and SMB_COM_CREATE_NEW */
7770 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7772 clientchar_t *pathp;
7778 cm_scache_t *dscp; /* dir we're dealing with */
7779 cm_scache_t *scp; /* file we're creating */
7781 int initialModeBits;
7784 clientchar_t *lastNamep;
7787 clientchar_t *tidPathp;
7789 int created = 0; /* the file was new */
7794 excl = (inp->inCom == 0x03)? 0 : 1;
7796 attributes = smb_GetSMBParm(inp, 0);
7797 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
7799 /* compute initial mode bits based on read-only flag in attributes */
7800 initialModeBits = 0666;
7801 if (attributes & SMB_ATTR_READONLY)
7802 initialModeBits &= ~0222;
7804 tp = smb_GetSMBData(inp, NULL);
7805 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
7807 if (!cm_IsValidClientString(pathp)) {
7809 clientchar_t * hexp;
7811 hexp = cm_GetRawCharsAlloc(pathp, -1);
7812 osi_Log1(smb_logp, "CoreCreate rejecting invalid name. [%S]",
7813 osi_LogSaveClientString(smb_logp, hexp));
7817 osi_Log0(smb_logp, "CoreCreate rejecting invalid name");
7819 return CM_ERROR_BADNTFILENAME;
7822 spacep = inp->spacep;
7823 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
7825 userp = smb_GetUserFromVCP(vcp, inp);
7827 caseFold = CM_FLAG_CASEFOLD;
7829 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7831 cm_ReleaseUser(userp);
7832 return CM_ERROR_NOSUCHPATH;
7834 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
7835 userp, tidPathp, &req, &dscp);
7838 cm_ReleaseUser(userp);
7843 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7844 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
7845 cm_ReleaseSCache(dscp);
7846 cm_ReleaseUser(userp);
7847 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7848 return CM_ERROR_PATH_NOT_COVERED;
7850 return CM_ERROR_BADSHARENAME;
7852 #endif /* DFS_SUPPORT */
7854 /* otherwise, scp points to the parent directory. Do a lookup, and
7855 * truncate the file if we find it, otherwise we create the file.
7862 if (!smb_IsLegalFilename(lastNamep))
7863 return CM_ERROR_BADNTFILENAME;
7865 osi_Log1(smb_logp, "SMB receive create [%S]", osi_LogSaveClientString( smb_logp, pathp ));
7866 #ifdef DEBUG_VERBOSE
7869 hexp = osi_HexifyString( lastNamep );
7870 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
7875 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
7876 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7877 cm_ReleaseSCache(dscp);
7878 cm_ReleaseUser(userp);
7882 /* if we get here, if code is 0, the file exists and is represented by
7883 * scp. Otherwise, we have to create it.
7887 /* oops, file shouldn't be there */
7888 cm_ReleaseSCache(dscp);
7889 cm_ReleaseSCache(scp);
7890 cm_ReleaseUser(userp);
7891 return CM_ERROR_EXISTS;
7894 setAttr.mask = CM_ATTRMASK_LENGTH;
7895 setAttr.length.LowPart = 0;
7896 setAttr.length.HighPart = 0;
7897 code = cm_SetAttr(scp, &setAttr, userp, &req);
7900 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7901 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
7902 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7906 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7907 smb_NotifyChange(FILE_ACTION_ADDED,
7908 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7909 dscp, lastNamep, NULL, TRUE);
7910 } else if (!excl && code == CM_ERROR_EXISTS) {
7911 /* not an exclusive create, and someone else tried
7912 * creating it already, then we open it anyway. We
7913 * don't bother retrying after this, since if this next
7914 * fails, that means that the file was deleted after
7915 * we started this call.
7917 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
7920 setAttr.mask = CM_ATTRMASK_LENGTH;
7921 setAttr.length.LowPart = 0;
7922 setAttr.length.HighPart = 0;
7923 code = cm_SetAttr(scp, &setAttr, userp, &req);
7928 /* we don't need this any longer */
7929 cm_ReleaseSCache(dscp);
7932 /* something went wrong creating or truncating the file */
7933 if (scp) cm_ReleaseSCache(scp);
7934 cm_ReleaseUser(userp);
7938 /* make sure we only open files */
7939 if (scp->fileType != CM_SCACHETYPE_FILE) {
7940 cm_ReleaseSCache(scp);
7941 cm_ReleaseUser(userp);
7942 return CM_ERROR_ISDIR;
7945 /* now all we have to do is open the file itself */
7946 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7947 osi_assertx(fidp, "null smb_fid_t");
7951 lock_ObtainMutex(&fidp->mx);
7952 /* always create it open for read/write */
7953 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
7955 /* remember that the file was newly created */
7957 fidp->flags |= SMB_FID_CREATED;
7959 osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
7961 /* save a pointer to the vnode */
7963 lock_ObtainWrite(&scp->rw);
7964 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7965 lock_ReleaseWrite(&scp->rw);
7968 fidp->userp = userp;
7969 lock_ReleaseMutex(&fidp->mx);
7971 smb_SetSMBParm(outp, 0, fidp->fid);
7972 smb_SetSMBDataLength(outp, 0);
7974 cm_Open(scp, 0, userp);
7976 smb_ReleaseFID(fidp);
7977 cm_ReleaseUser(userp);
7978 /* leave scp held since we put it in fidp->scp */
7983 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7986 osi_hyper_t new_offset;
7997 fd = smb_GetSMBParm(inp, 0);
7998 whence = smb_GetSMBParm(inp, 1);
7999 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
8001 /* try to find the file descriptor */
8002 fd = smb_ChainFID(fd, inp);
8003 fidp = smb_FindFID(vcp, fd, 0);
8005 return CM_ERROR_BADFD;
8007 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
8008 smb_CloseFID(vcp, fidp, NULL, 0);
8009 smb_ReleaseFID(fidp);
8010 return CM_ERROR_NOSUCHFILE;
8013 lock_ObtainMutex(&fidp->mx);
8014 if (fidp->flags & SMB_FID_IOCTL) {
8015 lock_ReleaseMutex(&fidp->mx);
8016 smb_ReleaseFID(fidp);
8017 return CM_ERROR_BADFD;
8019 lock_ReleaseMutex(&fidp->mx);
8021 userp = smb_GetUserFromVCP(vcp, inp);
8023 lock_ObtainMutex(&fidp->mx);
8026 lock_ReleaseMutex(&fidp->mx);
8027 lock_ObtainWrite(&scp->rw);
8028 code = cm_SyncOp(scp, NULL, userp, &req, 0,
8029 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8031 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8033 /* offset from current offset */
8034 new_offset = LargeIntegerAdd(fidp->offset,
8035 ConvertLongToLargeInteger(offset));
8037 else if (whence == 2) {
8038 /* offset from current EOF */
8039 new_offset = LargeIntegerAdd(scp->length,
8040 ConvertLongToLargeInteger(offset));
8042 new_offset = ConvertLongToLargeInteger(offset);
8045 fidp->offset = new_offset;
8046 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
8047 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
8048 smb_SetSMBDataLength(outp, 0);
8050 lock_ReleaseWrite(&scp->rw);
8051 smb_ReleaseFID(fidp);
8052 cm_ReleaseSCache(scp);
8053 cm_ReleaseUser(userp);
8057 /* dispatch all of the requests received in a packet. Due to chaining, this may
8058 * be more than one request.
8060 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
8061 NCB *ncbp, raw_write_cont_t *rwcp)
8065 unsigned long code = 0;
8066 unsigned char *outWctp;
8067 int nparms; /* # of bytes of parameters */
8069 int nbytes; /* bytes of data, excluding count */
8072 unsigned short errCode;
8073 unsigned long NTStatus;
8075 unsigned char errClass;
8076 unsigned int oldGen;
8077 DWORD oldTime, newTime;
8079 /* get easy pointer to the data */
8080 smbp = (smb_t *) inp->data;
8082 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
8083 /* setup the basic parms for the initial request in the packet */
8084 inp->inCom = smbp->com;
8085 inp->wctp = &smbp->wct;
8087 inp->ncb_length = ncbp->ncb_length;
8092 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
8093 /* log it and discard it */
8094 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
8095 __FILE__, __LINE__, ncbp->ncb_length);
8096 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
8100 /* We are an ongoing op */
8101 thrd_Increment(&ongoingOps);
8103 /* set up response packet for receiving output */
8104 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
8105 smb_FormatResponsePacket(vcp, inp, outp);
8106 outWctp = outp->wctp;
8108 /* Remember session generation number and time */
8109 oldGen = sessionGen;
8110 oldTime = GetTickCount();
8112 while (inp->inCom != 0xff) {
8113 dp = &smb_dispatchTable[inp->inCom];
8115 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
8116 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
8117 code = outp->resumeCode;
8121 /* process each request in the packet; inCom, wctp and inCount
8122 * are already set up.
8124 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
8127 /* now do the dispatch */
8128 /* start by formatting the response record a little, as a default */
8129 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
8131 outWctp[1] = 0xff; /* no operation */
8132 outWctp[2] = 0; /* padding */
8137 /* not a chained request, this is a more reasonable default */
8138 outWctp[0] = 0; /* wct of zero */
8139 outWctp[1] = 0; /* and bcc (word) of zero */
8143 /* once set, stays set. Doesn't matter, since we never chain
8144 * "no response" calls.
8146 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
8150 /* we have a recognized operation */
8151 char * opName = myCrt_Dispatch(inp->inCom);
8153 if (inp->inCom == 0x1d)
8155 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
8157 osi_Log4(smb_logp,"Dispatch %s vcp 0x%p lana %d lsn %d",
8158 opName,vcp,vcp->lana,vcp->lsn);
8159 code = (*(dp->procp)) (vcp, inp, outp);
8160 osi_Log4(smb_logp,"Dispatch return code 0x%x vcp 0x%p lana %d lsn %d",
8161 code,vcp,vcp->lana,vcp->lsn);
8163 if ( code == CM_ERROR_BADSMB ||
8164 code == CM_ERROR_BADOP )
8166 #endif /* LOG_PACKET */
8169 newTime = GetTickCount();
8170 osi_Log2(smb_logp, "Dispatch %s duration %d ms", opName, newTime - oldTime);
8172 /* ReceiveV3Tran2A handles its own logging */
8173 if (inp->inCom != 0x32 && newTime - oldTime > 45000) {
8176 clientchar_t *treepath = NULL; /* do not free */
8177 clientchar_t *pathname = NULL;
8178 cm_fid_t afid = {0,0,0,0,0};
8180 uidp = smb_FindUID(vcp, smbp->uid, 0);
8181 smb_LookupTIDPath(vcp,((smb_t *)inp)->tid, &treepath);
8182 fidp = smb_FindFID(vcp, inp->fid, 0);
8184 if (fidp && fidp->NTopen_pathp)
8185 pathname = fidp->NTopen_pathp;
8186 else if (inp->stringsp->wdata)
8187 pathname = inp->stringsp->wdata;
8189 if (fidp && fidp->scp)
8190 afid = fidp->scp->fid;
8192 afsi_log("Request %s duration %d ms user %S tid \"%S\" path? \"%S\" afid (%d.%d.%d.%d)",
8193 opName, newTime - oldTime,
8194 uidp ? uidp->unp->name : NULL,
8197 afid.cell, afid.volume, afid.vnode, afid.unique);
8200 smb_ReleaseUID(uidp);
8202 smb_ReleaseFID(fidp);
8205 if (oldGen != sessionGen) {
8206 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
8207 newTime - oldTime, ncbp->ncb_length);
8208 osi_Log3(smb_logp, "Request %s straddled session startup, "
8209 "took %d ms, ncb length %d", opName, newTime - oldTime, ncbp->ncb_length);
8212 FreeSMBStrings(inp);
8214 /* bad opcode, fail the request, after displaying it */
8215 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
8218 #endif /* LOG_PACKET */
8221 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
8222 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
8223 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
8224 if (code == IDCANCEL)
8227 code = CM_ERROR_BADOP;
8230 /* catastrophic failure: log as much as possible */
8231 if (code == CM_ERROR_BADSMB) {
8232 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
8236 #endif /* LOG_PACKET */
8237 osi_Log1(smb_logp, "Invalid SMB message, length %d",
8240 code = CM_ERROR_INVAL;
8243 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
8244 thrd_Decrement(&ongoingOps);
8249 /* now, if we failed, turn the current response into an empty
8250 * one, and fill in the response packet's error code.
8253 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8254 smb_MapNTError(code, &NTStatus);
8255 outWctp = outp->wctp;
8256 smbp = (smb_t *) &outp->data;
8257 if (code != CM_ERROR_PARTIALWRITE
8258 && code != CM_ERROR_BUFFERTOOSMALL
8259 && code != CM_ERROR_GSSCONTINUE) {
8260 /* nuke wct and bcc. For a partial
8261 * write or an in-process authentication handshake,
8262 * assume they're OK.
8268 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8269 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8270 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8271 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8272 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8276 smb_MapCoreError(code, vcp, &errCode, &errClass);
8277 outWctp = outp->wctp;
8278 smbp = (smb_t *) &outp->data;
8279 if (code != CM_ERROR_PARTIALWRITE) {
8280 /* nuke wct and bcc. For a partial
8281 * write, assume they're OK.
8287 smbp->errLow = (unsigned char) (errCode & 0xff);
8288 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8289 smbp->rcls = errClass;
8292 } /* error occurred */
8294 /* if we're here, we've finished one request. Look to see if
8295 * this is a chained opcode. If it is, setup things to process
8296 * the chained request, and setup the output buffer to hold the
8297 * chained response. Start by finding the next input record.
8299 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
8300 break; /* not a chained req */
8301 tp = inp->wctp; /* points to start of last request */
8302 /* in a chained request, the first two
8303 * parm fields are required, and are
8304 * AndXCommand/AndXReserved and
8306 if (tp[0] < 2) break;
8307 if (tp[1] == 0xff) break; /* no more chained opcodes */
8309 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
8312 /* and now append the next output request to the end of this
8313 * last request. Begin by finding out where the last response
8314 * ends, since that's where we'll put our new response.
8316 outWctp = outp->wctp; /* ptr to out parameters */
8317 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
8318 nparms = outWctp[0] << 1;
8319 tp = outWctp + nparms + 1; /* now points to bcc field */
8320 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
8321 tp += 2 /* for the count itself */ + nbytes;
8322 /* tp now points to the new output record; go back and patch the
8323 * second parameter (off2) to point to the new record.
8325 temp = (unsigned int)(tp - outp->data);
8326 outWctp[3] = (unsigned char) (temp & 0xff);
8327 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
8328 outWctp[2] = 0; /* padding */
8329 outWctp[1] = inp->inCom; /* next opcode */
8331 /* finally, setup for the next iteration */
8334 } /* while loop over all requests in the packet */
8336 /* now send the output packet, and return */
8338 smb_SendPacket(vcp, outp);
8339 thrd_Decrement(&ongoingOps);
8344 /* Wait for Netbios() calls to return, and make the results available to server
8345 * threads. Note that server threads can't wait on the NCBevents array
8346 * themselves, because NCB events are manual-reset, and the servers would race
8347 * each other to reset them.
8349 void smb_ClientWaiter(void *parmp)
8354 while (smbShutdownFlag == 0) {
8355 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
8357 if (code == WAIT_OBJECT_0)
8360 /* error checking */
8361 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8363 int abandonIdx = code - WAIT_ABANDONED_0;
8364 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8367 if (code == WAIT_IO_COMPLETION)
8369 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
8373 if (code == WAIT_TIMEOUT)
8375 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
8378 if (code == WAIT_FAILED)
8380 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
8383 idx = code - WAIT_OBJECT_0;
8385 /* check idx range! */
8386 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
8388 /* this is fatal - log as much as possible */
8389 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
8390 osi_assertx(0, "invalid index");
8393 thrd_ResetEvent(NCBevents[idx]);
8394 thrd_SetEvent(NCBreturns[0][idx]);
8399 * Try to have one NCBRECV request waiting for every live session. Not more
8400 * than one, because if there is more than one, it's hard to handle Write Raw.
8402 void smb_ServerWaiter(void *parmp)
8405 int idx_session, idx_NCB;
8408 while (smbShutdownFlag == 0) {
8410 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
8412 if (code == WAIT_OBJECT_0)
8415 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
8417 int abandonIdx = code - WAIT_ABANDONED_0;
8418 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8421 if (code == WAIT_IO_COMPLETION)
8423 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
8427 if (code == WAIT_TIMEOUT)
8429 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
8432 if (code == WAIT_FAILED)
8434 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
8437 idx_session = code - WAIT_OBJECT_0;
8439 /* check idx range! */
8440 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
8442 /* this is fatal - log as much as possible */
8443 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
8444 osi_assertx(0, "invalid index");
8449 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
8451 if (code == WAIT_OBJECT_0) {
8452 if (smbShutdownFlag == 1)
8458 /* error checking */
8459 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8461 int abandonIdx = code - WAIT_ABANDONED_0;
8462 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8465 if (code == WAIT_IO_COMPLETION)
8467 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
8471 if (code == WAIT_TIMEOUT)
8473 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
8476 if (code == WAIT_FAILED)
8478 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
8481 idx_NCB = code - WAIT_OBJECT_0;
8483 /* check idx range! */
8484 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
8486 /* this is fatal - log as much as possible */
8487 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
8488 osi_assertx(0, "invalid index");
8491 /* Link them together */
8492 NCBsessions[idx_NCB] = idx_session;
8495 ncbp = NCBs[idx_NCB];
8496 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
8497 ncbp->ncb_command = NCBRECV | ASYNCH;
8498 ncbp->ncb_lana_num = lanas[idx_session];
8499 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
8500 ncbp->ncb_event = NCBevents[idx_NCB];
8501 ncbp->ncb_length = SMB_PACKETSIZE;
8507 * The top level loop for handling SMB request messages. Each server thread
8508 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
8509 * NCB and buffer for the incoming request are loaned to us.
8511 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
8512 * to immediately send a request for the rest of the data. This must come
8513 * before any other traffic for that session, so we delay setting the session
8514 * event until that data has come in.
8516 void smb_Server(VOID *parmp)
8518 INT_PTR myIdx = (INT_PTR) parmp;
8522 smb_packet_t *outbufp;
8524 int idx_NCB, idx_session;
8526 smb_vc_t *vcp = NULL;
8528 extern void rx_StartClientThread(void);
8530 rx_StartClientThread();
8532 outncbp = smb_GetNCB();
8533 outbufp = smb_GetPacket();
8534 outbufp->ncbp = outncbp;
8542 smb_ResetServerPriority();
8544 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
8547 /* terminate silently if shutdown flag is set */
8548 if (code == WAIT_OBJECT_0) {
8549 if (smbShutdownFlag == 1) {
8550 thrd_SetEvent(smb_ServerShutdown[myIdx]);
8556 /* error checking */
8557 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8559 int abandonIdx = code - WAIT_ABANDONED_0;
8560 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
8563 if (code == WAIT_IO_COMPLETION)
8565 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
8569 if (code == WAIT_TIMEOUT)
8571 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
8574 if (code == WAIT_FAILED)
8576 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
8579 idx_NCB = code - WAIT_OBJECT_0;
8581 /* check idx range! */
8582 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
8584 /* this is fatal - log as much as possible */
8585 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
8586 osi_assertx(0, "invalid index");
8589 ncbp = NCBs[idx_NCB];
8590 idx_session = NCBsessions[idx_NCB];
8591 rc = ncbp->ncb_retcode;
8593 if (rc != NRC_PENDING && rc != NRC_GOODRET)
8594 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
8598 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8602 /* Can this happen? Or is it just my UNIX paranoia? */
8603 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
8608 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
8611 /* Client closed session */
8612 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8614 lock_ObtainMutex(&vcp->mx);
8615 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8616 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8618 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8619 lock_ReleaseMutex(&vcp->mx);
8620 lock_ObtainWrite(&smb_globalLock);
8621 dead_sessions[vcp->session] = TRUE;
8622 lock_ReleaseWrite(&smb_globalLock);
8624 lock_ReleaseMutex(&vcp->mx);
8626 smb_CleanupDeadVC(vcp);
8633 /* Treat as transient error */
8634 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
8637 "dispatch smb recv failed, message incomplete, ncb_length %d",
8640 "SMB message incomplete, "
8641 "length %d", ncbp->ncb_length);
8644 * We used to discard the packet.
8645 * Instead, try handling it normally.
8649 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8653 /* A weird error code. Log it, sleep, and continue. */
8654 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8656 lock_ObtainMutex(&vcp->mx);
8657 if (vcp->errorCount++ > 3) {
8658 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
8659 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8660 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8662 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8663 lock_ReleaseMutex(&vcp->mx);
8664 lock_ObtainWrite(&smb_globalLock);
8665 dead_sessions[vcp->session] = TRUE;
8666 lock_ReleaseWrite(&smb_globalLock);
8668 lock_ReleaseMutex(&vcp->mx);
8670 smb_CleanupDeadVC(vcp);
8676 lock_ReleaseMutex(&vcp->mx);
8680 thrd_SetEvent(SessionEvents[idx_session]);
8686 /* Success, so now dispatch on all the data in the packet */
8688 smb_concurrentCalls++;
8689 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
8690 smb_maxObsConcurrentCalls = smb_concurrentCalls;
8693 * If at this point vcp is NULL (implies that packet was invalid)
8694 * then we are in big trouble. This means either :
8695 * a) we have the wrong NCB.
8696 * b) Netbios screwed up the call.
8697 * c) The VC was already marked dead before we were able to
8699 * Obviously this implies that
8700 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
8701 * lanas[idx_session] != ncbp->ncb_lana_num )
8702 * Either way, we can't do anything with this packet.
8703 * Log, sleep and resume.
8706 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
8710 ncbp->ncb_lana_num);
8712 /* Also log in the trace log. */
8713 osi_Log4(smb_logp, "Server: VCP does not exist!"
8714 "LSNs[idx_session]=[%d],"
8715 "lanas[idx_session]=[%d],"
8716 "ncbp->ncb_lsn=[%d],"
8717 "ncbp->ncb_lana_num=[%d]",
8721 ncbp->ncb_lana_num);
8723 /* thrd_Sleep(1000); Don't bother sleeping */
8724 thrd_SetEvent(SessionEvents[idx_session]);
8725 smb_concurrentCalls--;
8729 smb_SetRequestStartTime();
8731 vcp->errorCount = 0;
8732 bufp = (struct smb_packet *) ncbp->ncb_buffer;
8733 smbp = (smb_t *)bufp->data;
8740 if (smbp->com == 0x1d) {
8741 /* Special handling for Write Raw */
8742 raw_write_cont_t rwc;
8743 EVENT_HANDLE rwevent;
8744 char eventName[MAX_PATH];
8746 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
8747 if (rwc.code == 0) {
8748 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
8749 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8750 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8751 ncbp->ncb_command = NCBRECV | ASYNCH;
8752 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
8753 ncbp->ncb_lana_num = vcp->lana;
8754 ncbp->ncb_buffer = rwc.buf;
8755 ncbp->ncb_length = 65535;
8756 ncbp->ncb_event = rwevent;
8758 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
8759 thrd_CloseHandle(rwevent);
8761 thrd_SetEvent(SessionEvents[idx_session]);
8763 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
8765 else if (smbp->com == 0xa0) {
8767 * Serialize the handling for NT Transact
8770 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
8771 thrd_SetEvent(SessionEvents[idx_session]);
8773 thrd_SetEvent(SessionEvents[idx_session]);
8774 /* TODO: what else needs to be serialized? */
8775 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
8779 __except( smb_ServerExceptionFilter() ) {
8783 smb_concurrentCalls--;
8786 thrd_SetEvent(NCBavails[idx_NCB]);
8791 smb_FreePacket(outbufp);
8793 smb_FreeNCB(outncbp);
8797 * Exception filter for the server threads. If an exception occurs in the
8798 * dispatch routines, which is where exceptions are most common, then do a
8799 * force trace and give control to upstream exception handlers. Useful for
8802 DWORD smb_ServerExceptionFilter(void) {
8803 /* While this is not the best time to do a trace, if it succeeds, then
8804 * we have a trace (assuming tracing was enabled). Otherwise, this should
8805 * throw a second exception.
8807 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
8808 afsd_ForceTrace(TRUE);
8809 buf_ForceTrace(TRUE);
8810 return EXCEPTION_CONTINUE_SEARCH;
8814 * Create a new NCB and associated events, packet buffer, and "space" buffer.
8815 * If the number of server threads is M, and the number of live sessions is
8816 * N, then the number of NCB's in use at any time either waiting for, or
8817 * holding, received messages is M + N, so that is how many NCB's get created.
8819 void InitNCBslot(int idx)
8821 struct smb_packet *bufp;
8822 EVENT_HANDLE retHandle;
8824 char eventName[MAX_PATH];
8826 osi_assertx( idx < (sizeof(NCBs) / sizeof(NCBs[0])), "invalid index" );
8828 NCBs[idx] = smb_GetNCB();
8829 sprintf(eventName,"NCBavails[%d]", idx);
8830 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8831 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8832 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8833 sprintf(eventName,"NCBevents[%d]", idx);
8834 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
8835 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8836 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8837 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
8838 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8839 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8840 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8841 for (i=0; i<smb_NumServerThreads; i++)
8842 NCBreturns[i][idx] = retHandle;
8843 bufp = smb_GetPacket();
8844 bufp->spacep = cm_GetSpace();
8848 /* listen for new connections */
8849 void smb_Listener(void *parmp)
8855 afs_uint32 session, thread;
8856 smb_vc_t *vcp = NULL;
8858 char rname[NCBNAMSZ+1];
8859 char cname[MAX_COMPUTERNAME_LENGTH+1];
8860 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
8861 INT_PTR lana = (INT_PTR) parmp;
8862 char eventName[MAX_PATH];
8863 int bridgeCount = 0;
8864 int nowildCount = 0;
8866 sprintf(eventName,"smb_Listener_lana_%d", (unsigned char)lana);
8867 ListenerShutdown[lana] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8868 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8869 thrd_ResetEvent(ListenerShutdown[lana]);
8871 ncbp = smb_GetNCB();
8873 /* retrieve computer name */
8874 GetComputerName(cname, &cnamelen);
8877 while (smb_ListenerState == SMB_LISTENER_STARTED) {
8878 memset(ncbp, 0, sizeof(NCB));
8881 ncbp->ncb_command = NCBLISTEN;
8882 ncbp->ncb_rto = 0; /* No receive timeout */
8883 ncbp->ncb_sto = 0; /* No send timeout */
8885 /* pad out with spaces instead of null termination */
8886 len = (long)strlen(smb_localNamep);
8887 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
8888 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
8890 strcpy(ncbp->ncb_callname, "*");
8891 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
8893 ncbp->ncb_lana_num = (UCHAR)lana;
8895 code = Netbios(ncbp);
8897 if (code == NRC_NAMERR) {
8898 /* An smb shutdown or Vista resume must have taken place */
8900 "NCBLISTEN lana=%d failed with NRC_NAMERR.",
8901 ncbp->ncb_lana_num);
8902 afsi_log("NCBLISTEN lana=%d failed with NRC_NAMERR.", ncbp->ncb_lana_num);
8904 if (lock_TryMutex(&smb_StartedLock)) {
8905 lana_list.lana[i] = LANA_INVALID;
8906 lock_ReleaseMutex(&smb_StartedLock);
8909 } else if (code == NRC_BRIDGE || code != 0) {
8910 int lanaRemaining = 0;
8912 if (code == NRC_BRIDGE) {
8913 if (++bridgeCount <= 5) {
8914 afsi_log("NCBLISTEN lana=%d failed with NRC_BRIDGE, retrying ...", ncbp->ncb_lana_num);
8917 } else if (code == NRC_NOWILD) {
8918 if (++nowildCount <= 5) {
8919 afsi_log("NCBLISTEN lana=%d failed with NRC_NOWILD, retrying ...", ncbp->ncb_lana_num);
8921 if (bridgeCount > 0) {
8922 memset(ncbp, 0, sizeof(*ncbp));
8923 ncbp->ncb_command = NCBADDNAME;
8924 ncbp->ncb_lana_num = (UCHAR)lana;
8925 /* pad out with spaces instead of null termination */
8926 len = (long)strlen(smb_localNamep);
8927 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
8928 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
8929 code = Netbios(ncbp);
8935 while (!lock_TryMutex(&smb_StartedLock)) {
8936 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
8942 "NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
8943 ncbp->ncb_lana_num, ncb_error_string(code));
8944 afsi_log("NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
8945 ncbp->ncb_lana_num, ncb_error_string(code));
8947 for (i = 0; i < lana_list.length; i++) {
8948 if (lana_list.lana[i] == lana) {
8949 smb_StopListener(ncbp, lana_list.lana[i], FALSE);
8950 lana_list.lana[i] = LANA_INVALID;
8952 if (lana_list.lana[i] != LANA_INVALID)
8956 if (lanaRemaining == 0) {
8957 cm_VolStatus_Network_Stopped(cm_NetbiosName
8962 smb_ListenerState = SMB_LISTENER_STOPPED;
8963 smb_LANadapter = LANA_INVALID;
8964 lana_list.length = 0;
8966 lock_ReleaseMutex(&smb_StartedLock);
8970 else if (code != 0) {
8971 char tbuffer[AFSPATHMAX];
8973 /* terminate silently if shutdown flag is set */
8974 while (!lock_TryMutex(&smb_StartedLock)) {
8975 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
8981 "NCBLISTEN lana=%d failed with code %d [%s]",
8982 ncbp->ncb_lana_num, code, ncb_error_string(code));
8984 "Client exiting due to network failure. Please restart client.\n");
8987 "Client exiting due to network failure. Please restart client.\n"
8988 "NCBLISTEN lana=%d failed with code %d [%s]",
8989 ncbp->ncb_lana_num, code, ncb_error_string(code));
8991 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
8992 MB_OK|MB_SERVICE_NOTIFICATION);
8993 osi_panic(tbuffer, __FILE__, __LINE__);
8995 lock_ReleaseMutex(&smb_StartedLock);
9000 /* a successful packet received. clear bridge error count */
9004 /* check for remote conns */
9005 /* first get remote name and insert null terminator */
9006 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
9007 for (i=NCBNAMSZ; i>0; i--) {
9008 if (rname[i-1] != ' ' && rname[i-1] != 0) {
9014 /* compare with local name */
9016 if (strncmp(rname, cname, NCBNAMSZ) != 0)
9017 flags |= SMB_VCFLAG_REMOTECONN;
9020 lock_ObtainMutex(&smb_ListenerLock);
9022 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
9023 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
9025 /* now ncbp->ncb_lsn is the connection ID */
9026 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
9027 if (vcp->session == 0) {
9028 /* New generation */
9029 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
9032 /* Log session startup */
9034 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9035 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9036 #endif /* NOTSERVICE */
9037 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9038 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9040 if (reportSessionStartups) {
9041 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9044 lock_ObtainMutex(&vcp->mx);
9045 cm_Utf8ToUtf16(rname, -1, vcp->rname, lengthof(vcp->rname));
9046 vcp->flags |= flags;
9047 lock_ReleaseMutex(&vcp->mx);
9049 /* Allocate slot in session arrays */
9050 /* Re-use dead session if possible, otherwise add one more */
9051 /* But don't look at session[0], it is reserved */
9052 lock_ObtainWrite(&smb_globalLock);
9053 for (session = 1; session < numSessions; session++) {
9054 if (dead_sessions[session]) {
9055 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
9056 dead_sessions[session] = FALSE;
9060 lock_ReleaseWrite(&smb_globalLock);
9062 /* We are re-using an existing VC because the lsn and lana
9064 session = vcp->session;
9066 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
9068 /* Log session startup */
9070 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9071 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9072 #endif /* NOTSERVICE */
9073 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9074 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9076 if (reportSessionStartups) {
9077 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9081 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
9082 unsigned long code = CM_ERROR_ALLBUSY;
9083 smb_packet_t * outp = smb_GetPacket();
9084 unsigned char *outWctp;
9087 smb_FormatResponsePacket(vcp, NULL, outp);
9090 if (vcp->flags & SMB_VCFLAG_STATUS32) {
9091 unsigned long NTStatus;
9092 smb_MapNTError(code, &NTStatus);
9093 outWctp = outp->wctp;
9094 smbp = (smb_t *) &outp->data;
9098 smbp->rcls = (unsigned char) (NTStatus & 0xff);
9099 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
9100 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
9101 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
9102 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9104 unsigned short errCode;
9105 unsigned char errClass;
9106 smb_MapCoreError(code, vcp, &errCode, &errClass);
9107 outWctp = outp->wctp;
9108 smbp = (smb_t *) &outp->data;
9112 smbp->errLow = (unsigned char) (errCode & 0xff);
9113 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
9114 smbp->rcls = errClass;
9117 smb_SendPacket(vcp, outp);
9118 smb_FreePacket(outp);
9120 lock_ObtainMutex(&vcp->mx);
9121 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9122 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9124 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9125 lock_ReleaseMutex(&vcp->mx);
9126 lock_ObtainWrite(&smb_globalLock);
9127 dead_sessions[vcp->session] = TRUE;
9128 lock_ReleaseWrite(&smb_globalLock);
9129 smb_CleanupDeadVC(vcp);
9131 lock_ReleaseMutex(&vcp->mx);
9134 /* assert that we do not exceed the maximum number of sessions or NCBs.
9135 * we should probably want to wait for a session to be freed in case
9138 osi_assertx(session < SESSION_MAX - 1, "invalid session");
9139 osi_assertx(numNCBs < NCB_MAX - 1, "invalid numNCBs"); /* if we pass this test we can allocate one more */
9141 lock_ObtainMutex(&vcp->mx);
9142 vcp->session = session;
9143 lock_ReleaseMutex(&vcp->mx);
9144 lock_ObtainWrite(&smb_globalLock);
9145 LSNs[session] = ncbp->ncb_lsn;
9146 lanas[session] = ncbp->ncb_lana_num;
9147 lock_ReleaseWrite(&smb_globalLock);
9149 if (session == numSessions) {
9150 /* Add new NCB for new session */
9151 char eventName[MAX_PATH];
9153 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
9155 InitNCBslot(numNCBs);
9156 lock_ObtainWrite(&smb_globalLock);
9158 lock_ReleaseWrite(&smb_globalLock);
9159 thrd_SetEvent(NCBavails[0]);
9160 thrd_SetEvent(NCBevents[0]);
9161 for (thread = 0; thread < smb_NumServerThreads; thread++)
9162 thrd_SetEvent(NCBreturns[thread][0]);
9163 /* Also add new session event */
9164 sprintf(eventName, "SessionEvents[%d]", session);
9165 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9166 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9167 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9168 lock_ObtainWrite(&smb_globalLock);
9170 lock_ReleaseWrite(&smb_globalLock);
9171 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
9172 thrd_SetEvent(SessionEvents[0]);
9174 thrd_SetEvent(SessionEvents[session]);
9180 lock_ReleaseMutex(&smb_ListenerLock);
9181 } /* dispatch while loop */
9185 thrd_SetEvent(ListenerShutdown[lana]);
9190 smb_LanAdapterChangeThread(void *param)
9193 * Give the IPAddrDaemon thread a chance
9194 * to block before we trigger.
9197 smb_LanAdapterChange(0);
9200 void smb_SetLanAdapterChangeDetected(void)
9205 lock_ObtainMutex(&smb_StartedLock);
9207 if (!powerStateSuspended) {
9208 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_LanAdapterChangeThread,
9209 NULL, 0, &lpid, "smb_LanAdapterChange");
9210 osi_assertx(phandle != NULL, "smb_LanAdapterChangeThread thread creation failure");
9211 thrd_CloseHandle(phandle);
9214 smb_LanAdapterChangeDetected = 1;
9215 lock_ReleaseMutex(&smb_StartedLock);
9218 void smb_LanAdapterChange(int locked) {
9219 lana_number_t lanaNum;
9221 char NetbiosName[MAX_NB_NAME_LENGTH] = "";
9223 LANA_ENUM temp_list;
9228 afsi_log("smb_LanAdapterChange");
9231 lock_ObtainMutex(&smb_StartedLock);
9233 smb_LanAdapterChangeDetected = 0;
9235 if (!powerStateSuspended &&
9236 SUCCEEDED(lana_GetUncServerNameEx(NetbiosName, &lanaNum, &bGateway,
9237 LANA_NETBIOS_NAME_FULL)) &&
9238 lanaNum != LANA_INVALID && smb_LANadapter != lanaNum) {
9239 if ( isGateway != bGateway ) {
9240 afsi_log("Lan Adapter Change detected (%d != %d): gateway %d != %d",
9241 smb_LANadapter, lanaNum, isGateway, bGateway);
9243 } else if (strcmp(cm_NetbiosName, NetbiosName) ) {
9244 afsi_log("Lan Adapter Change detected (%d != %d): name %s != %s",
9245 smb_LANadapter, lanaNum, cm_NetbiosName, NetbiosName);
9248 NCB *ncbp = smb_GetNCB();
9249 ncbp->ncb_command = NCBENUM;
9250 ncbp->ncb_buffer = (PUCHAR)&temp_list;
9251 ncbp->ncb_length = sizeof(temp_list);
9252 code = Netbios(ncbp);
9254 if (temp_list.length != lana_list.length) {
9255 afsi_log("Lan Adapter Change detected (%d != %d): lan list length changed %d != %d",
9256 smb_LANadapter, lanaNum, temp_list.length, lana_list.length);
9259 for (i=0; i<lana_list.length; i++) {
9260 if ( temp_list.lana[i] != lana_list.lana[i] ) {
9261 afsi_log("Lan Adapter Change detected (%d != %d): lana[%d] %d != %d",
9262 smb_LANadapter, lanaNum, i, temp_list.lana[i], lana_list.lana[i]);
9274 smb_StopListeners(1);
9275 smb_RestartListeners(1);
9278 lock_ReleaseMutex(&smb_StartedLock);
9281 /* initialize Netbios */
9282 int smb_NetbiosInit(int locked)
9285 int i, lana, code, l;
9287 int delname_tried=0;
9290 lana_number_t lanaNum;
9293 lock_ObtainMutex(&smb_StartedLock);
9295 if (smb_ListenerState != SMB_LISTENER_UNINITIALIZED &&
9296 smb_ListenerState != SMB_LISTENER_STOPPED) {
9299 lock_ReleaseMutex(&smb_StartedLock);
9302 /* setup the NCB system */
9303 ncbp = smb_GetNCB();
9305 /* Call lanahelper to get Netbios name, lan adapter number and gateway flag */
9306 if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
9307 smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
9309 if (smb_LANadapter != LANA_INVALID)
9310 afsi_log("LAN adapter number %d", smb_LANadapter);
9312 afsi_log("LAN adapter number not determined");
9315 afsi_log("Set for gateway service");
9317 afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
9319 /* something went horribly wrong. We can't proceed without a netbios name */
9321 StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
9322 osi_panic(buf, __FILE__, __LINE__);
9325 /* remember the name */
9326 len = (int)strlen(cm_NetbiosName);
9328 free(smb_localNamep);
9329 smb_localNamep = malloc(len+1);
9330 strcpy(smb_localNamep, cm_NetbiosName);
9331 afsi_log("smb_localNamep is >%s<", smb_localNamep);
9333 /* Also copy the value to the client character encoded string */
9334 cm_Utf8ToClientString(cm_NetbiosName, -1, cm_NetbiosNameC, MAX_NB_NAME_LENGTH);
9336 if (smb_LANadapter == LANA_INVALID) {
9337 ncbp->ncb_command = NCBENUM;
9338 ncbp->ncb_buffer = (PUCHAR)&lana_list;
9339 ncbp->ncb_length = sizeof(lana_list);
9340 code = Netbios(ncbp);
9342 afsi_log("Netbios NCBENUM error code %d", code);
9343 osi_panic(s, __FILE__, __LINE__);
9347 lana_list.length = 1;
9348 lana_list.lana[0] = smb_LANadapter;
9351 for (i = 0; i < lana_list.length; i++) {
9352 /* reset the adaptor: in Win32, this is required for every process, and
9353 * acts as an init call, not as a real hardware reset.
9355 ncbp->ncb_command = NCBRESET;
9356 ncbp->ncb_callname[0] = 100;
9357 ncbp->ncb_callname[2] = 100;
9358 ncbp->ncb_lana_num = lana_list.lana[i];
9359 code = Netbios(ncbp);
9361 code = ncbp->ncb_retcode;
9363 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
9364 lana_list.lana[i] = LANA_INVALID; /* invalid lana */
9366 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
9370 /* and declare our name so we can receive connections */
9371 memset(ncbp, 0, sizeof(*ncbp));
9372 len=lstrlen(smb_localNamep);
9373 memset(smb_sharename,' ',NCBNAMSZ);
9374 memcpy(smb_sharename,smb_localNamep,len);
9375 afsi_log("lana_list.length %d", lana_list.length);
9377 /* Keep the name so we can unregister it later */
9378 for (l = 0; l < lana_list.length; l++) {
9379 lana = lana_list.lana[l];
9381 ncbp->ncb_command = NCBADDNAME;
9382 ncbp->ncb_lana_num = lana;
9383 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9384 code = Netbios(ncbp);
9386 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
9387 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
9389 char name[NCBNAMSZ+1];
9391 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
9392 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
9396 code = ncbp->ncb_retcode;
9399 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
9402 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
9403 if (code == NRC_BRIDGE) { /* invalid LANA num */
9404 lana_list.lana[l] = LANA_INVALID;
9407 else if (code == NRC_DUPNAME) {
9408 afsi_log("Name already exists; try to delete it");
9409 memset(ncbp, 0, sizeof(*ncbp));
9410 ncbp->ncb_command = NCBDELNAME;
9411 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9412 ncbp->ncb_lana_num = lana;
9413 code = Netbios(ncbp);
9415 code = ncbp->ncb_retcode;
9417 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
9419 if (code != 0 || delname_tried) {
9420 lana_list.lana[l] = LANA_INVALID;
9422 else if (code == 0) {
9423 if (!delname_tried) {
9431 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
9432 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
9436 smb_LANadapter = lana;
9437 lana_found = 1; /* at least one worked */
9441 osi_assertx(lana_list.length >= 0, "empty lana list");
9443 afsi_log("No valid LANA numbers found!");
9444 lana_list.length = 0;
9445 smb_LANadapter = LANA_INVALID;
9446 smb_ListenerState = SMB_LISTENER_STOPPED;
9447 cm_VolStatus_Network_Stopped(cm_NetbiosName
9454 /* we're done with the NCB now */
9457 afsi_log("smb_NetbiosInit smb_LANadapter=%d",smb_LANadapter);
9458 if (lana_list.length > 0)
9459 osi_assert(smb_LANadapter != LANA_INVALID);
9462 lock_ReleaseMutex(&smb_StartedLock);
9464 return (lana_list.length > 0 ? 1 : 0);
9467 void smb_StartListeners(int locked)
9474 lock_ObtainMutex(&smb_StartedLock);
9476 if (smb_ListenerState == SMB_LISTENER_STARTED) {
9478 lock_ReleaseMutex(&smb_StartedLock);
9482 afsi_log("smb_StartListeners");
9483 smb_ListenerState = SMB_LISTENER_STARTED;
9484 cm_VolStatus_Network_Started(cm_NetbiosName
9490 for (i = 0; i < lana_list.length; i++) {
9491 if (lana_list.lana[i] == LANA_INVALID)
9493 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
9494 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
9495 osi_assertx(phandle != NULL, "smb_Listener thread creation failure");
9496 thrd_CloseHandle(phandle);
9499 lock_ReleaseMutex(&smb_StartedLock);
9502 void smb_RestartListeners(int locked)
9505 lock_ObtainMutex(&smb_StartedLock);
9507 if (powerStateSuspended)
9508 afsi_log("smb_RestartListeners called while suspended");
9510 if (!powerStateSuspended && smb_ListenerState != SMB_LISTENER_UNINITIALIZED) {
9511 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
9512 if (smb_NetbiosInit(1))
9513 smb_StartListeners(1);
9514 } else if (smb_LanAdapterChangeDetected) {
9515 smb_LanAdapterChange(1);
9519 lock_ReleaseMutex(&smb_StartedLock);
9522 void smb_StopListener(NCB *ncbp, int lana, int wait)
9526 memset(ncbp, 0, sizeof(*ncbp));
9527 ncbp->ncb_command = NCBDELNAME;
9528 ncbp->ncb_lana_num = lana;
9529 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9530 code = Netbios(ncbp);
9532 afsi_log("StopListener: Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
9533 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
9535 /* and then reset the LANA; this will cause the listener threads to exit */
9536 ncbp->ncb_command = NCBRESET;
9537 ncbp->ncb_callname[0] = 100;
9538 ncbp->ncb_callname[2] = 100;
9539 ncbp->ncb_lana_num = lana;
9540 code = Netbios(ncbp);
9542 code = ncbp->ncb_retcode;
9544 afsi_log("StopListener: Netbios NCBRESET lana %d error code %d", lana, code);
9546 afsi_log("StopListener: Netbios NCBRESET lana %d succeeded", lana);
9550 thrd_WaitForSingleObject_Event(ListenerShutdown[lana], INFINITE);
9553 void smb_StopListeners(int locked)
9559 lock_ObtainMutex(&smb_StartedLock);
9561 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
9563 lock_ReleaseMutex(&smb_StartedLock);
9567 afsi_log("smb_StopListeners");
9568 smb_ListenerState = SMB_LISTENER_STOPPED;
9569 cm_VolStatus_Network_Stopped(cm_NetbiosName
9575 ncbp = smb_GetNCB();
9577 /* Unregister the SMB name */
9578 for (l = 0; l < lana_list.length; l++) {
9579 lana = lana_list.lana[l];
9581 if (lana != LANA_INVALID) {
9582 smb_StopListener(ncbp, lana, TRUE);
9584 /* mark the adapter invalid */
9585 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
9589 /* force a re-evaluation of the network adapters */
9590 lana_list.length = 0;
9591 smb_LANadapter = LANA_INVALID;
9594 lock_ReleaseMutex(&smb_StartedLock);
9597 void smb_Init(osi_log_t *logp, int useV3,
9607 EVENT_HANDLE retHandle;
9608 char eventName[MAX_PATH];
9609 int startListeners = 0;
9611 smb_TlsRequestSlot = TlsAlloc();
9613 smb_MBfunc = aMBfunc;
9617 /* Initialize smb_localZero */
9618 myTime.tm_isdst = -1; /* compute whether on DST or not */
9619 myTime.tm_year = 70;
9625 smb_localZero = mktime(&myTime);
9627 #ifndef USE_NUMERIC_TIME_CONV
9628 /* Initialize kludge-GMT */
9629 smb_CalculateNowTZ();
9630 #endif /* USE_NUMERIC_TIME_CONV */
9631 #ifdef AFS_FREELANCE_CLIENT
9632 /* Make sure the root.afs volume has the correct time */
9633 cm_noteLocalMountPointChange();
9636 /* initialize the remote debugging log */
9639 /* and the global lock */
9640 lock_InitializeRWLock(&smb_globalLock, "smb global lock", LOCK_HIERARCHY_SMB_GLOBAL);
9641 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock", LOCK_HIERARCHY_SMB_RCT_GLOBAL);
9643 /* Raw I/O data structures */
9644 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock", LOCK_HIERARCHY_SMB_RAWBUF);
9646 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock", LOCK_HIERARCHY_SMB_LISTENER);
9647 lock_InitializeMutex(&smb_StartedLock, "smb started lock", LOCK_HIERARCHY_SMB_STARTED);
9649 /* 4 Raw I/O buffers */
9650 smb_RawBufs = calloc(65536,1);
9651 *((char **)smb_RawBufs) = NULL;
9652 for (i=0; i<3; i++) {
9653 char *rawBuf = calloc(65536,1);
9654 *((char **)rawBuf) = smb_RawBufs;
9655 smb_RawBufs = rawBuf;
9658 /* global free lists */
9659 smb_ncbFreeListp = NULL;
9660 smb_packetFreeListp = NULL;
9662 lock_ObtainMutex(&smb_StartedLock);
9663 startListeners = smb_NetbiosInit(1);
9665 /* Initialize listener and server structures */
9667 memset(dead_sessions, 0, sizeof(dead_sessions));
9668 sprintf(eventName, "SessionEvents[0]");
9669 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9670 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9671 afsi_log("Event Object Already Exists: %s", eventName);
9673 smb_NumServerThreads = nThreads;
9674 sprintf(eventName, "NCBavails[0]");
9675 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9676 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9677 afsi_log("Event Object Already Exists: %s", eventName);
9678 sprintf(eventName, "NCBevents[0]");
9679 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9680 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9681 afsi_log("Event Object Already Exists: %s", eventName);
9682 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
9683 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
9684 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9685 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9686 afsi_log("Event Object Already Exists: %s", eventName);
9687 for (i = 0; i < smb_NumServerThreads; i++) {
9688 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
9689 NCBreturns[i][0] = retHandle;
9692 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
9693 for (i = 0; i < smb_NumServerThreads; i++) {
9694 sprintf(eventName, "smb_ServerShutdown[%d]", i);
9695 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9696 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9697 afsi_log("Event Object Already Exists: %s", eventName);
9698 InitNCBslot((int)(i+1));
9700 numNCBs = smb_NumServerThreads + 1;
9702 /* Initialize dispatch table */
9703 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
9704 /* Prepare the table for unknown operations */
9705 for(i=0; i<= SMB_NOPCODES; i++) {
9706 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
9708 /* Fill in the ones we do know */
9709 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
9710 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
9711 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
9712 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
9713 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
9714 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
9715 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
9716 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
9717 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
9718 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
9719 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
9720 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
9721 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
9722 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
9723 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
9724 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
9725 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
9726 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
9727 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
9728 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
9729 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
9730 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9731 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
9732 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
9733 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
9734 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
9735 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
9736 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
9737 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9738 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
9739 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9740 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
9741 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
9742 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
9743 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9744 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
9745 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
9746 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
9747 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
9748 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
9749 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
9750 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
9751 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9752 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
9753 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9754 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
9755 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
9756 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
9757 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
9758 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
9759 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
9760 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
9761 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
9762 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
9763 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
9764 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
9765 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
9766 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
9767 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
9768 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
9769 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
9770 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
9771 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
9772 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
9773 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
9774 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9775 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
9776 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
9777 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
9778 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
9779 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
9780 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
9781 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
9782 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
9784 /* setup tran 2 dispatch table */
9785 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
9786 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
9787 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
9788 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
9789 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
9790 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
9791 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
9792 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
9793 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
9794 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
9795 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
9796 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
9797 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
9798 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
9799 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
9800 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
9801 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
9802 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
9804 /* setup the rap dispatch table */
9805 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
9806 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
9807 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
9808 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
9809 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
9813 /* if we are doing SMB authentication we have register outselves as a logon process */
9814 if (smb_authType != SMB_AUTH_NONE) {
9815 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
9816 LSA_STRING afsProcessName;
9817 LSA_OPERATIONAL_MODE dummy; /*junk*/
9819 afsProcessName.Buffer = "OpenAFSClientDaemon";
9820 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
9821 afsProcessName.MaximumLength = afsProcessName.Length + 1;
9823 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
9825 if (nts == STATUS_SUCCESS) {
9826 LSA_STRING packageName;
9827 /* we are registered. Find out the security package id */
9828 packageName.Buffer = MSV1_0_PACKAGE_NAME;
9829 packageName.Length = (USHORT)strlen(packageName.Buffer);
9830 packageName.MaximumLength = packageName.Length + 1;
9831 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
9832 if (nts == STATUS_SUCCESS) {
9834 * This code forces Windows to authenticate against the Logon Cache
9835 * first instead of attempting to authenticate against the Domain
9836 * Controller. When the Windows logon cache is enabled this improves
9837 * performance by removing the network access and works around a bug
9838 * seen at sites which are using a MIT Kerberos principal to login
9839 * to machines joined to a non-root domain in a multi-domain forest.
9840 * MsV1_0SetProcessOption was added in Windows XP.
9842 PVOID pResponse = NULL;
9843 ULONG cbResponse = 0;
9844 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
9846 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
9847 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
9848 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
9849 OptionsRequest.DisableOptions = FALSE;
9851 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
9854 sizeof(OptionsRequest),
9860 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
9861 char message[AFSPATHMAX];
9862 sprintf(message,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
9864 OutputDebugString(message);
9867 OutputDebugString("MsV1_0SetProcessOption success");
9868 afsi_log("MsV1_0SetProcessOption success");
9870 /* END - code from Larry */
9872 smb_lsaLogonOrigin.Buffer = "OpenAFS";
9873 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
9874 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
9876 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
9878 /* something went wrong. We report the error and revert back to no authentication
9879 because we can't perform any auth requests without a successful lsa handle
9880 or sec package id. */
9881 afsi_log("Reverting to NO SMB AUTH");
9882 smb_authType = SMB_AUTH_NONE;
9885 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
9887 /* something went wrong. We report the error and revert back to no authentication
9888 because we can't perform any auth requests without a successful lsa handle
9889 or sec package id. */
9890 afsi_log("Reverting to NO SMB AUTH");
9891 smb_authType = SMB_AUTH_NONE;
9895 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
9896 * time prevents the failure of authentication when logged into Windows with an
9897 * external Kerberos principal mapped to a local account.
9899 else if ( smb_authType == SMB_AUTH_EXTENDED) {
9900 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
9901 * then the only option is NTLMSSP anyway; so just fallback.
9906 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
9907 if (secBlobLength == 0) {
9908 smb_authType = SMB_AUTH_NTLM;
9909 afsi_log("Reverting to SMB AUTH NTLM");
9918 /* Now get ourselves a domain name. */
9919 /* For now we are using the local computer name as the domain name.
9920 * It is actually the domain for local logins, and we are acting as
9921 * a local SMB server.
9923 bufsize = lengthof(smb_ServerDomainName) - 1;
9924 GetComputerNameW(smb_ServerDomainName, &bufsize);
9925 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
9926 afsi_log("Setting SMB server domain name to [%S]", smb_ServerDomainName);
9929 /* Start listeners, waiters, servers, and daemons */
9931 smb_StartListeners(1);
9933 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
9934 NULL, 0, &lpid, "smb_ClientWaiter");
9935 osi_assertx(phandle != NULL, "smb_ClientWaiter thread creation failure");
9936 thrd_CloseHandle(phandle);
9938 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
9939 NULL, 0, &lpid, "smb_ServerWaiter");
9940 osi_assertx(phandle != NULL, "smb_ServerWaiter thread creation failure");
9941 thrd_CloseHandle(phandle);
9943 for (i=0; i<smb_NumServerThreads; i++) {
9944 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
9945 (void *) i, 0, &lpid, "smb_Server");
9946 osi_assertx(phandle != NULL, "smb_Server thread creation failure");
9947 thrd_CloseHandle(phandle);
9950 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
9951 NULL, 0, &lpid, "smb_Daemon");
9952 osi_assertx(phandle != NULL, "smb_Daemon thread creation failure");
9953 thrd_CloseHandle(phandle);
9955 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
9956 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
9957 osi_assertx(phandle != NULL, "smb_WaitingLocksDaemon thread creation failure");
9958 thrd_CloseHandle(phandle);
9960 lock_ReleaseMutex(&smb_StartedLock);
9964 void smb_Shutdown(void)
9971 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
9973 /* setup the NCB system */
9974 ncbp = smb_GetNCB();
9976 /* Block new sessions by setting shutdown flag */
9977 smbShutdownFlag = 1;
9979 /* Hang up all sessions */
9980 memset((char *)ncbp, 0, sizeof(NCB));
9981 for (i = 1; i < numSessions; i++)
9983 if (dead_sessions[i])
9986 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
9987 ncbp->ncb_command = NCBHANGUP;
9988 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
9989 ncbp->ncb_lsn = (UCHAR)LSNs[i];
9990 code = Netbios(ncbp);
9991 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
9992 if (code == 0) code = ncbp->ncb_retcode;
9994 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
9995 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
9999 /* Trigger the shutdown of all SMB threads */
10000 for (i = 0; i < smb_NumServerThreads; i++)
10001 thrd_SetEvent(NCBreturns[i][0]);
10003 thrd_SetEvent(NCBevents[0]);
10004 thrd_SetEvent(SessionEvents[0]);
10005 thrd_SetEvent(NCBavails[0]);
10007 for (i = 0;i < smb_NumServerThreads; i++) {
10008 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
10009 if (code == WAIT_OBJECT_0) {
10012 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
10013 thrd_SetEvent(NCBreturns[i--][0]);
10017 /* Delete Netbios name */
10018 memset((char *)ncbp, 0, sizeof(NCB));
10019 for (i = 0; i < lana_list.length; i++) {
10020 if (lana_list.lana[i] == LANA_INVALID) continue;
10021 ncbp->ncb_command = NCBDELNAME;
10022 ncbp->ncb_lana_num = lana_list.lana[i];
10023 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10024 code = Netbios(ncbp);
10026 code = ncbp->ncb_retcode;
10028 fprintf(stderr, "Shutdown: Netbios NCBDELNAME lana %d error code %d",
10029 ncbp->ncb_lana_num, code);
10034 /* Release the reference counts held by the VCs */
10035 lock_ObtainWrite(&smb_rctLock);
10036 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
10041 if (vcp->magic != SMB_VC_MAGIC)
10042 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
10043 __FILE__, __LINE__);
10045 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10047 if (fidp->scp != NULL) {
10050 lock_ReleaseWrite(&smb_rctLock);
10051 lock_ObtainMutex(&fidp->mx);
10052 if (fidp->scp != NULL) {
10055 lock_ObtainWrite(&scp->rw);
10056 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
10057 lock_ReleaseWrite(&scp->rw);
10058 osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
10059 cm_ReleaseSCache(scp);
10061 lock_ReleaseMutex(&fidp->mx);
10062 lock_ObtainWrite(&smb_rctLock);
10066 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10068 smb_ReleaseVCNoLock(tidp->vcp);
10070 cm_user_t *userp = tidp->userp;
10071 tidp->userp = NULL;
10072 cm_ReleaseUser(userp);
10076 lock_ReleaseWrite(&smb_rctLock);
10078 TlsFree(smb_TlsRequestSlot);
10081 /* Get the UNC \\<servername>\<sharename> prefix. */
10082 char *smb_GetSharename()
10087 /* Make sure we have been properly initialized. */
10088 if (smb_localNamep == NULL)
10091 /* Allocate space for \\<servername>\<sharename>, plus the
10094 len = (strlen(smb_localNamep) + strlen("ALL") + 4) * sizeof(char);
10095 name = malloc(len);
10096 snprintf(name, len, "\\\\%s\\%s", smb_localNamep, "ALL");
10102 void smb_LogPacket(smb_packet_t *packet)
10106 unsigned length, paramlen, datalen, i, j;
10108 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
10110 if (!packet) return;
10112 osi_Log0(smb_logp, "*** SMB packet dump ***");
10114 smbp = (smb_t *) packet->data;
10115 vp = (BYTE *) packet->data;
10117 paramlen = smbp->wct * 2;
10118 datalen = *((WORD *) (smbp->vdata + paramlen));
10119 length = sizeof(*smbp) + paramlen + 1 + datalen;
10121 for (i=0;i < length; i+=16)
10123 memset( buf, ' ', 80 );
10126 itoa( i, buf, 16 );
10128 buf[strlen(buf)] = ' ';
10130 cp = (BYTE*) buf + 7;
10132 for (j=0;j < 16 && (i+j)<length; j++)
10134 *(cp++) = hex[vp[i+j] >> 4];
10135 *(cp++) = hex[vp[i+j] & 0xf];
10145 for (j=0;j < 16 && (i+j)<length;j++)
10147 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
10158 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
10161 osi_Log0(smb_logp, "*** End SMB packet dump ***");
10163 #endif /* LOG_PACKET */
10166 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
10172 smb_username_t *unp;
10173 smb_waitingLockRequest_t *wlrp;
10176 lock_ObtainRead(&smb_rctLock);
10178 sprintf(output, "begin dumping smb_username_t\r\n");
10179 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10180 for (unp = usernamesp; unp; unp=unp->nextp)
10182 cm_ucell_t *ucellp;
10184 sprintf(output, "%s -- smb_unp=0x%p, refCount=%d, cm_userp=0x%p, flags=0x%x, logoff=%u, name=%S, machine=%S\r\n",
10185 cookie, unp, unp->refCount, unp->userp, unp->flags, unp->last_logoff_t,
10186 unp->name ? unp->name : _C("NULL"),
10187 unp->machine ? unp->machine : _C("NULL"));
10188 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10190 sprintf(output, " begin dumping cm_ucell_t\r\n");
10191 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10193 for ( ucellp = unp->userp->cellInfop; ucellp; ucellp = ucellp->nextp ) {
10194 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",
10195 cookie, ucellp, ucellp->cellp, ucellp->flags, ucellp->ticketLen, ucellp->kvno,
10196 ucellp->expirationTime, ucellp->gen,
10198 ucellp->cellp->name);
10199 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10202 sprintf(output, " done dumping cm_ucell_t\r\n");
10203 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10206 sprintf(output, "done dumping smb_username_t\r\n");
10207 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10210 sprintf(output, "begin dumping smb_waitingLockRequest_t\r\n");
10211 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10214 for ( wlrp = smb_allWaitingLocks; wlrp; wlrp = (smb_waitingLockRequest_t *) osi_QNext(&wlrp->q)) {
10215 smb_waitingLock_t *lockp;
10217 sprintf(output, "%s wlrp=0x%p vcp=0x%p, scp=0x%p, type=0x%x, start_t=0x%I64u msTimeout=0x%x\r\n",
10218 cookie, wlrp, wlrp->vcp, wlrp->scp, wlrp->lockType, wlrp->start_t, wlrp->msTimeout);
10219 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10221 sprintf(output, " begin dumping smb_waitingLock_t\r\n");
10222 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10223 for (lockp = wlrp->locks; lockp; lockp = (smb_waitingLock_t *) osi_QNext(&lockp->q)) {
10224 sprintf(output, " %s -- waitlockp=0x%p lockp=0x%p key=0x%I64x offset=0x%I64x length=0x%I64x state=0x%x\r\n",
10225 cookie, lockp, lockp->lockp, lockp->key, lockp->LOffset.QuadPart, lockp->LLength.QuadPart, lockp->state);
10226 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10228 sprintf(output, " done dumping smb_waitingLock_t\r\n");
10229 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10232 sprintf(output, "done dumping smb_waitingLockRequest_t\r\n");
10233 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10235 sprintf(output, "begin dumping smb_vc_t\r\n");
10236 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10238 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
10244 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
10245 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
10246 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10248 sprintf(output, " begin dumping smb_user_t\r\n");
10249 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10250 for (userp = vcp->usersp; userp; userp = userp->nextp) {
10251 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
10252 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
10253 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10255 sprintf(output, " done dumping smb_user_t\r\n");
10256 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10258 sprintf(output, " begin dumping smb_tid_t\r\n");
10259 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10260 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10261 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",
10262 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
10263 tidp->pathname ? tidp->pathname : _C("NULL"));
10264 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10266 sprintf(output, " done dumping smb_tid_t\r\n");
10267 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10269 sprintf(output, " begin dumping smb_fid_t\r\n");
10270 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10272 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10274 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",
10275 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
10276 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
10277 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
10278 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10281 sprintf(output, " done dumping smb_fid_t\r\n");
10282 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10285 sprintf(output, "done dumping smb_vc_t\r\n");
10286 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10288 sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
10289 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10291 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
10297 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
10298 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
10299 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10301 sprintf(output, " begin dumping smb_user_t\r\n");
10302 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10303 for (userp = vcp->usersp; userp; userp = userp->nextp) {
10304 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
10305 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
10306 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10308 sprintf(output, " done dumping smb_user_t\r\n");
10309 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10311 sprintf(output, " begin dumping smb_tid_t\r\n");
10312 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10313 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10314 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",
10315 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
10316 tidp->pathname ? tidp->pathname : _C("NULL"));
10317 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10319 sprintf(output, " done dumping smb_tid_t\r\n");
10320 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10322 sprintf(output, " begin dumping smb_fid_t\r\n");
10323 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10325 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10327 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",
10328 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
10329 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
10330 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
10331 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10334 sprintf(output, " done dumping smb_fid_t\r\n");
10335 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10338 sprintf(output, "done dumping DEAD smb_vc_t\r\n");
10339 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10342 lock_ReleaseRead(&smb_rctLock);
10346 long smb_IsNetworkStarted(void)
10349 lock_ObtainWrite(&smb_globalLock);
10350 rc = (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);
10351 lock_ReleaseWrite(&smb_globalLock);