2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afs/param.h>
15 #pragma warning(disable: 4005)
28 #include <rx/rx_prototypes.h>
29 #include <WINNT\afsreg.h>
32 #include "lanahelper.h"
34 #define STRSAFE_NO_DEPRECATE
37 /* These characters are illegal in Windows filenames */
38 static clientchar_t *illegalChars = _C("\\/:*?\"<>|");
40 static int smbShutdownFlag = 0;
41 static int smb_ListenerState = SMB_LISTENER_UNINITIALIZED;
43 int smb_LogoffTokenTransfer;
44 time_t smb_LogoffTransferTimeout;
46 int smb_StoreAnsiFilenames = 0;
48 DWORD last_msg_time = 0;
52 unsigned int sessionGen = 0;
54 extern void afsi_log(char *pattern, ...);
55 extern HANDLE afsi_file;
56 extern int powerStateSuspended;
58 osi_hyper_t hzero = {0, 0};
59 osi_hyper_t hones = {0xFFFFFFFF, -1};
62 osi_rwlock_t smb_globalLock;
63 osi_rwlock_t smb_rctLock;
64 osi_mutex_t smb_ListenerLock;
65 osi_mutex_t smb_StartedLock;
67 unsigned char smb_LANadapter = LANA_INVALID;
68 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
69 int smb_LanAdapterChangeDetected = 0;
70 afs_uint32 smb_AsyncStore = 1;
71 afs_uint32 smb_AsyncStoreSize = CM_CONFIGDEFAULT_ASYNCSTORESIZE;
73 BOOL isGateway = FALSE;
76 long smb_maxObsConcurrentCalls=0;
77 long smb_concurrentCalls=0;
79 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
81 smb_packet_t *smb_packetFreeListp;
82 smb_ncb_t *smb_ncbFreeListp;
84 afs_uint32 smb_NumServerThreads;
86 afs_uint32 numNCBs, numSessions, numVCs;
88 int smb_maxVCPerServer;
89 int smb_maxMpxRequests;
91 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
93 ULONG smb_lsaSecPackage;
94 LSA_STRING smb_lsaLogonOrigin;
96 #define NCB_MAX MAXIMUM_WAIT_OBJECTS
97 EVENT_HANDLE NCBavails[NCB_MAX], NCBevents[NCB_MAX];
98 EVENT_HANDLE **NCBreturns;
99 EVENT_HANDLE **NCBShutdown;
100 EVENT_HANDLE *smb_ServerShutdown;
101 EVENT_HANDLE ListenerShutdown[256];
102 DWORD NCBsessions[NCB_MAX];
104 struct smb_packet *bufs[NCB_MAX];
106 #define SESSION_MAX MAXIMUM_WAIT_OBJECTS - 4
107 EVENT_HANDLE SessionEvents[SESSION_MAX];
108 unsigned short LSNs[SESSION_MAX];
109 int lanas[SESSION_MAX];
110 BOOL dead_sessions[SESSION_MAX];
113 osi_mutex_t smb_RawBufLock;
116 #define SMB_MASKFLAG_TILDE 1
117 #define SMB_MASKFLAG_CASEFOLD 2
119 #define RAWTIMEOUT INFINITE
122 typedef struct raw_write_cont {
131 /* dir search stuff */
132 long smb_dirSearchCounter = 1;
133 smb_dirSearch_t *smb_firstDirSearchp;
134 smb_dirSearch_t *smb_lastDirSearchp;
136 /* hide dot files? */
137 int smb_hideDotFiles;
139 /* Negotiate Unicode support? */
142 /* global state about V3 protocols */
143 int smb_useV3; /* try to negotiate V3 */
145 static int showErrors = 0;
146 /* MessageBox or something like it */
147 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT)
151 * Time in Unix format of midnight, 1/1/1970 local time.
152 * When added to dosUTime, gives Unix (AFS) time.
154 time_t smb_localZero = 0;
156 #define USE_NUMERIC_TIME_CONV 1
158 #ifndef USE_NUMERIC_TIME_CONV
159 /* Time difference for converting to kludge-GMT */
160 afs_uint32 smb_NowTZ;
161 #endif /* USE_NUMERIC_TIME_CONV */
163 char *smb_localNamep = NULL;
165 smb_vc_t *smb_allVCsp;
166 smb_vc_t *smb_deadVCsp;
168 smb_username_t *usernamesp = NULL;
170 smb_waitingLockRequest_t *smb_allWaitingLocks;
172 DWORD smb_TlsRequestSlot = -1;
175 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
176 NCB *ncbp, raw_write_cont_t *rwcp);
177 int smb_NetbiosInit(int);
180 void smb_LogPacket(smb_packet_t *packet);
181 #endif /* LOG_PACKET */
183 clientchar_t smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = _C(""); /* domain name */
184 int smb_ServerDomainNameLength = 0;
185 clientchar_t smb_ServerOS[] = _C("Windows 5.0"); /* Faux OS String */
186 int smb_ServerOSLength = lengthof(smb_ServerOS);
187 clientchar_t smb_ServerLanManager[] = _C("Windows 2000 LAN Manager"); /* Faux LAN Manager string */
188 int smb_ServerLanManagerLength = lengthof(smb_ServerLanManager);
190 /* Faux server GUID. This is never checked. */
191 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
193 void smb_InitReq(cm_req_t *reqp)
196 reqp->flags |= CM_REQ_SOURCE_SMB;
199 void smb_ResetServerPriority()
201 void * p = TlsGetValue(smb_TlsRequestSlot);
204 TlsSetValue(smb_TlsRequestSlot, NULL);
205 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
209 void smb_SetRequestStartTime()
211 time_t * tp = TlsGetValue(smb_TlsRequestSlot);
213 tp = malloc(sizeof(time_t));
217 if (!TlsSetValue(smb_TlsRequestSlot, tp))
222 void smb_UpdateServerPriority()
224 time_t *tp = TlsGetValue(smb_TlsRequestSlot);
227 time_t now = osi_Time();
229 /* Give one priority boost for each 15 seconds */
230 SetThreadPriority(GetCurrentThread(), (int)((now - *tp) / 15));
235 const char * ncb_error_string(int code)
239 case 0x01: s = "NRC_BUFLEN llegal buffer length"; break;
240 case 0x03: s = "NRC_ILLCMD illegal command"; break;
241 case 0x05: s = "NRC_CMDTMO command timed out"; break;
242 case 0x06: s = "NRC_INCOMP message incomplete, issue another command"; break;
243 case 0x07: s = "NRC_BADDR illegal buffer address"; break;
244 case 0x08: s = "NRC_SNUMOUT session number out of range"; break;
245 case 0x09: s = "NRC_NORES no resource available"; break;
246 case 0x0a: s = "NRC_SCLOSED asession closed"; break;
247 case 0x0b: s = "NRC_CMDCAN command cancelled"; break;
248 case 0x0d: s = "NRC_DUPNAME duplicate name"; break;
249 case 0x0e: s = "NRC_NAMTFUL name table full"; break;
250 case 0x0f: s = "NRC_ACTSES no deletions, name has active sessions"; break;
251 case 0x11: s = "NRC_LOCTFUL local session table full"; break;
252 case 0x12: s = "NRC_REMTFUL remote session table full"; break;
253 case 0x13: s = "NRC_ILLNN illegal name number"; break;
254 case 0x14: s = "NRC_NOCALL no callname"; break;
255 case 0x15: s = "NRC_NOWILD cannot put * in NCB_NAME"; break;
256 case 0x16: s = "NRC_INUSE name in use on remote adapter"; break;
257 case 0x17: s = "NRC_NAMERR name deleted"; break;
258 case 0x18: s = "NRC_SABORT session ended abnormally"; break;
259 case 0x19: s = "NRC_NAMCONF name conflict detected"; break;
260 case 0x21: s = "NRC_IFBUSY interface busy, IRET before retrying"; break;
261 case 0x22: s = "NRC_TOOMANY too many commands outstanding, retry later";break;
262 case 0x23: s = "NRC_BRIDGE ncb_lana_num field invalid"; break;
263 case 0x24: s = "NRC_CANOCCR command completed while cancel occurring "; break;
264 case 0x26: s = "NRC_CANCEL command not valid to cancel"; break;
265 case 0x30: s = "NRC_DUPENV name defined by anther local process"; break;
266 case 0x34: s = "NRC_ENVNOTDEF xenvironment undefined. RESET required"; break;
267 case 0x35: s = "NRC_OSRESNOTAV required OS resources exhausted"; break;
268 case 0x36: s = "NRC_MAXAPPS max number of applications exceeded"; break;
269 case 0x37: s = "NRC_NOSAPS no saps available for netbios"; break;
270 case 0x38: s = "NRC_NORESOURCES requested resources are not available"; break;
271 case 0x39: s = "NRC_INVADDRESS invalid ncb address or length > segment"; break;
272 case 0x3B: s = "NRC_INVDDID invalid NCB DDID"; break;
273 case 0x3C: s = "NRC_LOCKFAILlock of user area failed"; break;
274 case 0x3f: s = "NRC_OPENERR NETBIOS not loaded"; break;
275 case 0x40: s = "NRC_SYSTEM system error"; break;
276 default: s = "unknown error";
282 char * myCrt_Dispatch(int i)
287 return "(00)ReceiveCoreMakeDir";
289 return "(01)ReceiveCoreRemoveDir";
291 return "(02)ReceiveCoreOpen";
293 return "(03)ReceiveCoreCreate";
295 return "(04)ReceiveCoreClose";
297 return "(05)ReceiveCoreFlush";
299 return "(06)ReceiveCoreUnlink";
301 return "(07)ReceiveCoreRename";
303 return "(08)ReceiveCoreGetFileAttributes";
305 return "(09)ReceiveCoreSetFileAttributes";
307 return "(0a)ReceiveCoreRead";
309 return "(0b)ReceiveCoreWrite";
311 return "(0c)ReceiveCoreLockRecord";
313 return "(0d)ReceiveCoreUnlockRecord";
315 return "(0e)SendCoreBadOp";
317 return "(0f)ReceiveCoreCreate";
319 return "(10)ReceiveCoreCheckPath";
321 return "(11)SendCoreBadOp";
323 return "(12)ReceiveCoreSeek";
325 return "(1a)ReceiveCoreReadRaw";
327 return "(1d)ReceiveCoreWriteRawDummy";
329 return "(22)ReceiveV3SetAttributes";
331 return "(23)ReceiveV3GetAttributes";
333 return "(24)ReceiveV3LockingX";
335 return "(25)ReceiveV3Trans";
337 return "(26)ReceiveV3Trans[aux]";
339 return "(29)SendCoreBadOp";
341 return "(2b)ReceiveCoreEcho";
343 return "(2d)ReceiveV3OpenX";
345 return "(2e)ReceiveV3ReadX";
347 return "(2f)ReceiveV3WriteX";
349 return "(32)ReceiveV3Tran2A";
351 return "(33)ReceiveV3Tran2A[aux]";
353 return "(34)ReceiveV3FindClose";
355 return "(35)ReceiveV3FindNotifyClose";
357 return "(70)ReceiveCoreTreeConnect";
359 return "(71)ReceiveCoreTreeDisconnect";
361 return "(72)ReceiveNegotiate";
363 return "(73)ReceiveV3SessionSetupX";
365 return "(74)ReceiveV3UserLogoffX";
367 return "(75)ReceiveV3TreeConnectX";
369 return "(80)ReceiveCoreGetDiskAttributes";
371 return "(81)ReceiveCoreSearchDir";
375 return "(83)FindUnique";
377 return "(84)FindClose";
379 return "(A0)ReceiveNTTransact";
381 return "(A2)ReceiveNTCreateX";
383 return "(A4)ReceiveNTCancel";
385 return "(A5)ReceiveNTRename";
387 return "(C0)OpenPrintFile";
389 return "(C1)WritePrintFile";
391 return "(C2)ClosePrintFile";
393 return "(C3)GetPrintQueue";
395 return "(D8)ReadBulk";
397 return "(D9)WriteBulk";
399 return "(DA)WriteBulkData";
401 return "unknown SMB op";
405 char * myCrt_2Dispatch(int i)
410 return "unknown SMB op-2";
412 return "S(00)CreateFile_ReceiveTran2Open";
414 return "S(01)FindFirst_ReceiveTran2SearchDir";
416 return "S(02)FindNext_ReceiveTran2SearchDir"; /* FindNext */
418 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
420 return "S(04)SetFileSystem_ReceiveTran2SetFSInfo";
422 return "S(05)QueryPathInfo_ReceiveTran2QPathInfo";
424 return "S(06)SetPathInfo_ReceiveTran2SetPathInfo";
426 return "S(07)QueryFileInfo_ReceiveTran2QFileInfo";
428 return "S(08)SetFileInfo_ReceiveTran2SetFileInfo";
430 return "S(09)_ReceiveTran2FSCTL";
432 return "S(0a)_ReceiveTran2IOCTL";
434 return "S(0b)_ReceiveTran2FindNotifyFirst";
436 return "S(0c)_ReceiveTran2FindNotifyNext";
438 return "S(0d)_ReceiveTran2CreateDirectory";
440 return "S(0e)_ReceiveTran2SessionSetup";
442 return "S(0f)_QueryFileSystemInformationFid";
444 return "S(10)_ReceiveTran2GetDfsReferral";
446 return "S(11)_ReceiveTran2ReportDfsInconsistency";
450 char * myCrt_RapDispatch(int i)
455 return "unknown RAP OP";
457 return "RAP(0)NetShareEnum";
459 return "RAP(1)NetShareGetInfo";
461 return "RAP(13)NetServerGetInfo";
463 return "RAP(63)NetWkStaGetInfo";
467 /* scache must be locked */
468 unsigned int smb_Attributes(cm_scache_t *scp)
472 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
473 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
474 scp->fileType == CM_SCACHETYPE_INVALID)
476 attrs = SMB_ATTR_DIRECTORY;
477 #ifdef SPECIAL_FOLDERS
478 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
479 #endif /* SPECIAL_FOLDERS */
480 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
481 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
486 * We used to mark a file RO if it was in an RO volume, but that
487 * turns out to be impolitic in NT. See defect 10007.
490 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
491 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
493 if ((scp->unixModeBits & 0222) == 0)
494 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
500 /* Check if the named file/dir is a dotfile/dotdir */
501 /* String pointed to by lastComp can have leading slashes, but otherwise should have
502 no other patch components */
503 unsigned int smb_IsDotFile(clientchar_t *lastComp) {
507 /* skip over slashes */
508 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
513 /* nulls, curdir and parent dir doesn't count */
519 if(*(s+1) == _C('.') && !*(s + 2))
526 static int ExtractBits(WORD bits, short start, short len)
533 num = bits << (16 - end);
534 num = num >> ((16 - end) + start);
539 void ShowUnixTime(char *FuncName, time_t unixTime)
544 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
546 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
547 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
549 int day, month, year, sec, min, hour;
552 day = ExtractBits(wDate, 0, 5);
553 month = ExtractBits(wDate, 5, 4);
554 year = ExtractBits(wDate, 9, 7) + 1980;
556 sec = ExtractBits(wTime, 0, 5);
557 min = ExtractBits(wTime, 5, 6);
558 hour = ExtractBits(wTime, 11, 5);
560 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
561 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
565 /* Determine if we are observing daylight savings time */
566 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
568 TIME_ZONE_INFORMATION timeZoneInformation;
569 SYSTEMTIME utc, local, localDST;
571 /* Get the time zone info. NT uses this to calc if we are in DST. */
572 GetTimeZoneInformation(&timeZoneInformation);
574 /* Return the daylight bias */
575 *pDstBias = timeZoneInformation.DaylightBias;
577 /* Return the bias */
578 *pBias = timeZoneInformation.Bias;
580 /* Now determine if DST is being observed */
582 /* Get the UTC (GMT) time */
585 /* Convert UTC time to local time using the time zone info. If we are
586 observing DST, the calculated local time will include this.
588 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
590 /* Set the daylight bias to 0. The daylight bias is the amount of change
591 * in time that we use for daylight savings time. By setting this to 0
592 * we cause there to be no change in time during daylight savings time.
594 timeZoneInformation.DaylightBias = 0;
596 /* Convert the utc time to local time again, but this time without any
597 adjustment for daylight savings time.
599 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
601 /* If the two times are different, then it means that the localDST that
602 we calculated includes the daylight bias, and therefore we are
603 observing daylight savings time.
605 *pDST = localDST.wHour != local.wHour;
609 void CompensateForSmbClientLastWriteTimeBugs(afs_uint32 *pLastWriteTime)
611 BOOL dst; /* Will be TRUE if observing DST */
612 LONG dstBias; /* Offset from local time if observing DST */
613 LONG bias; /* Offset from GMT for local time */
616 * This function will adjust the last write time to compensate
617 * for two bugs in the smb client:
619 * 1) During Daylight Savings Time, the LastWriteTime is ahead
620 * in time by the DaylightBias (ignoring the sign - the
621 * DaylightBias is always stored as a negative number). If
622 * the DaylightBias is -60, then the LastWriteTime will be
623 * ahead by 60 minutes.
625 * 2) If the local time zone is a positive offset from GMT, then
626 * the LastWriteTime will be the correct local time plus the
627 * Bias (ignoring the sign - a positive offset from GMT is
628 * always stored as a negative Bias). If the Bias is -120,
629 * then the LastWriteTime will be ahead by 120 minutes.
631 * These bugs can occur at the same time.
634 GetTimeZoneInfo(&dst, &dstBias, &bias);
636 /* First adjust for DST */
638 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
640 /* Now adjust for a positive offset from GMT (a negative bias). */
642 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
645 #ifndef USE_NUMERIC_TIME_CONV
647 * Calculate the difference (in seconds) between local time and GMT.
648 * This enables us to convert file times to kludge-GMT.
654 struct tm gmt_tm, local_tm;
655 int days, hours, minutes, seconds;
658 gmt_tm = *(gmtime(&t));
659 local_tm = *(localtime(&t));
661 days = local_tm.tm_yday - gmt_tm.tm_yday;
662 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour;
663 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
664 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
668 #endif /* USE_NUMERIC_TIME_CONV */
670 #ifdef USE_NUMERIC_TIME_CONV
671 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
673 // Note that LONGLONG is a 64-bit value
676 ll = Int32x32To64(unixTime, 10000000) + 116444736000000000;
677 largeTimep->dwLowDateTime = (DWORD)(ll & 0xFFFFFFFF);
678 largeTimep->dwHighDateTime = (DWORD)(ll >> 32);
681 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
686 time_t ersatz_unixTime;
689 * Must use kludge-GMT instead of real GMT.
690 * kludge-GMT is computed by adding time zone difference to localtime.
693 * ltp = gmtime(&unixTime);
695 ersatz_unixTime = unixTime - smb_NowTZ;
696 ltp = localtime(&ersatz_unixTime);
698 /* if we fail, make up something */
701 localJunk.tm_year = 89 - 20;
702 localJunk.tm_mon = 4;
703 localJunk.tm_mday = 12;
704 localJunk.tm_hour = 0;
705 localJunk.tm_min = 0;
706 localJunk.tm_sec = 0;
709 stm.wYear = ltp->tm_year + 1900;
710 stm.wMonth = ltp->tm_mon + 1;
711 stm.wDayOfWeek = ltp->tm_wday;
712 stm.wDay = ltp->tm_mday;
713 stm.wHour = ltp->tm_hour;
714 stm.wMinute = ltp->tm_min;
715 stm.wSecond = ltp->tm_sec;
716 stm.wMilliseconds = 0;
718 SystemTimeToFileTime(&stm, largeTimep);
720 #endif /* USE_NUMERIC_TIME_CONV */
722 #ifdef USE_NUMERIC_TIME_CONV
723 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
725 // Note that LONGLONG is a 64-bit value
728 ll = largeTimep->dwHighDateTime;
730 ll += largeTimep->dwLowDateTime;
732 ll -= 116444736000000000;
735 *unixTimep = (DWORD)ll;
737 #else /* USE_NUMERIC_TIME_CONV */
738 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
744 FileTimeToSystemTime(largeTimep, &stm);
746 lt.tm_year = stm.wYear - 1900;
747 lt.tm_mon = stm.wMonth - 1;
748 lt.tm_wday = stm.wDayOfWeek;
749 lt.tm_mday = stm.wDay;
750 lt.tm_hour = stm.wHour;
751 lt.tm_min = stm.wMinute;
752 lt.tm_sec = stm.wSecond;
755 save_timezone = _timezone;
756 _timezone += smb_NowTZ;
757 *unixTimep = mktime(<);
758 _timezone = save_timezone;
760 #endif /* USE_NUMERIC_TIME_CONV */
762 void smb_SearchTimeFromUnixTime(afs_uint32 *searchTimep, time_t unixTime)
772 /* if we fail, make up something */
775 localJunk.tm_year = 89 - 20;
776 localJunk.tm_mon = 4;
777 localJunk.tm_mday = 12;
778 localJunk.tm_hour = 0;
779 localJunk.tm_min = 0;
780 localJunk.tm_sec = 0;
783 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
784 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
785 *searchTimep = (dosDate<<16) | dosTime;
788 void smb_UnixTimeFromSearchTime(time_t *unixTimep, afs_uint32 searchTime)
790 unsigned short dosDate;
791 unsigned short dosTime;
794 dosDate = (unsigned short) (searchTime & 0xffff);
795 dosTime = (unsigned short) ((searchTime >> 16) & 0xffff);
797 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
798 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
799 localTm.tm_mday = (dosDate) & 0x1f;
800 localTm.tm_hour = (dosTime>>11) & 0x1f;
801 localTm.tm_min = (dosTime >> 5) & 0x3f;
802 localTm.tm_sec = (dosTime & 0x1f) * 2;
803 localTm.tm_isdst = -1; /* compute whether DST in effect */
805 *unixTimep = mktime(&localTm);
808 void smb_DosUTimeFromUnixTime(afs_uint32 *dosUTimep, time_t unixTime)
810 time_t diff_t = unixTime - smb_localZero;
811 #if defined(DEBUG) && !defined(_USE_32BIT_TIME_T)
812 osi_assertx(diff_t < _UI32_MAX, "time_t > _UI32_MAX");
814 *dosUTimep = (afs_uint32)diff_t;
817 void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
819 *unixTimep = dosTime + smb_localZero;
822 void smb_MarkAllVCsDead(smb_vc_t * exclude)
825 smb_vc_t **vcp_to_cleanup = NULL;
826 int n_to_cleanup = 0;
829 osi_Log1(smb_logp, "Marking all VCs as dead excluding %p", exclude);
831 lock_ObtainWrite(&smb_globalLock); /* for dead_sessions[] */
832 lock_ObtainWrite(&smb_rctLock);
833 for (vcp = smb_allVCsp; vcp; vcp = vcp->nextp) {
835 if (vcp->magic != SMB_VC_MAGIC)
836 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
842 lock_ObtainMutex(&vcp->mx);
843 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
844 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
845 lock_ReleaseMutex(&vcp->mx);
846 dead_sessions[vcp->session] = TRUE;
848 lock_ReleaseMutex(&vcp->mx);
853 vcp_to_cleanup = malloc(sizeof(vcp_to_cleanup[0]) * n_to_cleanup);
855 for (vcp = smb_allVCsp; vcp; vcp = vcp->nextp) {
859 vcp_to_cleanup[i++] = vcp;
860 smb_HoldVCNoLock(vcp);
863 osi_assert(i == n_to_cleanup);
865 lock_ReleaseWrite(&smb_rctLock);
866 lock_ReleaseWrite(&smb_globalLock);
868 for (i=0; i < n_to_cleanup; i++) {
869 smb_CleanupDeadVC(vcp_to_cleanup[i]);
870 smb_ReleaseVC(vcp_to_cleanup[i]);
871 vcp_to_cleanup[i] = 0;
874 free(vcp_to_cleanup);
877 #ifdef DEBUG_SMB_REFCOUNT
878 smb_vc_t *smb_FindVCDbg(unsigned short lsn, int flags, int lana, char *file, long line)
880 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
885 lock_ObtainWrite(&smb_globalLock); /* for numVCs */
886 lock_ObtainWrite(&smb_rctLock);
887 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
888 if (vcp->magic != SMB_VC_MAGIC)
889 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
892 lock_ObtainMutex(&vcp->mx);
893 if (lsn == vcp->lsn && lana == vcp->lana &&
894 !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
895 lock_ReleaseMutex(&vcp->mx);
896 smb_HoldVCNoLock(vcp);
899 lock_ReleaseMutex(&vcp->mx);
901 if (!vcp && (flags & SMB_FLAG_CREATE)) {
902 vcp = malloc(sizeof(*vcp));
903 memset(vcp, 0, sizeof(*vcp));
904 vcp->vcID = ++numVCs;
905 vcp->magic = SMB_VC_MAGIC;
906 vcp->refCount = 2; /* smb_allVCsp and caller */
909 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
910 vcp->nextp = smb_allVCsp;
912 lock_InitializeMutex(&vcp->mx, "vc_t mutex", LOCK_HIERARCHY_SMB_VC);
917 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
918 /* We must obtain a challenge for extended auth
919 * in case the client negotiates smb v3
921 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
922 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
923 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp = NULL;
924 ULONG lsaRespSize = 0;
926 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
928 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
935 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS) {
936 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
937 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
938 afsi_log("MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize %u",
939 nts, ntsEx, lsaRespSize);
941 osi_assertx(nts == STATUS_SUCCESS, "LsaCallAuthenticationPackage failed"); /* this had better work! */
943 if (ntsEx == STATUS_SUCCESS) {
944 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
947 * This will cause the subsequent authentication to fail but
948 * that is better than us dereferencing a NULL pointer and
951 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
954 LsaFreeReturnBuffer(lsaResp);
957 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
959 if (numVCs >= CM_SESSION_RESERVED) {
961 osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
964 #ifdef DEBUG_SMB_REFCOUNT
966 afsi_log("%s:%d smb_FindVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
967 osi_Log4(smb_logp,"%s:%d smb_FindVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
970 lock_ReleaseWrite(&smb_rctLock);
971 lock_ReleaseWrite(&smb_globalLock);
975 static int smb_Is8Dot3StarMask(clientchar_t *maskp)
980 for(i=0; i<11; i++) {
982 if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
988 static int smb_IsStarMask(clientchar_t *maskp)
994 if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
1000 #ifdef DEBUG_SMB_REFCOUNT
1001 void smb_ReleaseVCInternalDbg(smb_vc_t *vcp, char * file, long line)
1002 #define smb_ReleaseVCInternal(a) smb_ReleaseVCInternalDbg(a, file, line)
1004 void smb_ReleaseVCInternal(smb_vc_t *vcp)
1010 lock_AssertWrite(&smb_rctLock);
1013 if (vcp->refCount == 0) {
1014 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
1015 #ifdef DEBUG_SMB_REFCOUNT
1016 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
1017 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
1019 /* remove VCP from smb_deadVCsp */
1020 for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
1026 lock_FinalizeMutex(&vcp->mx);
1027 memset(vcp,0,sizeof(smb_vc_t));
1030 #ifdef DEBUG_SMB_REFCOUNT
1031 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is alive ref %d", file, line, vcp, vcp->refCount);
1033 for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
1037 osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
1038 avcp?"":"not ",vcp, vcp->refCount);
1040 /* This is a wrong. However, I suspect that there is an undercount
1041 * and I don't want to release 1.4.1 in a state that will allow
1042 * smb_vc_t objects to be deallocated while still in the
1043 * smb_allVCsp list. The list is supposed to keep a reference
1044 * to the smb_vc_t. Put it back.
1048 #ifdef DEBUG_SMB_REFCOUNT
1049 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
1050 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
1054 } else if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
1055 /* The reference count is non-zero but the VC is dead.
1056 * This implies that some FIDs, TIDs, etc on the VC have yet to
1057 * be cleaned up. If we were not called by smb_CleanupDeadVC(),
1058 * add a reference that will be dropped by
1059 * smb_CleanupDeadVC() and try to cleanup the VC again.
1060 * Eventually the refCount will drop to zero when all of the
1061 * active threads working with the VC end their task.
1063 if (!(vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS)) {
1064 vcp->refCount++; /* put the refCount back */
1065 lock_ReleaseWrite(&smb_rctLock);
1066 smb_CleanupDeadVC(vcp);
1067 #ifdef DEBUG_SMB_REFCOUNT
1068 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
1069 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
1071 lock_ObtainWrite(&smb_rctLock);
1074 #ifdef DEBUG_SMB_REFCOUNT
1075 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1076 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1081 #ifdef DEBUG_SMB_REFCOUNT
1082 void smb_ReleaseVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
1084 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
1087 lock_AssertWrite(&smb_rctLock);
1088 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
1089 smb_ReleaseVCInternal(vcp);
1092 #ifdef DEBUG_SMB_REFCOUNT
1093 void smb_ReleaseVCDbg(smb_vc_t *vcp, char * file, long line)
1095 void smb_ReleaseVC(smb_vc_t *vcp)
1098 lock_ObtainWrite(&smb_rctLock);
1099 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
1100 smb_ReleaseVCInternal(vcp);
1101 lock_ReleaseWrite(&smb_rctLock);
1104 #ifdef DEBUG_SMB_REFCOUNT
1105 void smb_HoldVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
1107 void smb_HoldVCNoLock(smb_vc_t *vcp)
1110 lock_AssertWrite(&smb_rctLock);
1112 #ifdef DEBUG_SMB_REFCOUNT
1113 afsi_log("%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1114 osi_Log4(smb_logp,"%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1116 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
1120 #ifdef DEBUG_SMB_REFCOUNT
1121 void smb_HoldVCDbg(smb_vc_t *vcp, char * file, long line)
1123 void smb_HoldVC(smb_vc_t *vcp)
1126 lock_ObtainWrite(&smb_rctLock);
1128 #ifdef DEBUG_SMB_REFCOUNT
1129 afsi_log("%s:%d smb_HoldVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1130 osi_Log4(smb_logp,"%s:%d smb_HoldVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1132 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
1134 lock_ReleaseWrite(&smb_rctLock);
1137 void smb_CleanupDeadVC(smb_vc_t *vcp)
1139 smb_fid_t *fidpIter;
1140 smb_fid_t *fidpNext;
1142 smb_tid_t *tidpIter;
1143 smb_tid_t *tidpNext;
1145 smb_user_t *uidpIter;
1146 smb_user_t *uidpNext;
1148 afs_uint32 refCount = 0;
1150 lock_ObtainMutex(&vcp->mx);
1151 if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
1152 lock_ReleaseMutex(&vcp->mx);
1153 osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
1156 vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
1157 lock_ReleaseMutex(&vcp->mx);
1158 osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
1160 lock_ObtainWrite(&smb_rctLock);
1161 /* remove VCP from smb_allVCsp */
1162 for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
1163 if ((*vcpp)->magic != SMB_VC_MAGIC)
1164 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
1165 __FILE__, __LINE__);
1168 vcp->nextp = smb_deadVCsp;
1170 /* Hold onto the reference until we are done with this function */
1175 for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
1176 fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
1178 if (fidpIter->deleteOk)
1181 fid = fidpIter->fid;
1182 osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1184 smb_HoldFIDNoLock(fidpIter);
1185 lock_ReleaseWrite(&smb_rctLock);
1187 smb_CloseFID(vcp, fidpIter, NULL, 0);
1188 smb_ReleaseFID(fidpIter);
1190 lock_ObtainWrite(&smb_rctLock);
1191 fidpNext = vcp->fidsp;
1194 for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1195 tidpNext = tidpIter->nextp;
1196 if (tidpIter->deleteOk)
1198 tidpIter->deleteOk = 1;
1200 tid = tidpIter->tid;
1201 osi_Log2(smb_logp, " Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1203 smb_HoldTIDNoLock(tidpIter);
1204 smb_ReleaseTID(tidpIter, TRUE);
1205 tidpNext = vcp->tidsp;
1208 for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1209 uidpNext = uidpIter->nextp;
1210 if (uidpIter->deleteOk)
1212 uidpIter->deleteOk = 1;
1214 /* do not add an additional reference count for the smb_user_t
1215 * as the smb_vc_t already is holding a reference */
1216 lock_ReleaseWrite(&smb_rctLock);
1218 smb_ReleaseUID(uidpIter);
1220 lock_ObtainWrite(&smb_rctLock);
1221 uidpNext = vcp->usersp;
1224 /* The vcp is now on the deadVCsp list. We intentionally drop the
1225 * reference so that the refcount can reach 0 and we can delete it
1227 * If the refCount == 1 going into the ReleaseVCNoLock call
1228 * the object will be freed and it won't be safe to clear
1231 refCount = vcp->refCount;
1232 smb_ReleaseVCNoLock(vcp);
1234 lock_ObtainMutex(&vcp->mx);
1235 vcp->flags &= ~SMB_VCFLAG_CLEAN_IN_PROGRESS;
1236 lock_ReleaseMutex(&vcp->mx);
1239 lock_ReleaseWrite(&smb_rctLock);
1240 osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1243 #ifdef DEBUG_SMB_REFCOUNT
1244 smb_tid_t *smb_FindTIDDbg(smb_vc_t *vcp, unsigned short tid, int flags, char * file, long line)
1246 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1251 lock_ObtainWrite(&smb_rctLock);
1253 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1254 if (tidp->refCount == 0 && tidp->deleteOk) {
1256 smb_ReleaseTID(tidp, TRUE);
1260 if (tid == tidp->tid) {
1265 if (!tidp && (flags & SMB_FLAG_CREATE)) {
1266 tidp = malloc(sizeof(*tidp));
1267 memset(tidp, 0, sizeof(*tidp));
1268 tidp->nextp = vcp->tidsp;
1271 smb_HoldVCNoLock(vcp);
1273 lock_InitializeMutex(&tidp->mx, "tid_t mutex", LOCK_HIERARCHY_SMB_TID);
1276 #ifdef DEBUG_SMB_REFCOUNT
1278 afsi_log("%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1279 osi_Log4(smb_logp,"%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1282 lock_ReleaseWrite(&smb_rctLock);
1286 #ifdef DEBUG_SMB_REFCOUNT
1287 void smb_HoldTIDNoLockDbg(smb_tid_t *tidp, char * file, long line)
1289 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1292 lock_AssertWrite(&smb_rctLock);
1294 #ifdef DEBUG_SMB_REFCOUNT
1295 afsi_log("%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1296 osi_Log4(smb_logp,"%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1300 #ifdef DEBUG_SMB_REFCOUNT
1301 void smb_ReleaseTIDDbg(smb_tid_t *tidp, afs_uint32 locked, char *file, long line)
1303 void smb_ReleaseTID(smb_tid_t *tidp, afs_uint32 locked)
1308 cm_user_t *userp = NULL;
1309 smb_vc_t *vcp = NULL;
1312 lock_ObtainWrite(&smb_rctLock);
1314 lock_AssertWrite(&smb_rctLock);
1316 osi_assertx(tidp->refCount-- > 0, "smb_tid_t refCount 0");
1317 #ifdef DEBUG_SMB_REFCOUNT
1318 afsi_log("%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1319 osi_Log5(smb_logp,"%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1321 if (tidp->refCount == 0) {
1322 if (tidp->deleteOk) {
1323 ltpp = &tidp->vcp->tidsp;
1324 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1328 osi_assertx(tp != NULL, "null smb_tid_t");
1330 lock_FinalizeMutex(&tidp->mx);
1331 userp = tidp->userp; /* remember to drop ref later */
1339 lock_ReleaseWrite(&smb_rctLock);
1341 cm_ReleaseUser(userp);
1343 smb_ReleaseVCNoLock(vcp);
1346 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1348 smb_user_t *uidp = NULL;
1350 lock_ObtainWrite(&smb_rctLock);
1351 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1352 if (uid == uidp->userID) {
1354 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%S]",
1356 ((uidp->unp)? osi_LogSaveClientString(smb_logp, uidp->unp->name):_C("")));
1360 if (!uidp && (flags & SMB_FLAG_CREATE)) {
1361 uidp = malloc(sizeof(*uidp));
1362 memset(uidp, 0, sizeof(*uidp));
1363 uidp->nextp = vcp->usersp;
1364 uidp->refCount = 2; /* one for the vcp and one for the caller */
1366 smb_HoldVCNoLock(vcp);
1368 lock_InitializeMutex(&uidp->mx, "user_t mutex", LOCK_HIERARCHY_SMB_UID);
1370 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%S]",
1372 ((uidp->unp)?osi_LogSaveClientString(smb_logp,uidp->unp->name):_C("")));
1374 lock_ReleaseWrite(&smb_rctLock);
1378 smb_username_t *smb_FindUserByName(clientchar_t *usern, clientchar_t *machine,
1381 smb_username_t *unp= NULL;
1383 lock_ObtainWrite(&smb_rctLock);
1384 for(unp = usernamesp; unp; unp = unp->nextp) {
1385 if (cm_ClientStrCmpI(unp->name, usern) == 0 &&
1386 cm_ClientStrCmpI(unp->machine, machine) == 0) {
1391 if (!unp && (flags & SMB_FLAG_CREATE)) {
1392 unp = malloc(sizeof(*unp));
1393 memset(unp, 0, sizeof(*unp));
1395 unp->nextp = usernamesp;
1396 unp->name = cm_ClientStrDup(usern);
1397 unp->machine = cm_ClientStrDup(machine);
1399 lock_InitializeMutex(&unp->mx, "username_t mutex", LOCK_HIERARCHY_SMB_USERNAME);
1400 if (flags & SMB_FLAG_AFSLOGON)
1401 unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1404 lock_ReleaseWrite(&smb_rctLock);
1408 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, clientchar_t *usern)
1410 smb_user_t *uidp= NULL;
1412 lock_ObtainWrite(&smb_rctLock);
1413 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1416 if (cm_stricmp_utf16(uidp->unp->name, usern) == 0) {
1418 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%S]",
1419 vcp,uidp->userID,osi_LogSaveClientString(smb_logp,usern));
1424 lock_ReleaseWrite(&smb_rctLock);
1428 void smb_ReleaseUsername(smb_username_t *unp)
1431 smb_username_t **lupp;
1432 cm_user_t *userp = NULL;
1433 time_t now = osi_Time();
1435 lock_ObtainWrite(&smb_rctLock);
1436 osi_assertx(unp->refCount-- > 0, "smb_username_t refCount 0");
1437 if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1438 (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1440 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1444 osi_assertx(up != NULL, "null smb_username_t");
1446 up->nextp = NULL; /* do not remove this */
1447 lock_FinalizeMutex(&unp->mx);
1453 lock_ReleaseWrite(&smb_rctLock);
1455 cm_ReleaseUser(userp);
1458 void smb_HoldUIDNoLock(smb_user_t *uidp)
1460 lock_AssertWrite(&smb_rctLock);
1464 void smb_ReleaseUID(smb_user_t *uidp)
1468 smb_username_t *unp = NULL;
1470 lock_ObtainWrite(&smb_rctLock);
1471 osi_assertx(uidp->refCount-- > 0, "smb_user_t refCount 0");
1472 if (uidp->refCount == 0) {
1473 lupp = &uidp->vcp->usersp;
1474 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1478 osi_assertx(up != NULL, "null smb_user_t");
1480 lock_FinalizeMutex(&uidp->mx);
1482 smb_ReleaseVCNoLock(uidp->vcp);
1486 lock_ReleaseWrite(&smb_rctLock);
1490 cm_ReleaseUserVCRef(unp->userp);
1491 smb_ReleaseUsername(unp);
1495 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1497 cm_user_t *up = NULL;
1502 lock_ObtainMutex(&uidp->mx);
1504 up = uidp->unp->userp;
1507 lock_ReleaseMutex(&uidp->mx);
1513 /* retrieve a held reference to a user structure corresponding to an incoming
1515 * corresponding release function is cm_ReleaseUser.
1517 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1520 cm_user_t *up = NULL;
1523 smbp = (smb_t *) inp;
1524 uidp = smb_FindUID(vcp, smbp->uid, 0);
1528 up = smb_GetUserFromUID(uidp);
1530 smb_ReleaseUID(uidp);
1535 * Return a pointer to a pathname extracted from a TID structure. The
1536 * TID structure is not held; assume it won't go away.
1538 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, clientchar_t ** treepath)
1543 tidp = smb_FindTID(vcp, tid, 0);
1547 if (tidp->flags & SMB_TIDFLAG_IPC) {
1548 code = CM_ERROR_TIDIPC;
1549 /* tidp->pathname would be NULL, but that's fine */
1551 *treepath = tidp->pathname;
1552 smb_ReleaseTID(tidp, FALSE);
1557 /* check to see if we have a chained fid, that is, a fid that comes from an
1558 * OpenAndX message that ran earlier in this packet. In this case, the fid
1559 * field in a read, for example, request, isn't set, since the value is
1560 * supposed to be inherited from the openAndX call.
1562 int smb_ChainFID(int fid, smb_packet_t *inp)
1564 if (inp->fid == 0 || inp->inCount == 0)
1570 /* are we a priv'd user? What does this mean on NT? */
1571 int smb_SUser(cm_user_t *userp)
1576 /* find a file ID. If we pass in 0 we select an unused File ID.
1577 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1578 * smb_fid_t data structure if desired File ID cannot be found.
1580 #ifdef DEBUG_SMB_REFCOUNT
1581 smb_fid_t *smb_FindFIDDbg(smb_vc_t *vcp, unsigned short fid, int flags, char *file, long line)
1583 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1589 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1592 lock_ObtainWrite(&smb_rctLock);
1593 /* figure out if we need to allocate a new file ID */
1596 fid = vcp->fidCounter;
1600 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1601 if (fidp->refCount == 0 && fidp->deleteOk) {
1603 lock_ReleaseWrite(&smb_rctLock);
1604 smb_ReleaseFID(fidp);
1605 lock_ObtainWrite(&smb_rctLock);
1608 if (fid == fidp->fid) {
1611 if (fid == 0xFFFF) {
1613 "New FID number wraps on vcp 0x%x", vcp);
1623 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1624 char eventName[MAX_PATH];
1626 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1627 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1628 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1629 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1630 thrd_CloseHandle(event);
1632 if (fid == 0xFFFF) {
1633 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1639 fidp = malloc(sizeof(*fidp));
1640 memset(fidp, 0, sizeof(*fidp));
1641 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1644 smb_HoldVCNoLock(vcp);
1645 lock_InitializeMutex(&fidp->mx, "fid_t mutex", LOCK_HIERARCHY_SMB_FID);
1647 fidp->curr_chunk = fidp->prev_chunk = -2;
1648 fidp->raw_write_event = event;
1650 vcp->fidCounter = fid+1;
1651 if (vcp->fidCounter == 0xFFFF) {
1652 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1654 vcp->fidCounter = 1;
1659 #ifdef DEBUG_SMB_REFCOUNT
1661 afsi_log("%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1662 osi_Log4(smb_logp,"%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1665 lock_ReleaseWrite(&smb_rctLock);
1669 #ifdef DEBUG_SMB_REFCOUNT
1670 smb_fid_t *smb_FindFIDByScacheDbg(smb_vc_t *vcp, cm_scache_t * scp, char *file, long line)
1672 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1675 smb_fid_t *fidp = NULL;
1681 lock_ObtainWrite(&smb_rctLock);
1682 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1683 if (scp == fidp->scp) {
1684 lock_ObtainMutex(&fidp->mx);
1685 if (scp == fidp->scp) {
1687 lock_ReleaseMutex(&fidp->mx);
1690 lock_ReleaseMutex(&fidp->mx);
1693 #ifdef DEBUG_SMB_REFCOUNT
1695 afsi_log("%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1696 osi_Log4(smb_logp,"%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1699 lock_ReleaseWrite(&smb_rctLock);
1703 #ifdef DEBUG_SMB_REFCOUNT
1704 void smb_HoldFIDNoLockDbg(smb_fid_t *fidp, char *file, long line)
1706 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1709 lock_AssertWrite(&smb_rctLock);
1711 #ifdef DEBUG_SMB_REFCOUNT
1712 afsi_log("%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1713 osi_Log4(smb_logp,"%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1718 /* smb_ReleaseFID cannot be called while an cm_scache_t mutex lock is held */
1719 /* the sm_fid_t->mx and smb_rctLock must not be held */
1720 #ifdef DEBUG_SMB_REFCOUNT
1721 void smb_ReleaseFIDDbg(smb_fid_t *fidp, char *file, long line)
1723 void smb_ReleaseFID(smb_fid_t *fidp)
1726 cm_scache_t *scp = NULL;
1727 cm_user_t *userp = NULL;
1728 smb_vc_t *vcp = NULL;
1729 smb_ioctl_t *ioctlp;
1731 lock_ObtainMutex(&fidp->mx);
1732 lock_ObtainWrite(&smb_rctLock);
1733 osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
1734 #ifdef DEBUG_SMB_REFCOUNT
1735 afsi_log("%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1736 osi_Log5(smb_logp,"%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1738 if (fidp->refCount == 0) {
1739 if (fidp->deleteOk) {
1742 scp = fidp->scp; /* release after lock is released */
1744 lock_ObtainWrite(&scp->rw);
1745 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1746 lock_ReleaseWrite(&scp->rw);
1747 osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1750 userp = fidp->userp;
1754 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1755 thrd_CloseHandle(fidp->raw_write_event);
1757 /* and see if there is ioctl stuff to free */
1758 ioctlp = fidp->ioctlp;
1761 cm_FreeSpace(ioctlp->prefix);
1762 if (ioctlp->ioctl.inAllocp)
1763 free(ioctlp->ioctl.inAllocp);
1764 if (ioctlp->ioctl.outAllocp)
1765 free(ioctlp->ioctl.outAllocp);
1768 lock_ReleaseMutex(&fidp->mx);
1769 lock_FinalizeMutex(&fidp->mx);
1774 smb_ReleaseVCNoLock(vcp);
1778 lock_ReleaseMutex(&fidp->mx);
1780 lock_ReleaseWrite(&smb_rctLock);
1782 /* now release the scache structure */
1784 cm_ReleaseSCache(scp);
1787 cm_ReleaseUser(userp);
1791 * Case-insensitive search for one string in another;
1792 * used to find variable names in submount pathnames.
1794 static clientchar_t *smb_stristr(clientchar_t *str1, clientchar_t *str2)
1796 clientchar_t *cursor;
1798 for (cursor = str1; *cursor; cursor++)
1799 if (cm_ClientStrCmpI(cursor, str2) == 0)
1806 * Substitute a variable value for its name in a submount pathname. Variable
1807 * name has been identified by smb_stristr() and is in substr. Variable name
1808 * length (plus one) is in substr_size. Variable value is in newstr.
1810 static void smb_subst(clientchar_t *str1, int cchstr1, clientchar_t *substr,
1811 unsigned int substr_size, clientchar_t *newstr)
1813 clientchar_t temp[1024];
1815 cm_ClientStrCpy(temp, lengthof(temp), substr + substr_size - 1);
1816 cm_ClientStrCpy(substr, cchstr1 - (substr - str1), newstr);
1817 cm_ClientStrCat(str1, cchstr1, temp);
1820 clientchar_t VNUserName[] = _C("%USERNAME%");
1821 clientchar_t VNLCUserName[] = _C("%LCUSERNAME%");
1822 clientchar_t VNComputerName[] = _C("%COMPUTERNAME%");
1823 clientchar_t VNLCComputerName[] = _C("%LCCOMPUTERNAME%");
1825 typedef struct smb_findShare_rock {
1826 clientchar_t * shareName;
1827 clientchar_t * match;
1829 } smb_findShare_rock_t;
1831 #define SMB_FINDSHARE_EXACT_MATCH 1
1832 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1834 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1838 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1839 normchar_t normName[MAX_PATH];
1841 if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(normName[0])) == 0) {
1842 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
1843 osi_LogSaveString(smb_logp, dep->name));
1847 if (!cm_ClientStrCmpNI(normName, vrock->shareName, 12)) {
1848 if(!cm_ClientStrCmpI(normName, vrock->shareName))
1849 matchType = SMB_FINDSHARE_EXACT_MATCH;
1851 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1854 vrock->match = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
1855 vrock->matchType = matchType;
1857 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1858 return CM_ERROR_STOPNOW;
1864 /* find a shareName in the table of submounts */
1865 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp,
1866 clientchar_t *shareName,
1867 clientchar_t **pathNamep)
1871 clientchar_t pathName[1024];
1874 clientchar_t *p, *q;
1875 fschar_t *cellname = NULL;
1878 DWORD allSubmount = 1;
1880 /* if allSubmounts == 0, only return the //mountRoot/all share
1881 * if in fact it has been been created in the subMounts table.
1882 * This is to allow sites that want to restrict access to the
1885 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1886 0, KEY_QUERY_VALUE, &parmKey);
1887 if (code == ERROR_SUCCESS) {
1888 cblen = sizeof(allSubmount);
1889 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1890 (BYTE *) &allSubmount, &cblen);
1891 if (code != ERROR_SUCCESS) {
1894 RegCloseKey (parmKey);
1897 if (allSubmount && cm_ClientStrCmpI(shareName, _C("all")) == 0) {
1902 /* In case, the all share is disabled we need to still be able
1903 * to handle ioctl requests
1905 if (cm_ClientStrCmpI(shareName, _C("ioctl$")) == 0) {
1906 *pathNamep = cm_ClientStrDup(_C("/.__ioctl__"));
1910 if (cm_ClientStrCmpIA(shareName, _C("IPC$")) == 0 ||
1911 cm_ClientStrCmpIA(shareName, _C("srvsvc")) == 0 ||
1912 cm_ClientStrCmpIA(shareName, _C("wkssvc")) == 0 ||
1913 cm_ClientStrCmpIA(shareName, _C(SMB_IOCTL_FILENAME_NOSLASH)) == 0 ||
1914 cm_ClientStrCmpIA(shareName, _C("DESKTOP.INI")) == 0
1920 /* Check for volume references
1922 * They look like <cell>{%,#}<volume>
1924 if (cm_ClientStrChr(shareName, '%') != NULL ||
1925 cm_ClientStrChr(shareName, '#') != NULL) {
1926 clientchar_t pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
1927 /* make room for '/@vol:' + mountchar + NULL terminator*/
1929 osi_Log1(smb_logp, "smb_FindShare found volume reference [%S]",
1930 osi_LogSaveClientString(smb_logp, shareName));
1932 cm_ClientStrPrintfN(pathstr, lengthof(pathstr),
1933 _C("/") _C(CM_PREFIX_VOL) _C("%s"), shareName);
1934 cchlen = (DWORD)(cm_ClientStrLen(pathstr) + 1);
1936 *pathNamep = malloc(cchlen * sizeof(clientchar_t));
1938 cm_ClientStrCpy(*pathNamep, cchlen, pathstr);
1939 cm_ClientStrLwr(*pathNamep);
1940 osi_Log1(smb_logp, " returning pathname [%S]",
1941 osi_LogSaveClientString(smb_logp, *pathNamep));
1949 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1950 0, KEY_QUERY_VALUE, &parmKey);
1951 if (code == ERROR_SUCCESS) {
1952 cblen = sizeof(pathName);
1953 code = RegQueryValueExW(parmKey, shareName, NULL, NULL,
1954 (BYTE *) pathName, &cblen);
1955 if (code != ERROR_SUCCESS)
1957 RegCloseKey (parmKey);
1961 cchlen = cblen / sizeof(clientchar_t);
1962 if (cchlen != 0 && cchlen != lengthof(pathName) - 1) {
1963 /* We can accept either unix or PC style AFS pathnames. Convert
1964 * Unix-style to PC style here for internal use.
1967 cchlen = lengthof(pathName);
1969 /* within this code block, we maintain, cchlen = writeable
1970 buffer length of p */
1972 if (cm_ClientStrCmpN(p, cm_mountRootC, cm_mountRootCLen) == 0) {
1973 p += cm_mountRootCLen; /* skip mount path */
1974 cchlen -= (DWORD)(p - pathName);
1979 if (*q == _C('/')) *q = _C('\\'); /* change to \ */
1985 clientchar_t temp[1024];
1987 if (var = smb_stristr(p, VNUserName)) {
1988 if (uidp && uidp->unp)
1989 smb_subst(p, cchlen, var, lengthof(VNUserName),uidp->unp->name);
1991 smb_subst(p, cchlen, var, lengthof(VNUserName), _C(" "));
1993 else if (var = smb_stristr(p, VNLCUserName))
1995 if (uidp && uidp->unp)
1996 cm_ClientStrCpy(temp, lengthof(temp), uidp->unp->name);
1998 cm_ClientStrCpy(temp, lengthof(temp), _C(" "));
1999 cm_ClientStrLwr(temp);
2000 smb_subst(p, cchlen, var, lengthof(VNLCUserName), temp);
2002 else if (var = smb_stristr(p, VNComputerName))
2004 sizeTemp = lengthof(temp);
2005 GetComputerNameW(temp, &sizeTemp);
2006 smb_subst(p, cchlen, var, lengthof(VNComputerName), temp);
2008 else if (var = smb_stristr(p, VNLCComputerName))
2010 sizeTemp = lengthof(temp);
2011 GetComputerName((LPTSTR)temp, &sizeTemp);
2012 cm_ClientStrLwr(temp);
2013 smb_subst(p, cchlen, var, lengthof(VNLCComputerName), temp);
2018 *pathNamep = cm_ClientStrDup(p);
2023 /* First lookup shareName in root.afs */
2025 smb_findShare_rock_t vrock;
2027 fschar_t ftemp[1024];
2028 clientchar_t * p = shareName;
2031 /* attempt to locate a partial match in root.afs. This is because
2032 when using the ANSI RAP calls, the share name is limited to 13 chars
2033 and hence is truncated. Of course we prefer exact matches. */
2035 thyper.HighPart = 0;
2038 vrock.shareName = cm_ClientStringToNormStringAlloc(shareName, -1, NULL);
2039 if (vrock.shareName == NULL)
2042 vrock.matchType = 0;
2044 cm_HoldSCache(cm_data.rootSCachep);
2045 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
2046 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
2047 cm_ReleaseSCache(cm_data.rootSCachep);
2049 free(vrock.shareName);
2050 vrock.shareName = NULL;
2052 if (vrock.matchType) {
2053 cm_ClientStrPrintfN(pathName, lengthof(pathName), _C("/%s/"), vrock.match);
2054 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
2059 /* if we get here, there was no match for the share in root.afs */
2060 /* so try to create \\<netbiosName>\<cellname> */
2065 /* Get the full name for this cell */
2066 cellname = cm_ClientStringToFsStringAlloc(p, -1, NULL);
2067 code = cm_SearchCellFile(cellname, ftemp, 0, 0);
2068 #ifdef AFS_AFSDB_ENV
2069 if (code && cm_dnsEnabled) {
2071 code = cm_SearchCellByDNS(cellname, ftemp, &ttl, 0, 0);
2077 /* construct the path */
2079 clientchar_t temp[1024];
2081 if (cm_FsStringToClientString(ftemp, -1, temp, 1024) != 0) {
2082 cm_ClientStrPrintfN(pathName, (int)lengthof(pathName),
2083 rw ? _C("/.%S/") : _C("/%S/"), temp);
2084 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
2094 /* Client-side offline caching policy types */
2095 #define CSC_POLICY_MANUAL 0
2096 #define CSC_POLICY_DOCUMENTS 1
2097 #define CSC_POLICY_PROGRAMS 2
2098 #define CSC_POLICY_DISABLE 3
2100 int smb_FindShareCSCPolicy(clientchar_t *shareName)
2103 clientchar_t policy[1024];
2106 int retval = CSC_POLICY_MANUAL;
2108 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
2109 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
2112 REG_OPTION_NON_VOLATILE,
2118 len = sizeof(policy);
2119 if ( RegQueryValueExW( hkCSCPolicy, shareName, 0, &dwType, (LPBYTE) policy, &len ) ||
2121 retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
2123 else if (cm_ClientStrCmpIA(policy, _C("documents")) == 0)
2125 retval = CSC_POLICY_DOCUMENTS;
2127 else if (cm_ClientStrCmpIA(policy, _C("programs")) == 0)
2129 retval = CSC_POLICY_PROGRAMS;
2131 else if (cm_ClientStrCmpIA(policy, _C("disable")) == 0)
2133 retval = CSC_POLICY_DISABLE;
2136 RegCloseKey(hkCSCPolicy);
2140 /* find a dir search structure by cookie value, and return it held.
2141 * Must be called with smb_globalLock held.
2143 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
2145 smb_dirSearch_t *dsp;
2147 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2148 if (dsp->cookie == cookie) {
2149 if (dsp != smb_firstDirSearchp) {
2150 /* move to head of LRU queue, too, if we're not already there */
2151 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
2152 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2153 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2154 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2155 if (!smb_lastDirSearchp)
2156 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2164 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
2165 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2166 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
2172 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
2174 lock_ObtainMutex(&dsp->mx);
2175 osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p",
2176 dsp->cookie, dsp, dsp->scp);
2177 dsp->flags |= SMB_DIRSEARCH_DELETE;
2178 if (dsp->scp != NULL) {
2179 lock_ObtainWrite(&dsp->scp->rw);
2180 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
2181 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2182 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2183 dsp->scp->bulkStatProgress = hzero;
2185 lock_ReleaseWrite(&dsp->scp->rw);
2187 lock_ReleaseMutex(&dsp->mx);
2190 /* Must be called with the smb_globalLock held */
2191 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
2193 cm_scache_t *scp = NULL;
2195 osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
2196 if (dsp->refCount == 0) {
2197 lock_ObtainMutex(&dsp->mx);
2198 if (dsp->flags & SMB_DIRSEARCH_DELETE) {
2199 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
2200 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
2201 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2202 lock_ReleaseMutex(&dsp->mx);
2203 lock_FinalizeMutex(&dsp->mx);
2205 osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p",
2206 dsp->cookie, dsp, scp);
2209 lock_ReleaseMutex(&dsp->mx);
2212 /* do this now to avoid spurious locking hierarchy creation */
2214 cm_ReleaseSCache(scp);
2217 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
2219 lock_ObtainWrite(&smb_globalLock);
2220 smb_ReleaseDirSearchNoLock(dsp);
2221 lock_ReleaseWrite(&smb_globalLock);
2224 /* find a dir search structure by cookie value, and return it held */
2225 smb_dirSearch_t *smb_FindDirSearch(long cookie)
2227 smb_dirSearch_t *dsp;
2229 lock_ObtainWrite(&smb_globalLock);
2230 dsp = smb_FindDirSearchNoLock(cookie);
2231 lock_ReleaseWrite(&smb_globalLock);
2235 /* GC some dir search entries, in the address space expected by the specific protocol.
2236 * Must be called with smb_globalLock held; release the lock temporarily.
2238 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
2239 void smb_GCDirSearches(int isV3)
2241 smb_dirSearch_t *prevp;
2242 smb_dirSearch_t *dsp;
2243 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
2247 victimCount = 0; /* how many have we got so far */
2248 for (dsp = smb_lastDirSearchp; dsp; dsp=prevp) {
2249 /* we'll move tp from queue, so
2252 prevp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2253 /* if no one is using this guy, and we're either in the new protocol,
2254 * or we're in the old one and this is a small enough ID to be useful
2255 * to the old protocol, GC this guy.
2257 if (dsp->refCount == 0 && (isV3 || dsp->cookie <= 255)) {
2258 /* hold and delete */
2259 lock_ObtainMutex(&dsp->mx);
2260 dsp->flags |= SMB_DIRSEARCH_DELETE;
2261 lock_ReleaseMutex(&dsp->mx);
2262 victimsp[victimCount++] = dsp;
2266 /* don't do more than this */
2267 if (victimCount >= SMB_DIRSEARCH_GCMAX)
2271 /* now release them */
2272 for (i = 0; i < victimCount; i++) {
2273 smb_ReleaseDirSearchNoLock(victimsp[i]);
2277 /* function for allocating a dir search entry. We need these to remember enough context
2278 * since we don't get passed the path from call to call during a directory search.
2280 * Returns a held dir search structure, and bumps the reference count on the vnode,
2281 * since it saves a pointer to the vnode.
2283 smb_dirSearch_t *smb_NewDirSearch(int isV3)
2285 smb_dirSearch_t *dsp;
2291 lock_ObtainWrite(&smb_globalLock);
2294 /* what's the biggest ID allowed in this version of the protocol */
2295 /* TODO: do we really want a non v3 dir search request to wrap
2296 smb_dirSearchCounter? */
2297 maxAllowed = isV3 ? 65535 : 255;
2298 if (smb_dirSearchCounter > maxAllowed)
2299 smb_dirSearchCounter = 1;
2301 start = smb_dirSearchCounter;
2304 /* twice so we have enough tries to find guys we GC after one pass;
2305 * 10 extra is just in case I mis-counted.
2307 if (++counter > 2*maxAllowed+10)
2308 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2310 if (smb_dirSearchCounter > maxAllowed) {
2311 smb_dirSearchCounter = 1;
2313 if (smb_dirSearchCounter == start) {
2315 smb_GCDirSearches(isV3);
2318 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2320 /* don't need to watch for refcount zero and deleted, since
2321 * we haven't dropped the global lock.
2324 ++smb_dirSearchCounter;
2328 dsp = malloc(sizeof(*dsp));
2329 memset(dsp, 0, sizeof(*dsp));
2330 dsp->cookie = smb_dirSearchCounter;
2331 ++smb_dirSearchCounter;
2333 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t", LOCK_HIERARCHY_SMB_DIRSEARCH);
2334 dsp->lastTime = osi_Time();
2335 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2336 if (!smb_lastDirSearchp)
2337 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2339 osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p",
2343 lock_ReleaseWrite(&smb_globalLock);
2347 static smb_packet_t *smb_GetPacket(void)
2351 lock_ObtainWrite(&smb_globalLock);
2352 tbp = smb_packetFreeListp;
2354 smb_packetFreeListp = tbp->nextp;
2355 lock_ReleaseWrite(&smb_globalLock);
2357 tbp = calloc(sizeof(*tbp),1);
2358 tbp->magic = SMB_PACKETMAGIC;
2361 tbp->resumeCode = 0;
2367 tbp->ncb_length = 0;
2370 tbp->stringsp = NULL;
2372 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2377 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2380 tbp = smb_GetPacket();
2381 memcpy(tbp, pkt, sizeof(smb_packet_t));
2382 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2383 tbp->stringsp = NULL;
2385 smb_HoldVC(tbp->vcp);
2389 static NCB *smb_GetNCB(void)
2394 lock_ObtainWrite(&smb_globalLock);
2395 tbp = smb_ncbFreeListp;
2397 smb_ncbFreeListp = tbp->nextp;
2398 lock_ReleaseWrite(&smb_globalLock);
2400 tbp = calloc(sizeof(*tbp),1);
2401 tbp->magic = SMB_NCBMAGIC;
2404 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2406 memset(&tbp->ncb, 0, sizeof(NCB));
2411 static void FreeSMBStrings(smb_packet_t * pkt)
2416 for (s = pkt->stringsp; s; s = ns) {
2420 pkt->stringsp = NULL;
2423 void smb_FreePacket(smb_packet_t *tbp)
2425 smb_vc_t * vcp = NULL;
2426 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2428 lock_ObtainWrite(&smb_globalLock);
2429 tbp->nextp = smb_packetFreeListp;
2430 smb_packetFreeListp = tbp;
2431 tbp->magic = SMB_PACKETMAGIC;
2435 tbp->resumeCode = 0;
2441 tbp->ncb_length = 0;
2443 FreeSMBStrings(tbp);
2444 lock_ReleaseWrite(&smb_globalLock);
2450 static void smb_FreeNCB(NCB *bufferp)
2454 tbp = (smb_ncb_t *) bufferp;
2455 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2457 lock_ObtainWrite(&smb_globalLock);
2458 tbp->nextp = smb_ncbFreeListp;
2459 smb_ncbFreeListp = tbp;
2460 lock_ReleaseWrite(&smb_globalLock);
2463 /* get a ptr to the data part of a packet, and its count */
2464 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2468 unsigned char *afterParmsp;
2470 parmBytes = *smbp->wctp << 1;
2471 afterParmsp = smbp->wctp + parmBytes + 1;
2473 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2474 if (nbytesp) *nbytesp = dataBytes;
2476 /* don't forget to skip the data byte count, since it follows
2477 * the parameters; that's where the "2" comes from below.
2479 return (unsigned char *) (afterParmsp + 2);
2482 /* must set all the returned parameters before playing around with the
2483 * data region, since the data region is located past the end of the
2484 * variable number of parameters.
2486 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2488 unsigned char *afterParmsp;
2490 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2492 *afterParmsp++ = dsize & 0xff;
2493 *afterParmsp = (dsize>>8) & 0xff;
2496 /* return the parm'th parameter in the smbp packet */
2497 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2500 unsigned char *parmDatap;
2502 parmCount = *smbp->wctp;
2504 if (parm >= parmCount) {
2507 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2508 parm, parmCount, smbp->ncb_length);
2509 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2510 parm, parmCount, smbp->ncb_length);
2511 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2512 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2513 osi_panic(s, __FILE__, __LINE__);
2515 parmDatap = smbp->wctp + (2*parm) + 1;
2517 return parmDatap[0] + (parmDatap[1] << 8);
2520 /* return the parm'th parameter in the smbp packet */
2521 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2524 unsigned char *parmDatap;
2526 parmCount = *smbp->wctp;
2528 if (parm >= parmCount) {
2531 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2532 parm, parmCount, smbp->ncb_length);
2533 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2534 parm, parmCount, smbp->ncb_length);
2535 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2536 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2537 osi_panic(s, __FILE__, __LINE__);
2539 parmDatap = smbp->wctp + (2*parm) + 1;
2541 return parmDatap[0];
2544 /* return the parm'th parameter in the smbp packet */
2545 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2548 unsigned char *parmDatap;
2550 parmCount = *smbp->wctp;
2552 if (parm + 1 >= parmCount) {
2555 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2556 parm, parmCount, smbp->ncb_length);
2557 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2558 parm, parmCount, smbp->ncb_length);
2559 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2560 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2561 osi_panic(s, __FILE__, __LINE__);
2563 parmDatap = smbp->wctp + (2*parm) + 1;
2565 return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2568 /* return the parm'th parameter in the smbp packet */
2569 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2572 unsigned char *parmDatap;
2574 parmCount = *smbp->wctp;
2576 if (parm * 2 + offset >= parmCount * 2) {
2579 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2580 parm, offset, parmCount, smbp->ncb_length);
2581 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2582 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2583 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2584 parm, offset, parmCount, smbp->ncb_length);
2585 osi_panic(s, __FILE__, __LINE__);
2587 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2589 return parmDatap[0] + (parmDatap[1] << 8);
2592 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2594 unsigned char *parmDatap;
2596 /* make sure we have enough slots */
2597 if (*smbp->wctp <= slot)
2598 *smbp->wctp = slot+1;
2600 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2601 *parmDatap++ = parmValue & 0xff;
2602 *parmDatap = (parmValue>>8) & 0xff;
2605 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2607 unsigned char *parmDatap;
2609 /* make sure we have enough slots */
2610 if (*smbp->wctp <= slot)
2611 *smbp->wctp = slot+2;
2613 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2614 *parmDatap++ = parmValue & 0xff;
2615 *parmDatap++ = (parmValue>>8) & 0xff;
2616 *parmDatap++ = (parmValue>>16) & 0xff;
2617 *parmDatap = (parmValue>>24) & 0xff;
2620 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2622 unsigned char *parmDatap;
2625 /* make sure we have enough slots */
2626 if (*smbp->wctp <= slot)
2627 *smbp->wctp = slot+4;
2629 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2631 *parmDatap++ = *parmValuep++;
2634 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2636 unsigned char *parmDatap;
2638 /* make sure we have enough slots */
2639 if (*smbp->wctp <= slot) {
2640 if (smbp->oddByte) {
2642 *smbp->wctp = slot+1;
2647 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2648 *parmDatap++ = parmValue & 0xff;
2653 void smb_StripLastComponent(clientchar_t *outPathp, clientchar_t **lastComponentp,
2654 clientchar_t *inPathp)
2656 clientchar_t *lastSlashp;
2658 lastSlashp = cm_ClientStrRChr(inPathp, '\\');
2660 *lastComponentp = lastSlashp;
2663 if (inPathp == lastSlashp)
2665 *outPathp++ = *inPathp++;
2674 clientchar_t *smb_ParseASCIIBlock(smb_packet_t * pktp, unsigned char *inp,
2675 char **chainpp, int flags)
2678 afs_uint32 type = *inp++;
2681 * The first byte specifies the type of the input string.
2682 * CIFS TR 1.0 3.2.10. This function only parses null terminated
2686 /* Length Counted */
2687 case 0x1: /* Data Block */
2688 case 0x5: /* Variable Block */
2689 cb = *inp++ << 16 | *inp++;
2692 /* Null-terminated string */
2693 case 0x4: /* ASCII */
2694 case 0x3: /* Pathname */
2695 case 0x2: /* Dialect */
2696 cb = sizeof(pktp->data) - (inp - pktp->data);
2697 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2698 #ifdef DEBUG_UNICODE
2701 cb = sizeof(pktp->data);
2706 return NULL; /* invalid input */
2710 if (type == 0x2 /* Dialect */ || !WANTS_UNICODE(pktp))
2711 flags |= SMB_STRF_FORCEASCII;
2714 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2717 clientchar_t *smb_ParseString(smb_packet_t * pktp, unsigned char * inp,
2718 char ** chainpp, int flags)
2723 if (!WANTS_UNICODE(pktp))
2724 flags |= SMB_STRF_FORCEASCII;
2727 cb = sizeof(pktp->data) - (inp - pktp->data);
2728 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2729 #ifdef DEBUG_UNICODE
2732 cb = sizeof(pktp->data);
2734 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp,
2735 flags | SMB_STRF_SRCNULTERM);
2738 clientchar_t *smb_ParseStringCb(smb_packet_t * pktp, unsigned char * inp,
2739 size_t cb, char ** chainpp, int flags)
2742 if (!WANTS_UNICODE(pktp))
2743 flags |= SMB_STRF_FORCEASCII;
2746 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2749 clientchar_t *smb_ParseStringCch(smb_packet_t * pktp, unsigned char * inp,
2750 size_t cch, char ** chainpp, int flags)
2755 if (!WANTS_UNICODE(pktp))
2756 flags |= SMB_STRF_FORCEASCII;
2758 cb = cch * sizeof(wchar_t);
2761 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2765 smb_ParseStringBuf(const unsigned char * bufbase,
2766 cm_space_t ** stringspp,
2767 unsigned char *inp, size_t *pcb_max,
2768 char **chainpp, int flags)
2771 if (!(flags & SMB_STRF_FORCEASCII)) {
2773 cm_space_t * spacep;
2776 if (bufbase && ((inp - bufbase) % 2) != 0) {
2777 inp++; /* unicode strings are always word aligned */
2781 if (FAILED(StringCchLengthW((const wchar_t *) inp, *pcb_max / sizeof(wchar_t),
2783 cch_src = *pcb_max / sizeof(wchar_t);
2787 *pcb_max -= (cch_src + 1) * sizeof(wchar_t);
2794 spacep = cm_GetSpace();
2795 spacep->nextp = *stringspp;
2796 *stringspp = spacep;
2800 *chainpp = inp + sizeof(wchar_t);
2803 *(spacep->wdata) = 0;
2804 return spacep->wdata;
2807 StringCchCopyNW(spacep->wdata,
2808 lengthof(spacep->wdata),
2809 (const clientchar_t *) inp, cch_src);
2812 *chainpp = inp + (cch_src + null_terms)*sizeof(wchar_t);
2814 return spacep->wdata;
2818 cm_space_t * spacep;
2821 /* Not using Unicode */
2823 *chainpp = inp + strlen(inp) + 1;
2826 spacep = cm_GetSpace();
2827 spacep->nextp = *stringspp;
2828 *stringspp = spacep;
2830 cchdest = lengthof(spacep->wdata);
2831 cm_Utf8ToUtf16(inp, (int)((flags & SMB_STRF_SRCNULTERM)? -1 : *pcb_max),
2832 spacep->wdata, cchdest);
2834 return spacep->wdata;
2840 unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
2842 size_t * plen, int flags)
2848 /* we are only calculating the required size */
2855 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2857 StringCbLengthW(str, SMB_STRINGBUFSIZE * sizeof(wchar_t), plen);
2858 if (!(flags & SMB_STRF_IGNORENUL))
2859 *plen += sizeof(wchar_t);
2861 return (unsigned char *) 1; /* return TRUE if we are using unicode */
2871 cch_str = cm_ClientStrLen(str);
2872 cch_dest = cm_ClientStringToUtf8(str, (int)cch_str, NULL, 0);
2875 *plen = ((flags & SMB_STRF_IGNORENUL)? cch_dest: cch_dest+1);
2883 /* if outp != NULL ... */
2885 /* Number of bytes left in the buffer.
2887 If outp lies inside the packet data buffer, we assume that the
2888 buffer is the packet data buffer. Otherwise we assume that the
2889 buffer is sizeof(packet->data).
2892 if (outp >= pktp->data && outp < pktp->data + sizeof(pktp->data)) {
2893 align = (int)((outp - pktp->data) % 2);
2894 buffersize = (pktp->data + sizeof(pktp->data)) - ((char *) outp);
2896 align = (int)(((size_t) outp) % 2);
2897 buffersize = (int)sizeof(pktp->data);
2902 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2908 if (*str == _C('\0')) {
2910 if (buffersize < sizeof(wchar_t))
2913 *((wchar_t *) outp) = L'\0';
2914 if (plen && !(flags & SMB_STRF_IGNORENUL))
2915 *plen += sizeof(wchar_t);
2916 return outp + sizeof(wchar_t);
2919 nchars = cm_ClientStringToUtf16(str, -1, (wchar_t *) outp, (int)(buffersize / sizeof(wchar_t)));
2921 osi_Log2(smb_logp, "UnparseString: Can't convert string to Unicode [%S], GLE=%d",
2922 osi_LogSaveClientString(smb_logp, str),
2928 *plen += sizeof(wchar_t) * ((flags & SMB_STRF_IGNORENUL)? nchars - 1: nchars);
2930 return outp + sizeof(wchar_t) * nchars;
2938 cch_dest = cm_ClientStringToUtf8(str, -1, outp, (int)buffersize);
2941 *plen += ((flags & SMB_STRF_IGNORENUL)? cch_dest - 1: cch_dest);
2943 return outp + cch_dest;
2947 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2953 tlen = inp[0] + (inp[1]<<8);
2954 inp += 2; /* skip length field */
2957 *chainpp = inp + tlen;
2966 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2970 if (*inp++ != 0x1) return NULL;
2971 tlen = inp[0] + (inp[1]<<8);
2972 inp += 2; /* skip length field */
2975 *chainpp = inp + tlen;
2978 if (lengthp) *lengthp = tlen;
2983 /* format a packet as a response */
2984 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2989 outp = (smb_t *) op;
2991 /* zero the basic structure through the smb_wct field, and zero the data
2992 * size field, assuming that wct stays zero; otherwise, you have to
2993 * explicitly set the data size field, too.
2995 inSmbp = (smb_t *) inp;
2996 memset(outp, 0, sizeof(smb_t)+2);
3002 outp->com = inSmbp->com;
3003 outp->tid = inSmbp->tid;
3004 outp->pid = inSmbp->pid;
3005 outp->uid = inSmbp->uid;
3006 outp->mid = inSmbp->mid;
3007 outp->res[0] = inSmbp->res[0];
3008 outp->res[1] = inSmbp->res[1];
3009 op->inCom = inSmbp->com;
3011 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
3012 #ifdef SEND_CANONICAL_PATHNAMES
3013 outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
3015 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
3017 if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
3018 outp->flg2 |= SMB_FLAGS2_UNICODE;
3021 /* copy fields in generic packet area */
3022 op->wctp = &outp->wct;
3025 /* send a (probably response) packet; vcp tells us to whom to send it.
3026 * we compute the length by looking at wct and bcc fields.
3028 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
3038 ncbp = smb_GetNCB();
3042 memset((char *)ncbp, 0, sizeof(NCB));
3044 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
3045 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
3046 extra += tp[0] + (tp[1]<<8);
3047 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
3048 extra += 3; /* wct and length fields */
3050 ncbp->ncb_length = extra; /* bytes to send */
3051 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
3052 ncbp->ncb_lana_num = vcp->lana;
3053 ncbp->ncb_command = NCBSEND; /* op means send data */
3054 ncbp->ncb_buffer = (char *) inp;/* packet */
3055 code = Netbios(ncbp);
3058 const char * s = ncb_error_string(code);
3059 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
3060 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
3062 lock_ObtainMutex(&vcp->mx);
3063 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
3064 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
3066 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
3067 lock_ReleaseMutex(&vcp->mx);
3068 lock_ObtainWrite(&smb_globalLock);
3069 dead_sessions[vcp->session] = TRUE;
3070 lock_ReleaseWrite(&smb_globalLock);
3071 smb_CleanupDeadVC(vcp);
3073 lock_ReleaseMutex(&vcp->mx);
3081 void smb_MapNTError(long code, unsigned long *NTStatusp)
3083 unsigned long NTStatus;
3085 /* map CM_ERROR_* errors to NT 32-bit status codes */
3086 /* NT Status codes are listed in ntstatus.h not winerror.h */
3090 else if (code == CM_ERROR_NOSUCHCELL) {
3091 NTStatus = 0xC000000FL; /* No such file */
3093 else if (code == CM_ERROR_NOSUCHVOLUME) {
3094 NTStatus = 0xC000000FL; /* No such file */
3096 else if (code == CM_ERROR_TIMEDOUT) {
3098 NTStatus = 0xC00000CFL; /* Sharing Paused */
3100 NTStatus = 0x00000102L; /* Timeout */
3103 else if (code == CM_ERROR_RETRY) {
3104 NTStatus = 0xC000022DL; /* Retry */
3106 else if (code == CM_ERROR_NOACCESS) {
3107 NTStatus = 0xC0000022L; /* Access denied */
3109 else if (code == CM_ERROR_READONLY) {
3110 NTStatus = 0xC00000A2L; /* Write protected */
3112 else if (code == CM_ERROR_NOSUCHFILE ||
3113 code == CM_ERROR_BPLUS_NOMATCH) {
3114 NTStatus = 0xC000000FL; /* No such file */
3116 else if (code == CM_ERROR_NOSUCHPATH) {
3117 NTStatus = 0xC000003AL; /* Object path not found */
3119 else if (code == CM_ERROR_TOOBIG) {
3120 NTStatus = 0xC000007BL; /* Invalid image format */
3122 else if (code == CM_ERROR_INVAL) {
3123 NTStatus = 0xC000000DL; /* Invalid parameter */
3125 else if (code == CM_ERROR_BADFD) {
3126 NTStatus = 0xC0000008L; /* Invalid handle */
3128 else if (code == CM_ERROR_BADFDOP) {
3129 NTStatus = 0xC0000022L; /* Access denied */
3131 else if (code == CM_ERROR_EXISTS) {
3132 NTStatus = 0xC0000035L; /* Object name collision */
3134 else if (code == CM_ERROR_NOTEMPTY) {
3135 NTStatus = 0xC0000101L; /* Directory not empty */
3137 else if (code == CM_ERROR_CROSSDEVLINK) {
3138 NTStatus = 0xC00000D4L; /* Not same device */
3140 else if (code == CM_ERROR_NOTDIR) {
3141 NTStatus = 0xC0000103L; /* Not a directory */
3143 else if (code == CM_ERROR_ISDIR) {
3144 NTStatus = 0xC00000BAL; /* File is a directory */
3146 else if (code == CM_ERROR_BADOP) {
3148 /* I have no idea where this comes from */
3149 NTStatus = 0xC09820FFL; /* SMB no support */
3151 NTStatus = 0xC00000BBL; /* Not supported */
3152 #endif /* COMMENT */
3154 else if (code == CM_ERROR_BADSHARENAME) {
3155 NTStatus = 0xC00000CCL; /* Bad network name */
3157 else if (code == CM_ERROR_NOIPC) {
3159 NTStatus = 0xC0000022L; /* Access Denied */
3161 NTStatus = 0xC000013DL; /* Remote Resources */
3164 else if (code == CM_ERROR_CLOCKSKEW) {
3165 NTStatus = 0xC0000133L; /* Time difference at DC */
3167 else if (code == CM_ERROR_BADTID) {
3168 NTStatus = 0xC0982005L; /* SMB bad TID */
3170 else if (code == CM_ERROR_USESTD) {
3171 NTStatus = 0xC09820FBL; /* SMB use standard */
3173 else if (code == CM_ERROR_QUOTA) {
3174 NTStatus = 0xC0000044L; /* Quota exceeded */
3176 else if (code == CM_ERROR_SPACE) {
3177 NTStatus = 0xC000007FL; /* Disk full */
3179 else if (code == CM_ERROR_ATSYS) {
3180 NTStatus = 0xC0000033L; /* Object name invalid */
3182 else if (code == CM_ERROR_BADNTFILENAME) {
3183 NTStatus = 0xC0000033L; /* Object name invalid */
3185 else if (code == CM_ERROR_WOULDBLOCK) {
3186 NTStatus = 0xC00000D8L; /* Can't wait */
3188 else if (code == CM_ERROR_SHARING_VIOLATION) {
3189 NTStatus = 0xC0000043L; /* Sharing violation */
3191 else if (code == CM_ERROR_LOCK_CONFLICT) {
3192 NTStatus = 0xC0000054L; /* Lock conflict */
3194 else if (code == CM_ERROR_PARTIALWRITE) {
3195 NTStatus = 0xC000007FL; /* Disk full */
3197 else if (code == CM_ERROR_BUFFERTOOSMALL) {
3198 NTStatus = 0xC0000023L; /* Buffer too small */
3200 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3201 NTStatus = 0xC0000035L; /* Object name collision */
3203 else if (code == CM_ERROR_BADPASSWORD) {
3204 NTStatus = 0xC000006DL; /* unknown username or bad password */
3206 else if (code == CM_ERROR_BADLOGONTYPE) {
3207 NTStatus = 0xC000015BL; /* logon type not granted */
3209 else if (code == CM_ERROR_GSSCONTINUE) {
3210 NTStatus = 0xC0000016L; /* more processing required */
3212 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3214 NTStatus = 0xC0000280L; /* reparse point not resolved */
3216 NTStatus = 0xC0000022L; /* Access Denied */
3219 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3220 NTStatus = 0xC0000257L; /* Path Not Covered */
3222 else if (code == CM_ERROR_ALLBUSY) {
3223 NTStatus = 0xC000022DL; /* Retry */
3225 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3226 NTStatus = 0xC00000BEL; /* Bad Network Path */
3228 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3229 NTStatus = 0xC0000322L; /* No Kerberos key */
3231 else if (code == CM_ERROR_BAD_LEVEL) {
3232 NTStatus = 0xC0000148L; /* Invalid Level */
3234 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3235 NTStatus = 0xC000007EL; /* Range Not Locked */
3237 else if (code == CM_ERROR_NOSUCHDEVICE) {
3238 NTStatus = 0xC000000EL; /* No Such Device */
3240 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3241 NTStatus = 0xC0000055L; /* Lock Not Granted */
3242 } else if (code == ENOMEM) {
3243 NTStatus = 0xC0000017L; /* Out of Memory */
3245 NTStatus = 0xC0982001L; /* SMB non-specific error */
3248 *NTStatusp = NTStatus;
3249 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
3252 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
3253 unsigned char *classp)
3255 unsigned char class;
3256 unsigned short error;
3258 /* map CM_ERROR_* errors to SMB errors */
3259 if (code == CM_ERROR_NOSUCHCELL) {
3261 error = 3; /* bad path */
3263 else if (code == CM_ERROR_NOSUCHVOLUME) {
3265 error = 3; /* bad path */
3267 else if (code == CM_ERROR_TIMEDOUT) {
3269 error = 81; /* server is paused */
3271 else if (code == CM_ERROR_RETRY) {
3272 class = 2; /* shouldn't happen */
3275 else if (code == CM_ERROR_NOACCESS) {
3277 error = 4; /* bad access */
3279 else if (code == CM_ERROR_READONLY) {
3281 error = 19; /* read only */
3283 else if (code == CM_ERROR_NOSUCHFILE ||
3284 code == CM_ERROR_BPLUS_NOMATCH) {
3286 error = 2; /* ENOENT! */
3288 else if (code == CM_ERROR_NOSUCHPATH) {
3290 error = 3; /* Bad path */
3292 else if (code == CM_ERROR_TOOBIG) {
3294 error = 11; /* bad format */
3296 else if (code == CM_ERROR_INVAL) {
3297 class = 2; /* server non-specific error code */
3300 else if (code == CM_ERROR_BADFD) {
3302 error = 6; /* invalid file handle */
3304 else if (code == CM_ERROR_BADFDOP) {
3305 class = 1; /* invalid op on FD */
3308 else if (code == CM_ERROR_EXISTS) {
3310 error = 80; /* file already exists */
3312 else if (code == CM_ERROR_NOTEMPTY) {
3314 error = 5; /* delete directory not empty */
3316 else if (code == CM_ERROR_CROSSDEVLINK) {
3318 error = 17; /* EXDEV */
3320 else if (code == CM_ERROR_NOTDIR) {
3321 class = 1; /* bad path */
3324 else if (code == CM_ERROR_ISDIR) {
3325 class = 1; /* access denied; DOS doesn't have a good match */
3328 else if (code == CM_ERROR_BADOP) {
3332 else if (code == CM_ERROR_BADSHARENAME) {
3336 else if (code == CM_ERROR_NOIPC) {
3338 error = 4; /* bad access */
3340 else if (code == CM_ERROR_CLOCKSKEW) {
3341 class = 1; /* invalid function */
3344 else if (code == CM_ERROR_BADTID) {
3348 else if (code == CM_ERROR_USESTD) {
3352 else if (code == CM_ERROR_REMOTECONN) {
3356 else if (code == CM_ERROR_QUOTA) {
3357 if (vcp->flags & SMB_VCFLAG_USEV3) {
3359 error = 39; /* disk full */
3363 error = 5; /* access denied */
3366 else if (code == CM_ERROR_SPACE) {
3367 if (vcp->flags & SMB_VCFLAG_USEV3) {
3369 error = 39; /* disk full */
3373 error = 5; /* access denied */
3376 else if (code == CM_ERROR_PARTIALWRITE) {
3378 error = 39; /* disk full */
3380 else if (code == CM_ERROR_ATSYS) {
3382 error = 2; /* ENOENT */
3384 else if (code == CM_ERROR_WOULDBLOCK) {
3386 error = 33; /* lock conflict */
3388 else if (code == CM_ERROR_LOCK_CONFLICT) {
3390 error = 33; /* lock conflict */
3392 else if (code == CM_ERROR_SHARING_VIOLATION) {
3394 error = 33; /* lock conflict */
3396 else if (code == CM_ERROR_NOFILES) {
3398 error = 18; /* no files in search */
3400 else if (code == CM_ERROR_RENAME_IDENTICAL) {
3402 error = 183; /* Samba uses this */
3404 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
3405 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
3407 error = 2; /* bad password */
3409 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3411 error = 3; /* bad path */
3420 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
3423 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3425 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
3426 return CM_ERROR_BADOP;
3430 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3432 unsigned short EchoCount, i;
3433 char *data, *outdata;
3436 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
3438 for (i=1; i<=EchoCount; i++) {
3439 data = smb_GetSMBData(inp, &dataSize);
3440 smb_SetSMBParm(outp, 0, i);
3441 smb_SetSMBDataLength(outp, dataSize);
3442 outdata = smb_GetSMBData(outp, NULL);
3443 memcpy(outdata, data, dataSize);
3444 smb_SendPacket(vcp, outp);
3450 /* SMB_COM_READ_RAW */
3451 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3454 long count, minCount, finalCount;
3458 smb_t *smbp = (smb_t*) inp;
3460 cm_user_t *userp = NULL;
3463 char *rawBuf = NULL;
3468 fd = smb_GetSMBParm(inp, 0);
3469 count = smb_GetSMBParm(inp, 3);
3470 minCount = smb_GetSMBParm(inp, 4);
3471 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3473 if (*inp->wctp == 10) {
3474 /* we were sent a request with 64-bit file offsets */
3475 #ifdef AFS_LARGEFILES
3476 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
3478 if (LargeIntegerLessThanZero(offset)) {
3479 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
3483 if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
3484 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset. Dropping request.");
3487 offset.HighPart = 0;
3491 /* we were sent a request with 32-bit file offsets */
3492 offset.HighPart = 0;
3495 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
3496 fd, offset.HighPart, offset.LowPart, count);
3498 fidp = smb_FindFID(vcp, fd, 0);
3502 lock_ObtainMutex(&fidp->mx);
3503 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3504 lock_ReleaseMutex(&fidp->mx);
3505 smb_CloseFID(vcp, fidp, NULL, 0);
3506 code = CM_ERROR_NOSUCHFILE;
3512 LARGE_INTEGER LOffset, LLength;
3515 key = cm_GenerateKey(vcp->vcID, pid, fd);
3517 LOffset.HighPart = offset.HighPart;
3518 LOffset.LowPart = offset.LowPart;
3519 LLength.HighPart = 0;
3520 LLength.LowPart = count;
3522 lock_ObtainWrite(&fidp->scp->rw);
3523 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
3524 lock_ReleaseWrite(&fidp->scp->rw);
3527 lock_ReleaseMutex(&fidp->mx);
3531 lock_ObtainMutex(&smb_RawBufLock);
3533 /* Get a raw buf, from head of list */
3534 rawBuf = smb_RawBufs;
3535 smb_RawBufs = *(char **)smb_RawBufs;
3537 lock_ReleaseMutex(&smb_RawBufLock);
3539 lock_ReleaseMutex(&fidp->mx);
3543 if (fidp->flags & SMB_FID_IOCTL)
3545 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
3547 /* Give back raw buffer */
3548 lock_ObtainMutex(&smb_RawBufLock);
3549 *((char **) rawBuf) = smb_RawBufs;
3551 smb_RawBufs = rawBuf;
3552 lock_ReleaseMutex(&smb_RawBufLock);
3555 lock_ReleaseMutex(&fidp->mx);
3556 smb_ReleaseFID(fidp);
3559 lock_ReleaseMutex(&fidp->mx);
3561 userp = smb_GetUserFromVCP(vcp, inp);
3563 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
3569 cm_ReleaseUser(userp);
3572 smb_ReleaseFID(fidp);
3576 memset((char *)ncbp, 0, sizeof(NCB));
3578 ncbp->ncb_length = (unsigned short) finalCount;
3579 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
3580 ncbp->ncb_lana_num = vcp->lana;
3581 ncbp->ncb_command = NCBSEND;
3582 ncbp->ncb_buffer = rawBuf;
3584 code = Netbios(ncbp);
3586 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
3589 /* Give back raw buffer */
3590 lock_ObtainMutex(&smb_RawBufLock);
3591 *((char **) rawBuf) = smb_RawBufs;
3593 smb_RawBufs = rawBuf;
3594 lock_ReleaseMutex(&smb_RawBufLock);
3600 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3602 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3607 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3609 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3614 /* SMB_COM_NEGOTIATE */
3615 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3622 int VistaProtoIndex;
3623 int protoIndex; /* index we're using */
3628 char protocol_array[10][1024]; /* protocol signature of the client */
3629 int caps; /* capabilities */
3632 TIME_ZONE_INFORMATION tzi;
3634 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3637 namep = smb_GetSMBData(inp, &dbytes);
3640 coreProtoIndex = -1; /* not found */
3643 VistaProtoIndex = -1;
3644 while(namex < dbytes) {
3645 osi_Log1(smb_logp, "Protocol %s",
3646 osi_LogSaveString(smb_logp, namep+1));
3647 strcpy(protocol_array[tcounter], namep+1);
3649 /* namep points at the first protocol, or really, a 0x02
3650 * byte preceding the null-terminated ASCII name.
3652 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3653 coreProtoIndex = tcounter;
3655 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3656 v3ProtoIndex = tcounter;
3658 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3659 NTProtoIndex = tcounter;
3661 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3662 VistaProtoIndex = tcounter;
3665 /* compute size of protocol entry */
3666 entryLength = (int)strlen(namep+1);
3667 entryLength += 2; /* 0x02 bytes and null termination */
3669 /* advance over this protocol entry */
3670 namex += entryLength;
3671 namep += entryLength;
3672 tcounter++; /* which proto entry we're looking at */
3675 lock_ObtainMutex(&vcp->mx);
3677 if (VistaProtoIndex != -1) {
3678 protoIndex = VistaProtoIndex;
3679 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3682 if (NTProtoIndex != -1) {
3683 protoIndex = NTProtoIndex;
3684 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3686 else if (v3ProtoIndex != -1) {
3687 protoIndex = v3ProtoIndex;
3688 vcp->flags |= SMB_VCFLAG_USEV3;
3690 else if (coreProtoIndex != -1) {
3691 protoIndex = coreProtoIndex;
3692 vcp->flags |= SMB_VCFLAG_USECORE;
3694 else protoIndex = -1;
3695 lock_ReleaseMutex(&vcp->mx);
3697 if (protoIndex == -1)
3698 return CM_ERROR_INVAL;
3699 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3700 smb_SetSMBParm(outp, 0, protoIndex);
3701 if (smb_authType != SMB_AUTH_NONE) {
3702 smb_SetSMBParmByte(outp, 1,
3703 NEGOTIATE_SECURITY_USER_LEVEL |
3704 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3706 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3708 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3709 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3710 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3711 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3712 /* The session key is not a well documented field however most clients
3713 * will echo back the session key to the server. Currently we are using
3714 * the same value for all sessions. We should generate a random value
3715 * and store it into the vcp
3717 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3718 smb_SetSMBParm(outp, 8, 1);
3720 * Tried changing the capabilities to support for W2K - defect 117695
3721 * Maybe something else needs to be changed here?
3725 smb_SetSMBParmLong(outp, 9, 0x43fd);
3727 smb_SetSMBParmLong(outp, 9, 0x251);
3730 * 32-bit error codes *
3736 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3738 NTNEGOTIATE_CAPABILITY_DFS |
3740 #ifdef AFS_LARGEFILES
3741 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3743 NTNEGOTIATE_CAPABILITY_NTFIND |
3744 NTNEGOTIATE_CAPABILITY_RAWMODE |
3745 NTNEGOTIATE_CAPABILITY_NTSMB;
3747 if ( smb_authType == SMB_AUTH_EXTENDED )
3748 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3751 if ( smb_UseUnicode ) {
3752 caps |= NTNEGOTIATE_CAPABILITY_UNICODE;
3756 smb_SetSMBParmLong(outp, 9, caps);
3758 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3759 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3760 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3762 GetTimeZoneInformation(&tzi);
3763 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3765 if (smb_authType == SMB_AUTH_NTLM) {
3766 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3767 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3768 /* paste in encryption key */
3769 datap = smb_GetSMBData(outp, NULL);
3770 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3771 /* and the faux domain name */
3772 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3773 datap + MSV1_0_CHALLENGE_LENGTH,
3774 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3775 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3779 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3781 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3783 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3785 datap = smb_GetSMBData(outp, NULL);
3786 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3789 datap += sizeof(smb_ServerGUID);
3790 memcpy(datap, secBlob, secBlobLength);
3794 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3795 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3798 else if (v3ProtoIndex != -1) {
3799 smb_SetSMBParm(outp, 0, protoIndex);
3801 /* NOTE: Extended authentication cannot be negotiated with v3
3802 * therefore we fail over to NTLM
3804 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3805 smb_SetSMBParm(outp, 1,
3806 NEGOTIATE_SECURITY_USER_LEVEL |
3807 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3809 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3811 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3812 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3813 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3814 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3815 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3816 smb_SetSMBParm(outp, 7, 1);
3818 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3819 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3820 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3822 GetTimeZoneInformation(&tzi);
3823 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3825 /* NOTE: Extended authentication cannot be negotiated with v3
3826 * therefore we fail over to NTLM
3828 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3829 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3830 smb_SetSMBParm(outp, 12, 0); /* resvd */
3831 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3832 datap = smb_GetSMBData(outp, NULL);
3833 /* paste in a new encryption key */
3834 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3835 /* and the faux domain name */
3836 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3837 datap + MSV1_0_CHALLENGE_LENGTH,
3838 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3840 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3841 smb_SetSMBParm(outp, 12, 0); /* resvd */
3842 smb_SetSMBDataLength(outp, 0);
3845 else if (coreProtoIndex != -1) { /* not really supported anymore */
3846 smb_SetSMBParm(outp, 0, protoIndex);
3847 smb_SetSMBDataLength(outp, 0);
3852 void smb_CheckVCs(void)
3854 smb_vc_t * vcp, *nextp;
3855 smb_packet_t * outp = smb_GetPacket();
3858 lock_ObtainWrite(&smb_rctLock);
3859 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
3861 if (vcp->magic != SMB_VC_MAGIC)
3862 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
3863 __FILE__, __LINE__);
3865 /* on the first pass hold 'vcp' which was not held as 'nextp' */
3867 smb_HoldVCNoLock(vcp);
3870 * obtain a reference to 'nextp' now because we drop the
3871 * smb_rctLock later and the list contents could change
3872 * or 'vcp' could be destroyed when released.
3876 smb_HoldVCNoLock(nextp);
3878 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
3879 smb_ReleaseVCNoLock(vcp);
3883 smb_FormatResponsePacket(vcp, NULL, outp);
3884 smbp = (smb_t *)outp;
3885 outp->inCom = smbp->com = 0x2b /* Echo */;
3893 smb_SetSMBParm(outp, 0, 0);
3894 smb_SetSMBDataLength(outp, 0);
3895 lock_ReleaseWrite(&smb_rctLock);
3897 smb_SendPacket(vcp, outp);
3899 lock_ObtainWrite(&smb_rctLock);
3900 smb_ReleaseVCNoLock(vcp);
3902 lock_ReleaseWrite(&smb_rctLock);
3903 smb_FreePacket(outp);
3906 void smb_Daemon(void *parmp)
3908 afs_uint32 count = 0;
3909 smb_username_t **unpp;
3912 while(smbShutdownFlag == 0) {
3916 if (smbShutdownFlag == 1)
3919 if ((count % 72) == 0) { /* every five minutes */
3921 time_t old_localZero = smb_localZero;
3923 /* Initialize smb_localZero */
3924 myTime.tm_isdst = -1; /* compute whether on DST or not */
3925 myTime.tm_year = 70;
3931 smb_localZero = mktime(&myTime);
3933 #ifndef USE_NUMERIC_TIME_CONV
3934 smb_CalculateNowTZ();
3935 #endif /* USE_NUMERIC_TIME_CONV */
3936 #ifdef AFS_FREELANCE
3937 if ( smb_localZero != old_localZero )
3938 cm_noteLocalMountPointChange();
3944 /* GC smb_username_t objects that will no longer be used */
3946 lock_ObtainWrite(&smb_rctLock);
3947 for ( unpp=&usernamesp; *unpp; ) {
3949 smb_username_t *unp;
3951 lock_ObtainMutex(&(*unpp)->mx);
3952 if ( (*unpp)->refCount > 0 ||
3953 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
3954 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
3956 else if (!smb_LogoffTokenTransfer ||
3957 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
3959 lock_ReleaseMutex(&(*unpp)->mx);
3967 lock_FinalizeMutex(&unp->mx);
3973 cm_ReleaseUser(userp);
3975 unpp = &(*unpp)->nextp;
3978 lock_ReleaseWrite(&smb_rctLock);
3980 /* XXX GC dir search entries */
3984 void smb_WaitingLocksDaemon()
3986 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3987 smb_waitingLock_t *wl, *wlNext;
3990 smb_packet_t *inp, *outp;
3994 while (smbShutdownFlag == 0) {
3995 lock_ObtainWrite(&smb_globalLock);
3996 nwlRequest = smb_allWaitingLocks;
3997 if (nwlRequest == NULL) {
3998 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
4003 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
4010 lock_ObtainWrite(&smb_globalLock);
4012 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
4014 wlRequest = nwlRequest;
4015 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
4016 lock_ReleaseWrite(&smb_globalLock);
4020 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
4021 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4024 if (wl->state == SMB_WAITINGLOCKSTATE_CANCELLED) {
4025 code = CM_ERROR_LOCK_NOT_GRANTED;
4029 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
4031 /* wl->state is either _DONE or _WAITING. _ERROR
4032 would no longer be on the queue. */
4033 code = cm_RetryLock( wl->lockp,
4034 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
4037 wl->state = SMB_WAITINGLOCKSTATE_DONE;
4038 } else if (code != CM_ERROR_WOULDBLOCK) {
4039 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
4044 if (code == CM_ERROR_WOULDBLOCK) {
4047 if (wlRequest->msTimeout != 0xffffffff
4048 && ((osi_Time() - wlRequest->start_t) * 1000 > wlRequest->msTimeout))
4060 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
4063 scp = wlRequest->scp;
4064 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
4068 lock_ObtainWrite(&scp->rw);
4070 for (wl = wlRequest->locks; wl; wl = wlNext) {
4071 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4073 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4074 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
4075 wl->LLength, wl->key, NULL, &req);
4077 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4082 lock_ReleaseWrite(&scp->rw);
4086 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
4089 for (wl = wlRequest->locks; wl; wl = wlNext) {
4090 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4091 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4096 vcp = wlRequest->vcp;
4097 inp = wlRequest->inp;
4098 outp = wlRequest->outp;
4099 ncbp = smb_GetNCB();
4100 ncbp->ncb_length = inp->ncb_length;
4101 inp->spacep = cm_GetSpace();
4103 /* Remove waitingLock from list */
4104 lock_ObtainWrite(&smb_globalLock);
4105 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
4107 lock_ReleaseWrite(&smb_globalLock);
4109 /* Resume packet processing */
4111 smb_SetSMBDataLength(outp, 0);
4112 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
4113 outp->resumeCode = code;
4115 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
4118 cm_FreeSpace(inp->spacep);
4119 smb_FreePacket(inp);
4120 smb_FreePacket(outp);
4122 cm_ReleaseSCache(wlRequest->scp);
4125 } while (nwlRequest && smbShutdownFlag == 0);
4130 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4132 osi_Log0(smb_logp, "SMB receive get disk attributes");
4134 smb_SetSMBParm(outp, 0, 32000);
4135 smb_SetSMBParm(outp, 1, 64);
4136 smb_SetSMBParm(outp, 2, 1024);
4137 smb_SetSMBParm(outp, 3, 30000);
4138 smb_SetSMBParm(outp, 4, 0);
4139 smb_SetSMBDataLength(outp, 0);
4143 /* SMB_COM_TREE_CONNECT */
4144 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
4148 unsigned short newTid;
4149 clientchar_t shareName[AFSPATHMAX];
4150 clientchar_t *sharePath;
4153 clientchar_t *pathp;
4156 osi_Log0(smb_logp, "SMB receive tree connect");
4158 /* parse input parameters */
4161 tbp = smb_GetSMBData(inp, NULL);
4162 pathp = smb_ParseASCIIBlock(inp, tbp, &tbp, SMB_STRF_ANSIPATH);
4164 return CM_ERROR_BADSMB;
4166 tp = cm_ClientStrRChr(pathp, '\\');
4168 return CM_ERROR_BADSMB;
4169 cm_ClientStrCpy(shareName, lengthof(shareName), tp+1);
4171 lock_ObtainMutex(&vcp->mx);
4172 newTid = vcp->tidCounter++;
4173 lock_ReleaseMutex(&vcp->mx);
4175 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
4176 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
4178 return CM_ERROR_BADSMB;
4179 userp = smb_GetUserFromUID(uidp);
4180 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
4181 smb_ReleaseUID(uidp);
4183 smb_ReleaseTID(tidp, FALSE);
4184 return CM_ERROR_BADSHARENAME;
4186 lock_ObtainMutex(&tidp->mx);
4187 tidp->userp = userp;
4188 tidp->pathname = sharePath;
4189 lock_ReleaseMutex(&tidp->mx);
4190 smb_ReleaseTID(tidp, FALSE);
4192 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
4193 smb_SetSMBParm(rsp, 1, newTid);
4194 smb_SetSMBDataLength(rsp, 0);
4196 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
4200 /* set maskp to the mask part of the incoming path.
4201 * Mask is 11 bytes long (8.3 with the dot elided).
4202 * Returns true if succeeds with a valid name, otherwise it does
4203 * its best, but returns false.
4205 int smb_Get8Dot3MaskFromPath(clientchar_t *maskp, clientchar_t *pathp)
4213 /* starts off valid */
4216 /* mask starts out all blanks */
4217 memset(maskp, ' ', 11);
4220 /* find last backslash, or use whole thing if there is none */
4221 tp = cm_ClientStrRChr(pathp, '\\');
4225 tp++; /* skip slash */
4229 /* names starting with a dot are illegal */
4237 if (tc == '.' || tc == '"')
4245 /* if we get here, tp point after the dot */
4246 up = maskp+8; /* ext goes here */
4253 if (tc == '.' || tc == '"')
4256 /* copy extension if not too long */
4266 int smb_Match8Dot3Mask(clientchar_t *unixNamep, clientchar_t *maskp)
4268 clientchar_t umask[11];
4276 /* XXX redo this, calling cm_MatchMask with a converted mask */
4278 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
4282 /* otherwise, we have a valid 8.3 name; see if we have a match,
4283 * treating '?' as a wildcard in maskp (but not in the file name).
4285 tp1 = umask; /* real name, in mask format */
4286 tp2 = maskp; /* mask, in mask format */
4287 for(i=0; i<11; i++) {
4288 tc1 = *tp1++; /* clientchar_t from real name */
4289 tc2 = *tp2++; /* clientchar_t from mask */
4290 tc1 = (clientchar_t) cm_foldUpper[(clientchar_t)tc1];
4291 tc2 = (clientchar_t) cm_foldUpper[(clientchar_t)tc2];
4294 if (tc2 == '?' && tc1 != ' ')
4301 /* we got a match */
4305 clientchar_t *smb_FindMask(clientchar_t *pathp)
4309 tp = cm_ClientStrRChr(pathp, '\\'); /* find last slash */
4312 return tp+1; /* skip the slash */
4314 return pathp; /* no slash, return the entire path */
4317 /* SMB_COM_SEARCH for a volume label
4319 (This is called from smb_ReceiveCoreSearchDir() and not an actual
4320 dispatch function.) */
4321 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4323 clientchar_t *pathp;
4325 clientchar_t mask[12];
4326 unsigned char *statBlockp;
4327 unsigned char initStatBlock[21];
4330 osi_Log0(smb_logp, "SMB receive search volume");
4332 /* pull pathname and stat block out of request */
4333 tp = smb_GetSMBData(inp, NULL);
4334 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4335 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4337 return CM_ERROR_BADSMB;
4338 statBlockp = smb_ParseVblBlock(tp, &tp, &statLen);
4339 osi_assertx(statBlockp != NULL, "null statBlock");
4341 statBlockp = initStatBlock;
4345 /* for returning to caller */
4346 smb_Get8Dot3MaskFromPath(mask, pathp);
4348 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
4349 tp = smb_GetSMBData(outp, NULL);
4351 *tp++ = 43; /* bytes in a dir entry */
4352 *tp++ = 0; /* high byte in counter */
4354 /* now marshall the dir entry, starting with the search status */
4355 *tp++ = statBlockp[0]; /* Reserved */
4356 memcpy(tp, mask, 11); tp += 11; /* FileName */
4358 /* now pass back server use info, with 1st byte non-zero */
4360 memset(tp, 0, 4); tp += 4; /* reserved for server use */
4362 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
4364 *tp++ = 0x8; /* attribute: volume */
4374 /* 4 byte file size */
4380 /* The filename is a UCHAR buffer that is ASCII even if Unicode
4383 /* finally, null-terminated 8.3 pathname, which we set to AFS */
4384 memset(tp, ' ', 13);
4387 /* set the length of the data part of the packet to 43 + 3, for the dir
4388 * entry plus the 5 and the length fields.
4390 smb_SetSMBDataLength(outp, 46);
4395 smb_ApplyDirListPatches(cm_scache_t * dscp, smb_dirListPatch_t **dirPatchespp,
4396 clientchar_t * tidPathp, clientchar_t * relPathp,
4397 cm_user_t *userp, cm_req_t *reqp)
4405 smb_dirListPatch_t *patchp;
4406 smb_dirListPatch_t *npatchp;
4407 clientchar_t path[AFSPATHMAX];
4409 afs_int32 mustFake = 0;
4411 code = cm_FindACLCache(dscp, userp, &rights);
4413 lock_ObtainWrite(&dscp->rw);
4414 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4415 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4416 lock_ReleaseWrite(&dscp->rw);
4417 if (code == CM_ERROR_NOACCESS) {
4425 if (!mustFake) { /* Bulk Stat */
4427 cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4429 memset(bsp, 0, sizeof(cm_bulkStat_t));
4431 for (patchp = *dirPatchespp, count=0;
4433 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4434 cm_scache_t *tscp = cm_FindSCache(&patchp->fid);
4438 if (lock_TryWrite(&tscp->rw)) {
4439 /* we have an entry that we can look at */
4440 if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
4441 /* we have a callback on it. Don't bother
4442 * fetching this stat entry, since we're happy
4443 * with the info we have.
4445 lock_ReleaseWrite(&tscp->rw);
4446 cm_ReleaseSCache(tscp);
4449 lock_ReleaseWrite(&tscp->rw);
4451 cm_ReleaseSCache(tscp);
4455 bsp->fids[i].Volume = patchp->fid.volume;
4456 bsp->fids[i].Vnode = patchp->fid.vnode;
4457 bsp->fids[i].Unique = patchp->fid.unique;
4459 if (bsp->counter == AFSCBMAX) {
4460 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4461 memset(bsp, 0, sizeof(cm_bulkStat_t));
4465 if (bsp->counter > 0)
4466 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4471 for (patchp = *dirPatchespp; patchp; patchp =
4472 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4474 dptr = patchp->dptr;
4476 cm_ClientStrPrintfN(path, AFSPATHMAX, _C("%s\\%s"),
4477 relPathp ? relPathp : _C(""), patchp->dep->name);
4478 reqp->relPathp = path;
4479 reqp->tidPathp = tidPathp;
4481 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4482 reqp->relPathp = reqp->tidPathp = NULL;
4485 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
4486 *dptr++ = SMB_ATTR_HIDDEN;
4489 lock_ObtainWrite(&scp->rw);
4490 if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
4491 lock_ReleaseWrite(&scp->rw);
4493 /* set the attribute */
4494 switch (scp->fileType) {
4495 case CM_SCACHETYPE_DIRECTORY:
4496 case CM_SCACHETYPE_MOUNTPOINT:
4497 case CM_SCACHETYPE_INVALID:
4498 attr = SMB_ATTR_DIRECTORY;
4500 case CM_SCACHETYPE_SYMLINK:
4501 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4502 attr = SMB_ATTR_DIRECTORY;
4504 attr = SMB_ATTR_NORMAL;
4507 /* if we get here we either have a normal file
4508 * or we have a file for which we have never
4509 * received status info. In this case, we can
4510 * check the even/odd value of the entry's vnode.
4511 * odd means it is to be treated as a directory
4512 * and even means it is to be treated as a file.
4514 if (mustFake && (scp->fid.vnode & 0x1))
4515 attr = SMB_ATTR_DIRECTORY;
4517 attr = SMB_ATTR_NORMAL;
4521 /* 1969-12-31 23:59:58 +00*/
4522 dosTime = 0xEBBFBF7D;
4525 shortTemp = (unsigned short) (dosTime & 0xffff);
4526 *((u_short *)dptr) = shortTemp;
4529 /* and copy out date */
4530 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4531 *((u_short *)dptr) = shortTemp;
4534 /* copy out file length */
4535 *((u_long *)dptr) = 0;
4538 lock_ConvertWToR(&scp->rw);
4539 attr = smb_Attributes(scp);
4540 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
4541 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
4542 attr |= SMB_ATTR_HIDDEN;
4546 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4549 shortTemp = (unsigned short) (dosTime & 0xffff);
4550 *((u_short *)dptr) = shortTemp;
4553 /* and copy out date */
4554 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4555 *((u_short *)dptr) = shortTemp;
4558 /* copy out file length */
4559 *((u_long *)dptr) = scp->length.LowPart;
4561 lock_ReleaseRead(&scp->rw);
4563 cm_ReleaseSCache(scp);
4566 /* now free the patches */
4567 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4568 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4572 /* and mark the list as empty */
4573 *dirPatchespp = NULL;
4579 /* SMB_COM_SEARCH */
4580 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4586 clientchar_t *pathp;
4587 cm_dirEntry_t *dep = 0;
4589 smb_dirListPatch_t *dirListPatchesp;
4590 smb_dirListPatch_t *curPatchp;
4594 osi_hyper_t dirLength;
4595 osi_hyper_t bufferOffset;
4596 osi_hyper_t curOffset;
4598 unsigned char *inCookiep;
4599 smb_dirSearch_t *dsp;
4603 unsigned long clientCookie;
4604 cm_pageHeader_t *pageHeaderp;
4605 cm_user_t *userp = NULL;
4607 clientchar_t mask[12];
4609 long nextEntryCookie;
4610 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4611 char resByte; /* reserved byte from the cookie */
4612 char *op; /* output data ptr */
4613 char *origOp; /* original value of op */
4614 cm_space_t *spacep; /* for pathname buffer */
4618 clientchar_t *tidPathp = 0;
4625 maxCount = smb_GetSMBParm(inp, 0);
4627 dirListPatchesp = NULL;
4629 caseFold = CM_FLAG_CASEFOLD;
4631 tp = smb_GetSMBData(inp, NULL);
4632 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4633 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4635 return CM_ERROR_BADSMB;
4637 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
4639 return CM_ERROR_BADSMB;
4641 /* We can handle long names */
4642 if (vcp->flags & SMB_VCFLAG_USENT)
4643 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
4645 /* make sure we got a whole search status */
4646 if (dataLength < 21) {
4647 nextCookie = 0; /* start at the beginning of the dir */
4650 attribute = smb_GetSMBParm(inp, 1);
4652 /* handle volume info in another function */
4653 if (attribute & 0x8)
4654 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
4656 osi_Log2(smb_logp, "SMB receive search dir count %d [%S]",
4657 maxCount, osi_LogSaveClientString(smb_logp, pathp));
4659 if (*pathp == 0) { /* null pathp, treat as root dir */
4660 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
4661 return CM_ERROR_NOFILES;
4665 dsp = smb_NewDirSearch(0);
4666 dsp->attribute = attribute;
4667 smb_Get8Dot3MaskFromPath(mask, pathp);
4668 memcpy(dsp->mask, mask, 12);
4670 /* track if this is likely to match a lot of entries */
4671 if (smb_Is8Dot3StarMask(mask))
4676 /* pull the next cookie value out of the search status block */
4677 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
4678 + (inCookiep[16]<<24);
4679 dsp = smb_FindDirSearch(inCookiep[12]);
4681 /* can't find dir search status; fatal error */
4682 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%S]",
4683 inCookiep[12], nextCookie, osi_LogSaveClientString(smb_logp, pathp));
4684 return CM_ERROR_BADFD;
4686 attribute = dsp->attribute;
4687 resByte = inCookiep[0];
4689 /* copy out client cookie, in host byte order. Don't bother
4690 * interpreting it, since we're just passing it through, anyway.
4692 memcpy(&clientCookie, &inCookiep[17], 4);
4694 memcpy(mask, dsp->mask, 12);
4696 /* assume we're doing a star match if it has continued for more
4702 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
4703 nextCookie, dsp->cookie, attribute);
4705 userp = smb_GetUserFromVCP(vcp, inp);
4707 /* try to get the vnode for the path name next */
4708 lock_ObtainMutex(&dsp->mx);
4711 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
4715 spacep = inp->spacep;
4716 smb_StripLastComponent(spacep->wdata, NULL, pathp);
4717 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4719 lock_ReleaseMutex(&dsp->mx);
4720 cm_ReleaseUser(userp);
4721 smb_DeleteDirSearch(dsp);
4722 smb_ReleaseDirSearch(dsp);
4723 return CM_ERROR_NOFILES;
4725 cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
4726 cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
4728 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
4729 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
4732 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4735 pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->wdata);
4736 cm_ReleaseSCache(scp);
4737 lock_ReleaseMutex(&dsp->mx);
4738 cm_ReleaseUser(userp);
4739 smb_DeleteDirSearch(dsp);
4740 smb_ReleaseDirSearch(dsp);
4741 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4742 return CM_ERROR_PATH_NOT_COVERED;
4744 return CM_ERROR_BADSHARENAME;
4746 #endif /* DFS_SUPPORT */
4749 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
4750 /* we need one hold for the entry we just stored into,
4751 * and one for our own processing. When we're done with this
4752 * function, we'll drop the one for our own processing.
4753 * We held it once from the namei call, and so we do another hold
4757 lock_ObtainWrite(&scp->rw);
4758 dsp->flags |= SMB_DIRSEARCH_BULKST;
4759 lock_ReleaseWrite(&scp->rw);
4762 lock_ReleaseMutex(&dsp->mx);
4764 cm_ReleaseUser(userp);
4765 smb_DeleteDirSearch(dsp);
4766 smb_ReleaseDirSearch(dsp);
4770 /* reserves space for parameter; we'll adjust it again later to the
4771 * real count of the # of entries we returned once we've actually
4772 * assembled the directory listing.
4774 smb_SetSMBParm(outp, 0, 0);
4776 /* get the directory size */
4777 lock_ObtainWrite(&scp->rw);
4778 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4779 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4781 lock_ReleaseWrite(&scp->rw);
4782 cm_ReleaseSCache(scp);
4783 cm_ReleaseUser(userp);
4784 smb_DeleteDirSearch(dsp);
4785 smb_ReleaseDirSearch(dsp);
4789 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4791 dirLength = scp->length;
4793 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4794 curOffset.HighPart = 0;
4795 curOffset.LowPart = nextCookie;
4796 origOp = op = smb_GetSMBData(outp, NULL);
4797 /* and write out the basic header */
4798 *op++ = 5; /* variable block */
4799 op += 2; /* skip vbl block length; we'll fill it in later */
4803 clientchar_t *actualName = NULL;
4804 int free_actualName = 0;
4805 clientchar_t shortName[13];
4806 clientchar_t *shortNameEnd;
4808 /* make sure that curOffset.LowPart doesn't point to the first
4809 * 32 bytes in the 2nd through last dir page, and that it doesn't
4810 * point at the first 13 32-byte chunks in the first dir page,
4811 * since those are dir and page headers, and don't contain useful
4814 temp = curOffset.LowPart & (2048-1);
4815 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4816 /* we're in the first page */
4817 if (temp < 13*32) temp = 13*32;
4820 /* we're in a later dir page */
4821 if (temp < 32) temp = 32;
4824 /* make sure the low order 5 bits are zero */
4827 /* now put temp bits back ito curOffset.LowPart */
4828 curOffset.LowPart &= ~(2048-1);
4829 curOffset.LowPart |= temp;
4831 /* check if we've returned all the names that will fit in the
4834 if (returnedNames >= maxCount) {
4835 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
4836 returnedNames, maxCount);
4840 /* check if we've passed the dir's EOF */
4841 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
4843 /* see if we can use the bufferp we have now; compute in which page
4844 * the current offset would be, and check whether that's the offset
4845 * of the buffer we have. If not, get the buffer.
4847 thyper.HighPart = curOffset.HighPart;
4848 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4849 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4852 buf_Release(bufferp);
4855 lock_ReleaseWrite(&scp->rw);
4856 code = buf_Get(scp, &thyper, &bufferp);
4857 lock_ObtainMutex(&dsp->mx);
4859 /* now, if we're doing a star match, do bulk fetching of all of
4860 * the status info for files in the dir.
4863 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
4865 lock_ObtainWrite(&scp->rw);
4866 lock_ReleaseMutex(&dsp->mx);
4868 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
4872 bufferOffset = thyper;
4874 /* now get the data in the cache */
4876 code = cm_SyncOp(scp, bufferp, userp, &req,
4878 CM_SCACHESYNC_NEEDCALLBACK |
4879 CM_SCACHESYNC_READ);
4881 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
4885 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
4887 if (cm_HaveBuffer(scp, bufferp, 0)) {
4888 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4892 /* otherwise, load the buffer and try again */
4893 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
4895 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4896 scp, bufferp, code);
4901 buf_Release(bufferp);
4905 } /* if (wrong buffer) ... */
4907 /* now we have the buffer containing the entry we're interested in; copy
4908 * it out if it represents a non-deleted entry.
4910 entryInDir = curOffset.LowPart & (2048-1);
4911 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4913 /* page header will help tell us which entries are free. Page header
4914 * can change more often than once per buffer, since AFS 3 dir page size
4915 * may be less than (but not more than a buffer package buffer.
4917 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
4918 temp &= ~(2048 - 1); /* turn off intra-page bits */
4919 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4921 /* now determine which entry we're looking at in the page. If it is
4922 * free (there's a free bitmap at the start of the dir), we should
4923 * skip these 32 bytes.
4925 slotInPage = (entryInDir & 0x7e0) >> 5;
4926 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
4927 /* this entry is free */
4928 numDirChunks = 1; /* only skip this guy */
4932 tp = bufferp->datap + entryInBuffer;
4933 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4935 /* while we're here, compute the next entry's location, too,
4936 * since we'll need it when writing out the cookie into the dir
4939 * XXXX Probably should do more sanity checking.
4941 numDirChunks = cm_NameEntries(dep->name, NULL);
4943 /* compute the offset of the cookie representing the next entry */
4944 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4946 /* Compute 8.3 name if necessary */
4947 actualName = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
4948 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
4951 cm_Gen8Dot3NameInt(dep->name, &dep->fid, shortName, &shortNameEnd);
4952 actualName = shortName;
4953 free_actualName = 0;
4955 free_actualName = 1;
4958 if (actualName == NULL) {
4959 /* Couldn't convert the name for some reason */
4960 osi_Log1(smb_logp, "SMB search dir skipping entry :[%s]",
4961 osi_LogSaveString(smb_logp, dep->name));
4965 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%S)",
4966 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
4967 osi_LogSaveClientString(smb_logp, actualName));
4969 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
4970 /* this is one of the entries to use: it is not deleted
4971 * and it matches the star pattern we're looking for.
4974 /* Eliminate entries that don't match requested
4977 /* no hidden files */
4978 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
4979 osi_Log0(smb_logp, "SMB search dir skipping hidden");
4983 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4985 /* We have already done the cm_TryBulkStat above */
4986 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
4987 fileType = cm_FindFileType(&fid);
4988 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
4989 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
4991 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4992 fileType == CM_SCACHETYPE_MOUNTPOINT ||
4993 fileType == CM_SCACHETYPE_DFSLINK ||
4994 fileType == CM_SCACHETYPE_INVALID)
4995 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
5000 memcpy(op, mask, 11); op += 11;
5001 *op++ = (unsigned char) dsp->cookie; /* they say it must be non-zero */
5002 *op++ = (unsigned char)(nextEntryCookie & 0xff);
5003 *op++ = (unsigned char)((nextEntryCookie>>8) & 0xff);
5004 *op++ = (unsigned char)((nextEntryCookie>>16) & 0xff);
5005 *op++ = (unsigned char)((nextEntryCookie>>24) & 0xff);
5006 memcpy(op, &clientCookie, 4); op += 4;
5008 /* now we emit the attribute. This is sort of tricky,
5009 * since we need to really stat the file to find out
5010 * what type of entry we've got. Right now, we're
5011 * copying out data from a buffer, while holding the
5012 * scp locked, so it isn't really convenient to stat
5013 * something now. We'll put in a place holder now,
5014 * and make a second pass before returning this to get
5015 * the real attributes. So, we just skip the data for
5016 * now, and adjust it later. We allocate a patch
5017 * record to make it easy to find this point later.
5018 * The replay will happen at a time when it is safe to
5019 * unlock the directory.
5021 curPatchp = malloc(sizeof(*curPatchp));
5022 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
5023 curPatchp->dptr = op;
5024 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5026 /* do hidden attribute here since name won't be around when applying
5030 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
5031 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5033 curPatchp->flags = 0;
5035 op += 9; /* skip attr, time, date and size */
5037 /* zero out name area. The spec says to pad with
5038 * spaces, but Samba doesn't, and neither do we.
5042 /* finally, we get to copy out the name; we know that
5043 * it fits in 8.3 or the pattern wouldn't match, but it
5044 * never hurts to be sure.
5046 cm_ClientStringToUtf8(actualName, -1, op, 13);
5047 if (smb_StoreAnsiFilenames)
5049 /* This is a UCHAR field, which is ASCII even if Unicode
5052 /* Uppercase if requested by client */
5053 if (!KNOWS_LONG_NAMES(inp))
5058 /* now, adjust the # of entries copied */
5060 } /* if we're including this name */
5063 if (free_actualName && actualName) {
5068 /* and adjust curOffset to be where the new cookie is */
5069 thyper.HighPart = 0;
5070 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5071 curOffset = LargeIntegerAdd(thyper, curOffset);
5072 } /* while copying data for dir listing */
5074 /* release the mutex */
5075 lock_ReleaseWrite(&scp->rw);
5077 buf_Release(bufferp);
5081 /* apply and free last set of patches; if not doing a star match, this
5082 * will be empty, but better safe (and freeing everything) than sorry.
5084 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
5086 /* special return code for unsuccessful search */
5087 if (code == 0 && dataLength < 21 && returnedNames == 0)
5088 code = CM_ERROR_NOFILES;
5090 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
5091 returnedNames, code);
5094 smb_DeleteDirSearch(dsp);
5095 smb_ReleaseDirSearch(dsp);
5096 cm_ReleaseSCache(scp);
5097 cm_ReleaseUser(userp);
5101 /* finalize the output buffer */
5102 smb_SetSMBParm(outp, 0, returnedNames);
5103 temp = (long) (op - origOp);
5104 smb_SetSMBDataLength(outp, temp);
5106 /* the data area is a variable block, which has a 5 (already there)
5107 * followed by the length of the # of data bytes. We now know this to
5108 * be "temp," although that includes the 3 bytes of vbl block header.
5109 * Deduct for them and fill in the length field.
5111 temp -= 3; /* deduct vbl block info */
5112 osi_assertx(temp == (43 * returnedNames), "unexpected data length");
5113 origOp[1] = (unsigned char)(temp & 0xff);
5114 origOp[2] = (unsigned char)((temp>>8) & 0xff);
5115 if (returnedNames == 0)
5116 smb_DeleteDirSearch(dsp);
5117 smb_ReleaseDirSearch(dsp);
5118 cm_ReleaseSCache(scp);
5119 cm_ReleaseUser(userp);
5124 /* verify that this is a valid path to a directory. I don't know why they
5125 * don't use the get file attributes call.
5127 * SMB_COM_CHECK_DIRECTORY
5129 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5131 clientchar_t *pathp;
5133 cm_scache_t *rootScp;
5134 cm_scache_t *newScp;
5138 clientchar_t *tidPathp;
5144 pdata = smb_GetSMBData(inp, NULL);
5145 pathp = smb_ParseASCIIBlock(inp, pdata, NULL, SMB_STRF_ANSIPATH);
5147 return CM_ERROR_BADSMB;
5148 osi_Log1(smb_logp, "SMB receive check path %S",
5149 osi_LogSaveClientString(smb_logp, pathp));
5151 rootScp = cm_data.rootSCachep;
5153 userp = smb_GetUserFromVCP(vcp, inp);
5155 caseFold = CM_FLAG_CASEFOLD;
5157 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5159 cm_ReleaseUser(userp);
5160 return CM_ERROR_NOSUCHPATH;
5162 code = cm_NameI(rootScp, pathp,
5163 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
5164 userp, tidPathp, &req, &newScp);
5167 cm_ReleaseUser(userp);
5172 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5173 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5174 cm_ReleaseSCache(newScp);
5175 cm_ReleaseUser(userp);
5176 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5177 return CM_ERROR_PATH_NOT_COVERED;
5179 return CM_ERROR_BADSHARENAME;
5181 #endif /* DFS_SUPPORT */
5183 /* now lock the vnode with a callback; returns with newScp locked */
5184 lock_ObtainWrite(&newScp->rw);
5185 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
5186 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5188 if (code != CM_ERROR_NOACCESS) {
5189 lock_ReleaseWrite(&newScp->rw);
5190 cm_ReleaseSCache(newScp);
5191 cm_ReleaseUser(userp);
5195 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5198 attrs = smb_Attributes(newScp);
5200 if (!(attrs & SMB_ATTR_DIRECTORY))
5201 code = CM_ERROR_NOTDIR;
5203 lock_ReleaseWrite(&newScp->rw);
5205 cm_ReleaseSCache(newScp);
5206 cm_ReleaseUser(userp);
5210 /* SMB_COM_SET_INFORMATION */
5211 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5213 clientchar_t *pathp;
5215 cm_scache_t *rootScp;
5216 unsigned short attribute;
5218 cm_scache_t *newScp;
5222 clientchar_t *tidPathp;
5228 /* decode basic attributes we're passed */
5229 attribute = smb_GetSMBParm(inp, 0);
5230 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5232 datap = smb_GetSMBData(inp, NULL);
5233 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5235 return CM_ERROR_BADSMB;
5237 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
5238 dosTime, attribute);
5240 rootScp = cm_data.rootSCachep;
5242 userp = smb_GetUserFromVCP(vcp, inp);
5244 caseFold = CM_FLAG_CASEFOLD;
5246 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5248 cm_ReleaseUser(userp);
5249 return CM_ERROR_NOSUCHFILE;
5251 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5252 tidPathp, &req, &newScp);
5255 cm_ReleaseUser(userp);
5260 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5261 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5262 cm_ReleaseSCache(newScp);
5263 cm_ReleaseUser(userp);
5264 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5265 return CM_ERROR_PATH_NOT_COVERED;
5267 return CM_ERROR_BADSHARENAME;
5269 #endif /* DFS_SUPPORT */
5271 /* now lock the vnode with a callback; returns with newScp locked; we
5272 * need the current status to determine what the new status is, in some
5275 lock_ObtainWrite(&newScp->rw);
5276 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5277 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5279 lock_ReleaseWrite(&newScp->rw);
5280 cm_ReleaseSCache(newScp);
5281 cm_ReleaseUser(userp);
5285 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5287 /* Check for RO volume */
5288 if (newScp->flags & CM_SCACHEFLAG_RO) {
5289 lock_ReleaseWrite(&newScp->rw);
5290 cm_ReleaseSCache(newScp);
5291 cm_ReleaseUser(userp);
5292 return CM_ERROR_READONLY;
5295 /* prepare for setattr call */
5298 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
5299 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
5301 if ((newScp->unixModeBits & 0222) && (attribute & SMB_ATTR_READONLY) != 0) {
5302 /* we're told to make a writable file read-only */
5303 attr.unixModeBits = newScp->unixModeBits & ~0222;
5304 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5306 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
5307 /* we're told to make a read-only file writable */
5308 attr.unixModeBits = newScp->unixModeBits | 0222;
5309 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5311 lock_ReleaseWrite(&newScp->rw);
5313 /* now call setattr */
5315 code = cm_SetAttr(newScp, &attr, userp, &req);
5319 cm_ReleaseSCache(newScp);
5320 cm_ReleaseUser(userp);
5326 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5328 clientchar_t *pathp;
5330 cm_scache_t *rootScp;
5331 cm_scache_t *newScp, *dscp;
5336 clientchar_t *tidPathp;
5338 clientchar_t *lastComp;
5344 datap = smb_GetSMBData(inp, NULL);
5345 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5347 return CM_ERROR_BADSMB;
5349 if (*pathp == 0) /* null path */
5352 osi_Log1(smb_logp, "SMB receive getfile attributes path %S",
5353 osi_LogSaveClientString(smb_logp, pathp));
5355 rootScp = cm_data.rootSCachep;
5357 userp = smb_GetUserFromVCP(vcp, inp);
5359 /* we shouldn't need this for V3 requests, but we seem to */
5360 caseFold = CM_FLAG_CASEFOLD;
5362 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5364 cm_ReleaseUser(userp);
5365 return CM_ERROR_NOSUCHFILE;
5369 * XXX Strange hack XXX
5371 * As of Patch 5 (16 July 97), we are having the following problem:
5372 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
5373 * requests to look up "desktop.ini" in all the subdirectories.
5374 * This can cause zillions of timeouts looking up non-existent cells
5375 * and volumes, especially in the top-level directory.
5377 * We have not found any way to avoid this or work around it except
5378 * to explicitly ignore the requests for mount points that haven't
5379 * yet been evaluated and for directories that haven't yet been
5382 * We should modify this hack to provide a fake desktop.ini file
5383 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
5385 spacep = inp->spacep;
5386 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
5387 #ifndef SPECIAL_FOLDERS
5388 if (lastComp && cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
5389 code = cm_NameI(rootScp, spacep->wdata,
5390 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
5391 userp, tidPathp, &req, &dscp);
5394 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5395 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
5397 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5398 return CM_ERROR_PATH_NOT_COVERED;
5400 return CM_ERROR_BADSHARENAME;
5402 #endif /* DFS_SUPPORT */
5403 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
5404 code = CM_ERROR_NOSUCHFILE;
5405 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
5406 cm_buf_t *bp = buf_Find(dscp, &hzero);
5411 code = CM_ERROR_NOSUCHFILE;
5413 cm_ReleaseSCache(dscp);
5415 cm_ReleaseUser(userp);
5420 #endif /* SPECIAL_FOLDERS */
5422 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5423 tidPathp, &req, &newScp);
5425 cm_ReleaseUser(userp);
5430 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5431 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5432 cm_ReleaseSCache(newScp);
5433 cm_ReleaseUser(userp);
5434 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5435 return CM_ERROR_PATH_NOT_COVERED;
5437 return CM_ERROR_BADSHARENAME;
5439 #endif /* DFS_SUPPORT */
5441 /* now lock the vnode with a callback; returns with newScp locked */
5442 lock_ObtainWrite(&newScp->rw);
5443 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5444 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5446 lock_ReleaseWrite(&newScp->rw);
5447 cm_ReleaseSCache(newScp);
5448 cm_ReleaseUser(userp);
5452 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5454 attrs = smb_Attributes(newScp);
5456 smb_SetSMBParm(outp, 0, attrs);
5458 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
5459 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
5460 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
5461 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
5462 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
5463 smb_SetSMBParm(outp, 5, 0);
5464 smb_SetSMBParm(outp, 6, 0);
5465 smb_SetSMBParm(outp, 7, 0);
5466 smb_SetSMBParm(outp, 8, 0);
5467 smb_SetSMBParm(outp, 9, 0);
5468 smb_SetSMBDataLength(outp, 0);
5469 lock_ReleaseWrite(&newScp->rw);
5471 cm_ReleaseSCache(newScp);
5472 cm_ReleaseUser(userp);
5477 /* SMB_COM_TREE_DISCONNECT */
5478 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5482 osi_Log0(smb_logp, "SMB receive tree disconnect");
5484 /* find the tree and free it */
5485 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
5487 lock_ObtainWrite(&smb_rctLock);
5489 smb_ReleaseTID(tidp, TRUE);
5490 lock_ReleaseWrite(&smb_rctLock);
5497 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5500 clientchar_t *pathp;
5501 clientchar_t *lastNamep;
5510 clientchar_t *tidPathp;
5516 datap = smb_GetSMBData(inp, NULL);
5517 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5519 return CM_ERROR_BADSMB;
5521 osi_Log1(smb_logp, "SMB receive open file [%S]", osi_LogSaveClientString(smb_logp, pathp));
5523 #ifdef DEBUG_VERBOSE
5527 hexpath = osi_HexifyString( pathp );
5528 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
5533 if (!cm_IsValidClientString(pathp)) {
5535 clientchar_t * hexp;
5537 hexp = cm_GetRawCharsAlloc(pathp, -1);
5538 osi_Log1(smb_logp, "CoreOpen rejecting invalid name. [%S]",
5539 osi_LogSaveClientString(smb_logp, hexp));
5543 osi_Log0(smb_logp, "CoreOpen rejecting invalid name");
5545 return CM_ERROR_BADNTFILENAME;
5548 share = smb_GetSMBParm(inp, 0);
5549 attribute = smb_GetSMBParm(inp, 1);
5551 spacep = inp->spacep;
5552 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5553 if (lastNamep && cm_ClientStrCmp(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0) {
5554 /* special case magic file name for receiving IOCTL requests
5555 * (since IOCTL calls themselves aren't getting through).
5557 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5558 smb_SetupIoctlFid(fidp, spacep);
5559 smb_SetSMBParm(outp, 0, fidp->fid);
5560 smb_SetSMBParm(outp, 1, 0); /* attrs */
5561 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
5562 smb_SetSMBParm(outp, 3, 0);
5563 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
5564 smb_SetSMBParm(outp, 5, 0x7fff);
5565 /* pass the open mode back */
5566 smb_SetSMBParm(outp, 6, (share & 0xf));
5567 smb_SetSMBDataLength(outp, 0);
5568 smb_ReleaseFID(fidp);
5572 userp = smb_GetUserFromVCP(vcp, inp);
5574 caseFold = CM_FLAG_CASEFOLD;
5576 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5578 cm_ReleaseUser(userp);
5579 return CM_ERROR_NOSUCHPATH;
5581 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5582 tidPathp, &req, &scp);
5585 cm_ReleaseUser(userp);
5590 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5591 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
5592 cm_ReleaseSCache(scp);
5593 cm_ReleaseUser(userp);
5594 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5595 return CM_ERROR_PATH_NOT_COVERED;
5597 return CM_ERROR_BADSHARENAME;
5599 #endif /* DFS_SUPPORT */
5601 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
5603 cm_ReleaseSCache(scp);
5604 cm_ReleaseUser(userp);
5608 /* don't need callback to check file type, since file types never
5609 * change, and namei and cm_Lookup all stat the object at least once on
5610 * a successful return.
5612 if (scp->fileType != CM_SCACHETYPE_FILE) {
5613 cm_ReleaseSCache(scp);
5614 cm_ReleaseUser(userp);
5615 return CM_ERROR_ISDIR;
5618 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5619 osi_assertx(fidp, "null smb_fid_t");
5621 lock_ObtainMutex(&fidp->mx);
5622 if ((share & 0xf) == 0)
5623 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5624 else if ((share & 0xf) == 1)
5625 fidp->flags |= SMB_FID_OPENWRITE;
5627 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
5631 fidp->userp = userp;
5633 /* and a pointer to the vnode */
5635 osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
5636 lock_ObtainWrite(&scp->rw);
5637 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5639 smb_SetSMBParm(outp, 0, fidp->fid);
5640 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
5641 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5642 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
5643 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
5644 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
5645 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
5646 /* pass the open mode back; XXXX add access checks */
5647 smb_SetSMBParm(outp, 6, (share & 0xf));
5648 smb_SetSMBDataLength(outp, 0);
5649 lock_ReleaseMutex(&fidp->mx);
5650 lock_ReleaseRead(&scp->rw);
5653 cm_Open(scp, 0, userp);
5655 /* send and free packet */
5656 smb_ReleaseFID(fidp);
5657 cm_ReleaseUser(userp);
5658 /* don't release scp, since we've squirreled away the pointer in the fid struct */
5662 typedef struct smb_unlinkRock {
5667 clientchar_t *maskp; /* pointer to the star pattern */
5670 cm_dirEntryList_t * matches;
5673 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5676 smb_unlinkRock_t *rockp;
5679 normchar_t matchName[MAX_PATH];
5683 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5684 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5685 caseFold |= CM_FLAG_8DOT3;
5687 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
5688 /* Can't convert name */
5689 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string.",
5690 osi_LogSaveString(smb_logp, dep->name));
5694 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5696 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5697 !cm_Is8Dot3(matchName)) {
5698 cm_Gen8Dot3Name(dep, matchName, NULL);
5699 /* 8.3 matches are always case insensitive */
5700 match = cm_MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
5703 osi_Log1(smb_logp, "Found match %S",
5704 osi_LogSaveClientString(smb_logp, matchName));
5706 cm_DirEntryListAdd(dep->name, &rockp->matches);
5710 /* If we made a case sensitive exact match, we might as well quit now. */
5711 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !cm_ClientStrCmp(matchName, rockp->maskp))
5712 code = CM_ERROR_STOPNOW;
5721 /* SMB_COM_DELETE */
5722 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5726 clientchar_t *pathp;
5730 clientchar_t *lastNamep;
5731 smb_unlinkRock_t rock;
5735 clientchar_t *tidPathp;
5739 memset(&rock, 0, sizeof(rock));
5741 attribute = smb_GetSMBParm(inp, 0);
5743 tp = smb_GetSMBData(inp, NULL);
5744 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
5746 return CM_ERROR_BADSMB;
5748 osi_Log1(smb_logp, "SMB receive unlink %S",
5749 osi_LogSaveClientString(smb_logp, pathp));
5751 spacep = inp->spacep;
5752 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5754 userp = smb_GetUserFromVCP(vcp, inp);
5756 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5758 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5760 cm_ReleaseUser(userp);
5761 return CM_ERROR_NOSUCHPATH;
5763 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold, userp, tidPathp,
5766 cm_ReleaseUser(userp);
5771 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5772 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
5773 cm_ReleaseSCache(dscp);
5774 cm_ReleaseUser(userp);
5775 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5776 return CM_ERROR_PATH_NOT_COVERED;
5778 return CM_ERROR_BADSHARENAME;
5780 #endif /* DFS_SUPPORT */
5782 /* otherwise, scp points to the parent directory. */
5789 rock.maskp = cm_ClientStringToNormStringAlloc(smb_FindMask(pathp), -1, NULL);
5791 code = CM_ERROR_NOSUCHFILE;
5794 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5797 thyper.HighPart = 0;
5802 rock.matches = NULL;
5804 /* Now, if we aren't dealing with a wildcard match, we first try an exact
5805 * match. If that fails, we do a case insensitve match.
5807 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
5808 !smb_IsStarMask(rock.maskp)) {
5809 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5812 thyper.HighPart = 0;
5813 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5818 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5820 if (code == CM_ERROR_STOPNOW)
5823 if (code == 0 && rock.matches) {
5824 cm_dirEntryList_t * entry;
5826 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
5827 normchar_t normalizedName[MAX_PATH];
5829 /* Note: entry->name is a non-normalized name */
5831 osi_Log1(smb_logp, "Unlinking %s",
5832 osi_LogSaveString(smb_logp, entry->name));
5834 /* We assume this works because entry->name was
5835 successfully converted in smb_UnlinkProc() once. */
5836 cm_FsStringToNormString(entry->name, -1,
5837 normalizedName, lengthof(normalizedName));
5839 code = cm_Unlink(dscp, entry->name, normalizedName, userp, &req);
5841 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5842 smb_NotifyChange(FILE_ACTION_REMOVED,
5843 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5844 dscp, normalizedName, NULL, TRUE);
5848 cm_DirEntryListFree(&rock.matches);
5852 cm_ReleaseUser(userp);
5855 cm_ReleaseSCache(dscp);
5860 if (code == 0 && !rock.any)
5861 code = CM_ERROR_NOSUCHFILE;
5865 typedef struct smb_renameRock {
5866 cm_scache_t *odscp; /* old dir */
5867 cm_scache_t *ndscp; /* new dir */
5868 cm_user_t *userp; /* user */
5869 cm_req_t *reqp; /* request struct */
5870 smb_vc_t *vcp; /* virtual circuit */
5871 normchar_t *maskp; /* pointer to star pattern of old file name */
5872 int flags; /* tilde, casefold, etc */
5873 clientchar_t *newNamep; /* ptr to the new file's name */
5874 fschar_t fsOldName[MAX_PATH]; /* raw FS name */
5875 clientchar_t clOldName[MAX_PATH]; /* client name */
5879 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5882 smb_renameRock_t *rockp;
5885 normchar_t matchName[MAX_PATH];
5887 rockp = (smb_renameRock_t *) vrockp;
5889 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
5890 /* Can't convert string */
5891 osi_Log1(smb_logp, "Skpping entry [%s]. Can't normalize FS string",
5892 osi_LogSaveString(smb_logp, dep->name));
5896 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5897 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5898 caseFold |= CM_FLAG_8DOT3;
5900 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5902 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5903 !cm_Is8Dot3(matchName)) {
5904 cm_Gen8Dot3Name(dep, matchName, NULL);
5905 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5910 StringCbCopyA(rockp->fsOldName, sizeof(rockp->fsOldName), dep->name);
5911 cm_ClientStrCpy(rockp->clOldName, lengthof(rockp->clOldName),
5913 code = CM_ERROR_STOPNOW;
5923 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp, int attrs)
5926 cm_space_t *spacep = NULL;
5927 smb_renameRock_t rock;
5928 cm_scache_t *oldDscp = NULL;
5929 cm_scache_t *newDscp = NULL;
5930 cm_scache_t *tmpscp= NULL;
5931 cm_scache_t *tmpscp2 = NULL;
5932 clientchar_t *oldLastNamep;
5933 clientchar_t *newLastNamep;
5937 clientchar_t *tidPathp;
5941 userp = smb_GetUserFromVCP(vcp, inp);
5942 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5944 cm_ReleaseUser(userp);
5945 return CM_ERROR_NOSUCHPATH;
5949 memset(&rock, 0, sizeof(rock));
5951 spacep = inp->spacep;
5952 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
5954 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5955 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
5956 userp, tidPathp, &req, &oldDscp);
5958 cm_ReleaseUser(userp);
5963 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5964 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
5965 cm_ReleaseSCache(oldDscp);
5966 cm_ReleaseUser(userp);
5967 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5968 return CM_ERROR_PATH_NOT_COVERED;
5970 return CM_ERROR_BADSHARENAME;
5972 #endif /* DFS_SUPPORT */
5974 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
5975 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
5976 userp, tidPathp, &req, &newDscp);
5979 cm_ReleaseSCache(oldDscp);
5980 cm_ReleaseUser(userp);
5985 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5986 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
5987 cm_ReleaseSCache(oldDscp);
5988 cm_ReleaseSCache(newDscp);
5989 cm_ReleaseUser(userp);
5990 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5991 return CM_ERROR_PATH_NOT_COVERED;
5993 return CM_ERROR_BADSHARENAME;
5995 #endif /* DFS_SUPPORT */
5998 /* otherwise, oldDscp and newDscp point to the corresponding directories.
5999 * next, get the component names, and lower case them.
6002 /* handle the old name first */
6004 oldLastNamep = oldPathp;
6008 /* and handle the new name, too */
6010 newLastNamep = newPathp;
6014 /* TODO: The old name could be a wildcard. The new name must not be */
6016 /* Check if the file already exists; if so return error */
6017 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6018 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6019 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6021 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6022 osi_LogSaveClientString(smb_logp, newLastNamep));
6024 /* Check if the old and the new names differ only in case. If so return
6025 * success, else return CM_ERROR_EXISTS
6027 if (!code && oldDscp == newDscp && !cm_ClientStrCmpI(oldLastNamep, newLastNamep)) {
6029 /* This would be a success only if the old file is *as same as* the new file */
6030 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
6032 if (tmpscp == tmpscp2)
6035 code = CM_ERROR_EXISTS;
6036 cm_ReleaseSCache(tmpscp2);
6039 code = CM_ERROR_NOSUCHFILE;
6042 /* file exist, do not rename, also fixes move */
6043 osi_Log0(smb_logp, "Can't rename. Target already exists");
6044 code = CM_ERROR_EXISTS;
6049 /* do the vnode call */
6050 rock.odscp = oldDscp;
6051 rock.ndscp = newDscp;
6055 rock.maskp = cm_ClientStringToNormStringAlloc(oldLastNamep, -1, NULL);
6057 code = CM_ERROR_NOSUCHFILE;
6060 rock.flags = ((cm_ClientStrChr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6061 rock.newNamep = newLastNamep;
6062 rock.fsOldName[0] = '\0';
6063 rock.clOldName[0] = '\0';
6066 /* Now search the directory for the pattern, and do the appropriate rename when found */
6067 thyper.LowPart = 0; /* search dir from here */
6068 thyper.HighPart = 0;
6070 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6071 if (code == 0 && !rock.any) {
6073 thyper.HighPart = 0;
6074 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6075 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6077 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
6079 if (code == CM_ERROR_STOPNOW && rock.fsOldName[0] != '\0') {
6080 code = cm_Rename(rock.odscp, rock.fsOldName, rock.clOldName,
6081 rock.ndscp, rock.newNamep, rock.userp,
6083 /* if the call worked, stop doing the search now, since we
6084 * really only want to rename one file.
6087 osi_Log0(smb_logp, "cm_Rename failure");
6088 osi_Log1(smb_logp, "cm_Rename returns %ld", code);
6089 } else if (code == 0) {
6090 code = CM_ERROR_NOSUCHFILE;
6093 /* Handle Change Notification */
6095 * Being lazy, not distinguishing between files and dirs in this
6096 * filter, since we'd have to do a lookup.
6099 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
6100 if (oldDscp == newDscp) {
6101 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6102 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6103 filter, oldDscp, rock.clOldName,
6104 newLastNamep, TRUE);
6106 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6107 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6108 filter, oldDscp, rock.clOldName,
6110 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6111 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
6112 filter, newDscp, newLastNamep,
6119 cm_ReleaseSCache(tmpscp);
6121 cm_ReleaseUser(userp);
6123 cm_ReleaseSCache(oldDscp);
6125 cm_ReleaseSCache(newDscp);
6133 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp)
6136 cm_space_t *spacep = NULL;
6137 cm_scache_t *oldDscp = NULL;
6138 cm_scache_t *newDscp = NULL;
6139 cm_scache_t *tmpscp= NULL;
6140 cm_scache_t *tmpscp2 = NULL;
6141 cm_scache_t *sscp = NULL;
6142 clientchar_t *oldLastNamep;
6143 clientchar_t *newLastNamep;
6146 clientchar_t *tidPathp;
6150 userp = smb_GetUserFromVCP(vcp, inp);
6152 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6154 cm_ReleaseUser(userp);
6155 return CM_ERROR_NOSUCHPATH;
6160 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6162 spacep = inp->spacep;
6163 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6165 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6166 userp, tidPathp, &req, &oldDscp);
6168 cm_ReleaseUser(userp);
6173 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6174 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6175 cm_ReleaseSCache(oldDscp);
6176 cm_ReleaseUser(userp);
6177 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6178 return CM_ERROR_PATH_NOT_COVERED;
6180 return CM_ERROR_BADSHARENAME;
6182 #endif /* DFS_SUPPORT */
6184 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6185 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6186 userp, tidPathp, &req, &newDscp);
6188 cm_ReleaseSCache(oldDscp);
6189 cm_ReleaseUser(userp);
6194 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6195 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6196 cm_ReleaseSCache(newDscp);
6197 cm_ReleaseSCache(oldDscp);
6198 cm_ReleaseUser(userp);
6199 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6200 return CM_ERROR_PATH_NOT_COVERED;
6202 return CM_ERROR_BADSHARENAME;
6204 #endif /* DFS_SUPPORT */
6206 /* Now, although we did two lookups for the two directories (because the same
6207 * directory can be referenced through different paths), we only allow hard links
6208 * within the same directory. */
6209 if (oldDscp != newDscp) {
6210 cm_ReleaseSCache(oldDscp);
6211 cm_ReleaseSCache(newDscp);
6212 cm_ReleaseUser(userp);
6213 return CM_ERROR_CROSSDEVLINK;
6216 /* handle the old name first */
6218 oldLastNamep = oldPathp;
6222 /* and handle the new name, too */
6224 newLastNamep = newPathp;
6228 /* now lookup the old name */
6229 osi_Log1(smb_logp," looking up [%S]", osi_LogSaveClientString(smb_logp,oldLastNamep));
6230 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
6232 cm_ReleaseSCache(oldDscp);
6233 cm_ReleaseSCache(newDscp);
6234 cm_ReleaseUser(userp);
6238 /* Check if the file already exists; if so return error */
6239 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6240 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6241 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6243 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6244 osi_LogSaveClientString(smb_logp, newLastNamep));
6246 /* if the existing link is to the same file, then we return success */
6248 if(sscp == tmpscp) {
6251 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
6252 code = CM_ERROR_EXISTS;
6257 cm_ReleaseSCache(tmpscp);
6258 cm_ReleaseSCache(sscp);
6259 cm_ReleaseSCache(newDscp);
6260 cm_ReleaseSCache(oldDscp);
6261 cm_ReleaseUser(userp);
6265 /* now create the hardlink */
6266 osi_Log1(smb_logp," Attempting to create new link [%S]", osi_LogSaveClientString(smb_logp, newLastNamep));
6267 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
6268 osi_Log1(smb_logp," Link returns 0x%x", code);
6270 /* Handle Change Notification */
6272 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
6273 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6274 smb_NotifyChange(FILE_ACTION_ADDED,
6275 filter, newDscp, newLastNamep,
6280 cm_ReleaseSCache(tmpscp);
6281 cm_ReleaseUser(userp);
6282 cm_ReleaseSCache(sscp);
6283 cm_ReleaseSCache(oldDscp);
6284 cm_ReleaseSCache(newDscp);
6288 /* SMB_COM_RENAME */
6290 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6292 clientchar_t *oldPathp;
6293 clientchar_t *newPathp;
6297 tp = smb_GetSMBData(inp, NULL);
6298 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6300 return CM_ERROR_BADSMB;
6301 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6303 return CM_ERROR_BADSMB;
6305 osi_Log2(smb_logp, "smb rename [%S] to [%S]",
6306 osi_LogSaveClientString(smb_logp, oldPathp),
6307 osi_LogSaveClientString(smb_logp, newPathp));
6309 if (!cm_IsValidClientString(newPathp)) {
6311 clientchar_t * hexp;
6313 hexp = cm_GetRawCharsAlloc(newPathp, -1);
6314 osi_Log1(smb_logp, "CoreRename rejecting invalid name. [%S]",
6315 osi_LogSaveClientString(smb_logp, hexp));
6319 osi_Log0(smb_logp, "CoreRename rejecting invalid name");
6321 return CM_ERROR_BADNTFILENAME;
6324 code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
6326 osi_Log1(smb_logp, "smb rename returns 0x%x", code);
6332 typedef struct smb_rmdirRock {
6336 normchar_t *maskp; /* pointer to the star pattern */
6339 cm_dirEntryList_t * matches;
6342 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6345 smb_rmdirRock_t *rockp;
6347 normchar_t matchName[MAX_PATH];
6349 rockp = (smb_rmdirRock_t *) vrockp;
6351 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6352 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6353 osi_LogSaveString(smb_logp, dep->name));
6357 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
6358 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6360 match = (cm_ClientStrCmp(matchName, rockp->maskp) == 0);
6362 (rockp->flags & SMB_MASKFLAG_TILDE) &&
6363 !cm_Is8Dot3(matchName)) {
6364 cm_Gen8Dot3Name(dep, matchName, NULL);
6365 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6370 cm_DirEntryListAdd(dep->name, &rockp->matches);
6377 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6380 clientchar_t *pathp;
6384 clientchar_t *lastNamep;
6385 smb_rmdirRock_t rock;
6389 clientchar_t *tidPathp;
6393 memset(&rock, 0, sizeof(rock));
6395 tp = smb_GetSMBData(inp, NULL);
6396 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6398 return CM_ERROR_BADSMB;
6400 spacep = inp->spacep;
6401 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
6403 userp = smb_GetUserFromVCP(vcp, inp);
6405 caseFold = CM_FLAG_CASEFOLD;
6407 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6409 cm_ReleaseUser(userp);
6410 return CM_ERROR_NOSUCHPATH;
6412 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
6413 userp, tidPathp, &req, &dscp);
6416 cm_ReleaseUser(userp);
6421 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6422 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
6423 cm_ReleaseSCache(dscp);
6424 cm_ReleaseUser(userp);
6425 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6426 return CM_ERROR_PATH_NOT_COVERED;
6428 return CM_ERROR_BADSHARENAME;
6430 #endif /* DFS_SUPPORT */
6432 /* otherwise, scp points to the parent directory. */
6439 rock.maskp = cm_ClientStringToNormStringAlloc(lastNamep, -1, NULL);
6441 code = CM_ERROR_NOSUCHFILE;
6444 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6447 thyper.HighPart = 0;
6451 rock.matches = NULL;
6453 /* First do a case sensitive match, and if that fails, do a case insensitive match */
6454 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6455 if (code == 0 && !rock.any) {
6457 thyper.HighPart = 0;
6458 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6459 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6462 if (code == 0 && rock.matches) {
6463 cm_dirEntryList_t * entry;
6465 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
6466 clientchar_t clientName[MAX_PATH];
6468 /* We assume this will succeed because smb_RmdirProc()
6469 successfully converted entry->name once above. */
6470 cm_FsStringToClientString(entry->name, -1, clientName, lengthof(clientName));
6472 osi_Log1(smb_logp, "Removing directory %s",
6473 osi_LogSaveString(smb_logp, entry->name));
6475 code = cm_RemoveDir(dscp, entry->name, clientName, userp, &req);
6477 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6478 smb_NotifyChange(FILE_ACTION_REMOVED,
6479 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6480 dscp, clientName, NULL, TRUE);
6486 cm_DirEntryListFree(&rock.matches);
6489 cm_ReleaseUser(userp);
6492 cm_ReleaseSCache(dscp);
6494 if (code == 0 && !rock.any)
6495 code = CM_ERROR_NOSUCHFILE;
6504 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6514 fid = smb_GetSMBParm(inp, 0);
6516 osi_Log1(smb_logp, "SMB flush fid %d", fid);
6518 fid = smb_ChainFID(fid, inp);
6519 fidp = smb_FindFID(vcp, fid, 0);
6521 return CM_ERROR_BADFD;
6523 userp = smb_GetUserFromVCP(vcp, inp);
6525 lock_ObtainMutex(&fidp->mx);
6526 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6527 lock_ReleaseMutex(&fidp->mx);
6528 cm_ReleaseUser(userp);
6529 smb_CloseFID(vcp, fidp, NULL, 0);
6530 smb_ReleaseFID(fidp);
6531 return CM_ERROR_NOSUCHFILE;
6534 if (fidp->flags & SMB_FID_IOCTL) {
6535 cm_ReleaseUser(userp);
6536 lock_ReleaseMutex(&fidp->mx);
6537 smb_ReleaseFID(fidp);
6538 return CM_ERROR_BADFD;
6541 if (fidp->scp && (fidp->flags & SMB_FID_OPENWRITE) && smb_AsyncStore != 2) {
6542 cm_scache_t * scp = fidp->scp;
6544 lock_ReleaseMutex(&fidp->mx);
6545 code = cm_FSync(scp, userp, &req);
6546 cm_ReleaseSCache(scp);
6548 lock_ReleaseMutex(&fidp->mx);
6552 cm_ReleaseUser(userp);
6553 smb_ReleaseFID(fidp);
6557 struct smb_FullNameRock {
6560 clientchar_t *fullName;
6561 fschar_t *originalName;
6564 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
6567 normchar_t matchName[MAX_PATH];
6568 struct smb_FullNameRock *vrockp;
6570 vrockp = (struct smb_FullNameRock *)rockp;
6572 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6573 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6574 osi_LogSaveString(smb_logp, dep->name));
6578 if (!cm_Is8Dot3(matchName)) {
6579 clientchar_t shortName[13];
6581 cm_Gen8Dot3Name(dep, shortName, NULL);
6583 if (cm_ClientStrCmpIA(shortName, vrockp->name) == 0) {
6584 vrockp->fullName = cm_ClientStrDup(matchName);
6585 vrockp->originalName = cm_FsStrDup(dep->name);
6586 return CM_ERROR_STOPNOW;
6589 if (cm_ClientStrCmpI(matchName, vrockp->name) == 0 &&
6590 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
6591 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
6592 vrockp->fullName = cm_ClientStrDup(matchName);
6593 vrockp->originalName = cm_FsStrDup(dep->name);
6594 return CM_ERROR_STOPNOW;
6599 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, clientchar_t *pathp,
6600 clientchar_t **newPathp, fschar_t ** originalPathp,
6601 cm_user_t *userp, cm_req_t *reqp)
6603 struct smb_FullNameRock rock;
6606 memset(&rock, 0, sizeof(rock));
6610 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
6611 if (code == CM_ERROR_STOPNOW) {
6612 *newPathp = rock.fullName;
6613 *originalPathp = rock.originalName;
6615 *newPathp = cm_ClientStrDup(pathp);
6616 *originalPathp = cm_ClientStringToFsStringAlloc(pathp, -1, NULL);
6620 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
6621 afs_uint32 dosTime) {
6624 cm_scache_t *dscp = NULL;
6625 clientchar_t *pathp = NULL;
6626 cm_scache_t * scp = NULL;
6627 cm_scache_t *delscp = NULL;
6628 int nullcreator = 0;
6630 osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
6631 fidp, fidp->fid, scp, vcp);
6634 lock_ObtainMutex(&fidp->mx);
6635 if (!fidp->userp && !(fidp->flags & SMB_FID_IOCTL)) {
6636 lock_ReleaseMutex(&fidp->mx);
6637 osi_Log0(smb_logp, " No user specified. Not closing fid");
6638 return CM_ERROR_BADFD;
6641 userp = fidp->userp; /* no hold required since fidp is held
6642 throughout the function */
6643 lock_ReleaseMutex(&fidp->mx);
6648 lock_ObtainWrite(&smb_rctLock);
6649 if (fidp->deleteOk) {
6650 osi_Log0(smb_logp, " Fid already closed.");
6651 lock_ReleaseWrite(&smb_rctLock);
6652 return CM_ERROR_BADFD;
6655 lock_ReleaseWrite(&smb_rctLock);
6657 lock_ObtainMutex(&fidp->mx);
6658 if (fidp->NTopen_dscp) {
6659 dscp = fidp->NTopen_dscp;
6660 cm_HoldSCache(dscp);
6663 if (fidp->NTopen_pathp)
6664 pathp = cm_ClientStrDup(fidp->NTopen_pathp);
6671 /* Don't jump the gun on an async raw write */
6672 while (fidp->raw_writers) {
6673 lock_ReleaseMutex(&fidp->mx);
6674 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
6675 lock_ObtainMutex(&fidp->mx);
6678 /* watch for ioctl closes, and read-only opens */
6680 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
6681 == SMB_FID_OPENWRITE) {
6682 if (dosTime != 0 && dosTime != -1) {
6683 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6684 /* This fixes defect 10958 */
6685 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
6686 smb_UnixTimeFromDosUTime(&scp->clientModTime, dosTime);
6688 if (smb_AsyncStore != 2) {
6689 lock_ReleaseMutex(&fidp->mx);
6690 code = cm_FSync(scp, userp, &req);
6691 lock_ObtainMutex(&fidp->mx);
6697 /* unlock any pending locks */
6698 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
6699 scp->fileType == CM_SCACHETYPE_FILE) {
6703 lock_ReleaseMutex(&fidp->mx);
6705 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
6707 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
6708 lock_ObtainWrite(&scp->rw);
6710 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
6711 CM_SCACHESYNC_NEEDCALLBACK
6712 | CM_SCACHESYNC_GETSTATUS
6713 | CM_SCACHESYNC_LOCK);
6717 "smb CoreClose SyncOp failure code 0x%x", tcode);
6718 goto post_syncopdone;
6721 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
6723 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
6727 lock_ReleaseWrite(&scp->rw);
6728 lock_ObtainMutex(&fidp->mx);
6731 if (fidp->flags & SMB_FID_DELONCLOSE) {
6732 clientchar_t *fullPathp = NULL;
6733 fschar_t *originalNamep = NULL;
6735 lock_ReleaseMutex(&fidp->mx);
6737 code = cm_Lookup(dscp, pathp, CM_FLAG_NOMOUNTCHASE, userp, &req, &delscp);
6742 smb_FullName(dscp, delscp, pathp, &fullPathp, &originalNamep, userp, &req);
6743 if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
6744 code = cm_RemoveDir(dscp, originalNamep, fullPathp, userp, &req);
6746 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6747 smb_NotifyChange(FILE_ACTION_REMOVED,
6748 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6749 dscp, fullPathp, NULL, TRUE);
6752 code = cm_Unlink(dscp, originalNamep, fullPathp, userp, &req);
6754 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6755 smb_NotifyChange(FILE_ACTION_REMOVED,
6756 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6757 dscp, fullPathp, NULL, TRUE);
6764 free(originalNamep);
6766 lock_ObtainMutex(&fidp->mx);
6767 fidp->flags &= ~SMB_FID_DELONCLOSE;
6770 /* if this was a newly created file, then clear the creator
6771 * in the stat cache entry. */
6772 if (fidp->flags & SMB_FID_CREATED) {
6774 fidp->flags &= ~SMB_FID_CREATED;
6777 if (fidp->flags & SMB_FID_NTOPEN) {
6778 cm_ReleaseSCache(fidp->NTopen_dscp);
6779 fidp->NTopen_dscp = NULL;
6780 free(fidp->NTopen_pathp);
6781 fidp->NTopen_pathp = NULL;
6782 fidp->flags &= ~SMB_FID_NTOPEN;
6784 osi_assertx(fidp->NTopen_dscp == NULL, "null NTopen_dsc");
6785 osi_assertx(fidp->NTopen_pathp == NULL, "null NTopen_path");
6788 if (fidp->NTopen_wholepathp) {
6789 free(fidp->NTopen_wholepathp);
6790 fidp->NTopen_wholepathp = NULL;
6794 cm_ReleaseSCache(fidp->scp);
6797 lock_ReleaseMutex(&fidp->mx);
6800 cm_ReleaseSCache(dscp);
6803 cm_ReleaseSCache(delscp);
6807 lock_ObtainWrite(&scp->rw);
6808 if (nullcreator && scp->creator == userp)
6809 scp->creator = NULL;
6810 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
6811 lock_ReleaseWrite(&scp->rw);
6812 cm_ReleaseSCache(scp);
6822 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6830 fid = smb_GetSMBParm(inp, 0);
6831 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6833 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
6835 fid = smb_ChainFID(fid, inp);
6836 fidp = smb_FindFID(vcp, fid, 0);
6838 return CM_ERROR_BADFD;
6841 userp = smb_GetUserFromVCP(vcp, inp);
6843 code = smb_CloseFID(vcp, fidp, userp, dosTime);
6845 smb_ReleaseFID(fidp);
6846 cm_ReleaseUser(userp);
6851 * smb_ReadData -- common code for Read, Read And X, and Raw Read
6853 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
6854 cm_user_t *userp, long *readp)
6860 osi_hyper_t fileLength;
6862 osi_hyper_t lastByte;
6863 osi_hyper_t bufferOffset;
6867 int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
6870 osi_Log3(smb_logp, "smb_ReadData fid %d, off 0x%x, size 0x%x",
6871 fidp->fid, offsetp->LowPart, count);
6875 lock_ObtainMutex(&fidp->mx);
6876 /* make sure we have a readable FD */
6877 if (!(fidp->flags & SMB_FID_OPENREAD_LISTDIR)) {
6878 osi_Log2(smb_logp, "smb_ReadData fid %d not OPENREAD_LISTDIR flags 0x%x",
6879 fidp->fid, fidp->flags);
6880 lock_ReleaseMutex(&fidp->mx);
6881 code = CM_ERROR_BADFDOP;
6886 lock_ReleaseMutex(&fidp->mx);
6887 code = CM_ERROR_BADFD;
6898 lock_ObtainWrite(&scp->rw);
6900 if (offset.HighPart == 0) {
6901 chunk = offset.LowPart >> cm_logChunkSize;
6902 if (chunk != fidp->curr_chunk) {
6903 fidp->prev_chunk = fidp->curr_chunk;
6904 fidp->curr_chunk = chunk;
6906 if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
6909 lock_ReleaseMutex(&fidp->mx);
6911 /* start by looking up the file's end */
6912 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6913 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6917 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6919 /* now we have the entry locked, look up the length */
6920 fileLength = scp->length;
6922 /* adjust count down so that it won't go past EOF */
6923 thyper.LowPart = count;
6924 thyper.HighPart = 0;
6925 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
6927 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6928 /* we'd read past EOF, so just stop at fileLength bytes.
6929 * Start by computing how many bytes remain in the file.
6931 thyper = LargeIntegerSubtract(fileLength, offset);
6933 /* if we are past EOF, read 0 bytes */
6934 if (LargeIntegerLessThanZero(thyper))
6937 count = thyper.LowPart;
6942 /* now, copy the data one buffer at a time,
6943 * until we've filled the request packet
6946 /* if we've copied all the data requested, we're done */
6947 if (count <= 0) break;
6949 /* otherwise, load up a buffer of data */
6950 thyper.HighPart = offset.HighPart;
6951 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6952 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6955 buf_Release(bufferp);
6958 lock_ReleaseWrite(&scp->rw);
6960 code = buf_Get(scp, &thyper, &bufferp);
6962 lock_ObtainWrite(&scp->rw);
6963 if (code) goto done;
6964 bufferOffset = thyper;
6966 /* now get the data in the cache */
6968 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6969 CM_SCACHESYNC_NEEDCALLBACK |
6970 CM_SCACHESYNC_READ);
6974 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
6976 if (cm_HaveBuffer(scp, bufferp, 0)) break;
6978 /* otherwise, load the buffer and try again */
6979 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
6983 buf_Release(bufferp);
6987 } /* if (wrong buffer) ... */
6989 /* now we have the right buffer loaded. Copy out the
6990 * data from here to the user's buffer.
6992 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6994 /* and figure out how many bytes we want from this buffer */
6995 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6996 if (nbytes > count) nbytes = count; /* don't go past EOF */
6998 /* now copy the data */
6999 memcpy(op, bufferp->datap + bufIndex, nbytes);
7001 /* adjust counters, pointers, etc. */
7004 thyper.LowPart = nbytes;
7005 thyper.HighPart = 0;
7006 offset = LargeIntegerAdd(thyper, offset);
7010 lock_ReleaseWrite(&scp->rw);
7012 buf_Release(bufferp);
7014 if (code == 0 && sequential)
7015 cm_ConsiderPrefetch(scp, &lastByte, *readp, userp, &req);
7017 cm_ReleaseSCache(scp);
7020 osi_Log3(smb_logp, "smb_ReadData fid %d returns 0x%x read %d bytes",
7021 fidp->fid, code, *readp);
7026 * smb_WriteData -- common code for Write and Raw Write
7028 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
7029 cm_user_t *userp, long *writtenp)
7031 osi_hyper_t offset = *offsetp;
7034 cm_scache_t *scp = NULL;
7035 osi_hyper_t fileLength; /* file's length at start of write */
7036 osi_hyper_t minLength; /* don't read past this */
7037 afs_uint32 nbytes; /* # of bytes to transfer this iteration */
7038 cm_buf_t *bufferp = NULL;
7039 osi_hyper_t thyper; /* hyper tmp variable */
7040 osi_hyper_t bufferOffset;
7041 afs_uint32 bufIndex; /* index in buffer where our data is */
7042 int doWriteBack = 0;
7043 osi_hyper_t writeBackOffset;/* offset of region to write back when I/O is done */
7047 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
7048 fidp->fid, offsetp->LowPart, count);
7052 lock_ObtainMutex(&fidp->mx);
7053 /* make sure we have a writable FD */
7054 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
7055 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
7056 fidp->fid, fidp->flags);
7057 lock_ReleaseMutex(&fidp->mx);
7058 code = CM_ERROR_BADFDOP;
7066 lock_ReleaseMutex(&fidp->mx);
7068 lock_ObtainWrite(&scp->rw);
7069 /* start by looking up the file's end */
7070 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7071 CM_SCACHESYNC_NEEDCALLBACK
7072 | CM_SCACHESYNC_SETSTATUS
7073 | CM_SCACHESYNC_GETSTATUS);
7077 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
7079 /* now we have the entry locked, look up the length */
7080 fileLength = scp->length;
7081 minLength = fileLength;
7082 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
7083 minLength = scp->serverLength;
7085 /* adjust file length if we extend past EOF */
7086 thyper.LowPart = count;
7087 thyper.HighPart = 0;
7088 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
7089 if (LargeIntegerGreaterThan(thyper, fileLength)) {
7090 /* we'd write past EOF, so extend the file */
7091 scp->mask |= CM_SCACHEMASK_LENGTH;
7092 scp->length = thyper;
7093 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
7095 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
7097 /* now, if the new position (thyper) and the old (offset) are in
7098 * different storeback windows, remember to store back the previous
7099 * storeback window when we're done with the write.
7101 * the purpose of this logic is to slow down the CIFS client
7102 * in order to avoid the client disconnecting during the CLOSE
7103 * operation if there are too many dirty buffers left to write
7104 * than can be accomplished during 45 seconds. This used to be
7105 * based upon cm_chunkSize but we desire cm_chunkSize to be large
7106 * so that we can read larger amounts of data at a time.
7108 if (smb_AsyncStore == 1 &&
7109 (thyper.LowPart & ~(smb_AsyncStoreSize-1)) !=
7110 (offset.LowPart & ~(smb_AsyncStoreSize-1))) {
7111 /* they're different */
7113 writeBackOffset.HighPart = offset.HighPart;
7114 writeBackOffset.LowPart = offset.LowPart & ~(smb_AsyncStoreSize-1);
7119 /* now, copy the data one buffer at a time, until we've filled the
7122 /* if we've copied all the data requested, we're done */
7126 /* handle over quota or out of space */
7127 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
7128 *writtenp = written;
7129 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
7133 /* otherwise, load up a buffer of data */
7134 thyper.HighPart = offset.HighPart;
7135 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7136 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7139 lock_ReleaseMutex(&bufferp->mx);
7140 buf_Release(bufferp);
7143 lock_ReleaseWrite(&scp->rw);
7145 code = buf_Get(scp, &thyper, &bufferp);
7147 lock_ObtainMutex(&bufferp->mx);
7148 lock_ObtainWrite(&scp->rw);
7149 if (code) goto done;
7151 bufferOffset = thyper;
7153 /* now get the data in the cache */
7155 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7156 CM_SCACHESYNC_NEEDCALLBACK
7157 | CM_SCACHESYNC_WRITE
7158 | CM_SCACHESYNC_BUFLOCKED);
7162 cm_SyncOpDone(scp, bufferp,
7163 CM_SCACHESYNC_NEEDCALLBACK
7164 | CM_SCACHESYNC_WRITE
7165 | CM_SCACHESYNC_BUFLOCKED);
7167 /* If we're overwriting the entire buffer, or
7168 * if we're writing at or past EOF, mark the
7169 * buffer as current so we don't call
7170 * cm_GetBuffer. This skips the fetch from the
7171 * server in those cases where we're going to
7172 * obliterate all the data in the buffer anyway,
7173 * or in those cases where there is no useful
7174 * data at the server to start with.
7176 * Use minLength instead of scp->length, since
7177 * the latter has already been updated by this
7180 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
7181 || LargeIntegerEqualTo(offset, bufferp->offset)
7182 && (count >= cm_data.buf_blockSize
7183 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
7184 ConvertLongToLargeInteger(count)),
7186 if (count < cm_data.buf_blockSize
7187 && bufferp->dataVersion == CM_BUF_VERSION_BAD)
7188 memset(bufferp->datap, 0,
7189 cm_data.buf_blockSize);
7190 bufferp->dataVersion = scp->dataVersion;
7193 if (cm_HaveBuffer(scp, bufferp, 1)) break;
7195 /* otherwise, load the buffer and try again */
7196 lock_ReleaseMutex(&bufferp->mx);
7197 code = cm_GetBuffer(scp, bufferp, NULL, userp,
7199 lock_ReleaseWrite(&scp->rw);
7200 lock_ObtainMutex(&bufferp->mx);
7201 lock_ObtainWrite(&scp->rw);
7205 lock_ReleaseMutex(&bufferp->mx);
7206 buf_Release(bufferp);
7210 } /* if (wrong buffer) ... */
7212 /* now we have the right buffer loaded. Copy out the
7213 * data from here to the user's buffer.
7215 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7217 /* and figure out how many bytes we want from this buffer */
7218 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
7220 nbytes = count; /* don't go past end of request */
7222 /* now copy the data */
7223 memcpy(bufferp->datap + bufIndex, op, nbytes);
7224 buf_SetDirty(bufferp, bufIndex, nbytes, userp);
7226 /* adjust counters, pointers, etc. */
7230 thyper.LowPart = nbytes;
7231 thyper.HighPart = 0;
7232 offset = LargeIntegerAdd(thyper, offset);
7236 lock_ReleaseWrite(&scp->rw);
7239 lock_ReleaseMutex(&bufferp->mx);
7240 buf_Release(bufferp);
7243 lock_ObtainMutex(&fidp->mx);
7244 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
7245 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7247 lock_ReleaseMutex(&fidp->mx);
7248 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
7249 fidp->NTopen_dscp, fidp->NTopen_pathp,
7252 lock_ReleaseMutex(&fidp->mx);
7256 if (smb_AsyncStore > 0) {
7260 lock_ObtainWrite(&scp->rw);
7261 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
7263 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
7264 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
7266 lock_ReleaseWrite(&scp->rw);
7267 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
7268 writeBackOffset.HighPart,
7269 smb_AsyncStoreSize, 0, userp);
7270 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
7273 cm_BufWrite(scp, offsetp, *writtenp, 0, userp, &req);
7277 cm_ReleaseSCache(scp);
7280 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
7281 fidp->fid, code, *writtenp);
7286 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7289 unsigned short count;
7291 unsigned short hint;
7292 long written = 0, total_written = 0;
7295 smb_t* smbp = (smb_t*) inp;
7299 cm_attr_t truncAttr; /* attribute struct used for truncating file */
7301 int inDataBlockCount;
7303 fd = smb_GetSMBParm(inp, 0);
7304 count = smb_GetSMBParm(inp, 1);
7305 offset.HighPart = 0; /* too bad */
7306 offset.LowPart = smb_GetSMBParmLong(inp, 2);
7307 hint = smb_GetSMBParm(inp, 4);
7309 op = smb_GetSMBData(inp, NULL);
7310 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
7312 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
7313 fd, offset.LowPart, count);
7315 fd = smb_ChainFID(fd, inp);
7316 fidp = smb_FindFID(vcp, fd, 0);
7318 osi_Log0(smb_logp, "smb_ReceiveCoreWrite fid not found");
7319 return CM_ERROR_BADFD;
7322 lock_ObtainMutex(&fidp->mx);
7323 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7324 lock_ReleaseMutex(&fidp->mx);
7325 smb_CloseFID(vcp, fidp, NULL, 0);
7326 smb_ReleaseFID(fidp);
7327 return CM_ERROR_NOSUCHFILE;
7330 if (fidp->flags & SMB_FID_IOCTL) {
7331 lock_ReleaseMutex(&fidp->mx);
7332 code = smb_IoctlWrite(fidp, vcp, inp, outp);
7333 smb_ReleaseFID(fidp);
7334 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
7339 lock_ReleaseMutex(&fidp->mx);
7340 smb_ReleaseFID(fidp);
7341 return CM_ERROR_BADFD;
7346 lock_ReleaseMutex(&fidp->mx);
7347 userp = smb_GetUserFromVCP(vcp, inp);
7351 LARGE_INTEGER LOffset;
7352 LARGE_INTEGER LLength;
7355 key = cm_GenerateKey(vcp->vcID, pid, fd);
7357 LOffset.HighPart = offset.HighPart;
7358 LOffset.LowPart = offset.LowPart;
7359 LLength.HighPart = 0;
7360 LLength.LowPart = count;
7362 lock_ObtainWrite(&scp->rw);
7363 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7364 lock_ReleaseWrite(&scp->rw);
7367 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
7372 /* special case: 0 bytes transferred means truncate to this position */
7376 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
7380 truncAttr.mask = CM_ATTRMASK_LENGTH;
7381 truncAttr.length.LowPart = offset.LowPart;
7382 truncAttr.length.HighPart = 0;
7383 lock_ObtainMutex(&fidp->mx);
7384 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
7385 fidp->flags |= SMB_FID_LENGTHSETDONE;
7386 lock_ReleaseMutex(&fidp->mx);
7387 smb_SetSMBParm(outp, 0, 0 /* count */);
7388 smb_SetSMBDataLength(outp, 0);
7393 * Work around bug in NT client
7395 * When copying a file, the NT client should first copy the data,
7396 * then copy the last write time. But sometimes the NT client does
7397 * these in the wrong order, so the data copies would inadvertently
7398 * cause the last write time to be overwritten. We try to detect this,
7399 * and don't set client mod time if we think that would go against the
7402 lock_ObtainMutex(&fidp->mx);
7403 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
7404 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7405 fidp->scp->clientModTime = time(NULL);
7407 lock_ReleaseMutex(&fidp->mx);
7410 while ( code == 0 && count > 0 ) {
7411 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7412 if (code == 0 && written == 0)
7413 code = CM_ERROR_PARTIALWRITE;
7415 offset = LargeIntegerAdd(offset,
7416 ConvertLongToLargeInteger(written));
7417 count -= (unsigned short)written;
7418 total_written += written;
7422 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
7423 total_written, code);
7425 /* set the packet data length to 3 bytes for the data block header,
7426 * plus the size of the data.
7428 smb_SetSMBParm(outp, 0, total_written);
7429 smb_SetSMBParmLong(outp, 1, offset.LowPart);
7430 smb_SetSMBParm(outp, 3, hint);
7431 smb_SetSMBDataLength(outp, 0);
7434 smb_ReleaseFID(fidp);
7435 cm_ReleaseUser(userp);
7436 cm_ReleaseSCache(scp);
7441 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7442 NCB *ncbp, raw_write_cont_t *rwcp)
7451 fd = smb_GetSMBParm(inp, 0);
7452 fidp = smb_FindFID(vcp, fd, 0);
7454 lock_ObtainMutex(&fidp->mx);
7455 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7456 lock_ReleaseMutex(&fidp->mx);
7457 smb_CloseFID(vcp, fidp, NULL, 0);
7458 smb_ReleaseFID(fidp);
7461 lock_ReleaseMutex(&fidp->mx);
7463 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
7464 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
7466 userp = smb_GetUserFromVCP(vcp, inp);
7469 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
7471 if (rwcp->writeMode & 0x1) { /* synchronous */
7474 smb_FormatResponsePacket(vcp, inp, outp);
7475 op = (smb_t *) outp;
7476 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7477 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
7478 smb_SetSMBDataLength(outp, 0);
7479 smb_SendPacket(vcp, outp);
7480 smb_FreePacket(outp);
7482 else { /* asynchronous */
7483 lock_ObtainMutex(&fidp->mx);
7484 fidp->raw_writers--;
7485 if (fidp->raw_writers == 0)
7486 thrd_SetEvent(fidp->raw_write_event);
7487 lock_ReleaseMutex(&fidp->mx);
7490 /* Give back raw buffer */
7491 lock_ObtainMutex(&smb_RawBufLock);
7492 *((char **)rawBuf) = smb_RawBufs;
7493 smb_RawBufs = rawBuf;
7494 lock_ReleaseMutex(&smb_RawBufLock);
7496 smb_ReleaseFID(fidp);
7497 cm_ReleaseUser(userp);
7500 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7505 /* SMB_COM_WRITE_RAW */
7506 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
7509 long count, written = 0, total_written = 0;
7513 smb_t *smbp = (smb_t*) inp;
7518 unsigned short writeMode;
7520 fd = smb_GetSMBParm(inp, 0);
7521 totalCount = smb_GetSMBParm(inp, 1);
7522 count = smb_GetSMBParm(inp, 10);
7523 writeMode = smb_GetSMBParm(inp, 7);
7525 op = (char *) inp->data;
7526 op += smb_GetSMBParm(inp, 11);
7528 offset.HighPart = 0;
7529 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
7531 if (*inp->wctp == 14) {
7532 /* we received a 64-bit file offset */
7533 #ifdef AFS_LARGEFILES
7534 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
7536 if (LargeIntegerLessThanZero(offset)) {
7538 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
7539 offset.HighPart, offset.LowPart);
7540 return CM_ERROR_BADSMB;
7543 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
7545 "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files");
7546 return CM_ERROR_BADSMB;
7549 offset.HighPart = 0;
7552 offset.HighPart = 0; /* 32-bit file offset */
7556 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
7557 fd, offset.HighPart, offset.LowPart, count);
7559 " WriteRaw WriteMode 0x%x",
7562 fd = smb_ChainFID(fd, inp);
7563 fidp = smb_FindFID(vcp, fd, 0);
7565 return CM_ERROR_BADFD;
7567 lock_ObtainMutex(&fidp->mx);
7568 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7569 lock_ReleaseMutex(&fidp->mx);
7570 smb_CloseFID(vcp, fidp, NULL, 0);
7571 smb_ReleaseFID(fidp);
7572 return CM_ERROR_NOSUCHFILE;
7576 lock_ReleaseMutex(&fidp->mx);
7577 smb_ReleaseFID(fidp);
7578 return CM_ERROR_BADFDOP;
7582 lock_ReleaseMutex(&fidp->mx);
7587 LARGE_INTEGER LOffset;
7588 LARGE_INTEGER LLength;
7591 key = cm_GenerateKey(vcp->vcID, pid, fd);
7593 LOffset.HighPart = offset.HighPart;
7594 LOffset.LowPart = offset.LowPart;
7595 LLength.HighPart = 0;
7596 LLength.LowPart = count;
7598 lock_ObtainWrite(&scp->rw);
7599 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7600 lock_ReleaseWrite(&scp->rw);
7603 cm_ReleaseSCache(scp);
7604 smb_ReleaseFID(fidp);
7609 userp = smb_GetUserFromVCP(vcp, inp);
7612 * Work around bug in NT client
7614 * When copying a file, the NT client should first copy the data,
7615 * then copy the last write time. But sometimes the NT client does
7616 * these in the wrong order, so the data copies would inadvertently
7617 * cause the last write time to be overwritten. We try to detect this,
7618 * and don't set client mod time if we think that would go against the
7621 lock_ObtainMutex(&fidp->mx);
7622 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
7623 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7624 fidp->scp->clientModTime = time(NULL);
7626 lock_ReleaseMutex(&fidp->mx);
7629 while ( code == 0 && count > 0 ) {
7630 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7631 if (code == 0 && written == 0)
7632 code = CM_ERROR_PARTIALWRITE;
7634 offset = LargeIntegerAdd(offset,
7635 ConvertLongToLargeInteger(written));
7638 total_written += written;
7642 /* Get a raw buffer */
7645 lock_ObtainMutex(&smb_RawBufLock);
7647 /* Get a raw buf, from head of list */
7648 rawBuf = smb_RawBufs;
7649 smb_RawBufs = *(char **)smb_RawBufs;
7652 code = CM_ERROR_USESTD;
7654 lock_ReleaseMutex(&smb_RawBufLock);
7657 /* Don't allow a premature Close */
7658 if (code == 0 && (writeMode & 1) == 0) {
7659 lock_ObtainMutex(&fidp->mx);
7660 fidp->raw_writers++;
7661 thrd_ResetEvent(fidp->raw_write_event);
7662 lock_ReleaseMutex(&fidp->mx);
7665 smb_ReleaseFID(fidp);
7666 cm_ReleaseUser(userp);
7667 cm_ReleaseSCache(scp);
7670 smb_SetSMBParm(outp, 0, total_written);
7671 smb_SetSMBDataLength(outp, 0);
7672 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7677 offset = LargeIntegerAdd(offset,
7678 ConvertLongToLargeInteger(count));
7682 rwcp->offset.HighPart = offset.HighPart;
7683 rwcp->offset.LowPart = offset.LowPart;
7684 rwcp->count = totalCount - count;
7685 rwcp->writeMode = writeMode;
7686 rwcp->alreadyWritten = total_written;
7688 /* set the packet data length to 3 bytes for the data block header,
7689 * plus the size of the data.
7691 smb_SetSMBParm(outp, 0, 0xffff);
7692 smb_SetSMBDataLength(outp, 0);
7698 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7701 long count, finalCount;
7705 smb_t *smbp = (smb_t*) inp;
7711 fd = smb_GetSMBParm(inp, 0);
7712 count = smb_GetSMBParm(inp, 1);
7713 offset.HighPart = 0; /* too bad */
7714 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7716 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
7717 fd, offset.LowPart, count);
7719 fd = smb_ChainFID(fd, inp);
7720 fidp = smb_FindFID(vcp, fd, 0);
7722 return CM_ERROR_BADFD;
7724 lock_ObtainMutex(&fidp->mx);
7725 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7726 lock_ReleaseMutex(&fidp->mx);
7727 smb_CloseFID(vcp, fidp, NULL, 0);
7728 smb_ReleaseFID(fidp);
7729 return CM_ERROR_NOSUCHFILE;
7732 if (fidp->flags & SMB_FID_IOCTL) {
7733 lock_ReleaseMutex(&fidp->mx);
7734 code = smb_IoctlRead(fidp, vcp, inp, outp);
7735 smb_ReleaseFID(fidp);
7740 lock_ReleaseMutex(&fidp->mx);
7741 smb_ReleaseFID(fidp);
7742 return CM_ERROR_BADFDOP;
7746 lock_ReleaseMutex(&fidp->mx);
7749 LARGE_INTEGER LOffset, LLength;
7753 key = cm_GenerateKey(vcp->vcID, pid, fd);
7755 LOffset.HighPart = 0;
7756 LOffset.LowPart = offset.LowPart;
7757 LLength.HighPart = 0;
7758 LLength.LowPart = count;
7760 lock_ObtainWrite(&scp->rw);
7761 code = cm_LockCheckRead(scp, LOffset, LLength, key);
7762 lock_ReleaseWrite(&scp->rw);
7765 cm_ReleaseSCache(scp);
7766 smb_ReleaseFID(fidp);
7770 userp = smb_GetUserFromVCP(vcp, inp);
7772 /* remember this for final results */
7773 smb_SetSMBParm(outp, 0, count);
7774 smb_SetSMBParm(outp, 1, 0);
7775 smb_SetSMBParm(outp, 2, 0);
7776 smb_SetSMBParm(outp, 3, 0);
7777 smb_SetSMBParm(outp, 4, 0);
7779 /* set the packet data length to 3 bytes for the data block header,
7780 * plus the size of the data.
7782 smb_SetSMBDataLength(outp, count+3);
7784 /* get op ptr after putting in the parms, since otherwise we don't
7785 * know where the data really is.
7787 op = smb_GetSMBData(outp, NULL);
7789 /* now emit the data block header: 1 byte of type and 2 bytes of length */
7790 *op++ = 1; /* data block marker */
7791 *op++ = (unsigned char) (count & 0xff);
7792 *op++ = (unsigned char) ((count >> 8) & 0xff);
7794 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
7796 /* fix some things up */
7797 smb_SetSMBParm(outp, 0, finalCount);
7798 smb_SetSMBDataLength(outp, finalCount+3);
7800 smb_ReleaseFID(fidp);
7802 cm_ReleaseUser(userp);
7803 cm_ReleaseSCache(scp);
7807 /* SMB_COM_CREATE_DIRECTORY */
7808 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7810 clientchar_t *pathp;
7815 cm_scache_t *dscp; /* dir we're dealing with */
7816 cm_scache_t *scp; /* file we're creating */
7818 int initialModeBits;
7819 clientchar_t *lastNamep;
7821 clientchar_t *tidPathp;
7828 /* compute initial mode bits based on read-only flag in attributes */
7829 initialModeBits = 0777;
7831 tp = smb_GetSMBData(inp, NULL);
7832 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
7834 return CM_ERROR_BADSMB;
7836 spacep = inp->spacep;
7837 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
7839 if (cm_ClientStrCmp(pathp, _C("\\")) == 0)
7840 return CM_ERROR_EXISTS;
7842 userp = smb_GetUserFromVCP(vcp, inp);
7844 caseFold = CM_FLAG_CASEFOLD;
7846 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7848 cm_ReleaseUser(userp);
7849 return CM_ERROR_NOSUCHPATH;
7852 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
7853 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
7854 userp, tidPathp, &req, &dscp);
7857 cm_ReleaseUser(userp);
7862 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7863 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
7864 cm_ReleaseSCache(dscp);
7865 cm_ReleaseUser(userp);
7866 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7867 return CM_ERROR_PATH_NOT_COVERED;
7869 return CM_ERROR_BADSHARENAME;
7871 #endif /* DFS_SUPPORT */
7873 /* otherwise, scp points to the parent directory. Do a lookup, and
7874 * fail if we find it. Otherwise, we do the create.
7880 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
7881 if (scp) cm_ReleaseSCache(scp);
7882 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7883 if (code == 0) code = CM_ERROR_EXISTS;
7884 cm_ReleaseSCache(dscp);
7885 cm_ReleaseUser(userp);
7889 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7890 setAttr.clientModTime = time(NULL);
7891 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
7892 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7893 smb_NotifyChange(FILE_ACTION_ADDED,
7894 FILE_NOTIFY_CHANGE_DIR_NAME,
7895 dscp, lastNamep, NULL, TRUE);
7897 /* we don't need this any longer */
7898 cm_ReleaseSCache(dscp);
7901 /* something went wrong creating or truncating the file */
7902 cm_ReleaseUser(userp);
7906 /* otherwise we succeeded */
7907 smb_SetSMBDataLength(outp, 0);
7908 cm_ReleaseUser(userp);
7913 BOOL smb_IsLegalFilename(clientchar_t *filename)
7916 * Find the longest substring of filename that does not contain
7917 * any of the chars in illegalChars. If that substring is less
7918 * than the length of the whole string, then one or more of the
7919 * illegal chars is in filename.
7921 if (cm_ClientStrCSpn(filename, illegalChars) < cm_ClientStrLen(filename))
7927 /* SMB_COM_CREATE and SMB_COM_CREATE_NEW */
7928 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7930 clientchar_t *pathp;
7936 cm_scache_t *dscp; /* dir we're dealing with */
7937 cm_scache_t *scp; /* file we're creating */
7939 int initialModeBits;
7942 clientchar_t *lastNamep;
7945 clientchar_t *tidPathp;
7947 int created = 0; /* the file was new */
7952 excl = (inp->inCom == 0x03)? 0 : 1;
7954 attributes = smb_GetSMBParm(inp, 0);
7955 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
7957 /* compute initial mode bits based on read-only flag in attributes */
7958 initialModeBits = 0666;
7959 if (attributes & SMB_ATTR_READONLY)
7960 initialModeBits &= ~0222;
7962 tp = smb_GetSMBData(inp, NULL);
7963 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
7965 return CM_ERROR_BADSMB;
7967 if (!cm_IsValidClientString(pathp)) {
7969 clientchar_t * hexp;
7971 hexp = cm_GetRawCharsAlloc(pathp, -1);
7972 osi_Log1(smb_logp, "CoreCreate rejecting invalid name. [%S]",
7973 osi_LogSaveClientString(smb_logp, hexp));
7977 osi_Log0(smb_logp, "CoreCreate rejecting invalid name");
7979 return CM_ERROR_BADNTFILENAME;
7982 spacep = inp->spacep;
7983 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
7985 userp = smb_GetUserFromVCP(vcp, inp);
7987 caseFold = CM_FLAG_CASEFOLD;
7989 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7991 cm_ReleaseUser(userp);
7992 return CM_ERROR_NOSUCHPATH;
7994 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
7995 userp, tidPathp, &req, &dscp);
7998 cm_ReleaseUser(userp);
8003 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8004 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8005 cm_ReleaseSCache(dscp);
8006 cm_ReleaseUser(userp);
8007 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8008 return CM_ERROR_PATH_NOT_COVERED;
8010 return CM_ERROR_BADSHARENAME;
8012 #endif /* DFS_SUPPORT */
8014 /* otherwise, scp points to the parent directory. Do a lookup, and
8015 * truncate the file if we find it, otherwise we create the file.
8022 if (!smb_IsLegalFilename(lastNamep))
8023 return CM_ERROR_BADNTFILENAME;
8025 osi_Log1(smb_logp, "SMB receive create [%S]", osi_LogSaveClientString( smb_logp, pathp ));
8026 #ifdef DEBUG_VERBOSE
8029 hexp = osi_HexifyString( lastNamep );
8030 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
8035 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
8036 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8037 cm_ReleaseSCache(dscp);
8038 cm_ReleaseUser(userp);
8042 /* if we get here, if code is 0, the file exists and is represented by
8043 * scp. Otherwise, we have to create it.
8047 /* oops, file shouldn't be there */
8048 cm_ReleaseSCache(dscp);
8049 cm_ReleaseSCache(scp);
8050 cm_ReleaseUser(userp);
8051 return CM_ERROR_EXISTS;
8054 setAttr.mask = CM_ATTRMASK_LENGTH;
8055 setAttr.length.LowPart = 0;
8056 setAttr.length.HighPart = 0;
8057 code = cm_SetAttr(scp, &setAttr, userp, &req);
8060 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8061 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
8062 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
8066 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
8067 smb_NotifyChange(FILE_ACTION_ADDED,
8068 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
8069 dscp, lastNamep, NULL, TRUE);
8070 } else if (!excl && code == CM_ERROR_EXISTS) {
8071 /* not an exclusive create, and someone else tried
8072 * creating it already, then we open it anyway. We
8073 * don't bother retrying after this, since if this next
8074 * fails, that means that the file was deleted after
8075 * we started this call.
8077 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
8080 setAttr.mask = CM_ATTRMASK_LENGTH;
8081 setAttr.length.LowPart = 0;
8082 setAttr.length.HighPart = 0;
8083 code = cm_SetAttr(scp, &setAttr, userp, &req);
8088 /* we don't need this any longer */
8089 cm_ReleaseSCache(dscp);
8092 /* something went wrong creating or truncating the file */
8093 if (scp) cm_ReleaseSCache(scp);
8094 cm_ReleaseUser(userp);
8098 /* make sure we only open files */
8099 if (scp->fileType != CM_SCACHETYPE_FILE) {
8100 cm_ReleaseSCache(scp);
8101 cm_ReleaseUser(userp);
8102 return CM_ERROR_ISDIR;
8105 /* now all we have to do is open the file itself */
8106 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8107 osi_assertx(fidp, "null smb_fid_t");
8111 lock_ObtainMutex(&fidp->mx);
8112 /* always create it open for read/write */
8113 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
8115 /* remember that the file was newly created */
8117 fidp->flags |= SMB_FID_CREATED;
8119 osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
8121 /* save a pointer to the vnode */
8123 lock_ObtainWrite(&scp->rw);
8124 scp->flags |= CM_SCACHEFLAG_SMB_FID;
8125 lock_ReleaseWrite(&scp->rw);
8128 fidp->userp = userp;
8129 lock_ReleaseMutex(&fidp->mx);
8131 smb_SetSMBParm(outp, 0, fidp->fid);
8132 smb_SetSMBDataLength(outp, 0);
8134 cm_Open(scp, 0, userp);
8136 smb_ReleaseFID(fidp);
8137 cm_ReleaseUser(userp);
8138 /* leave scp held since we put it in fidp->scp */
8143 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8146 osi_hyper_t new_offset;
8157 fd = smb_GetSMBParm(inp, 0);
8158 whence = smb_GetSMBParm(inp, 1);
8159 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
8161 /* try to find the file descriptor */
8162 fd = smb_ChainFID(fd, inp);
8163 fidp = smb_FindFID(vcp, fd, 0);
8165 return CM_ERROR_BADFD;
8167 lock_ObtainMutex(&fidp->mx);
8168 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
8169 lock_ReleaseMutex(&fidp->mx);
8170 smb_CloseFID(vcp, fidp, NULL, 0);
8171 smb_ReleaseFID(fidp);
8172 return CM_ERROR_NOSUCHFILE;
8175 if (fidp->flags & SMB_FID_IOCTL) {
8176 lock_ReleaseMutex(&fidp->mx);
8177 smb_ReleaseFID(fidp);
8178 return CM_ERROR_BADFD;
8182 lock_ReleaseMutex(&fidp->mx);
8183 smb_ReleaseFID(fidp);
8184 return CM_ERROR_BADFDOP;
8187 lock_ReleaseMutex(&fidp->mx);
8189 userp = smb_GetUserFromVCP(vcp, inp);
8191 lock_ObtainMutex(&fidp->mx);
8194 lock_ReleaseMutex(&fidp->mx);
8195 lock_ObtainWrite(&scp->rw);
8196 code = cm_SyncOp(scp, NULL, userp, &req, 0,
8197 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8199 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8201 /* offset from current offset */
8202 new_offset = LargeIntegerAdd(fidp->offset,
8203 ConvertLongToLargeInteger(offset));
8205 else if (whence == 2) {
8206 /* offset from current EOF */
8207 new_offset = LargeIntegerAdd(scp->length,
8208 ConvertLongToLargeInteger(offset));
8210 new_offset = ConvertLongToLargeInteger(offset);
8213 fidp->offset = new_offset;
8214 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
8215 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
8216 smb_SetSMBDataLength(outp, 0);
8218 lock_ReleaseWrite(&scp->rw);
8219 smb_ReleaseFID(fidp);
8220 cm_ReleaseSCache(scp);
8221 cm_ReleaseUser(userp);
8225 /* dispatch all of the requests received in a packet. Due to chaining, this may
8226 * be more than one request.
8228 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
8229 NCB *ncbp, raw_write_cont_t *rwcp)
8233 unsigned long code = 0;
8234 unsigned char *outWctp;
8235 int nparms; /* # of bytes of parameters */
8237 int nbytes; /* bytes of data, excluding count */
8240 unsigned short errCode;
8241 unsigned long NTStatus;
8243 unsigned char errClass;
8244 unsigned int oldGen;
8245 DWORD oldTime, newTime;
8247 /* get easy pointer to the data */
8248 smbp = (smb_t *) inp->data;
8250 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
8251 /* setup the basic parms for the initial request in the packet */
8252 inp->inCom = smbp->com;
8253 inp->wctp = &smbp->wct;
8255 inp->ncb_length = ncbp->ncb_length;
8260 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
8261 /* log it and discard it */
8262 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
8263 __FILE__, __LINE__, ncbp->ncb_length);
8264 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
8268 /* We are an ongoing op */
8269 thrd_Increment(&ongoingOps);
8271 /* set up response packet for receiving output */
8272 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
8273 smb_FormatResponsePacket(vcp, inp, outp);
8274 outWctp = outp->wctp;
8276 /* Remember session generation number and time */
8277 oldGen = sessionGen;
8278 oldTime = GetTickCount();
8280 while (inp->inCom != 0xff) {
8281 dp = &smb_dispatchTable[inp->inCom];
8283 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
8284 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
8285 code = outp->resumeCode;
8289 /* process each request in the packet; inCom, wctp and inCount
8290 * are already set up.
8292 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
8295 /* now do the dispatch */
8296 /* start by formatting the response record a little, as a default */
8297 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
8299 outWctp[1] = 0xff; /* no operation */
8300 outWctp[2] = 0; /* padding */
8305 /* not a chained request, this is a more reasonable default */
8306 outWctp[0] = 0; /* wct of zero */
8307 outWctp[1] = 0; /* and bcc (word) of zero */
8311 /* once set, stays set. Doesn't matter, since we never chain
8312 * "no response" calls.
8314 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
8318 /* we have a recognized operation */
8319 char * opName = myCrt_Dispatch(inp->inCom);
8321 if (inp->inCom == 0x1d)
8323 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
8325 osi_Log4(smb_logp,"Dispatch %s vcp 0x%p lana %d lsn %d",
8326 opName,vcp,vcp->lana,vcp->lsn);
8327 code = (*(dp->procp)) (vcp, inp, outp);
8328 osi_Log4(smb_logp,"Dispatch return code 0x%x vcp 0x%p lana %d lsn %d",
8329 code,vcp,vcp->lana,vcp->lsn);
8331 if ( code == CM_ERROR_BADSMB ||
8332 code == CM_ERROR_BADOP )
8334 #endif /* LOG_PACKET */
8337 newTime = GetTickCount();
8338 osi_Log2(smb_logp, "Dispatch %s duration %d ms", opName, newTime - oldTime);
8340 /* ReceiveV3Tran2A handles its own logging */
8341 if (inp->inCom != 0x32 && newTime - oldTime > 45000) {
8344 clientchar_t *treepath = NULL; /* do not free */
8345 clientchar_t *pathname = NULL;
8346 cm_fid_t afid = {0,0,0,0,0};
8348 uidp = smb_FindUID(vcp, smbp->uid, 0);
8349 smb_LookupTIDPath(vcp,((smb_t *)inp)->tid, &treepath);
8350 fidp = smb_FindFID(vcp, inp->fid, 0);
8353 lock_ObtainMutex(&fidp->mx);
8354 if (fidp->NTopen_pathp)
8355 pathname = fidp->NTopen_pathp;
8357 afid = fidp->scp->fid;
8359 if (inp->stringsp->wdata)
8360 pathname = inp->stringsp->wdata;
8363 afsi_log("Request %s duration %d ms user %S tid \"%S\" path? \"%S\" afid (%d.%d.%d.%d)",
8364 opName, newTime - oldTime,
8365 uidp ? uidp->unp->name : NULL,
8368 afid.cell, afid.volume, afid.vnode, afid.unique);
8371 lock_ReleaseMutex(&fidp->mx);
8374 smb_ReleaseUID(uidp);
8376 smb_ReleaseFID(fidp);
8379 if (oldGen != sessionGen) {
8380 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
8381 newTime - oldTime, ncbp->ncb_length);
8382 osi_Log3(smb_logp, "Request %s straddled session startup, "
8383 "took %d ms, ncb length %d", opName, newTime - oldTime, ncbp->ncb_length);
8386 FreeSMBStrings(inp);
8388 /* bad opcode, fail the request, after displaying it */
8389 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
8392 #endif /* LOG_PACKET */
8395 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
8396 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
8397 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
8398 if (code == IDCANCEL)
8401 code = CM_ERROR_BADOP;
8404 /* catastrophic failure: log as much as possible */
8405 if (code == CM_ERROR_BADSMB) {
8406 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
8410 #endif /* LOG_PACKET */
8411 osi_Log1(smb_logp, "Invalid SMB message, length %d",
8414 code = CM_ERROR_INVAL;
8417 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
8418 thrd_Decrement(&ongoingOps);
8423 /* now, if we failed, turn the current response into an empty
8424 * one, and fill in the response packet's error code.
8427 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8428 smb_MapNTError(code, &NTStatus);
8429 outWctp = outp->wctp;
8430 smbp = (smb_t *) &outp->data;
8431 if (code != CM_ERROR_PARTIALWRITE
8432 && code != CM_ERROR_BUFFERTOOSMALL
8433 && code != CM_ERROR_GSSCONTINUE) {
8434 /* nuke wct and bcc. For a partial
8435 * write or an in-process authentication handshake,
8436 * assume they're OK.
8442 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8443 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8444 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8445 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8446 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8450 smb_MapCoreError(code, vcp, &errCode, &errClass);
8451 outWctp = outp->wctp;
8452 smbp = (smb_t *) &outp->data;
8453 if (code != CM_ERROR_PARTIALWRITE) {
8454 /* nuke wct and bcc. For a partial
8455 * write, assume they're OK.
8461 smbp->errLow = (unsigned char) (errCode & 0xff);
8462 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8463 smbp->rcls = errClass;
8466 } /* error occurred */
8468 /* if we're here, we've finished one request. Look to see if
8469 * this is a chained opcode. If it is, setup things to process
8470 * the chained request, and setup the output buffer to hold the
8471 * chained response. Start by finding the next input record.
8473 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
8474 break; /* not a chained req */
8475 tp = inp->wctp; /* points to start of last request */
8476 /* in a chained request, the first two
8477 * parm fields are required, and are
8478 * AndXCommand/AndXReserved and
8480 if (tp[0] < 2) break;
8481 if (tp[1] == 0xff) break; /* no more chained opcodes */
8483 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
8486 /* and now append the next output request to the end of this
8487 * last request. Begin by finding out where the last response
8488 * ends, since that's where we'll put our new response.
8490 outWctp = outp->wctp; /* ptr to out parameters */
8491 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
8492 nparms = outWctp[0] << 1;
8493 tp = outWctp + nparms + 1; /* now points to bcc field */
8494 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
8495 tp += 2 /* for the count itself */ + nbytes;
8496 /* tp now points to the new output record; go back and patch the
8497 * second parameter (off2) to point to the new record.
8499 temp = (unsigned int)(tp - outp->data);
8500 outWctp[3] = (unsigned char) (temp & 0xff);
8501 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
8502 outWctp[2] = 0; /* padding */
8503 outWctp[1] = inp->inCom; /* next opcode */
8505 /* finally, setup for the next iteration */
8508 } /* while loop over all requests in the packet */
8510 /* now send the output packet, and return */
8512 smb_SendPacket(vcp, outp);
8513 thrd_Decrement(&ongoingOps);
8518 /* Wait for Netbios() calls to return, and make the results available to server
8519 * threads. Note that server threads can't wait on the NCBevents array
8520 * themselves, because NCB events are manual-reset, and the servers would race
8521 * each other to reset them.
8523 void smb_ClientWaiter(void *parmp)
8528 while (smbShutdownFlag == 0) {
8529 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
8531 if (code == WAIT_OBJECT_0)
8534 /* error checking */
8535 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8537 int abandonIdx = code - WAIT_ABANDONED_0;
8538 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8541 if (code == WAIT_IO_COMPLETION)
8543 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
8547 if (code == WAIT_TIMEOUT)
8549 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
8552 if (code == WAIT_FAILED)
8554 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
8557 idx = code - WAIT_OBJECT_0;
8559 /* check idx range! */
8560 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
8562 /* this is fatal - log as much as possible */
8563 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
8564 osi_assertx(0, "invalid index");
8567 thrd_ResetEvent(NCBevents[idx]);
8568 thrd_SetEvent(NCBreturns[0][idx]);
8573 * Try to have one NCBRECV request waiting for every live session. Not more
8574 * than one, because if there is more than one, it's hard to handle Write Raw.
8576 void smb_ServerWaiter(void *parmp)
8579 int idx_session, idx_NCB;
8582 while (smbShutdownFlag == 0) {
8584 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
8586 if (code == WAIT_OBJECT_0)
8589 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
8591 int abandonIdx = code - WAIT_ABANDONED_0;
8592 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8595 if (code == WAIT_IO_COMPLETION)
8597 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
8601 if (code == WAIT_TIMEOUT)
8603 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
8606 if (code == WAIT_FAILED)
8608 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
8611 idx_session = code - WAIT_OBJECT_0;
8613 /* check idx range! */
8614 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
8616 /* this is fatal - log as much as possible */
8617 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
8618 osi_assertx(0, "invalid index");
8623 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
8625 if (code == WAIT_OBJECT_0) {
8626 if (smbShutdownFlag == 1)
8632 /* error checking */
8633 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8635 int abandonIdx = code - WAIT_ABANDONED_0;
8636 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8639 if (code == WAIT_IO_COMPLETION)
8641 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
8645 if (code == WAIT_TIMEOUT)
8647 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
8650 if (code == WAIT_FAILED)
8652 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
8655 idx_NCB = code - WAIT_OBJECT_0;
8657 /* check idx range! */
8658 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
8660 /* this is fatal - log as much as possible */
8661 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
8662 osi_assertx(0, "invalid index");
8665 /* Link them together */
8666 NCBsessions[idx_NCB] = idx_session;
8669 ncbp = NCBs[idx_NCB];
8670 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
8671 ncbp->ncb_command = NCBRECV | ASYNCH;
8672 ncbp->ncb_lana_num = lanas[idx_session];
8673 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
8674 ncbp->ncb_event = NCBevents[idx_NCB];
8675 ncbp->ncb_length = SMB_PACKETSIZE;
8681 * The top level loop for handling SMB request messages. Each server thread
8682 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
8683 * NCB and buffer for the incoming request are loaned to us.
8685 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
8686 * to immediately send a request for the rest of the data. This must come
8687 * before any other traffic for that session, so we delay setting the session
8688 * event until that data has come in.
8690 void smb_Server(VOID *parmp)
8692 INT_PTR myIdx = (INT_PTR) parmp;
8696 smb_packet_t *outbufp;
8698 int idx_NCB, idx_session;
8700 smb_vc_t *vcp = NULL;
8702 extern void rx_StartClientThread(void);
8704 rx_StartClientThread();
8706 outncbp = smb_GetNCB();
8707 outbufp = smb_GetPacket();
8708 outbufp->ncbp = outncbp;
8716 smb_ResetServerPriority();
8718 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
8721 /* terminate silently if shutdown flag is set */
8722 if (code == WAIT_OBJECT_0) {
8723 if (smbShutdownFlag == 1) {
8724 thrd_SetEvent(smb_ServerShutdown[myIdx]);
8730 /* error checking */
8731 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8733 int abandonIdx = code - WAIT_ABANDONED_0;
8734 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
8737 if (code == WAIT_IO_COMPLETION)
8739 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
8743 if (code == WAIT_TIMEOUT)
8745 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
8748 if (code == WAIT_FAILED)
8750 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
8753 idx_NCB = code - WAIT_OBJECT_0;
8755 /* check idx range! */
8756 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
8758 /* this is fatal - log as much as possible */
8759 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
8760 osi_assertx(0, "invalid index");
8763 ncbp = NCBs[idx_NCB];
8764 idx_session = NCBsessions[idx_NCB];
8765 rc = ncbp->ncb_retcode;
8767 if (rc != NRC_PENDING && rc != NRC_GOODRET)
8768 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
8772 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8776 /* Can this happen? Or is it just my UNIX paranoia? */
8777 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
8782 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
8785 /* Client closed session */
8786 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8788 lock_ObtainMutex(&vcp->mx);
8789 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8790 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8792 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8793 lock_ReleaseMutex(&vcp->mx);
8794 lock_ObtainWrite(&smb_globalLock);
8795 dead_sessions[vcp->session] = TRUE;
8796 lock_ReleaseWrite(&smb_globalLock);
8798 lock_ReleaseMutex(&vcp->mx);
8800 smb_CleanupDeadVC(vcp);
8807 /* Treat as transient error */
8808 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
8811 "dispatch smb recv failed, message incomplete, ncb_length %d",
8814 "SMB message incomplete, "
8815 "length %d", ncbp->ncb_length);
8818 * We used to discard the packet.
8819 * Instead, try handling it normally.
8823 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8827 /* A weird error code. Log it, sleep, and continue. */
8828 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8830 lock_ObtainMutex(&vcp->mx);
8831 if (vcp->errorCount++ > 3) {
8832 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
8833 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8834 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8836 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8837 lock_ReleaseMutex(&vcp->mx);
8838 lock_ObtainWrite(&smb_globalLock);
8839 dead_sessions[vcp->session] = TRUE;
8840 lock_ReleaseWrite(&smb_globalLock);
8842 lock_ReleaseMutex(&vcp->mx);
8844 smb_CleanupDeadVC(vcp);
8850 lock_ReleaseMutex(&vcp->mx);
8854 thrd_SetEvent(SessionEvents[idx_session]);
8860 /* Success, so now dispatch on all the data in the packet */
8862 smb_concurrentCalls++;
8863 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
8864 smb_maxObsConcurrentCalls = smb_concurrentCalls;
8867 * If at this point vcp is NULL (implies that packet was invalid)
8868 * then we are in big trouble. This means either :
8869 * a) we have the wrong NCB.
8870 * b) Netbios screwed up the call.
8871 * c) The VC was already marked dead before we were able to
8873 * Obviously this implies that
8874 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
8875 * lanas[idx_session] != ncbp->ncb_lana_num )
8876 * Either way, we can't do anything with this packet.
8877 * Log, sleep and resume.
8880 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
8884 ncbp->ncb_lana_num);
8886 /* Also log in the trace log. */
8887 osi_Log4(smb_logp, "Server: VCP does not exist!"
8888 "LSNs[idx_session]=[%d],"
8889 "lanas[idx_session]=[%d],"
8890 "ncbp->ncb_lsn=[%d],"
8891 "ncbp->ncb_lana_num=[%d]",
8895 ncbp->ncb_lana_num);
8897 /* thrd_Sleep(1000); Don't bother sleeping */
8898 thrd_SetEvent(SessionEvents[idx_session]);
8899 smb_concurrentCalls--;
8903 smb_SetRequestStartTime();
8905 vcp->errorCount = 0;
8906 bufp = (struct smb_packet *) ncbp->ncb_buffer;
8907 smbp = (smb_t *)bufp->data;
8914 if (smbp->com == 0x1d) {
8915 /* Special handling for Write Raw */
8916 raw_write_cont_t rwc;
8918 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
8919 if (rwc.code == 0) {
8920 EVENT_HANDLE rwevent;
8921 char eventName[MAX_PATH];
8923 snprintf(eventName, MAX_PATH, "smb_Server() rwevent %d", myIdx);
8924 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8925 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8926 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8928 ncbp->ncb_command = NCBRECV | ASYNCH;
8929 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
8930 ncbp->ncb_lana_num = vcp->lana;
8931 ncbp->ncb_buffer = rwc.buf;
8932 ncbp->ncb_length = 65535;
8933 ncbp->ncb_event = rwevent;
8935 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
8936 thrd_CloseHandle(rwevent);
8938 thrd_SetEvent(SessionEvents[idx_session]);
8940 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
8942 else if (smbp->com == 0xa0) {
8944 * Serialize the handling for NT Transact
8947 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
8948 thrd_SetEvent(SessionEvents[idx_session]);
8950 thrd_SetEvent(SessionEvents[idx_session]);
8951 /* TODO: what else needs to be serialized? */
8952 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
8956 __except( smb_ServerExceptionFilter() ) {
8960 smb_concurrentCalls--;
8963 thrd_SetEvent(NCBavails[idx_NCB]);
8968 smb_FreePacket(outbufp);
8970 smb_FreeNCB(outncbp);
8974 * Exception filter for the server threads. If an exception occurs in the
8975 * dispatch routines, which is where exceptions are most common, then do a
8976 * force trace and give control to upstream exception handlers. Useful for
8979 DWORD smb_ServerExceptionFilter(void) {
8980 /* While this is not the best time to do a trace, if it succeeds, then
8981 * we have a trace (assuming tracing was enabled). Otherwise, this should
8982 * throw a second exception.
8984 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
8985 afsd_ForceTrace(TRUE);
8986 buf_ForceTrace(TRUE);
8987 return EXCEPTION_CONTINUE_SEARCH;
8991 * Create a new NCB and associated events, packet buffer, and "space" buffer.
8992 * If the number of server threads is M, and the number of live sessions is
8993 * N, then the number of NCB's in use at any time either waiting for, or
8994 * holding, received messages is M + N, so that is how many NCB's get created.
8996 void InitNCBslot(int idx)
8998 struct smb_packet *bufp;
8999 EVENT_HANDLE retHandle;
9001 char eventName[MAX_PATH];
9003 osi_assertx( idx < (sizeof(NCBs) / sizeof(NCBs[0])), "invalid index" );
9005 NCBs[idx] = smb_GetNCB();
9006 sprintf(eventName,"NCBavails[%d]", idx);
9007 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9008 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9009 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9010 sprintf(eventName,"NCBevents[%d]", idx);
9011 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
9012 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9013 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9014 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
9015 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9016 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9017 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9018 for (i=0; i<smb_NumServerThreads; i++)
9019 NCBreturns[i][idx] = retHandle;
9020 bufp = smb_GetPacket();
9021 bufp->spacep = cm_GetSpace();
9025 /* listen for new connections */
9026 void smb_Listener(void *parmp)
9032 afs_uint32 session, thread;
9033 smb_vc_t *vcp = NULL;
9035 char rname[NCBNAMSZ+1];
9036 char cname[MAX_COMPUTERNAME_LENGTH+1];
9037 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
9038 INT_PTR lana = (INT_PTR) parmp;
9039 char eventName[MAX_PATH];
9040 int bridgeCount = 0;
9041 int nowildCount = 0;
9043 sprintf(eventName,"smb_Listener_lana_%d", (unsigned char)lana);
9044 ListenerShutdown[lana] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9045 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9046 thrd_ResetEvent(ListenerShutdown[lana]);
9048 ncbp = smb_GetNCB();
9050 /* retrieve computer name */
9051 GetComputerName(cname, &cnamelen);
9054 while (smb_ListenerState == SMB_LISTENER_STARTED) {
9055 memset(ncbp, 0, sizeof(NCB));
9058 ncbp->ncb_command = NCBLISTEN;
9059 ncbp->ncb_rto = 0; /* No receive timeout */
9060 ncbp->ncb_sto = 0; /* No send timeout */
9062 /* pad out with spaces instead of null termination */
9063 len = (long)strlen(smb_localNamep);
9064 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9065 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9067 strcpy(ncbp->ncb_callname, "*");
9068 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
9070 ncbp->ncb_lana_num = (UCHAR)lana;
9072 code = Netbios(ncbp);
9074 if (code == NRC_NAMERR) {
9075 /* An smb shutdown or Vista resume must have taken place */
9077 "NCBLISTEN lana=%d failed with NRC_NAMERR.",
9078 ncbp->ncb_lana_num);
9079 afsi_log("NCBLISTEN lana=%d failed with NRC_NAMERR.", ncbp->ncb_lana_num);
9081 if (lock_TryMutex(&smb_StartedLock)) {
9082 lana_list.lana[i] = LANA_INVALID;
9083 lock_ReleaseMutex(&smb_StartedLock);
9086 } else if (code == NRC_BRIDGE || code != 0) {
9087 int lanaRemaining = 0;
9089 if (code == NRC_BRIDGE) {
9090 if (++bridgeCount <= 5) {
9091 afsi_log("NCBLISTEN lana=%d failed with NRC_BRIDGE, retrying ...", ncbp->ncb_lana_num);
9094 } else if (code == NRC_NOWILD) {
9095 if (++nowildCount <= 5) {
9096 afsi_log("NCBLISTEN lana=%d failed with NRC_NOWILD, retrying ...", ncbp->ncb_lana_num);
9098 if (bridgeCount > 0) {
9099 memset(ncbp, 0, sizeof(*ncbp));
9100 ncbp->ncb_command = NCBADDNAME;
9101 ncbp->ncb_lana_num = (UCHAR)lana;
9102 /* pad out with spaces instead of null termination */
9103 len = (long)strlen(smb_localNamep);
9104 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9105 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9106 code = Netbios(ncbp);
9112 while (!lock_TryMutex(&smb_StartedLock)) {
9113 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9119 "NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
9120 ncbp->ncb_lana_num, ncb_error_string(code));
9121 afsi_log("NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
9122 ncbp->ncb_lana_num, ncb_error_string(code));
9124 for (i = 0; i < lana_list.length; i++) {
9125 if (lana_list.lana[i] == lana) {
9126 smb_StopListener(ncbp, lana_list.lana[i], FALSE);
9127 lana_list.lana[i] = LANA_INVALID;
9129 if (lana_list.lana[i] != LANA_INVALID)
9133 if (lanaRemaining == 0) {
9134 cm_VolStatus_Network_Stopped(cm_NetbiosName
9139 smb_ListenerState = SMB_LISTENER_STOPPED;
9140 smb_LANadapter = LANA_INVALID;
9141 lana_list.length = 0;
9143 lock_ReleaseMutex(&smb_StartedLock);
9147 else if (code != 0) {
9148 char tbuffer[AFSPATHMAX];
9150 /* terminate silently if shutdown flag is set */
9151 while (!lock_TryMutex(&smb_StartedLock)) {
9152 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9158 "NCBLISTEN lana=%d failed with code %d [%s]",
9159 ncbp->ncb_lana_num, code, ncb_error_string(code));
9161 "Client exiting due to network failure. Please restart client.\n");
9164 "Client exiting due to network failure. Please restart client.\n"
9165 "NCBLISTEN lana=%d failed with code %d [%s]",
9166 ncbp->ncb_lana_num, code, ncb_error_string(code));
9168 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
9169 MB_OK|MB_SERVICE_NOTIFICATION);
9170 osi_panic(tbuffer, __FILE__, __LINE__);
9172 lock_ReleaseMutex(&smb_StartedLock);
9177 /* a successful packet received. clear bridge error count */
9181 /* check for remote conns */
9182 /* first get remote name and insert null terminator */
9183 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
9184 for (i=NCBNAMSZ; i>0; i--) {
9185 if (rname[i-1] != ' ' && rname[i-1] != 0) {
9191 /* compare with local name */
9193 if (strncmp(rname, cname, NCBNAMSZ) != 0)
9194 flags |= SMB_VCFLAG_REMOTECONN;
9197 lock_ObtainMutex(&smb_ListenerLock);
9199 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
9200 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
9202 /* now ncbp->ncb_lsn is the connection ID */
9203 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
9204 if (vcp->session == 0) {
9205 /* New generation */
9206 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
9209 /* Log session startup */
9211 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9212 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9213 #endif /* NOTSERVICE */
9214 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9215 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9217 if (reportSessionStartups) {
9218 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9221 lock_ObtainMutex(&vcp->mx);
9222 cm_Utf8ToUtf16(rname, -1, vcp->rname, lengthof(vcp->rname));
9223 vcp->flags |= flags;
9224 lock_ReleaseMutex(&vcp->mx);
9226 /* Allocate slot in session arrays */
9227 /* Re-use dead session if possible, otherwise add one more */
9228 /* But don't look at session[0], it is reserved */
9229 lock_ObtainWrite(&smb_globalLock);
9230 for (session = 1; session < numSessions; session++) {
9231 if (dead_sessions[session]) {
9232 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
9233 dead_sessions[session] = FALSE;
9237 lock_ReleaseWrite(&smb_globalLock);
9239 /* We are re-using an existing VC because the lsn and lana
9241 session = vcp->session;
9243 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
9245 /* Log session startup */
9247 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9248 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9249 #endif /* NOTSERVICE */
9250 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9251 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9253 if (reportSessionStartups) {
9254 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9258 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
9259 unsigned long code = CM_ERROR_ALLBUSY;
9260 smb_packet_t * outp = smb_GetPacket();
9261 unsigned char *outWctp;
9264 smb_FormatResponsePacket(vcp, NULL, outp);
9267 if (vcp->flags & SMB_VCFLAG_STATUS32) {
9268 unsigned long NTStatus;
9269 smb_MapNTError(code, &NTStatus);
9270 outWctp = outp->wctp;
9271 smbp = (smb_t *) &outp->data;
9275 smbp->rcls = (unsigned char) (NTStatus & 0xff);
9276 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
9277 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
9278 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
9279 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9281 unsigned short errCode;
9282 unsigned char errClass;
9283 smb_MapCoreError(code, vcp, &errCode, &errClass);
9284 outWctp = outp->wctp;
9285 smbp = (smb_t *) &outp->data;
9289 smbp->errLow = (unsigned char) (errCode & 0xff);
9290 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
9291 smbp->rcls = errClass;
9294 smb_SendPacket(vcp, outp);
9295 smb_FreePacket(outp);
9297 lock_ObtainMutex(&vcp->mx);
9298 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9299 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9301 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9302 lock_ReleaseMutex(&vcp->mx);
9303 lock_ObtainWrite(&smb_globalLock);
9304 dead_sessions[vcp->session] = TRUE;
9305 lock_ReleaseWrite(&smb_globalLock);
9306 smb_CleanupDeadVC(vcp);
9308 lock_ReleaseMutex(&vcp->mx);
9311 /* assert that we do not exceed the maximum number of sessions or NCBs.
9312 * we should probably want to wait for a session to be freed in case
9315 osi_assertx(session < SESSION_MAX - 1, "invalid session");
9316 osi_assertx(numNCBs < NCB_MAX - 1, "invalid numNCBs"); /* if we pass this test we can allocate one more */
9318 lock_ObtainMutex(&vcp->mx);
9319 vcp->session = session;
9320 lock_ReleaseMutex(&vcp->mx);
9321 lock_ObtainWrite(&smb_globalLock);
9322 LSNs[session] = ncbp->ncb_lsn;
9323 lanas[session] = ncbp->ncb_lana_num;
9324 lock_ReleaseWrite(&smb_globalLock);
9326 if (session == numSessions) {
9327 /* Add new NCB for new session */
9328 char eventName[MAX_PATH];
9330 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
9332 InitNCBslot(numNCBs);
9333 lock_ObtainWrite(&smb_globalLock);
9335 lock_ReleaseWrite(&smb_globalLock);
9336 thrd_SetEvent(NCBavails[0]);
9337 thrd_SetEvent(NCBevents[0]);
9338 for (thread = 0; thread < smb_NumServerThreads; thread++)
9339 thrd_SetEvent(NCBreturns[thread][0]);
9340 /* Also add new session event */
9341 sprintf(eventName, "SessionEvents[%d]", session);
9342 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9343 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9344 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9345 lock_ObtainWrite(&smb_globalLock);
9347 lock_ReleaseWrite(&smb_globalLock);
9348 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
9349 thrd_SetEvent(SessionEvents[0]);
9351 thrd_SetEvent(SessionEvents[session]);
9357 lock_ReleaseMutex(&smb_ListenerLock);
9358 } /* dispatch while loop */
9362 thrd_SetEvent(ListenerShutdown[lana]);
9367 smb_LanAdapterChangeThread(void *param)
9370 * Give the IPAddrDaemon thread a chance
9371 * to block before we trigger.
9374 smb_LanAdapterChange(0);
9377 void smb_SetLanAdapterChangeDetected(void)
9382 lock_ObtainMutex(&smb_StartedLock);
9384 if (!powerStateSuspended) {
9385 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_LanAdapterChangeThread,
9386 NULL, 0, &lpid, "smb_LanAdapterChange");
9387 osi_assertx(phandle != NULL, "smb_LanAdapterChangeThread thread creation failure");
9388 thrd_CloseHandle(phandle);
9391 smb_LanAdapterChangeDetected = 1;
9392 lock_ReleaseMutex(&smb_StartedLock);
9395 void smb_LanAdapterChange(int locked) {
9396 lana_number_t lanaNum;
9398 char NetbiosName[MAX_NB_NAME_LENGTH] = "";
9400 LANA_ENUM temp_list;
9405 afsi_log("smb_LanAdapterChange");
9408 lock_ObtainMutex(&smb_StartedLock);
9410 smb_LanAdapterChangeDetected = 0;
9412 if (!powerStateSuspended &&
9413 SUCCEEDED(lana_GetUncServerNameEx(NetbiosName, &lanaNum, &bGateway,
9414 LANA_NETBIOS_NAME_FULL)) &&
9415 lanaNum != LANA_INVALID && smb_LANadapter != lanaNum) {
9416 if ( isGateway != bGateway ) {
9417 afsi_log("Lan Adapter Change detected (%d != %d): gateway %d != %d",
9418 smb_LANadapter, lanaNum, isGateway, bGateway);
9420 } else if (strcmp(cm_NetbiosName, NetbiosName) ) {
9421 afsi_log("Lan Adapter Change detected (%d != %d): name %s != %s",
9422 smb_LANadapter, lanaNum, cm_NetbiosName, NetbiosName);
9425 NCB *ncbp = smb_GetNCB();
9426 ncbp->ncb_command = NCBENUM;
9427 ncbp->ncb_buffer = (PUCHAR)&temp_list;
9428 ncbp->ncb_length = sizeof(temp_list);
9429 code = Netbios(ncbp);
9431 if (temp_list.length != lana_list.length) {
9432 afsi_log("Lan Adapter Change detected (%d != %d): lan list length changed %d != %d",
9433 smb_LANadapter, lanaNum, temp_list.length, lana_list.length);
9436 for (i=0; i<lana_list.length; i++) {
9437 if ( temp_list.lana[i] != lana_list.lana[i] ) {
9438 afsi_log("Lan Adapter Change detected (%d != %d): lana[%d] %d != %d",
9439 smb_LANadapter, lanaNum, i, temp_list.lana[i], lana_list.lana[i]);
9451 smb_StopListeners(1);
9452 smb_RestartListeners(1);
9455 lock_ReleaseMutex(&smb_StartedLock);
9458 /* initialize Netbios */
9459 int smb_NetbiosInit(int locked)
9462 int i, lana, code, l;
9464 int delname_tried=0;
9467 lana_number_t lanaNum;
9470 lock_ObtainMutex(&smb_StartedLock);
9472 if (smb_ListenerState != SMB_LISTENER_UNINITIALIZED &&
9473 smb_ListenerState != SMB_LISTENER_STOPPED) {
9476 lock_ReleaseMutex(&smb_StartedLock);
9479 /* setup the NCB system */
9480 ncbp = smb_GetNCB();
9482 /* Call lanahelper to get Netbios name, lan adapter number and gateway flag */
9483 if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
9484 smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
9486 if (smb_LANadapter != LANA_INVALID)
9487 afsi_log("LAN adapter number %d", smb_LANadapter);
9489 afsi_log("LAN adapter number not determined");
9492 afsi_log("Set for gateway service");
9494 afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
9496 /* something went horribly wrong. We can't proceed without a netbios name */
9498 StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
9499 osi_panic(buf, __FILE__, __LINE__);
9502 /* remember the name */
9503 len = (int)strlen(cm_NetbiosName);
9505 free(smb_localNamep);
9506 smb_localNamep = malloc(len+1);
9507 strcpy(smb_localNamep, cm_NetbiosName);
9508 afsi_log("smb_localNamep is >%s<", smb_localNamep);
9510 /* Also copy the value to the client character encoded string */
9511 cm_Utf8ToClientString(cm_NetbiosName, -1, cm_NetbiosNameC, MAX_NB_NAME_LENGTH);
9513 if (smb_LANadapter == LANA_INVALID) {
9514 ncbp->ncb_command = NCBENUM;
9515 ncbp->ncb_buffer = (PUCHAR)&lana_list;
9516 ncbp->ncb_length = sizeof(lana_list);
9517 code = Netbios(ncbp);
9519 afsi_log("Netbios NCBENUM error code %d", code);
9520 osi_panic(s, __FILE__, __LINE__);
9524 lana_list.length = 1;
9525 lana_list.lana[0] = smb_LANadapter;
9528 for (i = 0; i < lana_list.length; i++) {
9529 /* reset the adaptor: in Win32, this is required for every process, and
9530 * acts as an init call, not as a real hardware reset.
9532 ncbp->ncb_command = NCBRESET;
9533 ncbp->ncb_callname[0] = 100;
9534 ncbp->ncb_callname[2] = 100;
9535 ncbp->ncb_lana_num = lana_list.lana[i];
9536 code = Netbios(ncbp);
9538 code = ncbp->ncb_retcode;
9540 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
9541 lana_list.lana[i] = LANA_INVALID; /* invalid lana */
9543 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
9547 /* and declare our name so we can receive connections */
9548 memset(ncbp, 0, sizeof(*ncbp));
9549 len=lstrlen(smb_localNamep);
9550 memset(smb_sharename,' ',NCBNAMSZ);
9551 memcpy(smb_sharename,smb_localNamep,len);
9552 afsi_log("lana_list.length %d", lana_list.length);
9554 /* Keep the name so we can unregister it later */
9555 for (l = 0; l < lana_list.length; l++) {
9556 lana = lana_list.lana[l];
9558 ncbp->ncb_command = NCBADDNAME;
9559 ncbp->ncb_lana_num = lana;
9560 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9561 code = Netbios(ncbp);
9563 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
9564 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
9566 char name[NCBNAMSZ+1];
9568 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
9569 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
9573 code = ncbp->ncb_retcode;
9576 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
9579 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
9580 if (code == NRC_BRIDGE) { /* invalid LANA num */
9581 lana_list.lana[l] = LANA_INVALID;
9584 else if (code == NRC_DUPNAME) {
9585 afsi_log("Name already exists; try to delete it");
9586 memset(ncbp, 0, sizeof(*ncbp));
9587 ncbp->ncb_command = NCBDELNAME;
9588 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9589 ncbp->ncb_lana_num = lana;
9590 code = Netbios(ncbp);
9592 code = ncbp->ncb_retcode;
9594 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
9596 if (code != 0 || delname_tried) {
9597 lana_list.lana[l] = LANA_INVALID;
9599 else if (code == 0) {
9600 if (!delname_tried) {
9608 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
9609 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
9613 smb_LANadapter = lana;
9614 lana_found = 1; /* at least one worked */
9618 osi_assertx(lana_list.length >= 0, "empty lana list");
9620 afsi_log("No valid LANA numbers found!");
9621 lana_list.length = 0;
9622 smb_LANadapter = LANA_INVALID;
9623 smb_ListenerState = SMB_LISTENER_STOPPED;
9624 cm_VolStatus_Network_Stopped(cm_NetbiosName
9631 /* we're done with the NCB now */
9634 afsi_log("smb_NetbiosInit smb_LANadapter=%d",smb_LANadapter);
9635 if (lana_list.length > 0)
9636 osi_assert(smb_LANadapter != LANA_INVALID);
9639 lock_ReleaseMutex(&smb_StartedLock);
9641 return (lana_list.length > 0 ? 1 : 0);
9644 void smb_StartListeners(int locked)
9651 lock_ObtainMutex(&smb_StartedLock);
9653 if (smb_ListenerState == SMB_LISTENER_STARTED) {
9655 lock_ReleaseMutex(&smb_StartedLock);
9659 afsi_log("smb_StartListeners");
9660 smb_ListenerState = SMB_LISTENER_STARTED;
9661 cm_VolStatus_Network_Started(cm_NetbiosName
9667 for (i = 0; i < lana_list.length; i++) {
9668 if (lana_list.lana[i] == LANA_INVALID)
9670 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
9671 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
9672 osi_assertx(phandle != NULL, "smb_Listener thread creation failure");
9673 thrd_CloseHandle(phandle);
9676 lock_ReleaseMutex(&smb_StartedLock);
9679 void smb_RestartListeners(int locked)
9682 lock_ObtainMutex(&smb_StartedLock);
9684 if (powerStateSuspended)
9685 afsi_log("smb_RestartListeners called while suspended");
9687 if (!powerStateSuspended && smb_ListenerState != SMB_LISTENER_UNINITIALIZED) {
9688 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
9689 if (smb_NetbiosInit(1))
9690 smb_StartListeners(1);
9691 } else if (smb_LanAdapterChangeDetected) {
9692 smb_LanAdapterChange(1);
9696 lock_ReleaseMutex(&smb_StartedLock);
9699 void smb_StopListener(NCB *ncbp, int lana, int wait)
9703 memset(ncbp, 0, sizeof(*ncbp));
9704 ncbp->ncb_command = NCBDELNAME;
9705 ncbp->ncb_lana_num = lana;
9706 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9707 code = Netbios(ncbp);
9709 afsi_log("StopListener: Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
9710 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
9712 /* and then reset the LANA; this will cause the listener threads to exit */
9713 ncbp->ncb_command = NCBRESET;
9714 ncbp->ncb_callname[0] = 100;
9715 ncbp->ncb_callname[2] = 100;
9716 ncbp->ncb_lana_num = lana;
9717 code = Netbios(ncbp);
9719 code = ncbp->ncb_retcode;
9721 afsi_log("StopListener: Netbios NCBRESET lana %d error code %d", lana, code);
9723 afsi_log("StopListener: Netbios NCBRESET lana %d succeeded", lana);
9727 thrd_WaitForSingleObject_Event(ListenerShutdown[lana], INFINITE);
9730 void smb_StopListeners(int locked)
9736 lock_ObtainMutex(&smb_StartedLock);
9738 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
9740 lock_ReleaseMutex(&smb_StartedLock);
9744 afsi_log("smb_StopListeners");
9745 smb_ListenerState = SMB_LISTENER_STOPPED;
9746 cm_VolStatus_Network_Stopped(cm_NetbiosName
9752 ncbp = smb_GetNCB();
9754 /* Unregister the SMB name */
9755 for (l = 0; l < lana_list.length; l++) {
9756 lana = lana_list.lana[l];
9758 if (lana != LANA_INVALID) {
9759 smb_StopListener(ncbp, lana, TRUE);
9761 /* mark the adapter invalid */
9762 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
9766 /* force a re-evaluation of the network adapters */
9767 lana_list.length = 0;
9768 smb_LANadapter = LANA_INVALID;
9771 lock_ReleaseMutex(&smb_StartedLock);
9774 void smb_Init(osi_log_t *logp, int useV3,
9784 EVENT_HANDLE retHandle;
9785 char eventName[MAX_PATH];
9786 int startListeners = 0;
9788 smb_TlsRequestSlot = TlsAlloc();
9790 smb_MBfunc = aMBfunc;
9794 /* Initialize smb_localZero */
9795 myTime.tm_isdst = -1; /* compute whether on DST or not */
9796 myTime.tm_year = 70;
9802 smb_localZero = mktime(&myTime);
9804 #ifndef USE_NUMERIC_TIME_CONV
9805 /* Initialize kludge-GMT */
9806 smb_CalculateNowTZ();
9807 #endif /* USE_NUMERIC_TIME_CONV */
9808 #ifdef AFS_FREELANCE_CLIENT
9809 /* Make sure the root.afs volume has the correct time */
9810 cm_noteLocalMountPointChange();
9813 /* initialize the remote debugging log */
9816 /* and the global lock */
9817 lock_InitializeRWLock(&smb_globalLock, "smb global lock", LOCK_HIERARCHY_SMB_GLOBAL);
9818 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock", LOCK_HIERARCHY_SMB_RCT_GLOBAL);
9820 /* Raw I/O data structures */
9821 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock", LOCK_HIERARCHY_SMB_RAWBUF);
9823 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock", LOCK_HIERARCHY_SMB_LISTENER);
9824 lock_InitializeMutex(&smb_StartedLock, "smb started lock", LOCK_HIERARCHY_SMB_STARTED);
9826 /* 4 Raw I/O buffers */
9827 smb_RawBufs = calloc(65536,1);
9828 *((char **)smb_RawBufs) = NULL;
9829 for (i=0; i<3; i++) {
9830 char *rawBuf = calloc(65536,1);
9831 *((char **)rawBuf) = smb_RawBufs;
9832 smb_RawBufs = rawBuf;
9835 /* global free lists */
9836 smb_ncbFreeListp = NULL;
9837 smb_packetFreeListp = NULL;
9839 lock_ObtainMutex(&smb_StartedLock);
9840 startListeners = smb_NetbiosInit(1);
9842 /* Initialize listener and server structures */
9844 memset(dead_sessions, 0, sizeof(dead_sessions));
9845 sprintf(eventName, "SessionEvents[0]");
9846 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9847 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9848 afsi_log("Event Object Already Exists: %s", eventName);
9850 smb_NumServerThreads = nThreads;
9851 sprintf(eventName, "NCBavails[0]");
9852 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9853 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9854 afsi_log("Event Object Already Exists: %s", eventName);
9855 sprintf(eventName, "NCBevents[0]");
9856 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9857 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9858 afsi_log("Event Object Already Exists: %s", eventName);
9859 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
9860 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
9861 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9862 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9863 afsi_log("Event Object Already Exists: %s", eventName);
9864 for (i = 0; i < smb_NumServerThreads; i++) {
9865 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
9866 NCBreturns[i][0] = retHandle;
9869 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
9870 for (i = 0; i < smb_NumServerThreads; i++) {
9871 sprintf(eventName, "smb_ServerShutdown[%d]", i);
9872 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9873 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9874 afsi_log("Event Object Already Exists: %s", eventName);
9875 InitNCBslot((int)(i+1));
9877 numNCBs = smb_NumServerThreads + 1;
9879 /* Initialize dispatch table */
9880 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
9881 /* Prepare the table for unknown operations */
9882 for(i=0; i<= SMB_NOPCODES; i++) {
9883 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
9885 /* Fill in the ones we do know */
9886 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
9887 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
9888 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
9889 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
9890 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
9891 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
9892 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
9893 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
9894 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
9895 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
9896 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
9897 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
9898 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
9899 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
9900 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
9901 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
9902 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
9903 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
9904 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
9905 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
9906 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
9907 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9908 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
9909 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
9910 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
9911 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
9912 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
9913 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
9914 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9915 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
9916 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9917 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
9918 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
9919 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
9920 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9921 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
9922 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
9923 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
9924 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
9925 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
9926 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
9927 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
9928 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9929 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
9930 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9931 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
9932 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
9933 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
9934 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
9935 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
9936 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
9937 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
9938 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
9939 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
9940 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
9941 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
9942 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
9943 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
9944 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
9945 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
9946 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
9947 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
9948 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
9949 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
9950 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
9951 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9952 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
9953 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
9954 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
9955 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
9956 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
9957 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
9958 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
9959 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
9961 /* setup tran 2 dispatch table */
9962 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
9963 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
9964 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
9965 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
9966 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
9967 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
9968 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
9969 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
9970 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
9971 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
9972 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
9973 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
9974 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
9975 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
9976 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
9977 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
9978 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
9979 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
9981 /* setup the rap dispatch table */
9982 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
9983 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
9984 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
9985 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
9986 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
9990 /* if we are doing SMB authentication we have register outselves as a logon process */
9991 if (smb_authType != SMB_AUTH_NONE) {
9992 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
9993 LSA_STRING afsProcessName;
9994 LSA_OPERATIONAL_MODE dummy; /*junk*/
9996 afsProcessName.Buffer = "OpenAFSClientDaemon";
9997 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
9998 afsProcessName.MaximumLength = afsProcessName.Length + 1;
10000 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
10002 if (nts == STATUS_SUCCESS) {
10003 LSA_STRING packageName;
10004 /* we are registered. Find out the security package id */
10005 packageName.Buffer = MSV1_0_PACKAGE_NAME;
10006 packageName.Length = (USHORT)strlen(packageName.Buffer);
10007 packageName.MaximumLength = packageName.Length + 1;
10008 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
10009 if (nts == STATUS_SUCCESS) {
10011 * This code forces Windows to authenticate against the Logon Cache
10012 * first instead of attempting to authenticate against the Domain
10013 * Controller. When the Windows logon cache is enabled this improves
10014 * performance by removing the network access and works around a bug
10015 * seen at sites which are using a MIT Kerberos principal to login
10016 * to machines joined to a non-root domain in a multi-domain forest.
10017 * MsV1_0SetProcessOption was added in Windows XP.
10019 PVOID pResponse = NULL;
10020 ULONG cbResponse = 0;
10021 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
10023 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
10024 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
10025 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
10026 OptionsRequest.DisableOptions = FALSE;
10028 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
10031 sizeof(OptionsRequest),
10037 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
10038 char message[AFSPATHMAX];
10039 sprintf(message,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
10041 OutputDebugString(message);
10044 OutputDebugString("MsV1_0SetProcessOption success");
10045 afsi_log("MsV1_0SetProcessOption success");
10047 /* END - code from Larry */
10049 smb_lsaLogonOrigin.Buffer = "OpenAFS";
10050 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
10051 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
10053 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
10055 /* something went wrong. We report the error and revert back to no authentication
10056 because we can't perform any auth requests without a successful lsa handle
10057 or sec package id. */
10058 afsi_log("Reverting to NO SMB AUTH");
10059 smb_authType = SMB_AUTH_NONE;
10062 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
10064 /* something went wrong. We report the error and revert back to no authentication
10065 because we can't perform any auth requests without a successful lsa handle
10066 or sec package id. */
10067 afsi_log("Reverting to NO SMB AUTH");
10068 smb_authType = SMB_AUTH_NONE;
10072 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
10073 * time prevents the failure of authentication when logged into Windows with an
10074 * external Kerberos principal mapped to a local account.
10076 else if ( smb_authType == SMB_AUTH_EXTENDED) {
10077 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
10078 * then the only option is NTLMSSP anyway; so just fallback.
10083 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
10084 if (secBlobLength == 0) {
10085 smb_authType = SMB_AUTH_NTLM;
10086 afsi_log("Reverting to SMB AUTH NTLM");
10095 /* Now get ourselves a domain name. */
10096 /* For now we are using the local computer name as the domain name.
10097 * It is actually the domain for local logins, and we are acting as
10098 * a local SMB server.
10100 bufsize = lengthof(smb_ServerDomainName) - 1;
10101 GetComputerNameW(smb_ServerDomainName, &bufsize);
10102 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
10103 afsi_log("Setting SMB server domain name to [%S]", smb_ServerDomainName);
10106 /* Start listeners, waiters, servers, and daemons */
10107 if (startListeners)
10108 smb_StartListeners(1);
10110 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
10111 NULL, 0, &lpid, "smb_ClientWaiter");
10112 osi_assertx(phandle != NULL, "smb_ClientWaiter thread creation failure");
10113 thrd_CloseHandle(phandle);
10115 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
10116 NULL, 0, &lpid, "smb_ServerWaiter");
10117 osi_assertx(phandle != NULL, "smb_ServerWaiter thread creation failure");
10118 thrd_CloseHandle(phandle);
10120 for (i=0; i<smb_NumServerThreads; i++) {
10121 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
10122 (void *) i, 0, &lpid, "smb_Server");
10123 osi_assertx(phandle != NULL, "smb_Server thread creation failure");
10124 thrd_CloseHandle(phandle);
10127 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
10128 NULL, 0, &lpid, "smb_Daemon");
10129 osi_assertx(phandle != NULL, "smb_Daemon thread creation failure");
10130 thrd_CloseHandle(phandle);
10132 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
10133 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
10134 osi_assertx(phandle != NULL, "smb_WaitingLocksDaemon thread creation failure");
10135 thrd_CloseHandle(phandle);
10137 lock_ReleaseMutex(&smb_StartedLock);
10141 void smb_Shutdown(void)
10148 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
10150 /* setup the NCB system */
10151 ncbp = smb_GetNCB();
10153 /* Block new sessions by setting shutdown flag */
10154 smbShutdownFlag = 1;
10156 /* Hang up all sessions */
10157 memset((char *)ncbp, 0, sizeof(NCB));
10158 for (i = 1; i < numSessions; i++)
10160 if (dead_sessions[i])
10163 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
10164 ncbp->ncb_command = NCBHANGUP;
10165 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
10166 ncbp->ncb_lsn = (UCHAR)LSNs[i];
10167 code = Netbios(ncbp);
10168 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
10169 if (code == 0) code = ncbp->ncb_retcode;
10171 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
10172 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
10176 /* Trigger the shutdown of all SMB threads */
10177 for (i = 0; i < smb_NumServerThreads; i++)
10178 thrd_SetEvent(NCBreturns[i][0]);
10180 thrd_SetEvent(NCBevents[0]);
10181 thrd_SetEvent(SessionEvents[0]);
10182 thrd_SetEvent(NCBavails[0]);
10184 for (i = 0;i < smb_NumServerThreads; i++) {
10185 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
10186 if (code == WAIT_OBJECT_0) {
10189 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
10190 thrd_SetEvent(NCBreturns[i--][0]);
10194 /* Delete Netbios name */
10195 memset((char *)ncbp, 0, sizeof(NCB));
10196 for (i = 0; i < lana_list.length; i++) {
10197 if (lana_list.lana[i] == LANA_INVALID) continue;
10198 ncbp->ncb_command = NCBDELNAME;
10199 ncbp->ncb_lana_num = lana_list.lana[i];
10200 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10201 code = Netbios(ncbp);
10203 code = ncbp->ncb_retcode;
10205 fprintf(stderr, "Shutdown: Netbios NCBDELNAME lana %d error code %d",
10206 ncbp->ncb_lana_num, code);
10211 /* Release the reference counts held by the VCs */
10212 lock_ObtainWrite(&smb_rctLock);
10213 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
10218 if (vcp->magic != SMB_VC_MAGIC)
10219 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
10220 __FILE__, __LINE__);
10222 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10224 if (fidp->scp != NULL) {
10227 lock_ReleaseWrite(&smb_rctLock);
10228 lock_ObtainMutex(&fidp->mx);
10229 if (fidp->scp != NULL) {
10232 lock_ObtainWrite(&scp->rw);
10233 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
10234 lock_ReleaseWrite(&scp->rw);
10235 osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
10236 cm_ReleaseSCache(scp);
10238 lock_ReleaseMutex(&fidp->mx);
10239 lock_ObtainWrite(&smb_rctLock);
10243 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10245 smb_ReleaseVCNoLock(tidp->vcp);
10247 cm_user_t *userp = tidp->userp;
10248 tidp->userp = NULL;
10249 cm_ReleaseUser(userp);
10253 lock_ReleaseWrite(&smb_rctLock);
10255 TlsFree(smb_TlsRequestSlot);
10258 /* Get the UNC \\<servername>\<sharename> prefix. */
10259 char *smb_GetSharename()
10264 /* Make sure we have been properly initialized. */
10265 if (smb_localNamep == NULL)
10268 /* Allocate space for \\<servername>\<sharename>, plus the
10271 len = (strlen(smb_localNamep) + strlen("ALL") + 4) * sizeof(char);
10272 name = malloc(len);
10273 snprintf(name, len, "\\\\%s\\%s", smb_localNamep, "ALL");
10279 void smb_LogPacket(smb_packet_t *packet)
10283 unsigned length, paramlen, datalen, i, j;
10285 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
10287 if (!packet) return;
10289 osi_Log0(smb_logp, "*** SMB packet dump ***");
10291 smbp = (smb_t *) packet->data;
10292 vp = (BYTE *) packet->data;
10294 paramlen = smbp->wct * 2;
10295 datalen = *((WORD *) (smbp->vdata + paramlen));
10296 length = sizeof(*smbp) + paramlen + 1 + datalen;
10298 for (i=0;i < length; i+=16)
10300 memset( buf, ' ', 80 );
10303 itoa( i, buf, 16 );
10305 buf[strlen(buf)] = ' ';
10307 cp = (BYTE*) buf + 7;
10309 for (j=0;j < 16 && (i+j)<length; j++)
10311 *(cp++) = hex[vp[i+j] >> 4];
10312 *(cp++) = hex[vp[i+j] & 0xf];
10322 for (j=0;j < 16 && (i+j)<length;j++)
10324 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
10335 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
10338 osi_Log0(smb_logp, "*** End SMB packet dump ***");
10340 #endif /* LOG_PACKET */
10343 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
10349 smb_username_t *unp;
10350 smb_waitingLockRequest_t *wlrp;
10353 lock_ObtainRead(&smb_rctLock);
10355 sprintf(output, "begin dumping smb_username_t\r\n");
10356 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10357 for (unp = usernamesp; unp; unp=unp->nextp)
10359 cm_ucell_t *ucellp;
10361 sprintf(output, "%s -- smb_unp=0x%p, refCount=%d, cm_userp=0x%p, flags=0x%x, logoff=%u, name=%S, machine=%S\r\n",
10362 cookie, unp, unp->refCount, unp->userp, unp->flags, unp->last_logoff_t,
10363 unp->name ? unp->name : _C("NULL"),
10364 unp->machine ? unp->machine : _C("NULL"));
10365 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10367 sprintf(output, " begin dumping cm_ucell_t\r\n");
10368 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10370 for ( ucellp = unp->userp->cellInfop; ucellp; ucellp = ucellp->nextp ) {
10371 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",
10372 cookie, ucellp, ucellp->cellp, ucellp->flags, ucellp->ticketLen, ucellp->kvno,
10373 ucellp->expirationTime, ucellp->gen,
10375 ucellp->cellp->name);
10376 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10379 sprintf(output, " done dumping cm_ucell_t\r\n");
10380 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10383 sprintf(output, "done dumping smb_username_t\r\n");
10384 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10387 sprintf(output, "begin dumping smb_waitingLockRequest_t\r\n");
10388 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10391 for ( wlrp = smb_allWaitingLocks; wlrp; wlrp = (smb_waitingLockRequest_t *) osi_QNext(&wlrp->q)) {
10392 smb_waitingLock_t *lockp;
10394 sprintf(output, "%s wlrp=0x%p vcp=0x%p, scp=0x%p, type=0x%x, start_t=0x%I64u msTimeout=0x%x\r\n",
10395 cookie, wlrp, wlrp->vcp, wlrp->scp, wlrp->lockType, wlrp->start_t, wlrp->msTimeout);
10396 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10398 sprintf(output, " begin dumping smb_waitingLock_t\r\n");
10399 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10400 for (lockp = wlrp->locks; lockp; lockp = (smb_waitingLock_t *) osi_QNext(&lockp->q)) {
10401 sprintf(output, " %s -- waitlockp=0x%p lockp=0x%p key=0x%I64x offset=0x%I64x length=0x%I64x state=0x%x\r\n",
10402 cookie, lockp, lockp->lockp, lockp->key, lockp->LOffset.QuadPart, lockp->LLength.QuadPart, lockp->state);
10403 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10405 sprintf(output, " done dumping smb_waitingLock_t\r\n");
10406 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10409 sprintf(output, "done dumping smb_waitingLockRequest_t\r\n");
10410 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10412 sprintf(output, "begin dumping smb_vc_t\r\n");
10413 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10415 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
10421 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
10422 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
10423 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10425 sprintf(output, " begin dumping smb_user_t\r\n");
10426 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10427 for (userp = vcp->usersp; userp; userp = userp->nextp) {
10428 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
10429 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
10430 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10432 sprintf(output, " done dumping smb_user_t\r\n");
10433 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10435 sprintf(output, " begin dumping smb_tid_t\r\n");
10436 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10437 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10438 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",
10439 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
10440 tidp->pathname ? tidp->pathname : _C("NULL"));
10441 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10443 sprintf(output, " done dumping smb_tid_t\r\n");
10444 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10446 sprintf(output, " begin dumping smb_fid_t\r\n");
10447 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10449 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10451 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",
10452 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
10453 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
10454 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
10455 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10458 sprintf(output, " done dumping smb_fid_t\r\n");
10459 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10462 sprintf(output, "done dumping smb_vc_t\r\n");
10463 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10465 sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
10466 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10468 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
10474 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
10475 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
10476 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10478 sprintf(output, " begin dumping smb_user_t\r\n");
10479 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10480 for (userp = vcp->usersp; userp; userp = userp->nextp) {
10481 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
10482 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
10483 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10485 sprintf(output, " done dumping smb_user_t\r\n");
10486 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10488 sprintf(output, " begin dumping smb_tid_t\r\n");
10489 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10490 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10491 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",
10492 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
10493 tidp->pathname ? tidp->pathname : _C("NULL"));
10494 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10496 sprintf(output, " done dumping smb_tid_t\r\n");
10497 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10499 sprintf(output, " begin dumping smb_fid_t\r\n");
10500 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10502 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10504 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",
10505 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
10506 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
10507 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
10508 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10511 sprintf(output, " done dumping smb_fid_t\r\n");
10512 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10515 sprintf(output, "done dumping DEAD smb_vc_t\r\n");
10516 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10519 lock_ReleaseRead(&smb_rctLock);
10523 long smb_IsNetworkStarted(void)
10526 lock_ObtainWrite(&smb_globalLock);
10527 rc = (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);
10528 lock_ReleaseWrite(&smb_globalLock);