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 char * myCrt_NmpipeDispatch(int i)
470 case SMB_TRANS_SET_NMPIPE_STATE:
471 return "SET NMPIPE STATE";
473 case SMB_TRANS_RAW_READ_NMPIPE:
474 return "RAW READ NMPIPE";
476 case SMB_TRANS_QUERY_NMPIPE_STATE:
477 return "QUERY NMPIPE STATE";
479 case SMB_TRANS_QUERY_NMPIPE_INFO:
480 return "QUERY NMPIPE INFO";
482 case SMB_TRANS_PEEK_NMPIPE:
483 return "PEEK NMPIPE";
485 case SMB_TRANS_TRANSACT_NMPIPE:
486 return "TRANSACT NMPIPE";
488 case SMB_TRANS_RAW_WRITE_NMPIPE:
489 return "WRITE NMPIPE";
491 case SMB_TRANS_READ_NMPIPE:
492 return "READ NMPIPE";
494 case SMB_TRANS_WRITE_NMPIPE:
495 return "WRITE NMPIPE";
497 case SMB_TRANS_WAIT_NMPIPE:
498 return "WAIT NMPIPE";
500 case SMB_TRANS_CALL_NMPIPE:
501 return "CALL NMPIPE";
506 /* scache must be locked */
507 unsigned int smb_Attributes(cm_scache_t *scp)
511 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
512 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
513 scp->fileType == CM_SCACHETYPE_INVALID)
515 attrs = SMB_ATTR_DIRECTORY;
516 #ifdef SPECIAL_FOLDERS
517 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
518 #endif /* SPECIAL_FOLDERS */
519 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
520 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
525 * We used to mark a file RO if it was in an RO volume, but that
526 * turns out to be impolitic in NT. See defect 10007.
529 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
530 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
532 if ((scp->unixModeBits & 0222) == 0)
533 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
539 /* Check if the named file/dir is a dotfile/dotdir */
540 /* String pointed to by lastComp can have leading slashes, but otherwise should have
541 no other patch components */
542 unsigned int smb_IsDotFile(clientchar_t *lastComp) {
546 /* skip over slashes */
547 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
552 /* nulls, curdir and parent dir doesn't count */
558 if(*(s+1) == _C('.') && !*(s + 2))
565 static int ExtractBits(WORD bits, short start, short len)
572 num = bits << (16 - end);
573 num = num >> ((16 - end) + start);
578 void ShowUnixTime(char *FuncName, time_t unixTime)
583 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
585 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
586 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
588 int day, month, year, sec, min, hour;
591 day = ExtractBits(wDate, 0, 5);
592 month = ExtractBits(wDate, 5, 4);
593 year = ExtractBits(wDate, 9, 7) + 1980;
595 sec = ExtractBits(wTime, 0, 5);
596 min = ExtractBits(wTime, 5, 6);
597 hour = ExtractBits(wTime, 11, 5);
599 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
600 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
604 /* Determine if we are observing daylight savings time */
605 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
607 TIME_ZONE_INFORMATION timeZoneInformation;
608 SYSTEMTIME utc, local, localDST;
610 /* Get the time zone info. NT uses this to calc if we are in DST. */
611 GetTimeZoneInformation(&timeZoneInformation);
613 /* Return the daylight bias */
614 *pDstBias = timeZoneInformation.DaylightBias;
616 /* Return the bias */
617 *pBias = timeZoneInformation.Bias;
619 /* Now determine if DST is being observed */
621 /* Get the UTC (GMT) time */
624 /* Convert UTC time to local time using the time zone info. If we are
625 observing DST, the calculated local time will include this.
627 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
629 /* Set the daylight bias to 0. The daylight bias is the amount of change
630 * in time that we use for daylight savings time. By setting this to 0
631 * we cause there to be no change in time during daylight savings time.
633 timeZoneInformation.DaylightBias = 0;
635 /* Convert the utc time to local time again, but this time without any
636 adjustment for daylight savings time.
638 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
640 /* If the two times are different, then it means that the localDST that
641 we calculated includes the daylight bias, and therefore we are
642 observing daylight savings time.
644 *pDST = localDST.wHour != local.wHour;
648 void CompensateForSmbClientLastWriteTimeBugs(afs_uint32 *pLastWriteTime)
650 BOOL dst; /* Will be TRUE if observing DST */
651 LONG dstBias; /* Offset from local time if observing DST */
652 LONG bias; /* Offset from GMT for local time */
655 * This function will adjust the last write time to compensate
656 * for two bugs in the smb client:
658 * 1) During Daylight Savings Time, the LastWriteTime is ahead
659 * in time by the DaylightBias (ignoring the sign - the
660 * DaylightBias is always stored as a negative number). If
661 * the DaylightBias is -60, then the LastWriteTime will be
662 * ahead by 60 minutes.
664 * 2) If the local time zone is a positive offset from GMT, then
665 * the LastWriteTime will be the correct local time plus the
666 * Bias (ignoring the sign - a positive offset from GMT is
667 * always stored as a negative Bias). If the Bias is -120,
668 * then the LastWriteTime will be ahead by 120 minutes.
670 * These bugs can occur at the same time.
673 GetTimeZoneInfo(&dst, &dstBias, &bias);
675 /* First adjust for DST */
677 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
679 /* Now adjust for a positive offset from GMT (a negative bias). */
681 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
684 #ifndef USE_NUMERIC_TIME_CONV
686 * Calculate the difference (in seconds) between local time and GMT.
687 * This enables us to convert file times to kludge-GMT.
693 struct tm gmt_tm, local_tm;
694 int days, hours, minutes, seconds;
697 gmt_tm = *(gmtime(&t));
698 local_tm = *(localtime(&t));
700 days = local_tm.tm_yday - gmt_tm.tm_yday;
701 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour;
702 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
703 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
707 #endif /* USE_NUMERIC_TIME_CONV */
709 #ifdef USE_NUMERIC_TIME_CONV
710 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
712 // Note that LONGLONG is a 64-bit value
715 ll = Int32x32To64(unixTime, 10000000) + 116444736000000000;
716 largeTimep->dwLowDateTime = (DWORD)(ll & 0xFFFFFFFF);
717 largeTimep->dwHighDateTime = (DWORD)(ll >> 32);
720 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
725 time_t ersatz_unixTime;
728 * Must use kludge-GMT instead of real GMT.
729 * kludge-GMT is computed by adding time zone difference to localtime.
732 * ltp = gmtime(&unixTime);
734 ersatz_unixTime = unixTime - smb_NowTZ;
735 ltp = localtime(&ersatz_unixTime);
737 /* if we fail, make up something */
740 localJunk.tm_year = 89 - 20;
741 localJunk.tm_mon = 4;
742 localJunk.tm_mday = 12;
743 localJunk.tm_hour = 0;
744 localJunk.tm_min = 0;
745 localJunk.tm_sec = 0;
748 stm.wYear = ltp->tm_year + 1900;
749 stm.wMonth = ltp->tm_mon + 1;
750 stm.wDayOfWeek = ltp->tm_wday;
751 stm.wDay = ltp->tm_mday;
752 stm.wHour = ltp->tm_hour;
753 stm.wMinute = ltp->tm_min;
754 stm.wSecond = ltp->tm_sec;
755 stm.wMilliseconds = 0;
757 SystemTimeToFileTime(&stm, largeTimep);
759 #endif /* USE_NUMERIC_TIME_CONV */
761 #ifdef USE_NUMERIC_TIME_CONV
762 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
764 // Note that LONGLONG is a 64-bit value
767 ll = largeTimep->dwHighDateTime;
769 ll += largeTimep->dwLowDateTime;
771 ll -= 116444736000000000;
774 *unixTimep = (DWORD)ll;
776 #else /* USE_NUMERIC_TIME_CONV */
777 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
783 FileTimeToSystemTime(largeTimep, &stm);
785 lt.tm_year = stm.wYear - 1900;
786 lt.tm_mon = stm.wMonth - 1;
787 lt.tm_wday = stm.wDayOfWeek;
788 lt.tm_mday = stm.wDay;
789 lt.tm_hour = stm.wHour;
790 lt.tm_min = stm.wMinute;
791 lt.tm_sec = stm.wSecond;
794 save_timezone = _timezone;
795 _timezone += smb_NowTZ;
796 *unixTimep = mktime(<);
797 _timezone = save_timezone;
799 #endif /* USE_NUMERIC_TIME_CONV */
801 void smb_SearchTimeFromUnixTime(afs_uint32 *searchTimep, time_t unixTime)
811 /* if we fail, make up something */
814 localJunk.tm_year = 89 - 20;
815 localJunk.tm_mon = 4;
816 localJunk.tm_mday = 12;
817 localJunk.tm_hour = 0;
818 localJunk.tm_min = 0;
819 localJunk.tm_sec = 0;
822 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
823 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
824 *searchTimep = (dosDate<<16) | dosTime;
827 void smb_UnixTimeFromSearchTime(time_t *unixTimep, afs_uint32 searchTime)
829 unsigned short dosDate;
830 unsigned short dosTime;
833 dosDate = (unsigned short) (searchTime & 0xffff);
834 dosTime = (unsigned short) ((searchTime >> 16) & 0xffff);
836 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
837 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
838 localTm.tm_mday = (dosDate) & 0x1f;
839 localTm.tm_hour = (dosTime>>11) & 0x1f;
840 localTm.tm_min = (dosTime >> 5) & 0x3f;
841 localTm.tm_sec = (dosTime & 0x1f) * 2;
842 localTm.tm_isdst = -1; /* compute whether DST in effect */
844 *unixTimep = mktime(&localTm);
847 void smb_DosUTimeFromUnixTime(afs_uint32 *dosUTimep, time_t unixTime)
849 time_t diff_t = unixTime - smb_localZero;
850 #if defined(DEBUG) && !defined(_USE_32BIT_TIME_T)
851 osi_assertx(diff_t < _UI32_MAX, "time_t > _UI32_MAX");
853 *dosUTimep = (afs_uint32)diff_t;
856 void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
858 *unixTimep = dosTime + smb_localZero;
861 void smb_MarkAllVCsDead(smb_vc_t * exclude)
864 smb_vc_t **vcp_to_cleanup = NULL;
865 int n_to_cleanup = 0;
868 osi_Log1(smb_logp, "Marking all VCs as dead excluding %p", exclude);
870 lock_ObtainWrite(&smb_globalLock); /* for dead_sessions[] */
871 lock_ObtainWrite(&smb_rctLock);
872 for (vcp = smb_allVCsp; vcp; vcp = vcp->nextp) {
874 if (vcp->magic != SMB_VC_MAGIC)
875 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
881 lock_ObtainMutex(&vcp->mx);
882 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
883 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
884 lock_ReleaseMutex(&vcp->mx);
885 dead_sessions[vcp->session] = TRUE;
887 lock_ReleaseMutex(&vcp->mx);
892 vcp_to_cleanup = malloc(sizeof(vcp_to_cleanup[0]) * n_to_cleanup);
894 for (vcp = smb_allVCsp; vcp; vcp = vcp->nextp) {
898 vcp_to_cleanup[i++] = vcp;
899 smb_HoldVCNoLock(vcp);
902 osi_assert(i == n_to_cleanup);
904 lock_ReleaseWrite(&smb_rctLock);
905 lock_ReleaseWrite(&smb_globalLock);
907 for (i=0; i < n_to_cleanup; i++) {
908 smb_CleanupDeadVC(vcp_to_cleanup[i]);
909 smb_ReleaseVC(vcp_to_cleanup[i]);
910 vcp_to_cleanup[i] = 0;
913 free(vcp_to_cleanup);
916 #ifdef DEBUG_SMB_REFCOUNT
917 smb_vc_t *smb_FindVCDbg(unsigned short lsn, int flags, int lana, char *file, long line)
919 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
924 lock_ObtainWrite(&smb_globalLock); /* for numVCs */
925 lock_ObtainWrite(&smb_rctLock);
926 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
927 if (vcp->magic != SMB_VC_MAGIC)
928 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
931 lock_ObtainMutex(&vcp->mx);
932 if (lsn == vcp->lsn && lana == vcp->lana &&
933 !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
934 lock_ReleaseMutex(&vcp->mx);
935 smb_HoldVCNoLock(vcp);
938 lock_ReleaseMutex(&vcp->mx);
940 if (!vcp && (flags & SMB_FLAG_CREATE)) {
941 vcp = malloc(sizeof(*vcp));
942 memset(vcp, 0, sizeof(*vcp));
943 vcp->vcID = ++numVCs;
944 vcp->magic = SMB_VC_MAGIC;
945 vcp->refCount = 2; /* smb_allVCsp and caller */
948 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
949 vcp->nextp = smb_allVCsp;
951 lock_InitializeMutex(&vcp->mx, "vc_t mutex", LOCK_HIERARCHY_SMB_VC);
956 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
957 /* We must obtain a challenge for extended auth
958 * in case the client negotiates smb v3
960 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
961 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
962 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp = NULL;
963 ULONG lsaRespSize = 0;
965 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
967 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
974 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS) {
975 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
976 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
977 afsi_log("MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize %u",
978 nts, ntsEx, lsaRespSize);
980 osi_assertx(nts == STATUS_SUCCESS, "LsaCallAuthenticationPackage failed"); /* this had better work! */
982 if (ntsEx == STATUS_SUCCESS) {
983 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
986 * This will cause the subsequent authentication to fail but
987 * that is better than us dereferencing a NULL pointer and
990 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
993 LsaFreeReturnBuffer(lsaResp);
996 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
998 if (numVCs >= CM_SESSION_RESERVED) {
1000 osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
1003 #ifdef DEBUG_SMB_REFCOUNT
1005 afsi_log("%s:%d smb_FindVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1006 osi_Log4(smb_logp,"%s:%d smb_FindVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1009 lock_ReleaseWrite(&smb_rctLock);
1010 lock_ReleaseWrite(&smb_globalLock);
1014 static int smb_Is8Dot3StarMask(clientchar_t *maskp)
1019 for(i=0; i<11; i++) {
1021 if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
1027 static int smb_IsStarMask(clientchar_t *maskp)
1033 if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
1039 #ifdef DEBUG_SMB_REFCOUNT
1040 void smb_ReleaseVCInternalDbg(smb_vc_t *vcp, char * file, long line)
1041 #define smb_ReleaseVCInternal(a) smb_ReleaseVCInternalDbg(a, file, line)
1043 void smb_ReleaseVCInternal(smb_vc_t *vcp)
1049 lock_AssertWrite(&smb_rctLock);
1052 if (vcp->refCount == 0) {
1053 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
1054 #ifdef DEBUG_SMB_REFCOUNT
1055 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
1056 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
1058 /* remove VCP from smb_deadVCsp */
1059 for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
1065 lock_FinalizeMutex(&vcp->mx);
1066 memset(vcp,0,sizeof(smb_vc_t));
1069 #ifdef DEBUG_SMB_REFCOUNT
1070 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is alive ref %d", file, line, vcp, vcp->refCount);
1072 for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
1076 osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
1077 avcp?"":"not ",vcp, vcp->refCount);
1079 /* This is a wrong. However, I suspect that there is an undercount
1080 * and I don't want to release 1.4.1 in a state that will allow
1081 * smb_vc_t objects to be deallocated while still in the
1082 * smb_allVCsp list. The list is supposed to keep a reference
1083 * to the smb_vc_t. Put it back.
1087 #ifdef DEBUG_SMB_REFCOUNT
1088 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
1089 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
1093 } else if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
1094 /* The reference count is non-zero but the VC is dead.
1095 * This implies that some FIDs, TIDs, etc on the VC have yet to
1096 * be cleaned up. If we were not called by smb_CleanupDeadVC(),
1097 * add a reference that will be dropped by
1098 * smb_CleanupDeadVC() and try to cleanup the VC again.
1099 * Eventually the refCount will drop to zero when all of the
1100 * active threads working with the VC end their task.
1102 if (!(vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS)) {
1103 vcp->refCount++; /* put the refCount back */
1104 lock_ReleaseWrite(&smb_rctLock);
1105 smb_CleanupDeadVC(vcp);
1106 #ifdef DEBUG_SMB_REFCOUNT
1107 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
1108 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
1110 lock_ObtainWrite(&smb_rctLock);
1113 #ifdef DEBUG_SMB_REFCOUNT
1114 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1115 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1120 #ifdef DEBUG_SMB_REFCOUNT
1121 void smb_ReleaseVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
1123 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
1126 lock_AssertWrite(&smb_rctLock);
1127 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
1128 smb_ReleaseVCInternal(vcp);
1131 #ifdef DEBUG_SMB_REFCOUNT
1132 void smb_ReleaseVCDbg(smb_vc_t *vcp, char * file, long line)
1134 void smb_ReleaseVC(smb_vc_t *vcp)
1137 lock_ObtainWrite(&smb_rctLock);
1138 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
1139 smb_ReleaseVCInternal(vcp);
1140 lock_ReleaseWrite(&smb_rctLock);
1143 #ifdef DEBUG_SMB_REFCOUNT
1144 void smb_HoldVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
1146 void smb_HoldVCNoLock(smb_vc_t *vcp)
1149 lock_AssertWrite(&smb_rctLock);
1151 #ifdef DEBUG_SMB_REFCOUNT
1152 afsi_log("%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1153 osi_Log4(smb_logp,"%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1155 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
1159 #ifdef DEBUG_SMB_REFCOUNT
1160 void smb_HoldVCDbg(smb_vc_t *vcp, char * file, long line)
1162 void smb_HoldVC(smb_vc_t *vcp)
1165 lock_ObtainWrite(&smb_rctLock);
1167 #ifdef DEBUG_SMB_REFCOUNT
1168 afsi_log("%s:%d smb_HoldVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1169 osi_Log4(smb_logp,"%s:%d smb_HoldVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1171 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
1173 lock_ReleaseWrite(&smb_rctLock);
1176 void smb_CleanupDeadVC(smb_vc_t *vcp)
1178 smb_fid_t *fidpIter;
1179 smb_fid_t *fidpNext;
1181 smb_tid_t *tidpIter;
1182 smb_tid_t *tidpNext;
1184 smb_user_t *uidpIter;
1185 smb_user_t *uidpNext;
1187 afs_uint32 refCount = 0;
1189 lock_ObtainMutex(&vcp->mx);
1190 if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
1191 lock_ReleaseMutex(&vcp->mx);
1192 osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
1195 vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
1196 lock_ReleaseMutex(&vcp->mx);
1197 osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
1199 lock_ObtainWrite(&smb_rctLock);
1200 /* remove VCP from smb_allVCsp */
1201 for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
1202 if ((*vcpp)->magic != SMB_VC_MAGIC)
1203 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
1204 __FILE__, __LINE__);
1207 vcp->nextp = smb_deadVCsp;
1209 /* Hold onto the reference until we are done with this function */
1214 for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
1215 fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
1217 if (fidpIter->deleteOk)
1220 fid = fidpIter->fid;
1221 osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1223 smb_HoldFIDNoLock(fidpIter);
1224 lock_ReleaseWrite(&smb_rctLock);
1226 smb_CloseFID(vcp, fidpIter, NULL, 0);
1227 smb_ReleaseFID(fidpIter);
1229 lock_ObtainWrite(&smb_rctLock);
1230 fidpNext = vcp->fidsp;
1233 for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1234 tidpNext = tidpIter->nextp;
1235 if (tidpIter->deleteOk)
1237 tidpIter->deleteOk = 1;
1239 tid = tidpIter->tid;
1240 osi_Log2(smb_logp, " Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1242 smb_HoldTIDNoLock(tidpIter);
1243 smb_ReleaseTID(tidpIter, TRUE);
1244 tidpNext = vcp->tidsp;
1247 for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1248 uidpNext = uidpIter->nextp;
1249 if (uidpIter->deleteOk)
1251 uidpIter->deleteOk = 1;
1253 /* do not add an additional reference count for the smb_user_t
1254 * as the smb_vc_t already is holding a reference */
1255 lock_ReleaseWrite(&smb_rctLock);
1257 smb_ReleaseUID(uidpIter);
1259 lock_ObtainWrite(&smb_rctLock);
1260 uidpNext = vcp->usersp;
1263 /* The vcp is now on the deadVCsp list. We intentionally drop the
1264 * reference so that the refcount can reach 0 and we can delete it
1266 * If the refCount == 1 going into the ReleaseVCNoLock call
1267 * the object will be freed and it won't be safe to clear
1270 refCount = vcp->refCount;
1271 smb_ReleaseVCNoLock(vcp);
1273 lock_ObtainMutex(&vcp->mx);
1274 vcp->flags &= ~SMB_VCFLAG_CLEAN_IN_PROGRESS;
1275 lock_ReleaseMutex(&vcp->mx);
1278 lock_ReleaseWrite(&smb_rctLock);
1279 osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1282 #ifdef DEBUG_SMB_REFCOUNT
1283 smb_tid_t *smb_FindTIDDbg(smb_vc_t *vcp, unsigned short tid, int flags, char * file, long line)
1285 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1290 lock_ObtainWrite(&smb_rctLock);
1292 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1293 if (tidp->refCount == 0 && tidp->deleteOk) {
1295 smb_ReleaseTID(tidp, TRUE);
1299 if (tid == tidp->tid) {
1304 if (!tidp && (flags & SMB_FLAG_CREATE)) {
1305 tidp = malloc(sizeof(*tidp));
1306 memset(tidp, 0, sizeof(*tidp));
1307 tidp->nextp = vcp->tidsp;
1310 smb_HoldVCNoLock(vcp);
1312 lock_InitializeMutex(&tidp->mx, "tid_t mutex", LOCK_HIERARCHY_SMB_TID);
1315 #ifdef DEBUG_SMB_REFCOUNT
1317 afsi_log("%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1318 osi_Log4(smb_logp,"%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1321 lock_ReleaseWrite(&smb_rctLock);
1325 #ifdef DEBUG_SMB_REFCOUNT
1326 void smb_HoldTIDNoLockDbg(smb_tid_t *tidp, char * file, long line)
1328 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1331 lock_AssertWrite(&smb_rctLock);
1333 #ifdef DEBUG_SMB_REFCOUNT
1334 afsi_log("%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1335 osi_Log4(smb_logp,"%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1339 #ifdef DEBUG_SMB_REFCOUNT
1340 void smb_ReleaseTIDDbg(smb_tid_t *tidp, afs_uint32 locked, char *file, long line)
1342 void smb_ReleaseTID(smb_tid_t *tidp, afs_uint32 locked)
1347 cm_user_t *userp = NULL;
1348 smb_vc_t *vcp = NULL;
1351 lock_ObtainWrite(&smb_rctLock);
1353 lock_AssertWrite(&smb_rctLock);
1355 osi_assertx(tidp->refCount-- > 0, "smb_tid_t refCount 0");
1356 #ifdef DEBUG_SMB_REFCOUNT
1357 afsi_log("%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1358 osi_Log5(smb_logp,"%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1360 if (tidp->refCount == 0) {
1361 if (tidp->deleteOk) {
1362 ltpp = &tidp->vcp->tidsp;
1363 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1367 osi_assertx(tp != NULL, "null smb_tid_t");
1369 lock_FinalizeMutex(&tidp->mx);
1370 userp = tidp->userp; /* remember to drop ref later */
1378 smb_ReleaseVCNoLock(vcp);
1380 lock_ReleaseWrite(&smb_rctLock);
1382 cm_ReleaseUser(userp);
1385 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1387 smb_user_t *uidp = NULL;
1389 lock_ObtainWrite(&smb_rctLock);
1390 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1391 if (uid == uidp->userID) {
1393 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%S]",
1395 ((uidp->unp)? osi_LogSaveClientString(smb_logp, uidp->unp->name):_C("")));
1399 if (!uidp && (flags & SMB_FLAG_CREATE)) {
1400 uidp = malloc(sizeof(*uidp));
1401 memset(uidp, 0, sizeof(*uidp));
1402 uidp->nextp = vcp->usersp;
1403 uidp->refCount = 2; /* one for the vcp and one for the caller */
1405 smb_HoldVCNoLock(vcp);
1407 lock_InitializeMutex(&uidp->mx, "user_t mutex", LOCK_HIERARCHY_SMB_UID);
1409 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%S]",
1411 ((uidp->unp)?osi_LogSaveClientString(smb_logp,uidp->unp->name):_C("")));
1413 lock_ReleaseWrite(&smb_rctLock);
1417 smb_username_t *smb_FindUserByName(clientchar_t *usern, clientchar_t *machine,
1420 smb_username_t *unp= NULL;
1422 lock_ObtainWrite(&smb_rctLock);
1423 for(unp = usernamesp; unp; unp = unp->nextp) {
1424 if (cm_ClientStrCmpI(unp->name, usern) == 0 &&
1425 cm_ClientStrCmpI(unp->machine, machine) == 0) {
1430 if (!unp && (flags & SMB_FLAG_CREATE)) {
1431 unp = malloc(sizeof(*unp));
1432 memset(unp, 0, sizeof(*unp));
1434 unp->nextp = usernamesp;
1435 unp->name = cm_ClientStrDup(usern);
1436 unp->machine = cm_ClientStrDup(machine);
1438 lock_InitializeMutex(&unp->mx, "username_t mutex", LOCK_HIERARCHY_SMB_USERNAME);
1439 if (flags & SMB_FLAG_AFSLOGON)
1440 unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1443 lock_ReleaseWrite(&smb_rctLock);
1447 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, clientchar_t *usern)
1449 smb_user_t *uidp= NULL;
1451 lock_ObtainWrite(&smb_rctLock);
1452 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1455 if (cm_stricmp_utf16(uidp->unp->name, usern) == 0) {
1457 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%S]",
1458 vcp,uidp->userID,osi_LogSaveClientString(smb_logp,usern));
1463 lock_ReleaseWrite(&smb_rctLock);
1467 void smb_ReleaseUsername(smb_username_t *unp)
1470 smb_username_t **lupp;
1471 cm_user_t *userp = NULL;
1472 time_t now = osi_Time();
1474 lock_ObtainWrite(&smb_rctLock);
1475 osi_assertx(unp->refCount-- > 0, "smb_username_t refCount 0");
1476 if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1477 (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1479 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1483 osi_assertx(up != NULL, "null smb_username_t");
1485 up->nextp = NULL; /* do not remove this */
1486 lock_FinalizeMutex(&unp->mx);
1492 lock_ReleaseWrite(&smb_rctLock);
1494 cm_ReleaseUser(userp);
1497 void smb_HoldUIDNoLock(smb_user_t *uidp)
1499 lock_AssertWrite(&smb_rctLock);
1503 void smb_ReleaseUID(smb_user_t *uidp)
1507 smb_username_t *unp = NULL;
1509 lock_ObtainWrite(&smb_rctLock);
1510 osi_assertx(uidp->refCount-- > 0, "smb_user_t refCount 0");
1511 if (uidp->refCount == 0) {
1512 lupp = &uidp->vcp->usersp;
1513 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1517 osi_assertx(up != NULL, "null smb_user_t");
1519 lock_FinalizeMutex(&uidp->mx);
1521 smb_ReleaseVCNoLock(uidp->vcp);
1525 lock_ReleaseWrite(&smb_rctLock);
1529 cm_ReleaseUserVCRef(unp->userp);
1530 smb_ReleaseUsername(unp);
1534 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1536 cm_user_t *up = NULL;
1541 lock_ObtainMutex(&uidp->mx);
1543 up = uidp->unp->userp;
1546 lock_ReleaseMutex(&uidp->mx);
1552 /* retrieve a held reference to a user structure corresponding to an incoming
1554 * corresponding release function is cm_ReleaseUser.
1556 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1559 cm_user_t *up = NULL;
1562 smbp = (smb_t *) inp;
1563 uidp = smb_FindUID(vcp, smbp->uid, 0);
1567 up = smb_GetUserFromUID(uidp);
1569 smb_ReleaseUID(uidp);
1574 * Return a pointer to a pathname extracted from a TID structure. The
1575 * TID structure is not held; assume it won't go away.
1577 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, clientchar_t ** treepath)
1582 tidp = smb_FindTID(vcp, tid, 0);
1586 if (tidp->flags & SMB_TIDFLAG_IPC) {
1587 code = CM_ERROR_TIDIPC;
1588 /* tidp->pathname would be NULL, but that's fine */
1590 *treepath = tidp->pathname;
1591 smb_ReleaseTID(tidp, FALSE);
1596 /* check to see if we have a chained fid, that is, a fid that comes from an
1597 * OpenAndX message that ran earlier in this packet. In this case, the fid
1598 * field in a read, for example, request, isn't set, since the value is
1599 * supposed to be inherited from the openAndX call.
1601 int smb_ChainFID(int fid, smb_packet_t *inp)
1603 if (inp->fid == 0 || inp->inCount == 0)
1609 /* are we a priv'd user? What does this mean on NT? */
1610 int smb_SUser(cm_user_t *userp)
1615 /* find a file ID. If we pass in 0 we select an unused File ID.
1616 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1617 * smb_fid_t data structure if desired File ID cannot be found.
1619 #ifdef DEBUG_SMB_REFCOUNT
1620 smb_fid_t *smb_FindFIDDbg(smb_vc_t *vcp, unsigned short fid, int flags, char *file, long line)
1622 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1628 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1631 lock_ObtainWrite(&smb_rctLock);
1632 /* figure out if we need to allocate a new file ID */
1635 fid = vcp->fidCounter;
1639 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1640 if (fidp->refCount == 0 && fidp->deleteOk) {
1642 lock_ReleaseWrite(&smb_rctLock);
1643 smb_ReleaseFID(fidp);
1644 lock_ObtainWrite(&smb_rctLock);
1647 if (fid == fidp->fid) {
1650 if (fid == 0xFFFF) {
1652 "New FID number wraps on vcp 0x%x", vcp);
1662 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1663 char eventName[MAX_PATH];
1665 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1666 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1667 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1668 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1669 thrd_CloseHandle(event);
1671 if (fid == 0xFFFF) {
1672 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1678 fidp = malloc(sizeof(*fidp));
1679 memset(fidp, 0, sizeof(*fidp));
1680 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1683 smb_HoldVCNoLock(vcp);
1684 lock_InitializeMutex(&fidp->mx, "fid_t mutex", LOCK_HIERARCHY_SMB_FID);
1686 fidp->curr_chunk = fidp->prev_chunk = -2;
1687 fidp->raw_write_event = event;
1689 vcp->fidCounter = fid+1;
1690 if (vcp->fidCounter == 0xFFFF) {
1691 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1693 vcp->fidCounter = 1;
1698 #ifdef DEBUG_SMB_REFCOUNT
1700 afsi_log("%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1701 osi_Log4(smb_logp,"%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1704 lock_ReleaseWrite(&smb_rctLock);
1709 /* Must not be called with scp->rw held because smb_ReleaseFID might be called */
1710 #ifdef DEBUG_SMB_REFCOUNT
1711 smb_fid_t *smb_FindFIDByScacheDbg(smb_vc_t *vcp, cm_scache_t * scp, char *file, long line)
1713 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1716 smb_fid_t *fidp = NULL, *nextp = NULL;
1722 * If the fidp->scp changes out from under us then
1723 * we must not grab a refCount. It means the *fidp
1724 * was processed by smb_CloseFID() and the *fidp is
1725 * no longer valid for use.
1727 lock_ObtainWrite(&smb_rctLock);
1728 for(fidp = vcp->fidsp, (fidp ? fidp->refCount++ : 0); fidp; fidp = nextp, nextp = NULL) {
1729 nextp = (smb_fid_t *) osi_QNext(&fidp->q);
1733 if (scp == fidp->scp) {
1734 lock_ReleaseWrite(&smb_rctLock);
1735 lock_ObtainMutex(&fidp->mx);
1736 lock_ObtainWrite(&smb_rctLock);
1737 if (scp == fidp->scp) {
1738 lock_ReleaseMutex(&fidp->mx);
1741 lock_ReleaseMutex(&fidp->mx);
1744 if (fidp->refCount > 1) {
1747 lock_ReleaseWrite(&smb_rctLock);
1748 smb_ReleaseFID(fidp);
1749 lock_ObtainWrite(&smb_rctLock);
1754 if (nextp->refCount > 1) {
1757 lock_ReleaseWrite(&smb_rctLock);
1758 smb_ReleaseFID(nextp);
1759 lock_ObtainWrite(&smb_rctLock);
1763 #ifdef DEBUG_SMB_REFCOUNT
1765 afsi_log("%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1766 osi_Log4(smb_logp,"%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1769 lock_ReleaseWrite(&smb_rctLock);
1773 #ifdef DEBUG_SMB_REFCOUNT
1774 void smb_HoldFIDNoLockDbg(smb_fid_t *fidp, char *file, long line)
1776 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1779 lock_AssertWrite(&smb_rctLock);
1781 #ifdef DEBUG_SMB_REFCOUNT
1782 afsi_log("%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1783 osi_Log4(smb_logp,"%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1788 /* smb_ReleaseFID cannot be called while a cm_scache_t rwlock is held */
1789 /* the smb_fid_t->mx and smb_rctLock must not be held */
1790 #ifdef DEBUG_SMB_REFCOUNT
1791 void smb_ReleaseFIDDbg(smb_fid_t *fidp, char *file, long line)
1793 void smb_ReleaseFID(smb_fid_t *fidp)
1796 cm_scache_t *scp = NULL;
1797 cm_user_t *userp = NULL;
1798 smb_vc_t *vcp = NULL;
1799 smb_ioctl_t *ioctlp;
1801 lock_ObtainMutex(&fidp->mx);
1802 lock_ObtainWrite(&smb_rctLock);
1803 osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
1804 #ifdef DEBUG_SMB_REFCOUNT
1805 afsi_log("%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1806 osi_Log5(smb_logp,"%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1808 if (fidp->refCount == 0) {
1809 if (fidp->deleteOk) {
1812 scp = fidp->scp; /* release after lock is released */
1814 lock_ObtainWrite(&scp->rw);
1815 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1816 lock_ReleaseWrite(&scp->rw);
1817 osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1820 userp = fidp->userp;
1824 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1825 thrd_CloseHandle(fidp->raw_write_event);
1827 /* and see if there is ioctl stuff to free */
1828 ioctlp = fidp->ioctlp;
1831 cm_FreeSpace(ioctlp->prefix);
1832 if (ioctlp->ioctl.inAllocp)
1833 free(ioctlp->ioctl.inAllocp);
1834 if (ioctlp->ioctl.outAllocp)
1835 free(ioctlp->ioctl.outAllocp);
1839 smb_CleanupRPCFid(fidp);
1841 lock_ReleaseMutex(&fidp->mx);
1842 lock_FinalizeMutex(&fidp->mx);
1847 smb_ReleaseVCNoLock(vcp);
1851 lock_ReleaseMutex(&fidp->mx);
1853 lock_ReleaseWrite(&smb_rctLock);
1855 /* now release the scache structure */
1857 cm_ReleaseSCache(scp);
1860 cm_ReleaseUser(userp);
1864 * Case-insensitive search for one string in another;
1865 * used to find variable names in submount pathnames.
1867 static clientchar_t *smb_stristr(clientchar_t *str1, clientchar_t *str2)
1869 clientchar_t *cursor;
1871 for (cursor = str1; *cursor; cursor++)
1872 if (cm_ClientStrCmpI(cursor, str2) == 0)
1879 * Substitute a variable value for its name in a submount pathname. Variable
1880 * name has been identified by smb_stristr() and is in substr. Variable name
1881 * length (plus one) is in substr_size. Variable value is in newstr.
1883 static void smb_subst(clientchar_t *str1, int cchstr1, clientchar_t *substr,
1884 unsigned int substr_size, clientchar_t *newstr)
1886 clientchar_t temp[1024];
1888 cm_ClientStrCpy(temp, lengthof(temp), substr + substr_size - 1);
1889 cm_ClientStrCpy(substr, cchstr1 - (substr - str1), newstr);
1890 cm_ClientStrCat(str1, cchstr1, temp);
1893 clientchar_t VNUserName[] = _C("%USERNAME%");
1894 clientchar_t VNLCUserName[] = _C("%LCUSERNAME%");
1895 clientchar_t VNComputerName[] = _C("%COMPUTERNAME%");
1896 clientchar_t VNLCComputerName[] = _C("%LCCOMPUTERNAME%");
1898 typedef struct smb_findShare_rock {
1899 clientchar_t * shareName;
1900 clientchar_t * match;
1902 } smb_findShare_rock_t;
1904 #define SMB_FINDSHARE_EXACT_MATCH 1
1905 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1907 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1911 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1912 normchar_t normName[MAX_PATH];
1914 if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(normName[0])) == 0) {
1915 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
1916 osi_LogSaveString(smb_logp, dep->name));
1920 if (!cm_ClientStrCmpNI(normName, vrock->shareName, 12)) {
1921 if(!cm_ClientStrCmpI(normName, vrock->shareName))
1922 matchType = SMB_FINDSHARE_EXACT_MATCH;
1924 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1927 vrock->match = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
1928 vrock->matchType = matchType;
1930 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1931 return CM_ERROR_STOPNOW;
1937 /* find a shareName in the table of submounts */
1938 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp,
1939 clientchar_t *shareName,
1940 clientchar_t **pathNamep)
1944 clientchar_t pathName[1024];
1947 clientchar_t *p, *q;
1948 fschar_t *cellname = NULL;
1951 DWORD allSubmount = 1;
1953 /* if allSubmounts == 0, only return the //mountRoot/all share
1954 * if in fact it has been been created in the subMounts table.
1955 * This is to allow sites that want to restrict access to the
1958 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1959 0, KEY_QUERY_VALUE, &parmKey);
1960 if (code == ERROR_SUCCESS) {
1961 cblen = sizeof(allSubmount);
1962 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1963 (BYTE *) &allSubmount, &cblen);
1964 if (code != ERROR_SUCCESS) {
1967 RegCloseKey (parmKey);
1970 if (allSubmount && cm_ClientStrCmpI(shareName, _C("all")) == 0) {
1975 /* In case, the all share is disabled we need to still be able
1976 * to handle ioctl requests
1978 if (cm_ClientStrCmpI(shareName, _C("ioctl$")) == 0) {
1979 *pathNamep = cm_ClientStrDup(_C("/.__ioctl__"));
1983 if (cm_ClientStrCmpIA(shareName, _C("IPC$")) == 0 ||
1984 cm_ClientStrCmpIA(shareName, _C("srvsvc")) == 0 ||
1985 cm_ClientStrCmpIA(shareName, _C("wkssvc")) == 0 ||
1986 cm_ClientStrCmpIA(shareName, _C(SMB_IOCTL_FILENAME_NOSLASH)) == 0 ||
1987 cm_ClientStrCmpIA(shareName, _C("DESKTOP.INI")) == 0
1993 /* Check for volume references
1995 * They look like <cell>{%,#}<volume>
1997 if (cm_ClientStrChr(shareName, '%') != NULL ||
1998 cm_ClientStrChr(shareName, '#') != NULL) {
1999 clientchar_t pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
2000 /* make room for '/@vol:' + mountchar + NULL terminator*/
2002 osi_Log1(smb_logp, "smb_FindShare found volume reference [%S]",
2003 osi_LogSaveClientString(smb_logp, shareName));
2005 cm_ClientStrPrintfN(pathstr, lengthof(pathstr),
2006 _C("/") _C(CM_PREFIX_VOL) _C("%s"), shareName);
2007 cchlen = (DWORD)(cm_ClientStrLen(pathstr) + 1);
2009 *pathNamep = malloc(cchlen * sizeof(clientchar_t));
2011 cm_ClientStrCpy(*pathNamep, cchlen, pathstr);
2012 cm_ClientStrLwr(*pathNamep);
2013 osi_Log1(smb_logp, " returning pathname [%S]",
2014 osi_LogSaveClientString(smb_logp, *pathNamep));
2022 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
2023 0, KEY_QUERY_VALUE, &parmKey);
2024 if (code == ERROR_SUCCESS) {
2025 cblen = sizeof(pathName);
2026 code = RegQueryValueExW(parmKey, shareName, NULL, NULL,
2027 (BYTE *) pathName, &cblen);
2028 if (code != ERROR_SUCCESS)
2030 RegCloseKey (parmKey);
2034 cchlen = cblen / sizeof(clientchar_t);
2035 if (cchlen != 0 && cchlen != lengthof(pathName) - 1) {
2036 /* We can accept either unix or PC style AFS pathnames. Convert
2037 * Unix-style to PC style here for internal use.
2040 cchlen = lengthof(pathName);
2042 /* within this code block, we maintain, cchlen = writeable
2043 buffer length of p */
2045 if (cm_ClientStrCmpN(p, cm_mountRootC, cm_mountRootCLen) == 0) {
2046 p += cm_mountRootCLen; /* skip mount path */
2047 cchlen -= (DWORD)(p - pathName);
2052 if (*q == _C('/')) *q = _C('\\'); /* change to \ */
2058 clientchar_t temp[1024];
2060 if (var = smb_stristr(p, VNUserName)) {
2061 if (uidp && uidp->unp)
2062 smb_subst(p, cchlen, var, lengthof(VNUserName),uidp->unp->name);
2064 smb_subst(p, cchlen, var, lengthof(VNUserName), _C(" "));
2066 else if (var = smb_stristr(p, VNLCUserName))
2068 if (uidp && uidp->unp)
2069 cm_ClientStrCpy(temp, lengthof(temp), uidp->unp->name);
2071 cm_ClientStrCpy(temp, lengthof(temp), _C(" "));
2072 cm_ClientStrLwr(temp);
2073 smb_subst(p, cchlen, var, lengthof(VNLCUserName), temp);
2075 else if (var = smb_stristr(p, VNComputerName))
2077 sizeTemp = lengthof(temp);
2078 GetComputerNameW(temp, &sizeTemp);
2079 smb_subst(p, cchlen, var, lengthof(VNComputerName), temp);
2081 else if (var = smb_stristr(p, VNLCComputerName))
2083 sizeTemp = lengthof(temp);
2084 GetComputerName((LPTSTR)temp, &sizeTemp);
2085 cm_ClientStrLwr(temp);
2086 smb_subst(p, cchlen, var, lengthof(VNLCComputerName), temp);
2091 *pathNamep = cm_ClientStrDup(p);
2096 /* First lookup shareName in root.afs */
2098 smb_findShare_rock_t vrock;
2100 fschar_t ftemp[1024];
2101 clientchar_t * p = shareName;
2104 /* attempt to locate a partial match in root.afs. This is because
2105 when using the ANSI RAP calls, the share name is limited to 13 chars
2106 and hence is truncated. Of course we prefer exact matches. */
2108 thyper.HighPart = 0;
2111 vrock.shareName = cm_ClientStringToNormStringAlloc(shareName, -1, NULL);
2112 if (vrock.shareName == NULL)
2115 vrock.matchType = 0;
2117 cm_HoldSCache(cm_data.rootSCachep);
2118 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
2119 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
2120 cm_ReleaseSCache(cm_data.rootSCachep);
2122 free(vrock.shareName);
2123 vrock.shareName = NULL;
2125 if (vrock.matchType) {
2126 cm_ClientStrPrintfN(pathName, lengthof(pathName), _C("/%s/"), vrock.match);
2127 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
2132 /* if we get here, there was no match for the share in root.afs */
2133 /* so try to create \\<netbiosName>\<cellname> */
2138 /* Get the full name for this cell */
2139 cellname = cm_ClientStringToFsStringAlloc(p, -1, NULL);
2140 code = cm_SearchCellRegistry(1, cellname, ftemp, 0, 0, 0);
2141 if (code && code != CM_ERROR_FORCE_DNS_LOOKUP)
2142 code = cm_SearchCellFile(cellname, ftemp, 0, 0);
2143 #ifdef AFS_AFSDB_ENV
2144 if (code && cm_dnsEnabled) {
2146 code = cm_SearchCellByDNS(cellname, ftemp, &ttl, 0, 0);
2152 /* construct the path */
2154 clientchar_t temp[1024];
2156 if (cm_FsStringToClientString(ftemp, -1, temp, 1024) != 0) {
2157 cm_ClientStrPrintfN(pathName, (int)lengthof(pathName),
2158 rw ? _C("/.%S/") : _C("/%S/"), temp);
2159 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
2169 /* Client-side offline caching policy types */
2170 #define CSC_POLICY_MANUAL 0
2171 #define CSC_POLICY_DOCUMENTS 1
2172 #define CSC_POLICY_PROGRAMS 2
2173 #define CSC_POLICY_DISABLE 3
2175 int smb_FindShareCSCPolicy(clientchar_t *shareName)
2178 clientchar_t policy[1024];
2181 int retval = CSC_POLICY_MANUAL;
2183 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
2184 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
2187 REG_OPTION_NON_VOLATILE,
2193 len = sizeof(policy);
2194 if ( RegQueryValueExW( hkCSCPolicy, shareName, 0, &dwType, (LPBYTE) policy, &len ) ||
2196 retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
2198 else if (cm_ClientStrCmpIA(policy, _C("documents")) == 0)
2200 retval = CSC_POLICY_DOCUMENTS;
2202 else if (cm_ClientStrCmpIA(policy, _C("programs")) == 0)
2204 retval = CSC_POLICY_PROGRAMS;
2206 else if (cm_ClientStrCmpIA(policy, _C("disable")) == 0)
2208 retval = CSC_POLICY_DISABLE;
2211 RegCloseKey(hkCSCPolicy);
2215 /* find a dir search structure by cookie value, and return it held.
2216 * Must be called with smb_globalLock held.
2218 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
2220 smb_dirSearch_t *dsp;
2222 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2223 if (dsp->cookie == cookie) {
2224 if (dsp != smb_firstDirSearchp) {
2225 /* move to head of LRU queue, too, if we're not already there */
2226 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
2227 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2228 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2229 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2230 if (!smb_lastDirSearchp)
2231 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2239 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
2240 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2241 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
2247 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
2249 lock_ObtainMutex(&dsp->mx);
2250 osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p",
2251 dsp->cookie, dsp, dsp->scp);
2252 dsp->flags |= SMB_DIRSEARCH_DELETE;
2253 if (dsp->scp != NULL) {
2254 lock_ObtainWrite(&dsp->scp->rw);
2255 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
2256 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2257 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2258 dsp->scp->bulkStatProgress = hzero;
2260 lock_ReleaseWrite(&dsp->scp->rw);
2262 lock_ReleaseMutex(&dsp->mx);
2265 /* Must be called with the smb_globalLock held */
2266 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
2268 cm_scache_t *scp = NULL;
2270 osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
2271 if (dsp->refCount == 0) {
2272 lock_ObtainMutex(&dsp->mx);
2273 if (dsp->flags & SMB_DIRSEARCH_DELETE) {
2274 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
2275 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
2276 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2277 lock_ReleaseMutex(&dsp->mx);
2278 lock_FinalizeMutex(&dsp->mx);
2280 osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p",
2281 dsp->cookie, dsp, scp);
2284 lock_ReleaseMutex(&dsp->mx);
2287 /* do this now to avoid spurious locking hierarchy creation */
2289 cm_ReleaseSCache(scp);
2292 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
2294 lock_ObtainWrite(&smb_globalLock);
2295 smb_ReleaseDirSearchNoLock(dsp);
2296 lock_ReleaseWrite(&smb_globalLock);
2299 /* find a dir search structure by cookie value, and return it held */
2300 smb_dirSearch_t *smb_FindDirSearch(long cookie)
2302 smb_dirSearch_t *dsp;
2304 lock_ObtainWrite(&smb_globalLock);
2305 dsp = smb_FindDirSearchNoLock(cookie);
2306 lock_ReleaseWrite(&smb_globalLock);
2310 /* GC some dir search entries, in the address space expected by the specific protocol.
2311 * Must be called with smb_globalLock held; release the lock temporarily.
2313 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
2314 void smb_GCDirSearches(int isV3)
2316 smb_dirSearch_t *prevp;
2317 smb_dirSearch_t *dsp;
2318 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
2322 victimCount = 0; /* how many have we got so far */
2323 for (dsp = smb_lastDirSearchp; dsp; dsp=prevp) {
2324 /* we'll move tp from queue, so
2327 prevp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2328 /* if no one is using this guy, and we're either in the new protocol,
2329 * or we're in the old one and this is a small enough ID to be useful
2330 * to the old protocol, GC this guy.
2332 if (dsp->refCount == 0 && (isV3 || dsp->cookie <= 255)) {
2333 /* hold and delete */
2334 lock_ObtainMutex(&dsp->mx);
2335 dsp->flags |= SMB_DIRSEARCH_DELETE;
2336 lock_ReleaseMutex(&dsp->mx);
2337 victimsp[victimCount++] = dsp;
2341 /* don't do more than this */
2342 if (victimCount >= SMB_DIRSEARCH_GCMAX)
2346 /* now release them */
2347 for (i = 0; i < victimCount; i++) {
2348 smb_ReleaseDirSearchNoLock(victimsp[i]);
2352 /* function for allocating a dir search entry. We need these to remember enough context
2353 * since we don't get passed the path from call to call during a directory search.
2355 * Returns a held dir search structure, and bumps the reference count on the vnode,
2356 * since it saves a pointer to the vnode.
2358 smb_dirSearch_t *smb_NewDirSearch(int isV3)
2360 smb_dirSearch_t *dsp;
2366 lock_ObtainWrite(&smb_globalLock);
2369 /* what's the biggest ID allowed in this version of the protocol */
2370 /* TODO: do we really want a non v3 dir search request to wrap
2371 smb_dirSearchCounter? */
2372 maxAllowed = isV3 ? 65535 : 255;
2373 if (smb_dirSearchCounter > maxAllowed)
2374 smb_dirSearchCounter = 1;
2376 start = smb_dirSearchCounter;
2379 /* twice so we have enough tries to find guys we GC after one pass;
2380 * 10 extra is just in case I mis-counted.
2382 if (++counter > 2*maxAllowed+10)
2383 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2385 if (smb_dirSearchCounter > maxAllowed) {
2386 smb_dirSearchCounter = 1;
2388 if (smb_dirSearchCounter == start) {
2390 smb_GCDirSearches(isV3);
2393 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2395 /* don't need to watch for refcount zero and deleted, since
2396 * we haven't dropped the global lock.
2399 ++smb_dirSearchCounter;
2403 dsp = malloc(sizeof(*dsp));
2404 memset(dsp, 0, sizeof(*dsp));
2405 dsp->cookie = smb_dirSearchCounter;
2406 ++smb_dirSearchCounter;
2408 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t", LOCK_HIERARCHY_SMB_DIRSEARCH);
2409 dsp->lastTime = osi_Time();
2410 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2411 if (!smb_lastDirSearchp)
2412 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2414 osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p",
2418 lock_ReleaseWrite(&smb_globalLock);
2422 static smb_packet_t *smb_GetPacket(void)
2426 lock_ObtainWrite(&smb_globalLock);
2427 tbp = smb_packetFreeListp;
2429 smb_packetFreeListp = tbp->nextp;
2430 lock_ReleaseWrite(&smb_globalLock);
2432 tbp = calloc(sizeof(*tbp),1);
2433 tbp->magic = SMB_PACKETMAGIC;
2436 tbp->resumeCode = 0;
2442 tbp->ncb_length = 0;
2445 tbp->stringsp = NULL;
2447 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2452 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2455 tbp = smb_GetPacket();
2456 memcpy(tbp, pkt, sizeof(smb_packet_t));
2457 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2458 tbp->stringsp = NULL;
2460 smb_HoldVC(tbp->vcp);
2464 static NCB *smb_GetNCB(void)
2469 lock_ObtainWrite(&smb_globalLock);
2470 tbp = smb_ncbFreeListp;
2472 smb_ncbFreeListp = tbp->nextp;
2473 lock_ReleaseWrite(&smb_globalLock);
2475 tbp = calloc(sizeof(*tbp),1);
2476 tbp->magic = SMB_NCBMAGIC;
2479 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2481 memset(&tbp->ncb, 0, sizeof(NCB));
2486 static void FreeSMBStrings(smb_packet_t * pkt)
2491 for (s = pkt->stringsp; s; s = ns) {
2495 pkt->stringsp = NULL;
2498 void smb_FreePacket(smb_packet_t *tbp)
2500 smb_vc_t * vcp = NULL;
2501 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2503 lock_ObtainWrite(&smb_globalLock);
2504 tbp->nextp = smb_packetFreeListp;
2505 smb_packetFreeListp = tbp;
2506 tbp->magic = SMB_PACKETMAGIC;
2510 tbp->resumeCode = 0;
2516 tbp->ncb_length = 0;
2518 FreeSMBStrings(tbp);
2519 lock_ReleaseWrite(&smb_globalLock);
2525 static void smb_FreeNCB(NCB *bufferp)
2529 tbp = (smb_ncb_t *) bufferp;
2530 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2532 lock_ObtainWrite(&smb_globalLock);
2533 tbp->nextp = smb_ncbFreeListp;
2534 smb_ncbFreeListp = tbp;
2535 lock_ReleaseWrite(&smb_globalLock);
2538 /* get a ptr to the data part of a packet, and its count */
2539 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2543 unsigned char *afterParmsp;
2545 parmBytes = *smbp->wctp << 1;
2546 afterParmsp = smbp->wctp + parmBytes + 1;
2548 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2549 if (nbytesp) *nbytesp = dataBytes;
2551 /* don't forget to skip the data byte count, since it follows
2552 * the parameters; that's where the "2" comes from below.
2554 return (unsigned char *) (afterParmsp + 2);
2557 /* must set all the returned parameters before playing around with the
2558 * data region, since the data region is located past the end of the
2559 * variable number of parameters.
2561 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2563 unsigned char *afterParmsp;
2565 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2567 *afterParmsp++ = dsize & 0xff;
2568 *afterParmsp = (dsize>>8) & 0xff;
2571 /* return the parm'th parameter in the smbp packet */
2572 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2575 unsigned char *parmDatap;
2577 parmCount = *smbp->wctp;
2579 if (parm >= parmCount) {
2582 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2583 parm, parmCount, smbp->ncb_length);
2584 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2585 parm, parmCount, smbp->ncb_length);
2586 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2587 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2588 osi_panic(s, __FILE__, __LINE__);
2590 parmDatap = smbp->wctp + (2*parm) + 1;
2592 return parmDatap[0] + (parmDatap[1] << 8);
2595 /* return the parm'th parameter in the smbp packet */
2596 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2599 unsigned char *parmDatap;
2601 parmCount = *smbp->wctp;
2603 if (parm >= parmCount) {
2606 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2607 parm, parmCount, smbp->ncb_length);
2608 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2609 parm, parmCount, smbp->ncb_length);
2610 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2611 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2612 osi_panic(s, __FILE__, __LINE__);
2614 parmDatap = smbp->wctp + (2*parm) + 1;
2616 return parmDatap[0];
2619 /* return the parm'th parameter in the smbp packet */
2620 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2623 unsigned char *parmDatap;
2625 parmCount = *smbp->wctp;
2627 if (parm + 1 >= parmCount) {
2630 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2631 parm, parmCount, smbp->ncb_length);
2632 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2633 parm, parmCount, smbp->ncb_length);
2634 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2635 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2636 osi_panic(s, __FILE__, __LINE__);
2638 parmDatap = smbp->wctp + (2*parm) + 1;
2640 return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2643 /* return the parm'th parameter in the smbp packet */
2644 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2647 unsigned char *parmDatap;
2649 parmCount = *smbp->wctp;
2651 if (parm * 2 + offset >= parmCount * 2) {
2654 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2655 parm, offset, parmCount, smbp->ncb_length);
2656 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2657 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2658 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2659 parm, offset, parmCount, smbp->ncb_length);
2660 osi_panic(s, __FILE__, __LINE__);
2662 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2664 return parmDatap[0] + (parmDatap[1] << 8);
2667 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2669 unsigned char *parmDatap;
2671 /* make sure we have enough slots */
2672 if (*smbp->wctp <= slot)
2673 *smbp->wctp = slot+1;
2675 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2676 *parmDatap++ = parmValue & 0xff;
2677 *parmDatap = (parmValue>>8) & 0xff;
2680 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2682 unsigned char *parmDatap;
2684 /* make sure we have enough slots */
2685 if (*smbp->wctp <= slot)
2686 *smbp->wctp = slot+2;
2688 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2689 *parmDatap++ = parmValue & 0xff;
2690 *parmDatap++ = (parmValue>>8) & 0xff;
2691 *parmDatap++ = (parmValue>>16) & 0xff;
2692 *parmDatap = (parmValue>>24) & 0xff;
2695 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2697 unsigned char *parmDatap;
2700 /* make sure we have enough slots */
2701 if (*smbp->wctp <= slot)
2702 *smbp->wctp = slot+4;
2704 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2706 *parmDatap++ = *parmValuep++;
2709 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2711 unsigned char *parmDatap;
2713 /* make sure we have enough slots */
2714 if (*smbp->wctp <= slot) {
2715 if (smbp->oddByte) {
2717 *smbp->wctp = slot+1;
2722 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2723 *parmDatap++ = parmValue & 0xff;
2728 void smb_StripLastComponent(clientchar_t *outPathp, clientchar_t **lastComponentp,
2729 clientchar_t *inPathp)
2731 clientchar_t *lastSlashp;
2733 lastSlashp = cm_ClientStrRChr(inPathp, '\\');
2735 *lastComponentp = lastSlashp;
2738 if (inPathp == lastSlashp)
2740 *outPathp++ = *inPathp++;
2749 clientchar_t *smb_ParseASCIIBlock(smb_packet_t * pktp, unsigned char *inp,
2750 char **chainpp, int flags)
2753 afs_uint32 type = *inp++;
2756 * The first byte specifies the type of the input string.
2757 * CIFS TR 1.0 3.2.10. This function only parses null terminated
2761 /* Length Counted */
2762 case 0x1: /* Data Block */
2763 case 0x5: /* Variable Block */
2764 cb = *inp++ << 16 | *inp++;
2767 /* Null-terminated string */
2768 case 0x4: /* ASCII */
2769 case 0x3: /* Pathname */
2770 case 0x2: /* Dialect */
2771 cb = sizeof(pktp->data) - (inp - pktp->data);
2772 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2773 #ifdef DEBUG_UNICODE
2776 cb = sizeof(pktp->data);
2781 return NULL; /* invalid input */
2785 if (type == 0x2 /* Dialect */ || !WANTS_UNICODE(pktp))
2786 flags |= SMB_STRF_FORCEASCII;
2789 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2792 clientchar_t *smb_ParseString(smb_packet_t * pktp, unsigned char * inp,
2793 char ** chainpp, int flags)
2798 if (!WANTS_UNICODE(pktp))
2799 flags |= SMB_STRF_FORCEASCII;
2802 cb = sizeof(pktp->data) - (inp - pktp->data);
2803 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2804 #ifdef DEBUG_UNICODE
2807 cb = sizeof(pktp->data);
2809 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp,
2810 flags | SMB_STRF_SRCNULTERM);
2813 clientchar_t *smb_ParseStringCb(smb_packet_t * pktp, unsigned char * inp,
2814 size_t cb, char ** chainpp, int flags)
2817 if (!WANTS_UNICODE(pktp))
2818 flags |= SMB_STRF_FORCEASCII;
2821 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2824 clientchar_t *smb_ParseStringCch(smb_packet_t * pktp, unsigned char * inp,
2825 size_t cch, char ** chainpp, int flags)
2830 if (!WANTS_UNICODE(pktp))
2831 flags |= SMB_STRF_FORCEASCII;
2833 cb = cch * sizeof(wchar_t);
2836 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2840 smb_ParseStringBuf(const unsigned char * bufbase,
2841 cm_space_t ** stringspp,
2842 unsigned char *inp, size_t *pcb_max,
2843 char **chainpp, int flags)
2846 if (!(flags & SMB_STRF_FORCEASCII)) {
2848 cm_space_t * spacep;
2851 if (bufbase && ((inp - bufbase) % 2) != 0) {
2852 inp++; /* unicode strings are always word aligned */
2856 if (FAILED(StringCchLengthW((const wchar_t *) inp, *pcb_max / sizeof(wchar_t),
2858 cch_src = *pcb_max / sizeof(wchar_t);
2862 *pcb_max -= (cch_src + 1) * sizeof(wchar_t);
2869 spacep = cm_GetSpace();
2870 spacep->nextp = *stringspp;
2871 *stringspp = spacep;
2875 *chainpp = inp + sizeof(wchar_t);
2878 *(spacep->wdata) = 0;
2879 return spacep->wdata;
2882 StringCchCopyNW(spacep->wdata,
2883 lengthof(spacep->wdata),
2884 (const clientchar_t *) inp, cch_src);
2887 *chainpp = inp + (cch_src + null_terms)*sizeof(wchar_t);
2889 return spacep->wdata;
2893 cm_space_t * spacep;
2896 /* Not using Unicode */
2898 *chainpp = inp + strlen(inp) + 1;
2901 spacep = cm_GetSpace();
2902 spacep->nextp = *stringspp;
2903 *stringspp = spacep;
2905 cchdest = lengthof(spacep->wdata);
2906 cm_Utf8ToUtf16(inp, (int)((flags & SMB_STRF_SRCNULTERM)? -1 : *pcb_max),
2907 spacep->wdata, cchdest);
2909 return spacep->wdata;
2915 unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
2917 size_t * plen, int flags)
2923 /* we are only calculating the required size */
2930 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2932 StringCbLengthW(str, SMB_STRINGBUFSIZE * sizeof(wchar_t), plen);
2933 if (!(flags & SMB_STRF_IGNORENUL))
2934 *plen += sizeof(wchar_t);
2936 return (unsigned char *) 1; /* return TRUE if we are using unicode */
2946 cch_str = cm_ClientStrLen(str);
2947 cch_dest = cm_ClientStringToUtf8(str, (int)cch_str, NULL, 0);
2950 *plen = ((flags & SMB_STRF_IGNORENUL)? cch_dest: cch_dest+1);
2958 /* if outp != NULL ... */
2960 /* Number of bytes left in the buffer.
2962 If outp lies inside the packet data buffer, we assume that the
2963 buffer is the packet data buffer. Otherwise we assume that the
2964 buffer is sizeof(packet->data).
2967 if (outp >= pktp->data && outp < pktp->data + sizeof(pktp->data)) {
2968 align = (int)((outp - pktp->data) % 2);
2969 buffersize = (pktp->data + sizeof(pktp->data)) - ((char *) outp);
2971 align = (int)(((size_t) outp) % 2);
2972 buffersize = (int)sizeof(pktp->data);
2977 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2983 if (*str == _C('\0')) {
2985 if (buffersize < sizeof(wchar_t))
2988 *((wchar_t *) outp) = L'\0';
2989 if (plen && !(flags & SMB_STRF_IGNORENUL))
2990 *plen += sizeof(wchar_t);
2991 return outp + sizeof(wchar_t);
2994 nchars = cm_ClientStringToUtf16(str, -1, (wchar_t *) outp, (int)(buffersize / sizeof(wchar_t)));
2996 osi_Log2(smb_logp, "UnparseString: Can't convert string to Unicode [%S], GLE=%d",
2997 osi_LogSaveClientString(smb_logp, str),
3003 *plen += sizeof(wchar_t) * ((flags & SMB_STRF_IGNORENUL)? nchars - 1: nchars);
3005 return outp + sizeof(wchar_t) * nchars;
3013 cch_dest = cm_ClientStringToUtf8(str, -1, outp, (int)buffersize);
3016 *plen += ((flags & SMB_STRF_IGNORENUL)? cch_dest - 1: cch_dest);
3018 return outp + cch_dest;
3022 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
3028 tlen = inp[0] + (inp[1]<<8);
3029 inp += 2; /* skip length field */
3032 *chainpp = inp + tlen;
3041 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3045 if (*inp++ != 0x1) return NULL;
3046 tlen = inp[0] + (inp[1]<<8);
3047 inp += 2; /* skip length field */
3050 *chainpp = inp + tlen;
3053 if (lengthp) *lengthp = tlen;
3058 /* format a packet as a response */
3059 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
3064 outp = (smb_t *) op;
3066 /* zero the basic structure through the smb_wct field, and zero the data
3067 * size field, assuming that wct stays zero; otherwise, you have to
3068 * explicitly set the data size field, too.
3070 inSmbp = (smb_t *) inp;
3071 memset(outp, 0, sizeof(smb_t)+2);
3077 outp->com = inSmbp->com;
3078 outp->tid = inSmbp->tid;
3079 outp->pid = inSmbp->pid;
3080 outp->uid = inSmbp->uid;
3081 outp->mid = inSmbp->mid;
3082 outp->res[0] = inSmbp->res[0];
3083 outp->res[1] = inSmbp->res[1];
3084 op->inCom = inSmbp->com;
3086 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
3087 #ifdef SEND_CANONICAL_PATHNAMES
3088 outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
3090 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
3092 if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
3093 outp->flg2 |= SMB_FLAGS2_UNICODE;
3096 /* copy fields in generic packet area */
3097 op->wctp = &outp->wct;
3100 /* send a (probably response) packet; vcp tells us to whom to send it.
3101 * we compute the length by looking at wct and bcc fields.
3103 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
3113 ncbp = smb_GetNCB();
3117 memset((char *)ncbp, 0, sizeof(NCB));
3119 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
3120 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
3121 extra += tp[0] + (tp[1]<<8);
3122 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
3123 extra += 3; /* wct and length fields */
3125 ncbp->ncb_length = extra; /* bytes to send */
3126 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
3127 ncbp->ncb_lana_num = vcp->lana;
3128 ncbp->ncb_command = NCBSEND; /* op means send data */
3129 ncbp->ncb_buffer = (char *) inp;/* packet */
3130 code = Netbios(ncbp);
3133 const char * s = ncb_error_string(code);
3134 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
3135 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
3137 lock_ObtainMutex(&vcp->mx);
3138 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
3139 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
3141 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
3142 lock_ReleaseMutex(&vcp->mx);
3143 lock_ObtainWrite(&smb_globalLock);
3144 dead_sessions[vcp->session] = TRUE;
3145 lock_ReleaseWrite(&smb_globalLock);
3146 smb_CleanupDeadVC(vcp);
3148 lock_ReleaseMutex(&vcp->mx);
3156 void smb_MapNTError(long code, unsigned long *NTStatusp)
3158 unsigned long NTStatus;
3160 /* map CM_ERROR_* errors to NT 32-bit status codes */
3161 /* NT Status codes are listed in ntstatus.h not winerror.h */
3165 else if (code == CM_ERROR_NOSUCHCELL) {
3166 NTStatus = 0xC000000FL; /* No such file */
3168 else if (code == CM_ERROR_NOSUCHVOLUME) {
3169 NTStatus = 0xC000000FL; /* No such file */
3171 else if (code == CM_ERROR_TIMEDOUT) {
3173 NTStatus = 0xC00000CFL; /* Sharing Paused */
3175 NTStatus = 0x00000102L; /* Timeout */
3178 else if (code == CM_ERROR_RETRY) {
3179 NTStatus = 0xC000022DL; /* Retry */
3181 else if (code == CM_ERROR_NOACCESS) {
3182 NTStatus = 0xC0000022L; /* Access denied */
3184 else if (code == CM_ERROR_READONLY) {
3185 NTStatus = 0xC00000A2L; /* Write protected */
3187 else if (code == CM_ERROR_NOSUCHFILE ||
3188 code == CM_ERROR_BPLUS_NOMATCH) {
3189 NTStatus = 0xC000000FL; /* No such file */
3191 else if (code == CM_ERROR_NOSUCHPATH) {
3192 NTStatus = 0xC000003AL; /* Object path not found */
3194 else if (code == CM_ERROR_TOOBIG) {
3195 NTStatus = 0xC000007BL; /* Invalid image format */
3197 else if (code == CM_ERROR_INVAL) {
3198 NTStatus = 0xC000000DL; /* Invalid parameter */
3200 else if (code == CM_ERROR_BADFD) {
3201 NTStatus = 0xC0000008L; /* Invalid handle */
3203 else if (code == CM_ERROR_BADFDOP) {
3204 NTStatus = 0xC0000022L; /* Access denied */
3206 else if (code == CM_ERROR_EXISTS) {
3207 NTStatus = 0xC0000035L; /* Object name collision */
3209 else if (code == CM_ERROR_NOTEMPTY) {
3210 NTStatus = 0xC0000101L; /* Directory not empty */
3212 else if (code == CM_ERROR_CROSSDEVLINK) {
3213 NTStatus = 0xC00000D4L; /* Not same device */
3215 else if (code == CM_ERROR_NOTDIR) {
3216 NTStatus = 0xC0000103L; /* Not a directory */
3218 else if (code == CM_ERROR_ISDIR) {
3219 NTStatus = 0xC00000BAL; /* File is a directory */
3221 else if (code == CM_ERROR_BADOP) {
3223 /* I have no idea where this comes from */
3224 NTStatus = 0xC09820FFL; /* SMB no support */
3226 NTStatus = 0xC00000BBL; /* Not supported */
3227 #endif /* COMMENT */
3229 else if (code == CM_ERROR_BADSHARENAME) {
3230 NTStatus = 0xC00000BEL; /* Bad network path (server valid, share bad) */
3232 else if (code == CM_ERROR_NOIPC) {
3234 NTStatus = 0xC0000022L; /* Access Denied */
3236 NTStatus = 0xC000013DL; /* Remote Resources */
3239 else if (code == CM_ERROR_CLOCKSKEW) {
3240 NTStatus = 0xC0000133L; /* Time difference at DC */
3242 else if (code == CM_ERROR_BADTID) {
3243 NTStatus = 0xC0982005L; /* SMB bad TID */
3245 else if (code == CM_ERROR_USESTD) {
3246 NTStatus = 0xC09820FBL; /* SMB use standard */
3248 else if (code == CM_ERROR_QUOTA) {
3249 NTStatus = 0xC0000044L; /* Quota exceeded */
3251 else if (code == CM_ERROR_SPACE) {
3252 NTStatus = 0xC000007FL; /* Disk full */
3254 else if (code == CM_ERROR_ATSYS) {
3255 NTStatus = 0xC0000033L; /* Object name invalid */
3257 else if (code == CM_ERROR_BADNTFILENAME) {
3258 NTStatus = 0xC0000033L; /* Object name invalid */
3260 else if (code == CM_ERROR_WOULDBLOCK) {
3261 NTStatus = 0xC00000D8L; /* Can't wait */
3263 else if (code == CM_ERROR_SHARING_VIOLATION) {
3264 NTStatus = 0xC0000043L; /* Sharing violation */
3266 else if (code == CM_ERROR_LOCK_CONFLICT) {
3267 NTStatus = 0xC0000054L; /* Lock conflict */
3269 else if (code == CM_ERROR_PARTIALWRITE) {
3270 NTStatus = 0xC000007FL; /* Disk full */
3272 else if (code == CM_ERROR_BUFFERTOOSMALL) {
3273 NTStatus = 0xC0000023L; /* Buffer too small */
3275 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3276 NTStatus = 0xC0000035L; /* Object name collision */
3278 else if (code == CM_ERROR_BADPASSWORD) {
3279 NTStatus = 0xC000006DL; /* unknown username or bad password */
3281 else if (code == CM_ERROR_BADLOGONTYPE) {
3282 NTStatus = 0xC000015BL; /* logon type not granted */
3284 else if (code == CM_ERROR_GSSCONTINUE) {
3285 NTStatus = 0xC0000016L; /* more processing required */
3287 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3289 NTStatus = 0xC0000280L; /* reparse point not resolved */
3291 NTStatus = 0xC0000022L; /* Access Denied */
3294 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3295 NTStatus = 0xC0000257L; /* Path Not Covered */
3297 else if (code == CM_ERROR_ALLBUSY) {
3298 NTStatus = 0xC000022DL; /* Retry */
3300 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3301 NTStatus = 0xC000003AL; /* Path not found */
3303 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3304 NTStatus = 0xC0000322L; /* No Kerberos key */
3306 else if (code == CM_ERROR_BAD_LEVEL) {
3307 NTStatus = 0xC0000148L; /* Invalid Level */
3309 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3310 NTStatus = 0xC000007EL; /* Range Not Locked */
3312 else if (code == CM_ERROR_NOSUCHDEVICE) {
3313 NTStatus = 0xC000000EL; /* No Such Device */
3315 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3316 NTStatus = 0xC0000055L; /* Lock Not Granted */
3318 else if (code == ENOMEM) {
3319 NTStatus = 0xC0000017L; /* Out of Memory */
3321 else if (code == CM_ERROR_RPC_MOREDATA) {
3322 NTStatus = 0x80000005L; /* Buffer overflow */
3325 NTStatus = 0xC0982001L; /* SMB non-specific error */
3328 *NTStatusp = NTStatus;
3329 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
3333 * NTSTATUS <-> Win32 Error Translation
3334 * http://support.microsoft.com/kb/113996
3336 void smb_MapWin32Error(long code, unsigned long *Win32Ep)
3338 unsigned long Win32E;
3340 /* map CM_ERROR_* errors to Win32 32-bit error codes */
3344 else if (code == CM_ERROR_NOSUCHCELL) {
3345 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3347 else if (code == CM_ERROR_NOSUCHVOLUME) {
3348 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3350 else if (code == CM_ERROR_TIMEDOUT) {
3352 Win32E = ERROR_SHARING_PAUSED; /* Sharing Paused */
3354 Win32E = ERROR_UNEXP_NET_ERR; /* Timeout */
3357 else if (code == CM_ERROR_RETRY) {
3358 Win32E = ERROR_RETRY; /* Retry */
3360 else if (code == CM_ERROR_NOACCESS) {
3361 Win32E = ERROR_ACCESS_DENIED; /* Access denied */
3363 else if (code == CM_ERROR_READONLY) {
3364 Win32E = ERROR_WRITE_PROTECT; /* Write protected */
3366 else if (code == CM_ERROR_NOSUCHFILE ||
3367 code == CM_ERROR_BPLUS_NOMATCH) {
3368 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3370 else if (code == CM_ERROR_NOSUCHPATH) {
3371 Win32E = ERROR_PATH_NOT_FOUND; /* Object path not found */
3373 else if (code == CM_ERROR_TOOBIG) {
3374 Win32E = ERROR_BAD_EXE_FORMAT; /* Invalid image format */
3376 else if (code == CM_ERROR_INVAL) {
3377 Win32E = ERROR_INVALID_PARAMETER;/* Invalid parameter */
3379 else if (code == CM_ERROR_BADFD) {
3380 Win32E = ERROR_INVALID_HANDLE; /* Invalid handle */
3382 else if (code == CM_ERROR_BADFDOP) {
3383 Win32E = ERROR_ACCESS_DENIED; /* Access denied */
3385 else if (code == CM_ERROR_EXISTS) {
3386 Win32E = ERROR_ALREADY_EXISTS; /* Object name collision */
3388 else if (code == CM_ERROR_NOTEMPTY) {
3389 Win32E = ERROR_DIR_NOT_EMPTY; /* Directory not empty */
3391 else if (code == CM_ERROR_CROSSDEVLINK) {
3392 Win32E = ERROR_NOT_SAME_DEVICE; /* Not same device */
3394 else if (code == CM_ERROR_NOTDIR) {
3395 Win32E = ERROR_DIRECTORY; /* Not a directory */
3397 else if (code == CM_ERROR_ISDIR) {
3398 Win32E = ERROR_ACCESS_DENIED; /* File is a directory */
3400 else if (code == CM_ERROR_BADOP) {
3401 Win32E = ERROR_NOT_SUPPORTED; /* Not supported */
3403 else if (code == CM_ERROR_BADSHARENAME) {
3404 Win32E = ERROR_BAD_NETPATH; /* Bad network path (server valid, share bad) */
3406 else if (code == CM_ERROR_NOIPC) {
3408 Win32E = ERROR_ACCESS_DENIED; /* Access Denied */
3410 Win32E = ERROR_REM_NOT_LIST; /* Remote Resources */
3413 else if (code == CM_ERROR_CLOCKSKEW) {
3414 Win32E = ERROR_TIME_SKEW; /* Time difference at DC */
3416 else if (code == CM_ERROR_BADTID) {
3417 Win32E = ERROR_FILE_NOT_FOUND; /* SMB bad TID */
3419 else if (code == CM_ERROR_USESTD) {
3420 Win32E = ERROR_ACCESS_DENIED; /* SMB use standard */
3422 else if (code == CM_ERROR_QUOTA) {
3423 Win32E = ERROR_NOT_ENOUGH_QUOTA;/* Quota exceeded */
3425 else if (code == CM_ERROR_SPACE) {
3426 Win32E = ERROR_DISK_FULL; /* Disk full */
3428 else if (code == CM_ERROR_ATSYS) {
3429 Win32E = ERROR_INVALID_NAME; /* Object name invalid */
3431 else if (code == CM_ERROR_BADNTFILENAME) {
3432 Win32E = ERROR_INVALID_NAME; /* Object name invalid */
3434 else if (code == CM_ERROR_WOULDBLOCK) {
3435 Win32E = WAIT_TIMEOUT; /* Can't wait */
3437 else if (code == CM_ERROR_SHARING_VIOLATION) {
3438 Win32E = ERROR_SHARING_VIOLATION; /* Sharing violation */
3440 else if (code == CM_ERROR_LOCK_CONFLICT) {
3441 Win32E = ERROR_LOCK_VIOLATION; /* Lock conflict */
3443 else if (code == CM_ERROR_PARTIALWRITE) {
3444 Win32E = ERROR_DISK_FULL; /* Disk full */
3446 else if (code == CM_ERROR_BUFFERTOOSMALL) {
3447 Win32E = ERROR_INSUFFICIENT_BUFFER; /* Buffer too small */
3449 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3450 Win32E = ERROR_ALREADY_EXISTS; /* Object name collision */
3452 else if (code == CM_ERROR_BADPASSWORD) {
3453 Win32E = ERROR_LOGON_FAILURE; /* unknown username or bad password */
3455 else if (code == CM_ERROR_BADLOGONTYPE) {
3456 Win32E = ERROR_INVALID_LOGON_TYPE; /* logon type not granted */
3458 else if (code == CM_ERROR_GSSCONTINUE) {
3459 Win32E = ERROR_MORE_DATA; /* more processing required */
3461 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3463 Win32E = ERROR_CANT_RESOLVE_FILENAME; /* reparse point not resolved */
3465 Win32E = ERROR_ACCESS_DENIED; /* Access Denied */
3468 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3469 Win32E = ERROR_HOST_UNREACHABLE; /* Path Not Covered */
3471 else if (code == CM_ERROR_ALLBUSY) {
3472 Win32E = ERROR_RETRY; /* Retry */
3474 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3475 Win32E = ERROR_HOST_UNREACHABLE; /* Path not found */
3477 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3478 Win32E = SEC_E_NO_KERB_KEY; /* No Kerberos key */
3480 else if (code == CM_ERROR_BAD_LEVEL) {
3481 Win32E = ERROR_INVALID_LEVEL; /* Invalid Level */
3483 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3484 Win32E = ERROR_NOT_LOCKED; /* Range Not Locked */
3486 else if (code == CM_ERROR_NOSUCHDEVICE) {
3487 Win32E = ERROR_FILE_NOT_FOUND; /* No Such Device */
3489 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3490 Win32E = ERROR_LOCK_VIOLATION; /* Lock Not Granted */
3492 else if (code == ENOMEM) {
3493 Win32E = ERROR_NOT_ENOUGH_MEMORY; /* Out of Memory */
3495 else if (code == CM_ERROR_RPC_MOREDATA) {
3496 Win32E = ERROR_MORE_DATA; /* Buffer overflow */
3499 Win32E = ERROR_GEN_FAILURE; /* SMB non-specific error */
3503 osi_Log2(smb_logp, "SMB SEND code %lX as Win32 %lX", code, Win32E);
3506 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
3507 unsigned char *classp)
3509 unsigned char class;
3510 unsigned short error;
3512 /* map CM_ERROR_* errors to SMB errors */
3513 if (code == CM_ERROR_NOSUCHCELL) {
3515 error = 3; /* bad path */
3517 else if (code == CM_ERROR_NOSUCHVOLUME) {
3519 error = 3; /* bad path */
3521 else if (code == CM_ERROR_TIMEDOUT) {
3523 error = 81; /* server is paused */
3525 else if (code == CM_ERROR_RETRY) {
3526 class = 2; /* shouldn't happen */
3529 else if (code == CM_ERROR_NOACCESS) {
3531 error = 4; /* bad access */
3533 else if (code == CM_ERROR_READONLY) {
3535 error = 19; /* read only */
3537 else if (code == CM_ERROR_NOSUCHFILE ||
3538 code == CM_ERROR_BPLUS_NOMATCH) {
3540 error = 2; /* ENOENT! */
3542 else if (code == CM_ERROR_NOSUCHPATH) {
3544 error = 3; /* Bad path */
3546 else if (code == CM_ERROR_TOOBIG) {
3548 error = 11; /* bad format */
3550 else if (code == CM_ERROR_INVAL) {
3551 class = 2; /* server non-specific error code */
3554 else if (code == CM_ERROR_BADFD) {
3556 error = 6; /* invalid file handle */
3558 else if (code == CM_ERROR_BADFDOP) {
3559 class = 1; /* invalid op on FD */
3562 else if (code == CM_ERROR_EXISTS) {
3564 error = 80; /* file already exists */
3566 else if (code == CM_ERROR_NOTEMPTY) {
3568 error = 5; /* delete directory not empty */
3570 else if (code == CM_ERROR_CROSSDEVLINK) {
3572 error = 17; /* EXDEV */
3574 else if (code == CM_ERROR_NOTDIR) {
3575 class = 1; /* bad path */
3578 else if (code == CM_ERROR_ISDIR) {
3579 class = 1; /* access denied; DOS doesn't have a good match */
3582 else if (code == CM_ERROR_BADOP) {
3586 else if (code == CM_ERROR_BADSHARENAME) {
3590 else if (code == CM_ERROR_NOIPC) {
3592 error = 4; /* bad access */
3594 else if (code == CM_ERROR_CLOCKSKEW) {
3595 class = 1; /* invalid function */
3598 else if (code == CM_ERROR_BADTID) {
3602 else if (code == CM_ERROR_USESTD) {
3606 else if (code == CM_ERROR_REMOTECONN) {
3610 else if (code == CM_ERROR_QUOTA) {
3611 if (vcp->flags & SMB_VCFLAG_USEV3) {
3613 error = 39; /* disk full */
3617 error = 5; /* access denied */
3620 else if (code == CM_ERROR_SPACE) {
3621 if (vcp->flags & SMB_VCFLAG_USEV3) {
3623 error = 39; /* disk full */
3627 error = 5; /* access denied */
3630 else if (code == CM_ERROR_PARTIALWRITE) {
3632 error = 39; /* disk full */
3634 else if (code == CM_ERROR_ATSYS) {
3636 error = 2; /* ENOENT */
3638 else if (code == CM_ERROR_WOULDBLOCK) {
3640 error = 33; /* lock conflict */
3642 else if (code == CM_ERROR_LOCK_CONFLICT) {
3644 error = 33; /* lock conflict */
3646 else if (code == CM_ERROR_SHARING_VIOLATION) {
3648 error = 33; /* lock conflict */
3650 else if (code == CM_ERROR_NOFILES) {
3652 error = 18; /* no files in search */
3654 else if (code == CM_ERROR_RENAME_IDENTICAL) {
3656 error = 183; /* Samba uses this */
3658 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
3659 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
3661 error = 2; /* bad password */
3663 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3665 error = 3; /* bad path */
3674 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
3677 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3679 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
3680 return CM_ERROR_BADOP;
3684 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3686 unsigned short EchoCount, i;
3687 char *data, *outdata;
3690 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
3692 for (i=1; i<=EchoCount; i++) {
3693 data = smb_GetSMBData(inp, &dataSize);
3694 smb_SetSMBParm(outp, 0, i);
3695 smb_SetSMBDataLength(outp, dataSize);
3696 outdata = smb_GetSMBData(outp, NULL);
3697 memcpy(outdata, data, dataSize);
3698 smb_SendPacket(vcp, outp);
3704 /* SMB_COM_READ_RAW */
3705 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3708 long count, minCount, finalCount;
3712 smb_t *smbp = (smb_t*) inp;
3714 cm_user_t *userp = NULL;
3717 char *rawBuf = NULL;
3722 fd = smb_GetSMBParm(inp, 0);
3723 count = smb_GetSMBParm(inp, 3);
3724 minCount = smb_GetSMBParm(inp, 4);
3725 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3727 if (*inp->wctp == 10) {
3728 /* we were sent a request with 64-bit file offsets */
3729 #ifdef AFS_LARGEFILES
3730 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
3732 if (LargeIntegerLessThanZero(offset)) {
3733 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
3737 if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
3738 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset. Dropping request.");
3741 offset.HighPart = 0;
3745 /* we were sent a request with 32-bit file offsets */
3746 offset.HighPart = 0;
3749 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
3750 fd, offset.HighPart, offset.LowPart, count);
3752 fidp = smb_FindFID(vcp, fd, 0);
3756 lock_ObtainMutex(&fidp->mx);
3758 lock_ReleaseMutex(&fidp->mx);
3759 smb_ReleaseFID(fidp);
3760 return CM_ERROR_BADFD;
3763 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
3764 lock_ReleaseMutex(&fidp->mx);
3765 smb_CloseFID(vcp, fidp, NULL, 0);
3766 code = CM_ERROR_NOSUCHFILE;
3772 LARGE_INTEGER LOffset, LLength;
3775 key = cm_GenerateKey(vcp->vcID, pid, fd);
3777 LOffset.HighPart = offset.HighPart;
3778 LOffset.LowPart = offset.LowPart;
3779 LLength.HighPart = 0;
3780 LLength.LowPart = count;
3782 lock_ObtainWrite(&fidp->scp->rw);
3783 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
3784 lock_ReleaseWrite(&fidp->scp->rw);
3787 lock_ReleaseMutex(&fidp->mx);
3791 lock_ObtainMutex(&smb_RawBufLock);
3793 /* Get a raw buf, from head of list */
3794 rawBuf = smb_RawBufs;
3795 smb_RawBufs = *(char **)smb_RawBufs;
3797 lock_ReleaseMutex(&smb_RawBufLock);
3799 lock_ReleaseMutex(&fidp->mx);
3803 if (fidp->flags & SMB_FID_IOCTL)
3805 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
3807 /* Give back raw buffer */
3808 lock_ObtainMutex(&smb_RawBufLock);
3809 *((char **) rawBuf) = smb_RawBufs;
3811 smb_RawBufs = rawBuf;
3812 lock_ReleaseMutex(&smb_RawBufLock);
3815 lock_ReleaseMutex(&fidp->mx);
3816 smb_ReleaseFID(fidp);
3819 lock_ReleaseMutex(&fidp->mx);
3821 userp = smb_GetUserFromVCP(vcp, inp);
3823 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
3829 cm_ReleaseUser(userp);
3832 smb_ReleaseFID(fidp);
3836 memset((char *)ncbp, 0, sizeof(NCB));
3838 ncbp->ncb_length = (unsigned short) finalCount;
3839 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
3840 ncbp->ncb_lana_num = vcp->lana;
3841 ncbp->ncb_command = NCBSEND;
3842 ncbp->ncb_buffer = rawBuf;
3844 code = Netbios(ncbp);
3846 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
3849 /* Give back raw buffer */
3850 lock_ObtainMutex(&smb_RawBufLock);
3851 *((char **) rawBuf) = smb_RawBufs;
3853 smb_RawBufs = rawBuf;
3854 lock_ReleaseMutex(&smb_RawBufLock);
3860 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3862 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3867 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3869 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3874 /* SMB_COM_NEGOTIATE */
3875 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3882 int VistaProtoIndex;
3883 int protoIndex; /* index we're using */
3888 char protocol_array[10][1024]; /* protocol signature of the client */
3889 int caps; /* capabilities */
3892 TIME_ZONE_INFORMATION tzi;
3894 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3897 namep = smb_GetSMBData(inp, &dbytes);
3900 coreProtoIndex = -1; /* not found */
3903 VistaProtoIndex = -1;
3904 while(namex < dbytes) {
3905 osi_Log1(smb_logp, "Protocol %s",
3906 osi_LogSaveString(smb_logp, namep+1));
3907 strcpy(protocol_array[tcounter], namep+1);
3909 /* namep points at the first protocol, or really, a 0x02
3910 * byte preceding the null-terminated ASCII name.
3912 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3913 coreProtoIndex = tcounter;
3915 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3916 v3ProtoIndex = tcounter;
3918 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3919 NTProtoIndex = tcounter;
3921 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3922 VistaProtoIndex = tcounter;
3925 /* compute size of protocol entry */
3926 entryLength = (int)strlen(namep+1);
3927 entryLength += 2; /* 0x02 bytes and null termination */
3929 /* advance over this protocol entry */
3930 namex += entryLength;
3931 namep += entryLength;
3932 tcounter++; /* which proto entry we're looking at */
3935 lock_ObtainMutex(&vcp->mx);
3937 if (VistaProtoIndex != -1) {
3938 protoIndex = VistaProtoIndex;
3939 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3942 if (NTProtoIndex != -1) {
3943 protoIndex = NTProtoIndex;
3944 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3946 else if (v3ProtoIndex != -1) {
3947 protoIndex = v3ProtoIndex;
3948 vcp->flags |= SMB_VCFLAG_USEV3;
3950 else if (coreProtoIndex != -1) {
3951 protoIndex = coreProtoIndex;
3952 vcp->flags |= SMB_VCFLAG_USECORE;
3954 else protoIndex = -1;
3955 lock_ReleaseMutex(&vcp->mx);
3957 if (protoIndex == -1)
3958 return CM_ERROR_INVAL;
3959 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3960 smb_SetSMBParm(outp, 0, protoIndex);
3961 if (smb_authType != SMB_AUTH_NONE) {
3962 smb_SetSMBParmByte(outp, 1,
3963 NEGOTIATE_SECURITY_USER_LEVEL |
3964 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3966 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3968 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3969 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3970 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3971 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3972 /* The session key is not a well documented field however most clients
3973 * will echo back the session key to the server. Currently we are using
3974 * the same value for all sessions. We should generate a random value
3975 * and store it into the vcp
3977 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3978 smb_SetSMBParm(outp, 8, 1);
3980 * Tried changing the capabilities to support for W2K - defect 117695
3981 * Maybe something else needs to be changed here?
3985 smb_SetSMBParmLong(outp, 9, 0x43fd);
3987 smb_SetSMBParmLong(outp, 9, 0x251);
3990 * 32-bit error codes *
3996 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3998 NTNEGOTIATE_CAPABILITY_DFS |
4000 #ifdef AFS_LARGEFILES
4001 NTNEGOTIATE_CAPABILITY_LARGEFILES |
4003 NTNEGOTIATE_CAPABILITY_NTFIND |
4004 NTNEGOTIATE_CAPABILITY_RAWMODE |
4005 NTNEGOTIATE_CAPABILITY_NTSMB;
4007 if ( smb_authType == SMB_AUTH_EXTENDED )
4008 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
4011 if ( smb_UseUnicode ) {
4012 caps |= NTNEGOTIATE_CAPABILITY_UNICODE;
4016 smb_SetSMBParmLong(outp, 9, caps);
4018 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
4019 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
4020 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
4022 GetTimeZoneInformation(&tzi);
4023 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
4025 if (smb_authType == SMB_AUTH_NTLM) {
4026 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
4027 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
4028 /* paste in encryption key */
4029 datap = smb_GetSMBData(outp, NULL);
4030 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
4031 /* and the faux domain name */
4032 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
4033 datap + MSV1_0_CHALLENGE_LENGTH,
4034 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
4035 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
4039 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
4041 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
4043 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
4045 datap = smb_GetSMBData(outp, NULL);
4046 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
4049 datap += sizeof(smb_ServerGUID);
4050 memcpy(datap, secBlob, secBlobLength);
4054 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
4055 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
4058 else if (v3ProtoIndex != -1) {
4059 smb_SetSMBParm(outp, 0, protoIndex);
4061 /* NOTE: Extended authentication cannot be negotiated with v3
4062 * therefore we fail over to NTLM
4064 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
4065 smb_SetSMBParm(outp, 1,
4066 NEGOTIATE_SECURITY_USER_LEVEL |
4067 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
4069 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
4071 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
4072 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
4073 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
4074 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
4075 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
4076 smb_SetSMBParm(outp, 7, 1);
4078 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
4079 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
4080 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
4082 GetTimeZoneInformation(&tzi);
4083 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
4085 /* NOTE: Extended authentication cannot be negotiated with v3
4086 * therefore we fail over to NTLM
4088 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
4089 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
4090 smb_SetSMBParm(outp, 12, 0); /* resvd */
4091 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
4092 datap = smb_GetSMBData(outp, NULL);
4093 /* paste in a new encryption key */
4094 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
4095 /* and the faux domain name */
4096 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
4097 datap + MSV1_0_CHALLENGE_LENGTH,
4098 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
4100 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
4101 smb_SetSMBParm(outp, 12, 0); /* resvd */
4102 smb_SetSMBDataLength(outp, 0);
4105 else if (coreProtoIndex != -1) { /* not really supported anymore */
4106 smb_SetSMBParm(outp, 0, protoIndex);
4107 smb_SetSMBDataLength(outp, 0);
4112 void smb_CheckVCs(void)
4114 smb_vc_t * vcp, *nextp;
4115 smb_packet_t * outp = smb_GetPacket();
4118 lock_ObtainWrite(&smb_rctLock);
4119 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
4121 if (vcp->magic != SMB_VC_MAGIC)
4122 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
4123 __FILE__, __LINE__);
4125 /* on the first pass hold 'vcp' which was not held as 'nextp' */
4127 smb_HoldVCNoLock(vcp);
4130 * obtain a reference to 'nextp' now because we drop the
4131 * smb_rctLock later and the list contents could change
4132 * or 'vcp' could be destroyed when released.
4136 smb_HoldVCNoLock(nextp);
4138 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
4139 smb_ReleaseVCNoLock(vcp);
4143 smb_FormatResponsePacket(vcp, NULL, outp);
4144 smbp = (smb_t *)outp;
4145 outp->inCom = smbp->com = 0x2b /* Echo */;
4153 smb_SetSMBParm(outp, 0, 0);
4154 smb_SetSMBDataLength(outp, 0);
4155 lock_ReleaseWrite(&smb_rctLock);
4157 smb_SendPacket(vcp, outp);
4159 lock_ObtainWrite(&smb_rctLock);
4160 smb_ReleaseVCNoLock(vcp);
4162 lock_ReleaseWrite(&smb_rctLock);
4163 smb_FreePacket(outp);
4166 void smb_Daemon(void *parmp)
4168 afs_uint32 count = 0;
4169 smb_username_t **unpp;
4172 while(smbShutdownFlag == 0) {
4176 if (smbShutdownFlag == 1)
4179 if ((count % 72) == 0) { /* every five minutes */
4181 time_t old_localZero = smb_localZero;
4183 /* Initialize smb_localZero */
4184 myTime.tm_isdst = -1; /* compute whether on DST or not */
4185 myTime.tm_year = 70;
4191 smb_localZero = mktime(&myTime);
4193 #ifndef USE_NUMERIC_TIME_CONV
4194 smb_CalculateNowTZ();
4195 #endif /* USE_NUMERIC_TIME_CONV */
4196 #ifdef AFS_FREELANCE
4197 if ( smb_localZero != old_localZero )
4198 cm_noteLocalMountPointChange();
4204 /* GC smb_username_t objects that will no longer be used */
4206 lock_ObtainWrite(&smb_rctLock);
4207 for ( unpp=&usernamesp; *unpp; ) {
4209 smb_username_t *unp;
4211 lock_ObtainMutex(&(*unpp)->mx);
4212 if ( (*unpp)->refCount > 0 ||
4213 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
4214 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
4216 else if (!smb_LogoffTokenTransfer ||
4217 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
4219 lock_ReleaseMutex(&(*unpp)->mx);
4227 lock_FinalizeMutex(&unp->mx);
4233 cm_ReleaseUser(userp);
4235 unpp = &(*unpp)->nextp;
4238 lock_ReleaseWrite(&smb_rctLock);
4240 /* XXX GC dir search entries */
4244 void smb_WaitingLocksDaemon()
4246 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
4247 smb_waitingLock_t *wl, *wlNext;
4250 smb_packet_t *inp, *outp;
4254 while (smbShutdownFlag == 0) {
4255 lock_ObtainWrite(&smb_globalLock);
4256 nwlRequest = smb_allWaitingLocks;
4257 if (nwlRequest == NULL) {
4258 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
4263 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
4270 lock_ObtainWrite(&smb_globalLock);
4272 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
4274 wlRequest = nwlRequest;
4275 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
4276 lock_ReleaseWrite(&smb_globalLock);
4280 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
4281 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4284 if (wl->state == SMB_WAITINGLOCKSTATE_CANCELLED) {
4285 code = CM_ERROR_LOCK_NOT_GRANTED;
4289 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
4291 /* wl->state is either _DONE or _WAITING. _ERROR
4292 would no longer be on the queue. */
4293 code = cm_RetryLock( wl->lockp,
4294 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
4297 wl->state = SMB_WAITINGLOCKSTATE_DONE;
4298 } else if (code != CM_ERROR_WOULDBLOCK) {
4299 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
4304 if (code == CM_ERROR_WOULDBLOCK) {
4307 if (wlRequest->msTimeout != 0xffffffff
4308 && ((osi_Time() - wlRequest->start_t) * 1000 > wlRequest->msTimeout))
4320 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
4323 scp = wlRequest->scp;
4324 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
4328 lock_ObtainWrite(&scp->rw);
4330 for (wl = wlRequest->locks; wl; wl = wlNext) {
4331 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4333 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4334 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
4335 wl->LLength, wl->key, 0, NULL, &req);
4337 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4342 lock_ReleaseWrite(&scp->rw);
4346 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
4349 for (wl = wlRequest->locks; wl; wl = wlNext) {
4350 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4351 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4356 vcp = wlRequest->vcp;
4357 inp = wlRequest->inp;
4358 outp = wlRequest->outp;
4359 ncbp = smb_GetNCB();
4360 ncbp->ncb_length = inp->ncb_length;
4361 inp->spacep = cm_GetSpace();
4363 /* Remove waitingLock from list */
4364 lock_ObtainWrite(&smb_globalLock);
4365 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
4367 lock_ReleaseWrite(&smb_globalLock);
4369 /* Resume packet processing */
4371 smb_SetSMBDataLength(outp, 0);
4372 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
4373 outp->resumeCode = code;
4375 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
4378 cm_FreeSpace(inp->spacep);
4379 smb_FreePacket(inp);
4380 smb_FreePacket(outp);
4382 cm_ReleaseSCache(wlRequest->scp);
4385 } while (nwlRequest && smbShutdownFlag == 0);
4390 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4392 osi_Log0(smb_logp, "SMB receive get disk attributes");
4394 smb_SetSMBParm(outp, 0, 32000);
4395 smb_SetSMBParm(outp, 1, 64);
4396 smb_SetSMBParm(outp, 2, 1024);
4397 smb_SetSMBParm(outp, 3, 30000);
4398 smb_SetSMBParm(outp, 4, 0);
4399 smb_SetSMBDataLength(outp, 0);
4403 /* SMB_COM_TREE_CONNECT */
4404 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
4408 unsigned short newTid;
4409 clientchar_t shareName[AFSPATHMAX];
4410 clientchar_t *sharePath;
4413 clientchar_t *pathp;
4416 osi_Log0(smb_logp, "SMB receive tree connect");
4418 /* parse input parameters */
4421 tbp = smb_GetSMBData(inp, NULL);
4422 pathp = smb_ParseASCIIBlock(inp, tbp, &tbp, SMB_STRF_ANSIPATH);
4424 return CM_ERROR_BADSMB;
4426 tp = cm_ClientStrRChr(pathp, '\\');
4428 return CM_ERROR_BADSMB;
4429 cm_ClientStrCpy(shareName, lengthof(shareName), tp+1);
4431 lock_ObtainMutex(&vcp->mx);
4432 newTid = vcp->tidCounter++;
4433 lock_ReleaseMutex(&vcp->mx);
4435 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
4436 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
4438 return CM_ERROR_BADSMB;
4439 userp = smb_GetUserFromUID(uidp);
4440 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
4441 smb_ReleaseUID(uidp);
4443 smb_ReleaseTID(tidp, FALSE);
4444 return CM_ERROR_BADSHARENAME;
4446 lock_ObtainMutex(&tidp->mx);
4447 tidp->userp = userp;
4448 tidp->pathname = sharePath;
4449 lock_ReleaseMutex(&tidp->mx);
4450 smb_ReleaseTID(tidp, FALSE);
4452 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
4453 smb_SetSMBParm(rsp, 1, newTid);
4454 smb_SetSMBDataLength(rsp, 0);
4456 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
4460 /* set maskp to the mask part of the incoming path.
4461 * Mask is 11 bytes long (8.3 with the dot elided).
4462 * Returns true if succeeds with a valid name, otherwise it does
4463 * its best, but returns false.
4465 int smb_Get8Dot3MaskFromPath(clientchar_t *maskp, clientchar_t *pathp)
4473 /* starts off valid */
4476 /* mask starts out all blanks */
4477 memset(maskp, ' ', 11);
4480 /* find last backslash, or use whole thing if there is none */
4481 tp = cm_ClientStrRChr(pathp, '\\');
4485 tp++; /* skip slash */
4489 /* names starting with a dot are illegal */
4497 if (tc == '.' || tc == '"')
4505 /* if we get here, tp point after the dot */
4506 up = maskp+8; /* ext goes here */
4513 if (tc == '.' || tc == '"')
4516 /* copy extension if not too long */
4526 int smb_Match8Dot3Mask(clientchar_t *unixNamep, clientchar_t *maskp)
4528 clientchar_t umask[11];
4536 /* XXX redo this, calling cm_MatchMask with a converted mask */
4538 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
4542 /* otherwise, we have a valid 8.3 name; see if we have a match,
4543 * treating '?' as a wildcard in maskp (but not in the file name).
4545 tp1 = umask; /* real name, in mask format */
4546 tp2 = maskp; /* mask, in mask format */
4547 for(i=0; i<11; i++) {
4548 tc1 = *tp1++; /* clientchar_t from real name */
4549 tc2 = *tp2++; /* clientchar_t from mask */
4550 tc1 = (clientchar_t) cm_foldUpper[(clientchar_t)tc1];
4551 tc2 = (clientchar_t) cm_foldUpper[(clientchar_t)tc2];
4554 if (tc2 == '?' && tc1 != ' ')
4561 /* we got a match */
4565 clientchar_t *smb_FindMask(clientchar_t *pathp)
4569 tp = cm_ClientStrRChr(pathp, '\\'); /* find last slash */
4572 return tp+1; /* skip the slash */
4574 return pathp; /* no slash, return the entire path */
4577 /* SMB_COM_SEARCH for a volume label
4579 (This is called from smb_ReceiveCoreSearchDir() and not an actual
4580 dispatch function.) */
4581 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4583 clientchar_t *pathp;
4585 clientchar_t mask[12];
4586 unsigned char *statBlockp;
4587 unsigned char initStatBlock[21];
4590 osi_Log0(smb_logp, "SMB receive search volume");
4592 /* pull pathname and stat block out of request */
4593 tp = smb_GetSMBData(inp, NULL);
4594 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4595 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4597 return CM_ERROR_BADSMB;
4598 statBlockp = smb_ParseVblBlock(tp, &tp, &statLen);
4599 osi_assertx(statBlockp != NULL, "null statBlock");
4601 statBlockp = initStatBlock;
4605 /* for returning to caller */
4606 smb_Get8Dot3MaskFromPath(mask, pathp);
4608 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
4609 tp = smb_GetSMBData(outp, NULL);
4611 *tp++ = 43; /* bytes in a dir entry */
4612 *tp++ = 0; /* high byte in counter */
4614 /* now marshall the dir entry, starting with the search status */
4615 *tp++ = statBlockp[0]; /* Reserved */
4616 memcpy(tp, mask, 11); tp += 11; /* FileName */
4618 /* now pass back server use info, with 1st byte non-zero */
4620 memset(tp, 0, 4); tp += 4; /* reserved for server use */
4622 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
4624 *tp++ = 0x8; /* attribute: volume */
4634 /* 4 byte file size */
4640 /* The filename is a UCHAR buffer that is ASCII even if Unicode
4643 /* finally, null-terminated 8.3 pathname, which we set to AFS */
4644 memset(tp, ' ', 13);
4647 /* set the length of the data part of the packet to 43 + 3, for the dir
4648 * entry plus the 5 and the length fields.
4650 smb_SetSMBDataLength(outp, 46);
4655 smb_ApplyDirListPatches(cm_scache_t * dscp, smb_dirListPatch_t **dirPatchespp,
4656 clientchar_t * tidPathp, clientchar_t * relPathp,
4657 cm_user_t *userp, cm_req_t *reqp)
4665 smb_dirListPatch_t *patchp;
4666 smb_dirListPatch_t *npatchp;
4667 clientchar_t path[AFSPATHMAX];
4669 afs_int32 mustFake = 0;
4671 code = cm_FindACLCache(dscp, userp, &rights);
4673 lock_ObtainWrite(&dscp->rw);
4674 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4675 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4676 lock_ReleaseWrite(&dscp->rw);
4677 if (code == CM_ERROR_NOACCESS) {
4685 if (!mustFake) { /* Bulk Stat */
4687 cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4689 memset(bsp, 0, sizeof(cm_bulkStat_t));
4691 for (patchp = *dirPatchespp, count=0;
4693 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4694 cm_scache_t *tscp = cm_FindSCache(&patchp->fid);
4698 if (lock_TryWrite(&tscp->rw)) {
4699 /* we have an entry that we can look at */
4700 if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
4701 /* we have a callback on it. Don't bother
4702 * fetching this stat entry, since we're happy
4703 * with the info we have.
4705 lock_ReleaseWrite(&tscp->rw);
4706 cm_ReleaseSCache(tscp);
4709 lock_ReleaseWrite(&tscp->rw);
4711 cm_ReleaseSCache(tscp);
4715 bsp->fids[i].Volume = patchp->fid.volume;
4716 bsp->fids[i].Vnode = patchp->fid.vnode;
4717 bsp->fids[i].Unique = patchp->fid.unique;
4719 if (bsp->counter == AFSCBMAX) {
4720 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4721 memset(bsp, 0, sizeof(cm_bulkStat_t));
4725 if (bsp->counter > 0)
4726 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4731 for (patchp = *dirPatchespp; patchp; patchp =
4732 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4734 dptr = patchp->dptr;
4736 cm_ClientStrPrintfN(path, AFSPATHMAX, _C("%s\\%s"),
4737 relPathp ? relPathp : _C(""), patchp->dep->name);
4738 reqp->relPathp = path;
4739 reqp->tidPathp = tidPathp;
4741 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4742 reqp->relPathp = reqp->tidPathp = NULL;
4745 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
4746 *dptr++ = SMB_ATTR_HIDDEN;
4749 lock_ObtainWrite(&scp->rw);
4750 if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
4751 lock_ReleaseWrite(&scp->rw);
4753 /* set the attribute */
4754 switch (scp->fileType) {
4755 case CM_SCACHETYPE_DIRECTORY:
4756 case CM_SCACHETYPE_MOUNTPOINT:
4757 case CM_SCACHETYPE_INVALID:
4758 attr = SMB_ATTR_DIRECTORY;
4760 case CM_SCACHETYPE_SYMLINK:
4761 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4762 attr = SMB_ATTR_DIRECTORY;
4764 attr = SMB_ATTR_NORMAL;
4767 /* if we get here we either have a normal file
4768 * or we have a file for which we have never
4769 * received status info. In this case, we can
4770 * check the even/odd value of the entry's vnode.
4771 * odd means it is to be treated as a directory
4772 * and even means it is to be treated as a file.
4774 if (mustFake && (scp->fid.vnode & 0x1))
4775 attr = SMB_ATTR_DIRECTORY;
4777 attr = SMB_ATTR_NORMAL;
4781 /* 1969-12-31 23:59:58 +00*/
4782 dosTime = 0xEBBFBF7D;
4785 shortTemp = (unsigned short) (dosTime & 0xffff);
4786 *((u_short *)dptr) = shortTemp;
4789 /* and copy out date */
4790 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4791 *((u_short *)dptr) = shortTemp;
4794 /* copy out file length */
4795 *((u_long *)dptr) = 0;
4798 lock_ConvertWToR(&scp->rw);
4799 attr = smb_Attributes(scp);
4800 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
4801 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
4802 attr |= SMB_ATTR_HIDDEN;
4806 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4809 shortTemp = (unsigned short) (dosTime & 0xffff);
4810 *((u_short *)dptr) = shortTemp;
4813 /* and copy out date */
4814 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4815 *((u_short *)dptr) = shortTemp;
4818 /* copy out file length */
4819 *((u_long *)dptr) = scp->length.LowPart;
4821 lock_ReleaseRead(&scp->rw);
4823 cm_ReleaseSCache(scp);
4826 /* now free the patches */
4827 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4828 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4832 /* and mark the list as empty */
4833 *dirPatchespp = NULL;
4839 /* SMB_COM_SEARCH */
4840 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4846 clientchar_t *pathp;
4847 cm_dirEntry_t *dep = 0;
4849 smb_dirListPatch_t *dirListPatchesp;
4850 smb_dirListPatch_t *curPatchp;
4854 osi_hyper_t dirLength;
4855 osi_hyper_t bufferOffset;
4856 osi_hyper_t curOffset;
4858 unsigned char *inCookiep;
4859 smb_dirSearch_t *dsp;
4863 unsigned long clientCookie;
4864 cm_pageHeader_t *pageHeaderp;
4865 cm_user_t *userp = NULL;
4867 clientchar_t mask[12];
4869 long nextEntryCookie;
4870 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4871 char resByte; /* reserved byte from the cookie */
4872 char *op; /* output data ptr */
4873 char *origOp; /* original value of op */
4874 cm_space_t *spacep; /* for pathname buffer */
4878 clientchar_t *tidPathp = 0;
4885 maxCount = smb_GetSMBParm(inp, 0);
4887 dirListPatchesp = NULL;
4889 caseFold = CM_FLAG_CASEFOLD;
4891 tp = smb_GetSMBData(inp, NULL);
4892 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4893 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4895 return CM_ERROR_BADSMB;
4897 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
4899 return CM_ERROR_BADSMB;
4901 /* We can handle long names */
4902 if (vcp->flags & SMB_VCFLAG_USENT)
4903 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
4905 /* make sure we got a whole search status */
4906 if (dataLength < 21) {
4907 nextCookie = 0; /* start at the beginning of the dir */
4910 attribute = smb_GetSMBParm(inp, 1);
4912 /* handle volume info in another function */
4913 if (attribute & 0x8)
4914 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
4916 osi_Log2(smb_logp, "SMB receive search dir count %d [%S]",
4917 maxCount, osi_LogSaveClientString(smb_logp, pathp));
4919 if (*pathp == 0) { /* null pathp, treat as root dir */
4920 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
4921 return CM_ERROR_NOFILES;
4925 dsp = smb_NewDirSearch(0);
4926 dsp->attribute = attribute;
4927 smb_Get8Dot3MaskFromPath(mask, pathp);
4928 memcpy(dsp->mask, mask, 12);
4930 /* track if this is likely to match a lot of entries */
4931 if (smb_Is8Dot3StarMask(mask))
4936 /* pull the next cookie value out of the search status block */
4937 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
4938 + (inCookiep[16]<<24);
4939 dsp = smb_FindDirSearch(inCookiep[12]);
4941 /* can't find dir search status; fatal error */
4942 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%S]",
4943 inCookiep[12], nextCookie, osi_LogSaveClientString(smb_logp, pathp));
4944 return CM_ERROR_BADFD;
4946 attribute = dsp->attribute;
4947 resByte = inCookiep[0];
4949 /* copy out client cookie, in host byte order. Don't bother
4950 * interpreting it, since we're just passing it through, anyway.
4952 memcpy(&clientCookie, &inCookiep[17], 4);
4954 memcpy(mask, dsp->mask, 12);
4956 /* assume we're doing a star match if it has continued for more
4962 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
4963 nextCookie, dsp->cookie, attribute);
4965 userp = smb_GetUserFromVCP(vcp, inp);
4967 /* try to get the vnode for the path name next */
4968 lock_ObtainMutex(&dsp->mx);
4971 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
4975 spacep = inp->spacep;
4976 smb_StripLastComponent(spacep->wdata, NULL, pathp);
4977 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4979 lock_ReleaseMutex(&dsp->mx);
4980 cm_ReleaseUser(userp);
4981 smb_DeleteDirSearch(dsp);
4982 smb_ReleaseDirSearch(dsp);
4983 return CM_ERROR_NOFILES;
4985 cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
4986 cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
4988 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
4989 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
4992 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4995 pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->wdata);
4996 cm_ReleaseSCache(scp);
4997 lock_ReleaseMutex(&dsp->mx);
4998 cm_ReleaseUser(userp);
4999 smb_DeleteDirSearch(dsp);
5000 smb_ReleaseDirSearch(dsp);
5001 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5002 return CM_ERROR_PATH_NOT_COVERED;
5004 return CM_ERROR_NOSUCHPATH;
5006 #endif /* DFS_SUPPORT */
5009 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
5010 /* we need one hold for the entry we just stored into,
5011 * and one for our own processing. When we're done with this
5012 * function, we'll drop the one for our own processing.
5013 * We held it once from the namei call, and so we do another hold
5017 lock_ObtainWrite(&scp->rw);
5018 dsp->flags |= SMB_DIRSEARCH_BULKST;
5019 lock_ReleaseWrite(&scp->rw);
5022 lock_ReleaseMutex(&dsp->mx);
5024 cm_ReleaseUser(userp);
5025 smb_DeleteDirSearch(dsp);
5026 smb_ReleaseDirSearch(dsp);
5030 /* reserves space for parameter; we'll adjust it again later to the
5031 * real count of the # of entries we returned once we've actually
5032 * assembled the directory listing.
5034 smb_SetSMBParm(outp, 0, 0);
5036 /* get the directory size */
5037 lock_ObtainWrite(&scp->rw);
5038 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5039 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5041 lock_ReleaseWrite(&scp->rw);
5042 cm_ReleaseSCache(scp);
5043 cm_ReleaseUser(userp);
5044 smb_DeleteDirSearch(dsp);
5045 smb_ReleaseDirSearch(dsp);
5049 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5051 dirLength = scp->length;
5053 bufferOffset.LowPart = bufferOffset.HighPart = 0;
5054 curOffset.HighPart = 0;
5055 curOffset.LowPart = nextCookie;
5056 origOp = op = smb_GetSMBData(outp, NULL);
5057 /* and write out the basic header */
5058 *op++ = 5; /* variable block */
5059 op += 2; /* skip vbl block length; we'll fill it in later */
5063 clientchar_t *actualName = NULL;
5064 int free_actualName = 0;
5065 clientchar_t shortName[13];
5066 clientchar_t *shortNameEnd;
5068 /* make sure that curOffset.LowPart doesn't point to the first
5069 * 32 bytes in the 2nd through last dir page, and that it doesn't
5070 * point at the first 13 32-byte chunks in the first dir page,
5071 * since those are dir and page headers, and don't contain useful
5074 temp = curOffset.LowPart & (2048-1);
5075 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
5076 /* we're in the first page */
5077 if (temp < 13*32) temp = 13*32;
5080 /* we're in a later dir page */
5081 if (temp < 32) temp = 32;
5084 /* make sure the low order 5 bits are zero */
5087 /* now put temp bits back ito curOffset.LowPart */
5088 curOffset.LowPart &= ~(2048-1);
5089 curOffset.LowPart |= temp;
5091 /* check if we've returned all the names that will fit in the
5094 if (returnedNames >= maxCount) {
5095 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
5096 returnedNames, maxCount);
5100 /* check if we've passed the dir's EOF */
5101 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
5103 /* see if we can use the bufferp we have now; compute in which page
5104 * the current offset would be, and check whether that's the offset
5105 * of the buffer we have. If not, get the buffer.
5107 thyper.HighPart = curOffset.HighPart;
5108 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
5109 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5112 buf_Release(bufferp);
5115 lock_ReleaseWrite(&scp->rw);
5116 code = buf_Get(scp, &thyper, &req, &bufferp);
5117 lock_ObtainMutex(&dsp->mx);
5119 /* now, if we're doing a star match, do bulk fetching of all of
5120 * the status info for files in the dir.
5123 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
5125 lock_ObtainWrite(&scp->rw);
5126 lock_ReleaseMutex(&dsp->mx);
5128 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
5132 bufferOffset = thyper;
5134 /* now get the data in the cache */
5136 code = cm_SyncOp(scp, bufferp, userp, &req,
5138 CM_SCACHESYNC_NEEDCALLBACK |
5139 CM_SCACHESYNC_READ);
5141 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
5145 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5147 if (cm_HaveBuffer(scp, bufferp, 0)) {
5148 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
5152 /* otherwise, load the buffer and try again */
5153 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
5155 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
5156 scp, bufferp, code);
5161 buf_Release(bufferp);
5165 } /* if (wrong buffer) ... */
5167 /* now we have the buffer containing the entry we're interested in; copy
5168 * it out if it represents a non-deleted entry.
5170 entryInDir = curOffset.LowPart & (2048-1);
5171 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5173 /* page header will help tell us which entries are free. Page header
5174 * can change more often than once per buffer, since AFS 3 dir page size
5175 * may be less than (but not more than a buffer package buffer.
5177 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
5178 temp &= ~(2048 - 1); /* turn off intra-page bits */
5179 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5181 /* now determine which entry we're looking at in the page. If it is
5182 * free (there's a free bitmap at the start of the dir), we should
5183 * skip these 32 bytes.
5185 slotInPage = (entryInDir & 0x7e0) >> 5;
5186 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
5187 /* this entry is free */
5188 numDirChunks = 1; /* only skip this guy */
5192 tp = bufferp->datap + entryInBuffer;
5193 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
5195 /* while we're here, compute the next entry's location, too,
5196 * since we'll need it when writing out the cookie into the dir
5199 * XXXX Probably should do more sanity checking.
5201 numDirChunks = cm_NameEntries(dep->name, NULL);
5203 /* compute the offset of the cookie representing the next entry */
5204 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5206 /* Compute 8.3 name if necessary */
5207 actualName = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
5208 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
5211 cm_Gen8Dot3NameInt(dep->name, &dep->fid, shortName, &shortNameEnd);
5212 actualName = shortName;
5213 free_actualName = 0;
5215 free_actualName = 1;
5218 if (actualName == NULL) {
5219 /* Couldn't convert the name for some reason */
5220 osi_Log1(smb_logp, "SMB search dir skipping entry :[%s]",
5221 osi_LogSaveString(smb_logp, dep->name));
5225 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%S)",
5226 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
5227 osi_LogSaveClientString(smb_logp, actualName));
5229 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
5230 /* this is one of the entries to use: it is not deleted
5231 * and it matches the star pattern we're looking for.
5234 /* Eliminate entries that don't match requested
5237 /* no hidden files */
5238 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
5239 osi_Log0(smb_logp, "SMB search dir skipping hidden");
5243 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
5245 /* We have already done the cm_TryBulkStat above */
5246 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5247 fileType = cm_FindFileType(&fid);
5248 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
5249 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
5251 if (fileType == CM_SCACHETYPE_DIRECTORY ||
5252 fileType == CM_SCACHETYPE_MOUNTPOINT ||
5253 fileType == CM_SCACHETYPE_DFSLINK ||
5254 fileType == CM_SCACHETYPE_INVALID)
5255 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
5260 memcpy(op, mask, 11); op += 11;
5261 *op++ = (unsigned char) dsp->cookie; /* they say it must be non-zero */
5262 *op++ = (unsigned char)(nextEntryCookie & 0xff);
5263 *op++ = (unsigned char)((nextEntryCookie>>8) & 0xff);
5264 *op++ = (unsigned char)((nextEntryCookie>>16) & 0xff);
5265 *op++ = (unsigned char)((nextEntryCookie>>24) & 0xff);
5266 memcpy(op, &clientCookie, 4); op += 4;
5268 /* now we emit the attribute. This is sort of tricky,
5269 * since we need to really stat the file to find out
5270 * what type of entry we've got. Right now, we're
5271 * copying out data from a buffer, while holding the
5272 * scp locked, so it isn't really convenient to stat
5273 * something now. We'll put in a place holder now,
5274 * and make a second pass before returning this to get
5275 * the real attributes. So, we just skip the data for
5276 * now, and adjust it later. We allocate a patch
5277 * record to make it easy to find this point later.
5278 * The replay will happen at a time when it is safe to
5279 * unlock the directory.
5281 curPatchp = malloc(sizeof(*curPatchp));
5282 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
5283 curPatchp->dptr = op;
5284 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5286 /* do hidden attribute here since name won't be around when applying
5290 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
5291 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5293 curPatchp->flags = 0;
5295 op += 9; /* skip attr, time, date and size */
5297 /* zero out name area. The spec says to pad with
5298 * spaces, but Samba doesn't, and neither do we.
5302 /* finally, we get to copy out the name; we know that
5303 * it fits in 8.3 or the pattern wouldn't match, but it
5304 * never hurts to be sure.
5306 cm_ClientStringToUtf8(actualName, -1, op, 13);
5307 if (smb_StoreAnsiFilenames)
5309 /* This is a UCHAR field, which is ASCII even if Unicode
5312 /* Uppercase if requested by client */
5313 if (!KNOWS_LONG_NAMES(inp))
5318 /* now, adjust the # of entries copied */
5320 } /* if we're including this name */
5323 if (free_actualName && actualName) {
5328 /* and adjust curOffset to be where the new cookie is */
5329 thyper.HighPart = 0;
5330 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5331 curOffset = LargeIntegerAdd(thyper, curOffset);
5332 } /* while copying data for dir listing */
5334 /* release the mutex */
5335 lock_ReleaseWrite(&scp->rw);
5337 buf_Release(bufferp);
5341 /* apply and free last set of patches; if not doing a star match, this
5342 * will be empty, but better safe (and freeing everything) than sorry.
5344 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
5346 /* special return code for unsuccessful search */
5347 if (code == 0 && dataLength < 21 && returnedNames == 0)
5348 code = CM_ERROR_NOFILES;
5350 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
5351 returnedNames, code);
5354 smb_DeleteDirSearch(dsp);
5355 smb_ReleaseDirSearch(dsp);
5356 cm_ReleaseSCache(scp);
5357 cm_ReleaseUser(userp);
5361 /* finalize the output buffer */
5362 smb_SetSMBParm(outp, 0, returnedNames);
5363 temp = (long) (op - origOp);
5364 smb_SetSMBDataLength(outp, temp);
5366 /* the data area is a variable block, which has a 5 (already there)
5367 * followed by the length of the # of data bytes. We now know this to
5368 * be "temp," although that includes the 3 bytes of vbl block header.
5369 * Deduct for them and fill in the length field.
5371 temp -= 3; /* deduct vbl block info */
5372 osi_assertx(temp == (43 * returnedNames), "unexpected data length");
5373 origOp[1] = (unsigned char)(temp & 0xff);
5374 origOp[2] = (unsigned char)((temp>>8) & 0xff);
5375 if (returnedNames == 0)
5376 smb_DeleteDirSearch(dsp);
5377 smb_ReleaseDirSearch(dsp);
5378 cm_ReleaseSCache(scp);
5379 cm_ReleaseUser(userp);
5384 /* verify that this is a valid path to a directory. I don't know why they
5385 * don't use the get file attributes call.
5387 * SMB_COM_CHECK_DIRECTORY
5389 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5391 clientchar_t *pathp;
5393 cm_scache_t *rootScp;
5394 cm_scache_t *newScp;
5398 clientchar_t *tidPathp;
5404 pdata = smb_GetSMBData(inp, NULL);
5405 pathp = smb_ParseASCIIBlock(inp, pdata, NULL, SMB_STRF_ANSIPATH);
5407 return CM_ERROR_BADSMB;
5408 osi_Log1(smb_logp, "SMB receive check path %S",
5409 osi_LogSaveClientString(smb_logp, pathp));
5411 rootScp = cm_data.rootSCachep;
5413 userp = smb_GetUserFromVCP(vcp, inp);
5415 caseFold = CM_FLAG_CASEFOLD;
5417 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5419 cm_ReleaseUser(userp);
5420 return CM_ERROR_NOSUCHPATH;
5422 code = cm_NameI(rootScp, pathp,
5423 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
5424 userp, tidPathp, &req, &newScp);
5427 cm_ReleaseUser(userp);
5432 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5433 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5434 cm_ReleaseSCache(newScp);
5435 cm_ReleaseUser(userp);
5436 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5437 return CM_ERROR_PATH_NOT_COVERED;
5439 return CM_ERROR_NOSUCHPATH;
5441 #endif /* DFS_SUPPORT */
5443 /* now lock the vnode with a callback; returns with newScp locked */
5444 lock_ObtainWrite(&newScp->rw);
5445 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
5446 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5448 if (code != CM_ERROR_NOACCESS) {
5449 lock_ReleaseWrite(&newScp->rw);
5450 cm_ReleaseSCache(newScp);
5451 cm_ReleaseUser(userp);
5455 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5458 attrs = smb_Attributes(newScp);
5460 if (!(attrs & SMB_ATTR_DIRECTORY))
5461 code = CM_ERROR_NOTDIR;
5463 lock_ReleaseWrite(&newScp->rw);
5465 cm_ReleaseSCache(newScp);
5466 cm_ReleaseUser(userp);
5470 /* SMB_COM_SET_INFORMATION */
5471 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5473 clientchar_t *pathp;
5475 cm_scache_t *rootScp;
5476 unsigned short attribute;
5478 cm_scache_t *newScp;
5482 clientchar_t *tidPathp;
5488 /* decode basic attributes we're passed */
5489 attribute = smb_GetSMBParm(inp, 0);
5490 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5492 datap = smb_GetSMBData(inp, NULL);
5493 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5495 return CM_ERROR_BADSMB;
5497 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
5498 dosTime, attribute);
5500 rootScp = cm_data.rootSCachep;
5502 userp = smb_GetUserFromVCP(vcp, inp);
5504 caseFold = CM_FLAG_CASEFOLD;
5506 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5508 cm_ReleaseUser(userp);
5509 return CM_ERROR_NOSUCHFILE;
5511 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5512 tidPathp, &req, &newScp);
5515 cm_ReleaseUser(userp);
5520 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5521 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5522 cm_ReleaseSCache(newScp);
5523 cm_ReleaseUser(userp);
5524 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5525 return CM_ERROR_PATH_NOT_COVERED;
5527 return CM_ERROR_NOSUCHPATH;
5529 #endif /* DFS_SUPPORT */
5531 /* now lock the vnode with a callback; returns with newScp locked; we
5532 * need the current status to determine what the new status is, in some
5535 lock_ObtainWrite(&newScp->rw);
5536 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5537 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5539 lock_ReleaseWrite(&newScp->rw);
5540 cm_ReleaseSCache(newScp);
5541 cm_ReleaseUser(userp);
5545 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5547 /* Check for RO volume */
5548 if (newScp->flags & CM_SCACHEFLAG_RO) {
5549 lock_ReleaseWrite(&newScp->rw);
5550 cm_ReleaseSCache(newScp);
5551 cm_ReleaseUser(userp);
5552 return CM_ERROR_READONLY;
5555 /* prepare for setattr call */
5558 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
5559 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
5561 if ((newScp->unixModeBits & 0222) && (attribute & SMB_ATTR_READONLY) != 0) {
5562 /* we're told to make a writable file read-only */
5563 attr.unixModeBits = newScp->unixModeBits & ~0222;
5564 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5566 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
5567 /* we're told to make a read-only file writable */
5568 attr.unixModeBits = newScp->unixModeBits | 0222;
5569 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5571 lock_ReleaseWrite(&newScp->rw);
5573 /* now call setattr */
5575 code = cm_SetAttr(newScp, &attr, userp, &req);
5579 cm_ReleaseSCache(newScp);
5580 cm_ReleaseUser(userp);
5586 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5588 clientchar_t *pathp;
5590 cm_scache_t *rootScp;
5591 cm_scache_t *newScp, *dscp;
5596 clientchar_t *tidPathp;
5598 clientchar_t *lastComp;
5604 datap = smb_GetSMBData(inp, NULL);
5605 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5607 return CM_ERROR_BADSMB;
5609 if (*pathp == 0) /* null path */
5612 osi_Log1(smb_logp, "SMB receive getfile attributes path %S",
5613 osi_LogSaveClientString(smb_logp, pathp));
5615 rootScp = cm_data.rootSCachep;
5617 userp = smb_GetUserFromVCP(vcp, inp);
5619 /* we shouldn't need this for V3 requests, but we seem to */
5620 caseFold = CM_FLAG_CASEFOLD;
5622 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5624 cm_ReleaseUser(userp);
5625 return CM_ERROR_NOSUCHFILE;
5629 * XXX Strange hack XXX
5631 * As of Patch 5 (16 July 97), we are having the following problem:
5632 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
5633 * requests to look up "desktop.ini" in all the subdirectories.
5634 * This can cause zillions of timeouts looking up non-existent cells
5635 * and volumes, especially in the top-level directory.
5637 * We have not found any way to avoid this or work around it except
5638 * to explicitly ignore the requests for mount points that haven't
5639 * yet been evaluated and for directories that haven't yet been
5642 * We should modify this hack to provide a fake desktop.ini file
5643 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
5645 spacep = inp->spacep;
5646 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
5647 #ifndef SPECIAL_FOLDERS
5648 if (lastComp && cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
5649 code = cm_NameI(rootScp, spacep->wdata,
5650 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
5651 userp, tidPathp, &req, &dscp);
5654 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5655 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
5657 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5658 return CM_ERROR_PATH_NOT_COVERED;
5660 return CM_ERROR_NOSUCHPATH;
5662 #endif /* DFS_SUPPORT */
5663 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
5664 code = CM_ERROR_NOSUCHFILE;
5665 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
5666 cm_buf_t *bp = buf_Find(dscp, &hzero);
5671 code = CM_ERROR_NOSUCHFILE;
5673 cm_ReleaseSCache(dscp);
5675 cm_ReleaseUser(userp);
5680 #endif /* SPECIAL_FOLDERS */
5682 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5683 tidPathp, &req, &newScp);
5685 cm_ReleaseUser(userp);
5690 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5691 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5692 cm_ReleaseSCache(newScp);
5693 cm_ReleaseUser(userp);
5694 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5695 return CM_ERROR_PATH_NOT_COVERED;
5697 return CM_ERROR_NOSUCHPATH;
5699 #endif /* DFS_SUPPORT */
5701 /* now lock the vnode with a callback; returns with newScp locked */
5702 lock_ObtainWrite(&newScp->rw);
5703 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5704 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5706 lock_ReleaseWrite(&newScp->rw);
5707 cm_ReleaseSCache(newScp);
5708 cm_ReleaseUser(userp);
5712 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5714 attrs = smb_Attributes(newScp);
5716 smb_SetSMBParm(outp, 0, attrs);
5718 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
5719 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
5720 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
5721 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
5722 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
5723 smb_SetSMBParm(outp, 5, 0);
5724 smb_SetSMBParm(outp, 6, 0);
5725 smb_SetSMBParm(outp, 7, 0);
5726 smb_SetSMBParm(outp, 8, 0);
5727 smb_SetSMBParm(outp, 9, 0);
5728 smb_SetSMBDataLength(outp, 0);
5729 lock_ReleaseWrite(&newScp->rw);
5731 cm_ReleaseSCache(newScp);
5732 cm_ReleaseUser(userp);
5737 /* SMB_COM_TREE_DISCONNECT */
5738 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5742 osi_Log0(smb_logp, "SMB receive tree disconnect");
5744 /* find the tree and free it */
5745 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
5747 lock_ObtainWrite(&smb_rctLock);
5749 smb_ReleaseTID(tidp, TRUE);
5750 lock_ReleaseWrite(&smb_rctLock);
5757 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5760 clientchar_t *pathp;
5761 clientchar_t *lastNamep;
5770 clientchar_t *tidPathp;
5776 datap = smb_GetSMBData(inp, NULL);
5777 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5779 return CM_ERROR_BADSMB;
5781 osi_Log1(smb_logp, "SMB receive open file [%S]", osi_LogSaveClientString(smb_logp, pathp));
5783 #ifdef DEBUG_VERBOSE
5787 hexpath = osi_HexifyString( pathp );
5788 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
5793 if (!cm_IsValidClientString(pathp)) {
5795 clientchar_t * hexp;
5797 hexp = cm_GetRawCharsAlloc(pathp, -1);
5798 osi_Log1(smb_logp, "CoreOpen rejecting invalid name. [%S]",
5799 osi_LogSaveClientString(smb_logp, hexp));
5803 osi_Log0(smb_logp, "CoreOpen rejecting invalid name");
5805 return CM_ERROR_BADNTFILENAME;
5808 share = smb_GetSMBParm(inp, 0);
5809 attribute = smb_GetSMBParm(inp, 1);
5811 spacep = inp->spacep;
5812 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5813 if (lastNamep && cm_ClientStrCmp(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0) {
5814 /* special case magic file name for receiving IOCTL requests
5815 * (since IOCTL calls themselves aren't getting through).
5817 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5818 smb_SetupIoctlFid(fidp, spacep);
5819 smb_SetSMBParm(outp, 0, fidp->fid);
5820 smb_SetSMBParm(outp, 1, 0); /* attrs */
5821 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
5822 smb_SetSMBParm(outp, 3, 0);
5823 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
5824 smb_SetSMBParm(outp, 5, 0x7fff);
5825 /* pass the open mode back */
5826 smb_SetSMBParm(outp, 6, (share & 0xf));
5827 smb_SetSMBDataLength(outp, 0);
5828 smb_ReleaseFID(fidp);
5832 userp = smb_GetUserFromVCP(vcp, inp);
5834 caseFold = CM_FLAG_CASEFOLD;
5836 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5838 cm_ReleaseUser(userp);
5839 return CM_ERROR_NOSUCHPATH;
5841 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5842 tidPathp, &req, &scp);
5845 cm_ReleaseUser(userp);
5850 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5851 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
5852 cm_ReleaseSCache(scp);
5853 cm_ReleaseUser(userp);
5854 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5855 return CM_ERROR_PATH_NOT_COVERED;
5857 return CM_ERROR_NOSUCHPATH;
5859 #endif /* DFS_SUPPORT */
5861 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
5863 cm_ReleaseSCache(scp);
5864 cm_ReleaseUser(userp);
5868 /* don't need callback to check file type, since file types never
5869 * change, and namei and cm_Lookup all stat the object at least once on
5870 * a successful return.
5872 if (scp->fileType != CM_SCACHETYPE_FILE) {
5873 cm_ReleaseSCache(scp);
5874 cm_ReleaseUser(userp);
5875 return CM_ERROR_ISDIR;
5878 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5879 osi_assertx(fidp, "null smb_fid_t");
5881 lock_ObtainMutex(&fidp->mx);
5882 if ((share & 0xf) == 0)
5883 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5884 else if ((share & 0xf) == 1)
5885 fidp->flags |= SMB_FID_OPENWRITE;
5887 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
5891 fidp->userp = userp;
5893 /* and a pointer to the vnode */
5895 osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
5896 lock_ObtainWrite(&scp->rw);
5897 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5899 smb_SetSMBParm(outp, 0, fidp->fid);
5900 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
5901 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5902 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
5903 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
5904 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
5905 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
5906 /* pass the open mode back; XXXX add access checks */
5907 smb_SetSMBParm(outp, 6, (share & 0xf));
5908 smb_SetSMBDataLength(outp, 0);
5909 lock_ReleaseMutex(&fidp->mx);
5910 lock_ReleaseRead(&scp->rw);
5913 cm_Open(scp, 0, userp);
5915 /* send and free packet */
5916 smb_ReleaseFID(fidp);
5917 cm_ReleaseUser(userp);
5918 /* don't release scp, since we've squirreled away the pointer in the fid struct */
5922 typedef struct smb_unlinkRock {
5927 clientchar_t *maskp; /* pointer to the star pattern */
5930 cm_dirEntryList_t * matches;
5933 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5936 smb_unlinkRock_t *rockp;
5939 normchar_t matchName[MAX_PATH];
5943 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5944 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5945 caseFold |= CM_FLAG_8DOT3;
5947 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
5948 /* Can't convert name */
5949 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string.",
5950 osi_LogSaveString(smb_logp, dep->name));
5954 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5956 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5957 !cm_Is8Dot3(matchName)) {
5958 cm_Gen8Dot3Name(dep, matchName, NULL);
5959 /* 8.3 matches are always case insensitive */
5960 match = cm_MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
5963 osi_Log1(smb_logp, "Found match %S",
5964 osi_LogSaveClientString(smb_logp, matchName));
5966 cm_DirEntryListAdd(dep->name, &rockp->matches);
5970 /* If we made a case sensitive exact match, we might as well quit now. */
5971 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !cm_ClientStrCmp(matchName, rockp->maskp))
5972 code = CM_ERROR_STOPNOW;
5981 /* SMB_COM_DELETE */
5982 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5986 clientchar_t *pathp;
5990 clientchar_t *lastNamep;
5991 smb_unlinkRock_t rock;
5995 clientchar_t *tidPathp;
5999 memset(&rock, 0, sizeof(rock));
6001 attribute = smb_GetSMBParm(inp, 0);
6003 tp = smb_GetSMBData(inp, NULL);
6004 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6006 return CM_ERROR_BADSMB;
6008 osi_Log1(smb_logp, "SMB receive unlink %S",
6009 osi_LogSaveClientString(smb_logp, pathp));
6011 spacep = inp->spacep;
6012 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
6014 userp = smb_GetUserFromVCP(vcp, inp);
6016 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6018 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6020 cm_ReleaseUser(userp);
6021 return CM_ERROR_NOSUCHPATH;
6023 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold, userp, tidPathp,
6026 cm_ReleaseUser(userp);
6031 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6032 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
6033 cm_ReleaseSCache(dscp);
6034 cm_ReleaseUser(userp);
6035 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6036 return CM_ERROR_PATH_NOT_COVERED;
6038 return CM_ERROR_NOSUCHPATH;
6040 #endif /* DFS_SUPPORT */
6042 /* otherwise, scp points to the parent directory. */
6049 rock.maskp = cm_ClientStringToNormStringAlloc(smb_FindMask(pathp), -1, NULL);
6051 code = CM_ERROR_NOSUCHFILE;
6054 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6057 thyper.HighPart = 0;
6062 rock.matches = NULL;
6064 /* Now, if we aren't dealing with a wildcard match, we first try an exact
6065 * match. If that fails, we do a case insensitve match.
6067 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
6068 !smb_IsStarMask(rock.maskp)) {
6069 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
6072 thyper.HighPart = 0;
6073 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6078 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
6080 if (code == CM_ERROR_STOPNOW)
6083 if (code == 0 && rock.matches) {
6084 cm_dirEntryList_t * entry;
6086 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
6087 normchar_t normalizedName[MAX_PATH];
6089 /* Note: entry->name is a non-normalized name */
6091 osi_Log1(smb_logp, "Unlinking %s",
6092 osi_LogSaveString(smb_logp, entry->name));
6094 /* We assume this works because entry->name was
6095 successfully converted in smb_UnlinkProc() once. */
6096 cm_FsStringToNormString(entry->name, -1,
6097 normalizedName, lengthof(normalizedName));
6099 code = cm_Unlink(dscp, entry->name, normalizedName, userp, &req);
6101 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6102 smb_NotifyChange(FILE_ACTION_REMOVED,
6103 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6104 dscp, normalizedName, NULL, TRUE);
6108 cm_DirEntryListFree(&rock.matches);
6112 cm_ReleaseUser(userp);
6115 cm_ReleaseSCache(dscp);
6120 if (code == 0 && !rock.any)
6121 code = CM_ERROR_NOSUCHFILE;
6125 typedef struct smb_renameRock {
6126 cm_scache_t *odscp; /* old dir */
6127 cm_scache_t *ndscp; /* new dir */
6128 cm_user_t *userp; /* user */
6129 cm_req_t *reqp; /* request struct */
6130 smb_vc_t *vcp; /* virtual circuit */
6131 normchar_t *maskp; /* pointer to star pattern of old file name */
6132 int flags; /* tilde, casefold, etc */
6133 clientchar_t *newNamep; /* ptr to the new file's name */
6134 fschar_t fsOldName[MAX_PATH]; /* raw FS name */
6135 clientchar_t clOldName[MAX_PATH]; /* client name */
6139 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6142 smb_renameRock_t *rockp;
6145 normchar_t matchName[MAX_PATH];
6147 rockp = (smb_renameRock_t *) vrockp;
6149 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6150 /* Can't convert string */
6151 osi_Log1(smb_logp, "Skpping entry [%s]. Can't normalize FS string",
6152 osi_LogSaveString(smb_logp, dep->name));
6156 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
6157 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
6158 caseFold |= CM_FLAG_8DOT3;
6160 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
6162 (rockp->flags & SMB_MASKFLAG_TILDE) &&
6163 !cm_Is8Dot3(matchName)) {
6164 cm_Gen8Dot3Name(dep, matchName, NULL);
6165 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
6170 StringCbCopyA(rockp->fsOldName, sizeof(rockp->fsOldName), dep->name);
6171 cm_ClientStrCpy(rockp->clOldName, lengthof(rockp->clOldName),
6173 code = CM_ERROR_STOPNOW;
6183 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp, int attrs)
6186 cm_space_t *spacep = NULL;
6187 smb_renameRock_t rock;
6188 cm_scache_t *oldDscp = NULL;
6189 cm_scache_t *newDscp = NULL;
6190 cm_scache_t *tmpscp= NULL;
6191 cm_scache_t *tmpscp2 = NULL;
6192 clientchar_t *oldLastNamep;
6193 clientchar_t *newLastNamep;
6197 clientchar_t *tidPathp;
6201 userp = smb_GetUserFromVCP(vcp, inp);
6202 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6204 cm_ReleaseUser(userp);
6205 return CM_ERROR_NOSUCHPATH;
6209 memset(&rock, 0, sizeof(rock));
6211 spacep = inp->spacep;
6212 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6214 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6215 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6216 userp, tidPathp, &req, &oldDscp);
6218 cm_ReleaseUser(userp);
6223 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6224 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6225 cm_ReleaseSCache(oldDscp);
6226 cm_ReleaseUser(userp);
6227 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6228 return CM_ERROR_PATH_NOT_COVERED;
6230 return CM_ERROR_NOSUCHPATH;
6232 #endif /* DFS_SUPPORT */
6234 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6235 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6236 userp, tidPathp, &req, &newDscp);
6239 cm_ReleaseSCache(oldDscp);
6240 cm_ReleaseUser(userp);
6245 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6246 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6247 cm_ReleaseSCache(oldDscp);
6248 cm_ReleaseSCache(newDscp);
6249 cm_ReleaseUser(userp);
6250 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6251 return CM_ERROR_PATH_NOT_COVERED;
6253 return CM_ERROR_NOSUCHPATH;
6255 #endif /* DFS_SUPPORT */
6258 /* otherwise, oldDscp and newDscp point to the corresponding directories.
6259 * next, get the component names, and lower case them.
6262 /* handle the old name first */
6264 oldLastNamep = oldPathp;
6268 /* and handle the new name, too */
6270 newLastNamep = newPathp;
6274 /* TODO: The old name could be a wildcard. The new name must not be */
6276 /* Check if the file already exists; if so return error */
6277 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6278 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6279 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6281 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6282 osi_LogSaveClientString(smb_logp, newLastNamep));
6284 /* Check if the old and the new names differ only in case. If so return
6285 * success, else return CM_ERROR_EXISTS
6287 if (!code && oldDscp == newDscp && !cm_ClientStrCmpI(oldLastNamep, newLastNamep)) {
6289 /* This would be a success only if the old file is *as same as* the new file */
6290 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
6292 if (tmpscp == tmpscp2)
6295 code = CM_ERROR_EXISTS;
6296 cm_ReleaseSCache(tmpscp2);
6299 code = CM_ERROR_NOSUCHFILE;
6302 /* file exist, do not rename, also fixes move */
6303 osi_Log0(smb_logp, "Can't rename. Target already exists");
6304 code = CM_ERROR_EXISTS;
6309 /* do the vnode call */
6310 rock.odscp = oldDscp;
6311 rock.ndscp = newDscp;
6315 rock.maskp = cm_ClientStringToNormStringAlloc(oldLastNamep, -1, NULL);
6317 code = CM_ERROR_NOSUCHFILE;
6320 rock.flags = ((cm_ClientStrChr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6321 rock.newNamep = newLastNamep;
6322 rock.fsOldName[0] = '\0';
6323 rock.clOldName[0] = '\0';
6326 /* Now search the directory for the pattern, and do the appropriate rename when found */
6327 thyper.LowPart = 0; /* search dir from here */
6328 thyper.HighPart = 0;
6330 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6331 if (code == 0 && !rock.any) {
6333 thyper.HighPart = 0;
6334 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6335 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6337 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
6339 if (code == CM_ERROR_STOPNOW && rock.fsOldName[0] != '\0') {
6340 code = cm_Rename(rock.odscp, rock.fsOldName, rock.clOldName,
6341 rock.ndscp, rock.newNamep, rock.userp,
6343 /* if the call worked, stop doing the search now, since we
6344 * really only want to rename one file.
6347 osi_Log0(smb_logp, "cm_Rename failure");
6348 osi_Log1(smb_logp, "cm_Rename returns %ld", code);
6349 } else if (code == 0) {
6350 code = CM_ERROR_NOSUCHFILE;
6353 /* Handle Change Notification */
6355 * Being lazy, not distinguishing between files and dirs in this
6356 * filter, since we'd have to do a lookup.
6359 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
6360 if (oldDscp == newDscp) {
6361 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6362 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6363 filter, oldDscp, rock.clOldName,
6364 newLastNamep, TRUE);
6366 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6367 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6368 filter, oldDscp, rock.clOldName,
6370 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6371 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
6372 filter, newDscp, newLastNamep,
6379 cm_ReleaseSCache(tmpscp);
6381 cm_ReleaseUser(userp);
6383 cm_ReleaseSCache(oldDscp);
6385 cm_ReleaseSCache(newDscp);
6393 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp)
6396 cm_space_t *spacep = NULL;
6397 cm_scache_t *oldDscp = NULL;
6398 cm_scache_t *newDscp = NULL;
6399 cm_scache_t *tmpscp= NULL;
6400 cm_scache_t *tmpscp2 = NULL;
6401 cm_scache_t *sscp = NULL;
6402 clientchar_t *oldLastNamep;
6403 clientchar_t *newLastNamep;
6406 clientchar_t *tidPathp;
6410 userp = smb_GetUserFromVCP(vcp, inp);
6412 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6414 cm_ReleaseUser(userp);
6415 return CM_ERROR_NOSUCHPATH;
6420 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6422 spacep = inp->spacep;
6423 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6425 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6426 userp, tidPathp, &req, &oldDscp);
6428 cm_ReleaseUser(userp);
6433 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6434 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6435 cm_ReleaseSCache(oldDscp);
6436 cm_ReleaseUser(userp);
6437 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6438 return CM_ERROR_PATH_NOT_COVERED;
6440 return CM_ERROR_NOSUCHPATH;
6442 #endif /* DFS_SUPPORT */
6444 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6445 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6446 userp, tidPathp, &req, &newDscp);
6448 cm_ReleaseSCache(oldDscp);
6449 cm_ReleaseUser(userp);
6454 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6455 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6456 cm_ReleaseSCache(newDscp);
6457 cm_ReleaseSCache(oldDscp);
6458 cm_ReleaseUser(userp);
6459 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6460 return CM_ERROR_PATH_NOT_COVERED;
6462 return CM_ERROR_NOSUCHPATH;
6464 #endif /* DFS_SUPPORT */
6466 /* Now, although we did two lookups for the two directories (because the same
6467 * directory can be referenced through different paths), we only allow hard links
6468 * within the same directory. */
6469 if (oldDscp != newDscp) {
6470 cm_ReleaseSCache(oldDscp);
6471 cm_ReleaseSCache(newDscp);
6472 cm_ReleaseUser(userp);
6473 return CM_ERROR_CROSSDEVLINK;
6476 /* handle the old name first */
6478 oldLastNamep = oldPathp;
6482 /* and handle the new name, too */
6484 newLastNamep = newPathp;
6488 /* now lookup the old name */
6489 osi_Log1(smb_logp," looking up [%S]", osi_LogSaveClientString(smb_logp,oldLastNamep));
6490 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
6492 cm_ReleaseSCache(oldDscp);
6493 cm_ReleaseSCache(newDscp);
6494 cm_ReleaseUser(userp);
6498 /* Check if the file already exists; if so return error */
6499 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6500 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6501 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6503 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6504 osi_LogSaveClientString(smb_logp, newLastNamep));
6506 /* if the existing link is to the same file, then we return success */
6508 if(sscp == tmpscp) {
6511 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
6512 code = CM_ERROR_EXISTS;
6517 cm_ReleaseSCache(tmpscp);
6518 cm_ReleaseSCache(sscp);
6519 cm_ReleaseSCache(newDscp);
6520 cm_ReleaseSCache(oldDscp);
6521 cm_ReleaseUser(userp);
6525 /* now create the hardlink */
6526 osi_Log1(smb_logp," Attempting to create new link [%S]", osi_LogSaveClientString(smb_logp, newLastNamep));
6527 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
6528 osi_Log1(smb_logp," Link returns 0x%x", code);
6530 /* Handle Change Notification */
6532 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
6533 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6534 smb_NotifyChange(FILE_ACTION_ADDED,
6535 filter, newDscp, newLastNamep,
6540 cm_ReleaseSCache(tmpscp);
6541 cm_ReleaseUser(userp);
6542 cm_ReleaseSCache(sscp);
6543 cm_ReleaseSCache(oldDscp);
6544 cm_ReleaseSCache(newDscp);
6548 /* SMB_COM_RENAME */
6550 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6552 clientchar_t *oldPathp;
6553 clientchar_t *newPathp;
6557 tp = smb_GetSMBData(inp, NULL);
6558 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6560 return CM_ERROR_BADSMB;
6561 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6563 return CM_ERROR_BADSMB;
6565 osi_Log2(smb_logp, "smb rename [%S] to [%S]",
6566 osi_LogSaveClientString(smb_logp, oldPathp),
6567 osi_LogSaveClientString(smb_logp, newPathp));
6569 if (!cm_IsValidClientString(newPathp)) {
6571 clientchar_t * hexp;
6573 hexp = cm_GetRawCharsAlloc(newPathp, -1);
6574 osi_Log1(smb_logp, "CoreRename rejecting invalid name. [%S]",
6575 osi_LogSaveClientString(smb_logp, hexp));
6579 osi_Log0(smb_logp, "CoreRename rejecting invalid name");
6581 return CM_ERROR_BADNTFILENAME;
6584 code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
6586 osi_Log1(smb_logp, "smb rename returns 0x%x", code);
6592 typedef struct smb_rmdirRock {
6596 normchar_t *maskp; /* pointer to the star pattern */
6599 cm_dirEntryList_t * matches;
6602 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6605 smb_rmdirRock_t *rockp;
6607 normchar_t matchName[MAX_PATH];
6609 rockp = (smb_rmdirRock_t *) vrockp;
6611 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6612 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6613 osi_LogSaveString(smb_logp, dep->name));
6617 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
6618 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6620 match = (cm_ClientStrCmp(matchName, rockp->maskp) == 0);
6622 (rockp->flags & SMB_MASKFLAG_TILDE) &&
6623 !cm_Is8Dot3(matchName)) {
6624 cm_Gen8Dot3Name(dep, matchName, NULL);
6625 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6630 cm_DirEntryListAdd(dep->name, &rockp->matches);
6637 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6640 clientchar_t *pathp;
6644 clientchar_t *lastNamep;
6645 smb_rmdirRock_t rock;
6649 clientchar_t *tidPathp;
6653 memset(&rock, 0, sizeof(rock));
6655 tp = smb_GetSMBData(inp, NULL);
6656 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6658 return CM_ERROR_BADSMB;
6660 spacep = inp->spacep;
6661 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
6663 userp = smb_GetUserFromVCP(vcp, inp);
6665 caseFold = CM_FLAG_CASEFOLD;
6667 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6669 cm_ReleaseUser(userp);
6670 return CM_ERROR_NOSUCHPATH;
6672 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
6673 userp, tidPathp, &req, &dscp);
6676 cm_ReleaseUser(userp);
6681 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6682 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
6683 cm_ReleaseSCache(dscp);
6684 cm_ReleaseUser(userp);
6685 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6686 return CM_ERROR_PATH_NOT_COVERED;
6688 return CM_ERROR_NOSUCHPATH;
6690 #endif /* DFS_SUPPORT */
6692 /* otherwise, scp points to the parent directory. */
6699 rock.maskp = cm_ClientStringToNormStringAlloc(lastNamep, -1, NULL);
6701 code = CM_ERROR_NOSUCHFILE;
6704 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6707 thyper.HighPart = 0;
6711 rock.matches = NULL;
6713 /* First do a case sensitive match, and if that fails, do a case insensitive match */
6714 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6715 if (code == 0 && !rock.any) {
6717 thyper.HighPart = 0;
6718 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6719 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6722 if (code == 0 && rock.matches) {
6723 cm_dirEntryList_t * entry;
6725 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
6726 clientchar_t clientName[MAX_PATH];
6728 /* We assume this will succeed because smb_RmdirProc()
6729 successfully converted entry->name once above. */
6730 cm_FsStringToClientString(entry->name, -1, clientName, lengthof(clientName));
6732 osi_Log1(smb_logp, "Removing directory %s",
6733 osi_LogSaveString(smb_logp, entry->name));
6735 code = cm_RemoveDir(dscp, entry->name, clientName, userp, &req);
6737 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6738 smb_NotifyChange(FILE_ACTION_REMOVED,
6739 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6740 dscp, clientName, NULL, TRUE);
6746 cm_DirEntryListFree(&rock.matches);
6749 cm_ReleaseUser(userp);
6752 cm_ReleaseSCache(dscp);
6754 if (code == 0 && !rock.any)
6755 code = CM_ERROR_NOSUCHFILE;
6764 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6774 fid = smb_GetSMBParm(inp, 0);
6776 osi_Log1(smb_logp, "SMB flush fid %d", fid);
6778 fid = smb_ChainFID(fid, inp);
6779 fidp = smb_FindFID(vcp, fid, 0);
6781 return CM_ERROR_BADFD;
6783 userp = smb_GetUserFromVCP(vcp, inp);
6785 lock_ObtainMutex(&fidp->mx);
6786 if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
6787 cm_ReleaseUser(userp);
6788 lock_ReleaseMutex(&fidp->mx);
6789 smb_ReleaseFID(fidp);
6790 return CM_ERROR_BADFD;
6793 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
6794 lock_ReleaseMutex(&fidp->mx);
6795 cm_ReleaseUser(userp);
6796 smb_CloseFID(vcp, fidp, NULL, 0);
6797 smb_ReleaseFID(fidp);
6798 return CM_ERROR_NOSUCHFILE;
6801 if ((fidp->flags & SMB_FID_OPENWRITE) && smb_AsyncStore != 2) {
6802 cm_scache_t * scp = fidp->scp;
6804 lock_ReleaseMutex(&fidp->mx);
6805 code = cm_FSync(scp, userp, &req);
6806 cm_ReleaseSCache(scp);
6808 lock_ReleaseMutex(&fidp->mx);
6812 cm_ReleaseUser(userp);
6813 smb_ReleaseFID(fidp);
6817 struct smb_FullNameRock {
6820 clientchar_t *fullName;
6821 fschar_t *originalName;
6824 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
6827 normchar_t matchName[MAX_PATH];
6828 struct smb_FullNameRock *vrockp;
6830 vrockp = (struct smb_FullNameRock *)rockp;
6832 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6833 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6834 osi_LogSaveString(smb_logp, dep->name));
6838 if (!cm_Is8Dot3(matchName)) {
6839 clientchar_t shortName[13];
6841 cm_Gen8Dot3Name(dep, shortName, NULL);
6843 if (cm_ClientStrCmpIA(shortName, vrockp->name) == 0) {
6844 vrockp->fullName = cm_ClientStrDup(matchName);
6845 vrockp->originalName = cm_FsStrDup(dep->name);
6846 return CM_ERROR_STOPNOW;
6849 if (cm_ClientStrCmpI(matchName, vrockp->name) == 0 &&
6850 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
6851 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
6852 vrockp->fullName = cm_ClientStrDup(matchName);
6853 vrockp->originalName = cm_FsStrDup(dep->name);
6854 return CM_ERROR_STOPNOW;
6859 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, clientchar_t *pathp,
6860 clientchar_t **newPathp, fschar_t ** originalPathp,
6861 cm_user_t *userp, cm_req_t *reqp)
6863 struct smb_FullNameRock rock;
6866 memset(&rock, 0, sizeof(rock));
6870 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
6871 if (code == CM_ERROR_STOPNOW) {
6872 *newPathp = rock.fullName;
6873 *originalPathp = rock.originalName;
6875 *newPathp = cm_ClientStrDup(pathp);
6876 *originalPathp = cm_ClientStringToFsStringAlloc(pathp, -1, NULL);
6880 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
6881 afs_uint32 dosTime) {
6884 cm_scache_t *dscp = NULL;
6885 clientchar_t *pathp = NULL;
6886 cm_scache_t * scp = NULL;
6887 cm_scache_t *delscp = NULL;
6888 int nullcreator = 0;
6890 osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
6891 fidp, fidp->fid, scp, vcp);
6894 lock_ObtainMutex(&fidp->mx);
6895 if (!fidp->userp && !(fidp->flags & (SMB_FID_IOCTL|
6897 lock_ReleaseMutex(&fidp->mx);
6898 osi_Log0(smb_logp, " No user specified. Not closing fid");
6899 return CM_ERROR_BADFD;
6902 userp = fidp->userp; /* no hold required since fidp is held
6903 throughout the function */
6904 lock_ReleaseMutex(&fidp->mx);
6909 lock_ObtainWrite(&smb_rctLock);
6910 if (fidp->deleteOk) {
6911 osi_Log0(smb_logp, " Fid already closed.");
6912 lock_ReleaseWrite(&smb_rctLock);
6913 return CM_ERROR_BADFD;
6916 lock_ReleaseWrite(&smb_rctLock);
6918 lock_ObtainMutex(&fidp->mx);
6919 if (fidp->NTopen_dscp) {
6920 dscp = fidp->NTopen_dscp;
6921 cm_HoldSCache(dscp);
6924 if (fidp->NTopen_pathp)
6925 pathp = cm_ClientStrDup(fidp->NTopen_pathp);
6932 /* Don't jump the gun on an async raw write */
6933 while (fidp->raw_writers) {
6934 lock_ReleaseMutex(&fidp->mx);
6935 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
6936 lock_ObtainMutex(&fidp->mx);
6939 /* watch for ioctl closes, and read-only opens */
6941 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
6942 == SMB_FID_OPENWRITE) {
6943 if (dosTime != 0 && dosTime != -1) {
6944 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6945 /* This fixes defect 10958 */
6946 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
6947 smb_UnixTimeFromDosUTime(&scp->clientModTime, dosTime);
6949 if (smb_AsyncStore != 2) {
6950 lock_ReleaseMutex(&fidp->mx);
6951 code = cm_FSync(scp, userp, &req);
6952 lock_ObtainMutex(&fidp->mx);
6958 /* unlock any pending locks */
6959 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
6960 scp->fileType == CM_SCACHETYPE_FILE) {
6964 lock_ReleaseMutex(&fidp->mx);
6966 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
6968 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
6969 lock_ObtainWrite(&scp->rw);
6971 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
6972 CM_SCACHESYNC_NEEDCALLBACK
6973 | CM_SCACHESYNC_GETSTATUS
6974 | CM_SCACHESYNC_LOCK);
6978 "smb CoreClose SyncOp failure code 0x%x", tcode);
6979 goto post_syncopdone;
6982 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
6984 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
6988 lock_ReleaseWrite(&scp->rw);
6989 lock_ObtainMutex(&fidp->mx);
6992 if (fidp->flags & SMB_FID_DELONCLOSE) {
6993 clientchar_t *fullPathp = NULL;
6994 fschar_t *originalNamep = NULL;
6996 lock_ReleaseMutex(&fidp->mx);
6998 code = cm_Lookup(dscp, pathp, CM_FLAG_NOMOUNTCHASE, userp, &req, &delscp);
7003 smb_FullName(dscp, delscp, pathp, &fullPathp, &originalNamep, userp, &req);
7004 if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
7005 code = cm_RemoveDir(dscp, originalNamep, fullPathp, userp, &req);
7007 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7008 smb_NotifyChange(FILE_ACTION_REMOVED,
7009 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
7010 dscp, fullPathp, NULL, TRUE);
7013 code = cm_Unlink(dscp, originalNamep, fullPathp, userp, &req);
7015 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7016 smb_NotifyChange(FILE_ACTION_REMOVED,
7017 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7018 dscp, fullPathp, NULL, TRUE);
7025 free(originalNamep);
7027 lock_ObtainMutex(&fidp->mx);
7028 fidp->flags &= ~SMB_FID_DELONCLOSE;
7031 /* if this was a newly created file, then clear the creator
7032 * in the stat cache entry. */
7033 if (fidp->flags & SMB_FID_CREATED) {
7035 fidp->flags &= ~SMB_FID_CREATED;
7038 if (fidp->flags & SMB_FID_NTOPEN) {
7039 cm_ReleaseSCache(fidp->NTopen_dscp);
7040 fidp->NTopen_dscp = NULL;
7041 free(fidp->NTopen_pathp);
7042 fidp->NTopen_pathp = NULL;
7043 fidp->flags &= ~SMB_FID_NTOPEN;
7045 osi_assertx(fidp->NTopen_dscp == NULL, "null NTopen_dsc");
7046 osi_assertx(fidp->NTopen_pathp == NULL, "null NTopen_path");
7049 if (fidp->NTopen_wholepathp) {
7050 free(fidp->NTopen_wholepathp);
7051 fidp->NTopen_wholepathp = NULL;
7055 cm_ReleaseSCache(fidp->scp);
7058 lock_ReleaseMutex(&fidp->mx);
7061 cm_ReleaseSCache(dscp);
7064 cm_ReleaseSCache(delscp);
7068 lock_ObtainWrite(&scp->rw);
7069 if (nullcreator && scp->creator == userp)
7070 scp->creator = NULL;
7071 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
7072 lock_ReleaseWrite(&scp->rw);
7073 cm_ReleaseSCache(scp);
7083 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7091 fid = smb_GetSMBParm(inp, 0);
7092 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
7094 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
7096 fid = smb_ChainFID(fid, inp);
7097 fidp = smb_FindFID(vcp, fid, 0);
7099 return CM_ERROR_BADFD;
7102 userp = smb_GetUserFromVCP(vcp, inp);
7104 code = smb_CloseFID(vcp, fidp, userp, dosTime);
7106 smb_ReleaseFID(fidp);
7107 cm_ReleaseUser(userp);
7112 * smb_ReadData -- common code for Read, Read And X, and Raw Read
7114 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
7115 cm_user_t *userp, long *readp)
7121 osi_hyper_t fileLength;
7123 osi_hyper_t lastByte;
7124 osi_hyper_t bufferOffset;
7128 int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
7131 osi_Log3(smb_logp, "smb_ReadData fid %d, off 0x%x, size 0x%x",
7132 fidp->fid, offsetp->LowPart, count);
7136 lock_ObtainMutex(&fidp->mx);
7137 /* make sure we have a readable FD */
7138 if (!(fidp->flags & SMB_FID_OPENREAD_LISTDIR)) {
7139 osi_Log2(smb_logp, "smb_ReadData fid %d not OPENREAD_LISTDIR flags 0x%x",
7140 fidp->fid, fidp->flags);
7141 lock_ReleaseMutex(&fidp->mx);
7142 code = CM_ERROR_BADFDOP;
7147 lock_ReleaseMutex(&fidp->mx);
7148 code = CM_ERROR_BADFD;
7159 lock_ObtainWrite(&scp->rw);
7161 if (offset.HighPart == 0) {
7162 chunk = offset.LowPart >> cm_logChunkSize;
7163 if (chunk != fidp->curr_chunk) {
7164 fidp->prev_chunk = fidp->curr_chunk;
7165 fidp->curr_chunk = chunk;
7167 if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
7170 lock_ReleaseMutex(&fidp->mx);
7172 /* start by looking up the file's end */
7173 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7174 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7178 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7180 /* now we have the entry locked, look up the length */
7181 fileLength = scp->length;
7183 /* adjust count down so that it won't go past EOF */
7184 thyper.LowPart = count;
7185 thyper.HighPart = 0;
7186 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
7188 if (LargeIntegerGreaterThan(thyper, fileLength)) {
7189 /* we'd read past EOF, so just stop at fileLength bytes.
7190 * Start by computing how many bytes remain in the file.
7192 thyper = LargeIntegerSubtract(fileLength, offset);
7194 /* if we are past EOF, read 0 bytes */
7195 if (LargeIntegerLessThanZero(thyper))
7198 count = thyper.LowPart;
7203 /* now, copy the data one buffer at a time,
7204 * until we've filled the request packet
7207 /* if we've copied all the data requested, we're done */
7208 if (count <= 0) break;
7210 /* otherwise, load up a buffer of data */
7211 thyper.HighPart = offset.HighPart;
7212 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7213 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7216 buf_Release(bufferp);
7219 lock_ReleaseWrite(&scp->rw);
7221 code = buf_Get(scp, &thyper, &req, &bufferp);
7223 lock_ObtainWrite(&scp->rw);
7224 if (code) goto done;
7225 bufferOffset = thyper;
7227 /* now get the data in the cache */
7229 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7230 CM_SCACHESYNC_NEEDCALLBACK |
7231 CM_SCACHESYNC_READ);
7235 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
7237 if (cm_HaveBuffer(scp, bufferp, 0)) break;
7239 /* otherwise, load the buffer and try again */
7240 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
7244 buf_Release(bufferp);
7248 } /* if (wrong buffer) ... */
7250 /* now we have the right buffer loaded. Copy out the
7251 * data from here to the user's buffer.
7253 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7255 /* and figure out how many bytes we want from this buffer */
7256 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
7257 if (nbytes > count) nbytes = count; /* don't go past EOF */
7259 /* now copy the data */
7260 memcpy(op, bufferp->datap + bufIndex, nbytes);
7262 /* adjust counters, pointers, etc. */
7265 thyper.LowPart = nbytes;
7266 thyper.HighPart = 0;
7267 offset = LargeIntegerAdd(thyper, offset);
7271 lock_ReleaseWrite(&scp->rw);
7273 buf_Release(bufferp);
7275 if (code == 0 && sequential)
7276 cm_ConsiderPrefetch(scp, &lastByte, *readp, userp, &req);
7278 cm_ReleaseSCache(scp);
7281 osi_Log3(smb_logp, "smb_ReadData fid %d returns 0x%x read %d bytes",
7282 fidp->fid, code, *readp);
7287 * smb_WriteData -- common code for Write and Raw Write
7289 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
7290 cm_user_t *userp, long *writtenp)
7292 osi_hyper_t offset = *offsetp;
7295 cm_scache_t *scp = NULL;
7296 osi_hyper_t fileLength; /* file's length at start of write */
7297 osi_hyper_t minLength; /* don't read past this */
7298 afs_uint32 nbytes; /* # of bytes to transfer this iteration */
7299 cm_buf_t *bufferp = NULL;
7300 osi_hyper_t thyper; /* hyper tmp variable */
7301 osi_hyper_t bufferOffset;
7302 afs_uint32 bufIndex; /* index in buffer where our data is */
7303 int doWriteBack = 0;
7304 osi_hyper_t writeBackOffset;/* offset of region to write back when I/O is done */
7308 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
7309 fidp->fid, offsetp->LowPart, count);
7313 lock_ObtainMutex(&fidp->mx);
7314 /* make sure we have a writable FD */
7315 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
7316 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
7317 fidp->fid, fidp->flags);
7318 lock_ReleaseMutex(&fidp->mx);
7319 code = CM_ERROR_BADFDOP;
7327 lock_ReleaseMutex(&fidp->mx);
7329 lock_ObtainWrite(&scp->rw);
7330 /* start by looking up the file's end */
7331 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7332 CM_SCACHESYNC_NEEDCALLBACK
7333 | CM_SCACHESYNC_SETSTATUS
7334 | CM_SCACHESYNC_GETSTATUS);
7338 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
7340 /* now we have the entry locked, look up the length */
7341 fileLength = scp->length;
7342 minLength = fileLength;
7343 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
7344 minLength = scp->serverLength;
7346 /* adjust file length if we extend past EOF */
7347 thyper.LowPart = count;
7348 thyper.HighPart = 0;
7349 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
7350 if (LargeIntegerGreaterThan(thyper, fileLength)) {
7351 /* we'd write past EOF, so extend the file */
7352 scp->mask |= CM_SCACHEMASK_LENGTH;
7353 scp->length = thyper;
7354 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
7356 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
7358 /* now, if the new position (thyper) and the old (offset) are in
7359 * different storeback windows, remember to store back the previous
7360 * storeback window when we're done with the write.
7362 * the purpose of this logic is to slow down the CIFS client
7363 * in order to avoid the client disconnecting during the CLOSE
7364 * operation if there are too many dirty buffers left to write
7365 * than can be accomplished during 45 seconds. This used to be
7366 * based upon cm_chunkSize but we desire cm_chunkSize to be large
7367 * so that we can read larger amounts of data at a time.
7369 if (smb_AsyncStore == 1 &&
7370 (thyper.LowPart & ~(smb_AsyncStoreSize-1)) !=
7371 (offset.LowPart & ~(smb_AsyncStoreSize-1))) {
7372 /* they're different */
7374 writeBackOffset.HighPart = offset.HighPart;
7375 writeBackOffset.LowPart = offset.LowPart & ~(smb_AsyncStoreSize-1);
7380 /* now, copy the data one buffer at a time, until we've filled the
7383 /* if we've copied all the data requested, we're done */
7387 /* handle over quota or out of space */
7388 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
7389 *writtenp = written;
7390 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
7394 /* otherwise, load up a buffer of data */
7395 thyper.HighPart = offset.HighPart;
7396 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7397 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7400 lock_ReleaseMutex(&bufferp->mx);
7401 buf_Release(bufferp);
7404 lock_ReleaseWrite(&scp->rw);
7406 code = buf_Get(scp, &thyper, &req, &bufferp);
7408 lock_ObtainMutex(&bufferp->mx);
7409 lock_ObtainWrite(&scp->rw);
7410 if (code) goto done;
7412 bufferOffset = thyper;
7414 /* now get the data in the cache */
7416 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7417 CM_SCACHESYNC_NEEDCALLBACK
7418 | CM_SCACHESYNC_WRITE
7419 | CM_SCACHESYNC_BUFLOCKED);
7423 cm_SyncOpDone(scp, bufferp,
7424 CM_SCACHESYNC_NEEDCALLBACK
7425 | CM_SCACHESYNC_WRITE
7426 | CM_SCACHESYNC_BUFLOCKED);
7428 /* If we're overwriting the entire buffer, or
7429 * if we're writing at or past EOF, mark the
7430 * buffer as current so we don't call
7431 * cm_GetBuffer. This skips the fetch from the
7432 * server in those cases where we're going to
7433 * obliterate all the data in the buffer anyway,
7434 * or in those cases where there is no useful
7435 * data at the server to start with.
7437 * Use minLength instead of scp->length, since
7438 * the latter has already been updated by this
7441 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
7442 || LargeIntegerEqualTo(offset, bufferp->offset)
7443 && (count >= cm_data.buf_blockSize
7444 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
7445 ConvertLongToLargeInteger(count)),
7447 if (count < cm_data.buf_blockSize
7448 && bufferp->dataVersion == CM_BUF_VERSION_BAD)
7449 memset(bufferp->datap, 0,
7450 cm_data.buf_blockSize);
7451 bufferp->dataVersion = scp->dataVersion;
7454 if (cm_HaveBuffer(scp, bufferp, 1)) break;
7456 /* otherwise, load the buffer and try again */
7457 lock_ReleaseMutex(&bufferp->mx);
7458 code = cm_GetBuffer(scp, bufferp, NULL, userp,
7460 lock_ReleaseWrite(&scp->rw);
7461 lock_ObtainMutex(&bufferp->mx);
7462 lock_ObtainWrite(&scp->rw);
7466 lock_ReleaseMutex(&bufferp->mx);
7467 buf_Release(bufferp);
7471 } /* if (wrong buffer) ... */
7473 /* now we have the right buffer loaded. Copy out the
7474 * data from here to the user's buffer.
7476 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7478 /* and figure out how many bytes we want from this buffer */
7479 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
7481 nbytes = count; /* don't go past end of request */
7483 /* now copy the data */
7484 memcpy(bufferp->datap + bufIndex, op, nbytes);
7485 buf_SetDirty(bufferp, bufIndex, nbytes, userp);
7487 /* adjust counters, pointers, etc. */
7491 thyper.LowPart = nbytes;
7492 thyper.HighPart = 0;
7493 offset = LargeIntegerAdd(thyper, offset);
7497 lock_ReleaseWrite(&scp->rw);
7500 lock_ReleaseMutex(&bufferp->mx);
7501 buf_Release(bufferp);
7504 lock_ObtainMutex(&fidp->mx);
7505 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
7506 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7508 lock_ReleaseMutex(&fidp->mx);
7509 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
7510 fidp->NTopen_dscp, fidp->NTopen_pathp,
7513 lock_ReleaseMutex(&fidp->mx);
7517 if (smb_AsyncStore > 0) {
7521 lock_ObtainWrite(&scp->rw);
7522 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
7524 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
7525 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
7527 lock_ReleaseWrite(&scp->rw);
7528 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
7529 writeBackOffset.HighPart,
7530 smb_AsyncStoreSize, 0, userp);
7531 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
7534 cm_BufWrite(scp, offsetp, *writtenp, 0, userp, &req);
7538 cm_ReleaseSCache(scp);
7541 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
7542 fidp->fid, code, *writtenp);
7547 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7550 unsigned short count;
7552 unsigned short hint;
7553 long written = 0, total_written = 0;
7556 smb_t* smbp = (smb_t*) inp;
7560 cm_attr_t truncAttr; /* attribute struct used for truncating file */
7562 int inDataBlockCount;
7564 fd = smb_GetSMBParm(inp, 0);
7565 count = smb_GetSMBParm(inp, 1);
7566 offset.HighPart = 0; /* too bad */
7567 offset.LowPart = smb_GetSMBParmLong(inp, 2);
7568 hint = smb_GetSMBParm(inp, 4);
7570 op = smb_GetSMBData(inp, NULL);
7571 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
7573 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
7574 fd, offset.LowPart, count);
7576 fd = smb_ChainFID(fd, inp);
7577 fidp = smb_FindFID(vcp, fd, 0);
7579 osi_Log0(smb_logp, "smb_ReceiveCoreWrite fid not found");
7580 return CM_ERROR_BADFD;
7583 lock_ObtainMutex(&fidp->mx);
7584 if (fidp->flags & SMB_FID_IOCTL) {
7585 lock_ReleaseMutex(&fidp->mx);
7586 code = smb_IoctlWrite(fidp, vcp, inp, outp);
7587 smb_ReleaseFID(fidp);
7588 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
7592 if (fidp->flags & SMB_FID_RPC) {
7593 lock_ReleaseMutex(&fidp->mx);
7594 code = smb_RPCWrite(fidp, vcp, inp, outp);
7595 smb_ReleaseFID(fidp);
7596 osi_Log1(smb_logp, "smb_ReceiveCoreWrite RPC code 0x%x", code);
7601 lock_ReleaseMutex(&fidp->mx);
7602 smb_ReleaseFID(fidp);
7603 return CM_ERROR_BADFD;
7606 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7607 lock_ReleaseMutex(&fidp->mx);
7608 smb_CloseFID(vcp, fidp, NULL, 0);
7609 smb_ReleaseFID(fidp);
7610 return CM_ERROR_NOSUCHFILE;
7615 lock_ReleaseMutex(&fidp->mx);
7616 userp = smb_GetUserFromVCP(vcp, inp);
7620 LARGE_INTEGER LOffset;
7621 LARGE_INTEGER LLength;
7624 key = cm_GenerateKey(vcp->vcID, pid, fd);
7626 LOffset.HighPart = offset.HighPart;
7627 LOffset.LowPart = offset.LowPart;
7628 LLength.HighPart = 0;
7629 LLength.LowPart = count;
7631 lock_ObtainWrite(&scp->rw);
7632 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7633 lock_ReleaseWrite(&scp->rw);
7636 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
7641 /* special case: 0 bytes transferred means truncate to this position */
7645 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
7649 truncAttr.mask = CM_ATTRMASK_LENGTH;
7650 truncAttr.length.LowPart = offset.LowPart;
7651 truncAttr.length.HighPart = 0;
7652 lock_ObtainMutex(&fidp->mx);
7653 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
7654 fidp->flags |= SMB_FID_LENGTHSETDONE;
7655 lock_ReleaseMutex(&fidp->mx);
7656 smb_SetSMBParm(outp, 0, 0 /* count */);
7657 smb_SetSMBDataLength(outp, 0);
7662 * Work around bug in NT client
7664 * When copying a file, the NT client should first copy the data,
7665 * then copy the last write time. But sometimes the NT client does
7666 * these in the wrong order, so the data copies would inadvertently
7667 * cause the last write time to be overwritten. We try to detect this,
7668 * and don't set client mod time if we think that would go against the
7671 lock_ObtainMutex(&fidp->mx);
7672 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
7673 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7674 fidp->scp->clientModTime = time(NULL);
7676 lock_ReleaseMutex(&fidp->mx);
7679 while ( code == 0 && count > 0 ) {
7680 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7681 if (code == 0 && written == 0)
7682 code = CM_ERROR_PARTIALWRITE;
7684 offset = LargeIntegerAdd(offset,
7685 ConvertLongToLargeInteger(written));
7686 count -= (unsigned short)written;
7687 total_written += written;
7691 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
7692 total_written, code);
7694 /* set the packet data length to 3 bytes for the data block header,
7695 * plus the size of the data.
7697 smb_SetSMBParm(outp, 0, total_written);
7698 smb_SetSMBParmLong(outp, 1, offset.LowPart);
7699 smb_SetSMBParm(outp, 3, hint);
7700 smb_SetSMBDataLength(outp, 0);
7703 smb_ReleaseFID(fidp);
7704 cm_ReleaseUser(userp);
7705 cm_ReleaseSCache(scp);
7710 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7711 NCB *ncbp, raw_write_cont_t *rwcp)
7720 fd = smb_GetSMBParm(inp, 0);
7721 fidp = smb_FindFID(vcp, fd, 0);
7723 lock_ObtainMutex(&fidp->mx);
7725 lock_ReleaseMutex(&fidp->mx);
7726 smb_ReleaseFID(fidp);
7730 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7731 lock_ReleaseMutex(&fidp->mx);
7732 smb_CloseFID(vcp, fidp, NULL, 0);
7733 smb_ReleaseFID(fidp);
7736 lock_ReleaseMutex(&fidp->mx);
7738 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
7739 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
7741 userp = smb_GetUserFromVCP(vcp, inp);
7744 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
7746 if (rwcp->writeMode & 0x1) { /* synchronous */
7749 smb_FormatResponsePacket(vcp, inp, outp);
7750 op = (smb_t *) outp;
7751 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7752 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
7753 smb_SetSMBDataLength(outp, 0);
7754 smb_SendPacket(vcp, outp);
7755 smb_FreePacket(outp);
7757 else { /* asynchronous */
7758 lock_ObtainMutex(&fidp->mx);
7759 fidp->raw_writers--;
7760 if (fidp->raw_writers == 0)
7761 thrd_SetEvent(fidp->raw_write_event);
7762 lock_ReleaseMutex(&fidp->mx);
7765 /* Give back raw buffer */
7766 lock_ObtainMutex(&smb_RawBufLock);
7767 *((char **)rawBuf) = smb_RawBufs;
7768 smb_RawBufs = rawBuf;
7769 lock_ReleaseMutex(&smb_RawBufLock);
7771 smb_ReleaseFID(fidp);
7772 cm_ReleaseUser(userp);
7775 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7780 /* SMB_COM_WRITE_RAW */
7781 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
7784 long count, written = 0, total_written = 0;
7788 smb_t *smbp = (smb_t*) inp;
7793 unsigned short writeMode;
7795 fd = smb_GetSMBParm(inp, 0);
7796 totalCount = smb_GetSMBParm(inp, 1);
7797 count = smb_GetSMBParm(inp, 10);
7798 writeMode = smb_GetSMBParm(inp, 7);
7800 op = (char *) inp->data;
7801 op += smb_GetSMBParm(inp, 11);
7803 offset.HighPart = 0;
7804 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
7806 if (*inp->wctp == 14) {
7807 /* we received a 64-bit file offset */
7808 #ifdef AFS_LARGEFILES
7809 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
7811 if (LargeIntegerLessThanZero(offset)) {
7813 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
7814 offset.HighPart, offset.LowPart);
7815 return CM_ERROR_BADSMB;
7818 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
7820 "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files");
7821 return CM_ERROR_BADSMB;
7824 offset.HighPart = 0;
7827 offset.HighPart = 0; /* 32-bit file offset */
7831 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
7832 fd, offset.HighPart, offset.LowPart, count);
7834 " WriteRaw WriteMode 0x%x",
7837 fd = smb_ChainFID(fd, inp);
7838 fidp = smb_FindFID(vcp, fd, 0);
7840 return CM_ERROR_BADFD;
7842 lock_ObtainMutex(&fidp->mx);
7844 lock_ReleaseMutex(&fidp->mx);
7845 smb_ReleaseFID(fidp);
7846 return CM_ERROR_BADFD;
7849 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7850 lock_ReleaseMutex(&fidp->mx);
7851 smb_CloseFID(vcp, fidp, NULL, 0);
7852 smb_ReleaseFID(fidp);
7853 return CM_ERROR_NOSUCHFILE;
7858 lock_ReleaseMutex(&fidp->mx);
7863 LARGE_INTEGER LOffset;
7864 LARGE_INTEGER LLength;
7867 key = cm_GenerateKey(vcp->vcID, pid, fd);
7869 LOffset.HighPart = offset.HighPart;
7870 LOffset.LowPart = offset.LowPart;
7871 LLength.HighPart = 0;
7872 LLength.LowPart = count;
7874 lock_ObtainWrite(&scp->rw);
7875 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7876 lock_ReleaseWrite(&scp->rw);
7879 cm_ReleaseSCache(scp);
7880 smb_ReleaseFID(fidp);
7885 userp = smb_GetUserFromVCP(vcp, inp);
7888 * Work around bug in NT client
7890 * When copying a file, the NT client should first copy the data,
7891 * then copy the last write time. But sometimes the NT client does
7892 * these in the wrong order, so the data copies would inadvertently
7893 * cause the last write time to be overwritten. We try to detect this,
7894 * and don't set client mod time if we think that would go against the
7897 lock_ObtainMutex(&fidp->mx);
7898 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
7899 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7900 fidp->scp->clientModTime = time(NULL);
7902 lock_ReleaseMutex(&fidp->mx);
7905 while ( code == 0 && count > 0 ) {
7906 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7907 if (code == 0 && written == 0)
7908 code = CM_ERROR_PARTIALWRITE;
7910 offset = LargeIntegerAdd(offset,
7911 ConvertLongToLargeInteger(written));
7914 total_written += written;
7918 /* Get a raw buffer */
7921 lock_ObtainMutex(&smb_RawBufLock);
7923 /* Get a raw buf, from head of list */
7924 rawBuf = smb_RawBufs;
7925 smb_RawBufs = *(char **)smb_RawBufs;
7928 code = CM_ERROR_USESTD;
7930 lock_ReleaseMutex(&smb_RawBufLock);
7933 /* Don't allow a premature Close */
7934 if (code == 0 && (writeMode & 1) == 0) {
7935 lock_ObtainMutex(&fidp->mx);
7936 fidp->raw_writers++;
7937 thrd_ResetEvent(fidp->raw_write_event);
7938 lock_ReleaseMutex(&fidp->mx);
7941 smb_ReleaseFID(fidp);
7942 cm_ReleaseUser(userp);
7943 cm_ReleaseSCache(scp);
7946 smb_SetSMBParm(outp, 0, total_written);
7947 smb_SetSMBDataLength(outp, 0);
7948 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7953 offset = LargeIntegerAdd(offset,
7954 ConvertLongToLargeInteger(count));
7958 rwcp->offset.HighPart = offset.HighPart;
7959 rwcp->offset.LowPart = offset.LowPart;
7960 rwcp->count = totalCount - count;
7961 rwcp->writeMode = writeMode;
7962 rwcp->alreadyWritten = total_written;
7964 /* set the packet data length to 3 bytes for the data block header,
7965 * plus the size of the data.
7967 smb_SetSMBParm(outp, 0, 0xffff);
7968 smb_SetSMBDataLength(outp, 0);
7974 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7977 long count, finalCount;
7981 smb_t *smbp = (smb_t*) inp;
7987 fd = smb_GetSMBParm(inp, 0);
7988 count = smb_GetSMBParm(inp, 1);
7989 offset.HighPart = 0; /* too bad */
7990 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7992 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
7993 fd, offset.LowPart, count);
7995 fd = smb_ChainFID(fd, inp);
7996 fidp = smb_FindFID(vcp, fd, 0);
7998 return CM_ERROR_BADFD;
8000 lock_ObtainMutex(&fidp->mx);
8001 if (fidp->flags & SMB_FID_IOCTL) {
8002 lock_ReleaseMutex(&fidp->mx);
8003 code = smb_IoctlRead(fidp, vcp, inp, outp);
8004 smb_ReleaseFID(fidp);
8008 if (fidp->flags & SMB_FID_RPC) {
8009 lock_ReleaseMutex(&fidp->mx);
8010 code = smb_RPCRead(fidp, vcp, inp, outp);
8011 smb_ReleaseFID(fidp);
8016 lock_ReleaseMutex(&fidp->mx);
8017 smb_ReleaseFID(fidp);
8018 return CM_ERROR_BADFD;
8021 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
8022 lock_ReleaseMutex(&fidp->mx);
8023 smb_CloseFID(vcp, fidp, NULL, 0);
8024 smb_ReleaseFID(fidp);
8025 return CM_ERROR_NOSUCHFILE;
8030 lock_ReleaseMutex(&fidp->mx);
8033 LARGE_INTEGER LOffset, LLength;
8037 key = cm_GenerateKey(vcp->vcID, pid, fd);
8039 LOffset.HighPart = 0;
8040 LOffset.LowPart = offset.LowPart;
8041 LLength.HighPart = 0;
8042 LLength.LowPart = count;
8044 lock_ObtainWrite(&scp->rw);
8045 code = cm_LockCheckRead(scp, LOffset, LLength, key);
8046 lock_ReleaseWrite(&scp->rw);
8049 cm_ReleaseSCache(scp);
8050 smb_ReleaseFID(fidp);
8054 userp = smb_GetUserFromVCP(vcp, inp);
8056 /* remember this for final results */
8057 smb_SetSMBParm(outp, 0, count);
8058 smb_SetSMBParm(outp, 1, 0);
8059 smb_SetSMBParm(outp, 2, 0);
8060 smb_SetSMBParm(outp, 3, 0);
8061 smb_SetSMBParm(outp, 4, 0);
8063 /* set the packet data length to 3 bytes for the data block header,
8064 * plus the size of the data.
8066 smb_SetSMBDataLength(outp, count+3);
8068 /* get op ptr after putting in the parms, since otherwise we don't
8069 * know where the data really is.
8071 op = smb_GetSMBData(outp, NULL);
8073 /* now emit the data block header: 1 byte of type and 2 bytes of length */
8074 *op++ = 1; /* data block marker */
8075 *op++ = (unsigned char) (count & 0xff);
8076 *op++ = (unsigned char) ((count >> 8) & 0xff);
8078 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
8080 /* fix some things up */
8081 smb_SetSMBParm(outp, 0, finalCount);
8082 smb_SetSMBDataLength(outp, finalCount+3);
8084 smb_ReleaseFID(fidp);
8086 cm_ReleaseUser(userp);
8087 cm_ReleaseSCache(scp);
8091 /* SMB_COM_CREATE_DIRECTORY */
8092 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8094 clientchar_t *pathp;
8099 cm_scache_t *dscp; /* dir we're dealing with */
8100 cm_scache_t *scp; /* file we're creating */
8102 int initialModeBits;
8103 clientchar_t *lastNamep;
8105 clientchar_t *tidPathp;
8112 /* compute initial mode bits based on read-only flag in attributes */
8113 initialModeBits = 0777;
8115 tp = smb_GetSMBData(inp, NULL);
8116 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
8118 return CM_ERROR_BADSMB;
8120 spacep = inp->spacep;
8121 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
8123 if (cm_ClientStrCmp(pathp, _C("\\")) == 0)
8124 return CM_ERROR_EXISTS;
8126 userp = smb_GetUserFromVCP(vcp, inp);
8128 caseFold = CM_FLAG_CASEFOLD;
8130 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8132 cm_ReleaseUser(userp);
8133 return CM_ERROR_NOSUCHPATH;
8136 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
8137 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
8138 userp, tidPathp, &req, &dscp);
8141 cm_ReleaseUser(userp);
8146 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8147 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8148 cm_ReleaseSCache(dscp);
8149 cm_ReleaseUser(userp);
8150 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8151 return CM_ERROR_PATH_NOT_COVERED;
8153 return CM_ERROR_NOSUCHPATH;
8155 #endif /* DFS_SUPPORT */
8157 /* otherwise, scp points to the parent directory. Do a lookup, and
8158 * fail if we find it. Otherwise, we do the create.
8164 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
8165 if (scp) cm_ReleaseSCache(scp);
8166 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8167 if (code == 0) code = CM_ERROR_EXISTS;
8168 cm_ReleaseSCache(dscp);
8169 cm_ReleaseUser(userp);
8173 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8174 setAttr.clientModTime = time(NULL);
8175 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
8176 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
8177 smb_NotifyChange(FILE_ACTION_ADDED,
8178 FILE_NOTIFY_CHANGE_DIR_NAME,
8179 dscp, lastNamep, NULL, TRUE);
8181 /* we don't need this any longer */
8182 cm_ReleaseSCache(dscp);
8185 /* something went wrong creating or truncating the file */
8186 cm_ReleaseUser(userp);
8190 /* otherwise we succeeded */
8191 smb_SetSMBDataLength(outp, 0);
8192 cm_ReleaseUser(userp);
8197 BOOL smb_IsLegalFilename(clientchar_t *filename)
8200 * Find the longest substring of filename that does not contain
8201 * any of the chars in illegalChars. If that substring is less
8202 * than the length of the whole string, then one or more of the
8203 * illegal chars is in filename.
8205 if (cm_ClientStrCSpn(filename, illegalChars) < cm_ClientStrLen(filename))
8211 /* SMB_COM_CREATE and SMB_COM_CREATE_NEW */
8212 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8214 clientchar_t *pathp;
8220 cm_scache_t *dscp; /* dir we're dealing with */
8221 cm_scache_t *scp; /* file we're creating */
8223 int initialModeBits;
8226 clientchar_t *lastNamep;
8229 clientchar_t *tidPathp;
8231 int created = 0; /* the file was new */
8236 excl = (inp->inCom == 0x03)? 0 : 1;
8238 attributes = smb_GetSMBParm(inp, 0);
8239 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
8241 /* compute initial mode bits based on read-only flag in attributes */
8242 initialModeBits = 0666;
8243 if (attributes & SMB_ATTR_READONLY)
8244 initialModeBits &= ~0222;
8246 tp = smb_GetSMBData(inp, NULL);
8247 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
8249 return CM_ERROR_BADSMB;
8251 if (!cm_IsValidClientString(pathp)) {
8253 clientchar_t * hexp;
8255 hexp = cm_GetRawCharsAlloc(pathp, -1);
8256 osi_Log1(smb_logp, "CoreCreate rejecting invalid name. [%S]",
8257 osi_LogSaveClientString(smb_logp, hexp));
8261 osi_Log0(smb_logp, "CoreCreate rejecting invalid name");
8263 return CM_ERROR_BADNTFILENAME;
8266 spacep = inp->spacep;
8267 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
8269 userp = smb_GetUserFromVCP(vcp, inp);
8271 caseFold = CM_FLAG_CASEFOLD;
8273 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8275 cm_ReleaseUser(userp);
8276 return CM_ERROR_NOSUCHPATH;
8278 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
8279 userp, tidPathp, &req, &dscp);
8282 cm_ReleaseUser(userp);
8287 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8288 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8289 cm_ReleaseSCache(dscp);
8290 cm_ReleaseUser(userp);
8291 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8292 return CM_ERROR_PATH_NOT_COVERED;
8294 return CM_ERROR_NOSUCHPATH;
8296 #endif /* DFS_SUPPORT */
8298 /* otherwise, scp points to the parent directory. Do a lookup, and
8299 * truncate the file if we find it, otherwise we create the file.
8306 if (!smb_IsLegalFilename(lastNamep))
8307 return CM_ERROR_BADNTFILENAME;
8309 osi_Log1(smb_logp, "SMB receive create [%S]", osi_LogSaveClientString( smb_logp, pathp ));
8310 #ifdef DEBUG_VERBOSE
8313 hexp = osi_HexifyString( lastNamep );
8314 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
8319 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
8320 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8321 cm_ReleaseSCache(dscp);
8322 cm_ReleaseUser(userp);
8326 /* if we get here, if code is 0, the file exists and is represented by
8327 * scp. Otherwise, we have to create it.
8331 /* oops, file shouldn't be there */
8332 cm_ReleaseSCache(dscp);
8333 cm_ReleaseSCache(scp);
8334 cm_ReleaseUser(userp);
8335 return CM_ERROR_EXISTS;
8338 setAttr.mask = CM_ATTRMASK_LENGTH;
8339 setAttr.length.LowPart = 0;
8340 setAttr.length.HighPart = 0;
8341 code = cm_SetAttr(scp, &setAttr, userp, &req);
8344 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8345 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
8346 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
8350 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
8351 smb_NotifyChange(FILE_ACTION_ADDED,
8352 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
8353 dscp, lastNamep, NULL, TRUE);
8354 } else if (!excl && code == CM_ERROR_EXISTS) {
8355 /* not an exclusive create, and someone else tried
8356 * creating it already, then we open it anyway. We
8357 * don't bother retrying after this, since if this next
8358 * fails, that means that the file was deleted after
8359 * we started this call.
8361 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
8364 setAttr.mask = CM_ATTRMASK_LENGTH;
8365 setAttr.length.LowPart = 0;
8366 setAttr.length.HighPart = 0;
8367 code = cm_SetAttr(scp, &setAttr, userp, &req);
8372 /* we don't need this any longer */
8373 cm_ReleaseSCache(dscp);
8376 /* something went wrong creating or truncating the file */
8377 if (scp) cm_ReleaseSCache(scp);
8378 cm_ReleaseUser(userp);
8382 /* make sure we only open files */
8383 if (scp->fileType != CM_SCACHETYPE_FILE) {
8384 cm_ReleaseSCache(scp);
8385 cm_ReleaseUser(userp);
8386 return CM_ERROR_ISDIR;
8389 /* now all we have to do is open the file itself */
8390 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8391 osi_assertx(fidp, "null smb_fid_t");
8395 lock_ObtainMutex(&fidp->mx);
8396 /* always create it open for read/write */
8397 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
8399 /* remember that the file was newly created */
8401 fidp->flags |= SMB_FID_CREATED;
8403 osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
8405 /* save a pointer to the vnode */
8407 lock_ObtainWrite(&scp->rw);
8408 scp->flags |= CM_SCACHEFLAG_SMB_FID;
8409 lock_ReleaseWrite(&scp->rw);
8412 fidp->userp = userp;
8413 lock_ReleaseMutex(&fidp->mx);
8415 smb_SetSMBParm(outp, 0, fidp->fid);
8416 smb_SetSMBDataLength(outp, 0);
8418 cm_Open(scp, 0, userp);
8420 smb_ReleaseFID(fidp);
8421 cm_ReleaseUser(userp);
8422 /* leave scp held since we put it in fidp->scp */
8427 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8430 osi_hyper_t new_offset;
8441 fd = smb_GetSMBParm(inp, 0);
8442 whence = smb_GetSMBParm(inp, 1);
8443 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
8445 /* try to find the file descriptor */
8446 fd = smb_ChainFID(fd, inp);
8447 fidp = smb_FindFID(vcp, fd, 0);
8449 return CM_ERROR_BADFD;
8451 lock_ObtainMutex(&fidp->mx);
8452 if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
8453 lock_ReleaseMutex(&fidp->mx);
8454 smb_ReleaseFID(fidp);
8455 return CM_ERROR_BADFD;
8458 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
8459 lock_ReleaseMutex(&fidp->mx);
8460 smb_CloseFID(vcp, fidp, NULL, 0);
8461 smb_ReleaseFID(fidp);
8462 return CM_ERROR_NOSUCHFILE;
8465 lock_ReleaseMutex(&fidp->mx);
8467 userp = smb_GetUserFromVCP(vcp, inp);
8469 lock_ObtainMutex(&fidp->mx);
8472 lock_ReleaseMutex(&fidp->mx);
8473 lock_ObtainWrite(&scp->rw);
8474 code = cm_SyncOp(scp, NULL, userp, &req, 0,
8475 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8477 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8479 /* offset from current offset */
8480 new_offset = LargeIntegerAdd(fidp->offset,
8481 ConvertLongToLargeInteger(offset));
8483 else if (whence == 2) {
8484 /* offset from current EOF */
8485 new_offset = LargeIntegerAdd(scp->length,
8486 ConvertLongToLargeInteger(offset));
8488 new_offset = ConvertLongToLargeInteger(offset);
8491 fidp->offset = new_offset;
8492 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
8493 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
8494 smb_SetSMBDataLength(outp, 0);
8496 lock_ReleaseWrite(&scp->rw);
8497 smb_ReleaseFID(fidp);
8498 cm_ReleaseSCache(scp);
8499 cm_ReleaseUser(userp);
8503 /* dispatch all of the requests received in a packet. Due to chaining, this may
8504 * be more than one request.
8506 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
8507 NCB *ncbp, raw_write_cont_t *rwcp)
8511 unsigned long code = 0;
8512 unsigned char *outWctp;
8513 int nparms; /* # of bytes of parameters */
8515 int nbytes; /* bytes of data, excluding count */
8518 unsigned short errCode;
8519 unsigned long NTStatus;
8521 unsigned char errClass;
8522 unsigned int oldGen;
8523 DWORD oldTime, newTime;
8525 /* get easy pointer to the data */
8526 smbp = (smb_t *) inp->data;
8528 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
8529 /* setup the basic parms for the initial request in the packet */
8530 inp->inCom = smbp->com;
8531 inp->wctp = &smbp->wct;
8533 inp->ncb_length = ncbp->ncb_length;
8538 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
8539 /* log it and discard it */
8540 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
8541 __FILE__, __LINE__, ncbp->ncb_length);
8542 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
8546 /* We are an ongoing op */
8547 thrd_Increment(&ongoingOps);
8549 /* set up response packet for receiving output */
8550 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
8551 smb_FormatResponsePacket(vcp, inp, outp);
8552 outWctp = outp->wctp;
8554 /* Remember session generation number and time */
8555 oldGen = sessionGen;
8556 oldTime = GetTickCount();
8558 while (inp->inCom != 0xff) {
8559 dp = &smb_dispatchTable[inp->inCom];
8561 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
8562 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
8563 code = outp->resumeCode;
8567 /* process each request in the packet; inCom, wctp and inCount
8568 * are already set up.
8570 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
8573 /* now do the dispatch */
8574 /* start by formatting the response record a little, as a default */
8575 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
8577 outWctp[1] = 0xff; /* no operation */
8578 outWctp[2] = 0; /* padding */
8583 /* not a chained request, this is a more reasonable default */
8584 outWctp[0] = 0; /* wct of zero */
8585 outWctp[1] = 0; /* and bcc (word) of zero */
8589 /* once set, stays set. Doesn't matter, since we never chain
8590 * "no response" calls.
8592 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
8596 /* we have a recognized operation */
8597 char * opName = myCrt_Dispatch(inp->inCom);
8600 smbp = (smb_t *) inp;
8602 osi_Log5(smb_logp,"Dispatch %s mid 0x%x vcp 0x%p lana %d lsn %d",
8603 opName, smbp->mid, vcp,vcp->lana,vcp->lsn);
8604 if (inp->inCom == 0x1d) {
8606 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
8608 code = (*(dp->procp)) (vcp, inp, outp);
8610 osi_Log5(smb_logp,"Dispatch return code 0x%x mid 0x%x vcp 0x%p lana %d lsn %d",
8611 code, smbp->mid, vcp,vcp->lana,vcp->lsn);
8613 newTime = GetTickCount();
8614 osi_Log3(smb_logp, "Dispatch %s mid 0x%x duration %d ms",
8615 opName, smbp->mid, newTime - oldTime);
8618 if ( code == CM_ERROR_BADSMB ||
8619 code == CM_ERROR_BADOP )
8621 #endif /* LOG_PACKET */
8623 /* ReceiveV3Tran2A handles its own logging */
8624 if (inp->inCom != 0x32 && newTime - oldTime > 45000) {
8627 clientchar_t *treepath = NULL; /* do not free */
8628 clientchar_t *pathname = NULL;
8629 cm_fid_t afid = {0,0,0,0,0};
8631 uidp = smb_FindUID(vcp, smbp->uid, 0);
8632 smb_LookupTIDPath(vcp, smbp->tid, &treepath);
8633 fidp = smb_FindFID(vcp, inp->fid, 0);
8636 lock_ObtainMutex(&fidp->mx);
8637 if (fidp->NTopen_pathp)
8638 pathname = fidp->NTopen_pathp;
8640 afid = fidp->scp->fid;
8642 if (inp->stringsp->wdata)
8643 pathname = inp->stringsp->wdata;
8646 afsi_log("Request %s duration %d ms user 0x%x \"%S\" pid 0x%x mid 0x%x tid 0x%x \"%S\" path? \"%S\" afid (%d.%d.%d.%d)",
8647 opName, newTime - oldTime,
8648 smbp->uid, uidp ? uidp->unp->name : NULL,
8649 smbp->pid, smbp->mid, smbp->tid,
8652 afid.cell, afid.volume, afid.vnode, afid.unique);
8655 lock_ReleaseMutex(&fidp->mx);
8658 smb_ReleaseUID(uidp);
8660 smb_ReleaseFID(fidp);
8663 if (oldGen != sessionGen) {
8664 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
8665 newTime - oldTime, ncbp->ncb_length);
8666 osi_Log3(smb_logp, "Request %s straddled session startup, "
8667 "took %d ms, ncb length %d", opName, newTime - oldTime, ncbp->ncb_length);
8670 FreeSMBStrings(inp);
8672 /* bad opcode, fail the request, after displaying it */
8673 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
8676 #endif /* LOG_PACKET */
8679 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
8680 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
8681 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
8682 if (code == IDCANCEL)
8685 code = CM_ERROR_BADOP;
8688 /* catastrophic failure: log as much as possible */
8689 if (code == CM_ERROR_BADSMB) {
8690 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
8694 #endif /* LOG_PACKET */
8695 osi_Log1(smb_logp, "Invalid SMB message, length %d",
8698 code = CM_ERROR_INVAL;
8701 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
8702 thrd_Decrement(&ongoingOps);
8707 /* now, if we failed, turn the current response into an empty
8708 * one, and fill in the response packet's error code.
8711 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8712 smb_MapNTError(code, &NTStatus);
8713 outWctp = outp->wctp;
8714 smbp = (smb_t *) &outp->data;
8715 if (code != CM_ERROR_PARTIALWRITE
8716 && code != CM_ERROR_BUFFERTOOSMALL
8717 && code != CM_ERROR_GSSCONTINUE) {
8718 /* nuke wct and bcc. For a partial
8719 * write or an in-process authentication handshake,
8720 * assume they're OK.
8726 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8727 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8728 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8729 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8730 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8734 smb_MapCoreError(code, vcp, &errCode, &errClass);
8735 outWctp = outp->wctp;
8736 smbp = (smb_t *) &outp->data;
8737 if (code != CM_ERROR_PARTIALWRITE) {
8738 /* nuke wct and bcc. For a partial
8739 * write, assume they're OK.
8745 smbp->errLow = (unsigned char) (errCode & 0xff);
8746 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8747 smbp->rcls = errClass;
8750 } /* error occurred */
8752 /* if we're here, we've finished one request. Look to see if
8753 * this is a chained opcode. If it is, setup things to process
8754 * the chained request, and setup the output buffer to hold the
8755 * chained response. Start by finding the next input record.
8757 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
8758 break; /* not a chained req */
8759 tp = inp->wctp; /* points to start of last request */
8760 /* in a chained request, the first two
8761 * parm fields are required, and are
8762 * AndXCommand/AndXReserved and
8764 if (tp[0] < 2) break;
8765 if (tp[1] == 0xff) break; /* no more chained opcodes */
8767 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
8770 /* and now append the next output request to the end of this
8771 * last request. Begin by finding out where the last response
8772 * ends, since that's where we'll put our new response.
8774 outWctp = outp->wctp; /* ptr to out parameters */
8775 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
8776 nparms = outWctp[0] << 1;
8777 tp = outWctp + nparms + 1; /* now points to bcc field */
8778 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
8779 tp += 2 /* for the count itself */ + nbytes;
8780 /* tp now points to the new output record; go back and patch the
8781 * second parameter (off2) to point to the new record.
8783 temp = (unsigned int)(tp - outp->data);
8784 outWctp[3] = (unsigned char) (temp & 0xff);
8785 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
8786 outWctp[2] = 0; /* padding */
8787 outWctp[1] = inp->inCom; /* next opcode */
8789 /* finally, setup for the next iteration */
8792 } /* while loop over all requests in the packet */
8794 /* now send the output packet, and return */
8796 smb_SendPacket(vcp, outp);
8797 thrd_Decrement(&ongoingOps);
8802 /* Wait for Netbios() calls to return, and make the results available to server
8803 * threads. Note that server threads can't wait on the NCBevents array
8804 * themselves, because NCB events are manual-reset, and the servers would race
8805 * each other to reset them.
8807 void smb_ClientWaiter(void *parmp)
8812 while (smbShutdownFlag == 0) {
8813 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
8815 if (code == WAIT_OBJECT_0)
8818 /* error checking */
8819 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8821 int abandonIdx = code - WAIT_ABANDONED_0;
8822 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8825 if (code == WAIT_IO_COMPLETION)
8827 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
8831 if (code == WAIT_TIMEOUT)
8833 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
8836 if (code == WAIT_FAILED)
8838 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
8841 idx = code - WAIT_OBJECT_0;
8843 /* check idx range! */
8844 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
8846 /* this is fatal - log as much as possible */
8847 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
8848 osi_assertx(0, "invalid index");
8851 thrd_ResetEvent(NCBevents[idx]);
8852 thrd_SetEvent(NCBreturns[0][idx]);
8857 * Try to have one NCBRECV request waiting for every live session. Not more
8858 * than one, because if there is more than one, it's hard to handle Write Raw.
8860 void smb_ServerWaiter(void *parmp)
8863 int idx_session, idx_NCB;
8866 while (smbShutdownFlag == 0) {
8868 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
8870 if (code == WAIT_OBJECT_0)
8873 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
8875 int abandonIdx = code - WAIT_ABANDONED_0;
8876 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8879 if (code == WAIT_IO_COMPLETION)
8881 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
8885 if (code == WAIT_TIMEOUT)
8887 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
8890 if (code == WAIT_FAILED)
8892 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
8895 idx_session = code - WAIT_OBJECT_0;
8897 /* check idx range! */
8898 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
8900 /* this is fatal - log as much as possible */
8901 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
8902 osi_assertx(0, "invalid index");
8907 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
8909 if (code == WAIT_OBJECT_0) {
8910 if (smbShutdownFlag == 1)
8916 /* error checking */
8917 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8919 int abandonIdx = code - WAIT_ABANDONED_0;
8920 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8923 if (code == WAIT_IO_COMPLETION)
8925 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
8929 if (code == WAIT_TIMEOUT)
8931 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
8934 if (code == WAIT_FAILED)
8936 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
8939 idx_NCB = code - WAIT_OBJECT_0;
8941 /* check idx range! */
8942 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
8944 /* this is fatal - log as much as possible */
8945 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
8946 osi_assertx(0, "invalid index");
8949 /* Link them together */
8950 NCBsessions[idx_NCB] = idx_session;
8953 ncbp = NCBs[idx_NCB];
8954 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
8955 ncbp->ncb_command = NCBRECV | ASYNCH;
8956 ncbp->ncb_lana_num = lanas[idx_session];
8957 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
8958 ncbp->ncb_event = NCBevents[idx_NCB];
8959 ncbp->ncb_length = SMB_PACKETSIZE;
8965 * The top level loop for handling SMB request messages. Each server thread
8966 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
8967 * NCB and buffer for the incoming request are loaned to us.
8969 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
8970 * to immediately send a request for the rest of the data. This must come
8971 * before any other traffic for that session, so we delay setting the session
8972 * event until that data has come in.
8974 void smb_Server(VOID *parmp)
8976 INT_PTR myIdx = (INT_PTR) parmp;
8980 smb_packet_t *outbufp;
8982 int idx_NCB, idx_session;
8984 smb_vc_t *vcp = NULL;
8986 extern void rx_StartClientThread(void);
8988 rx_StartClientThread();
8990 outncbp = smb_GetNCB();
8991 outbufp = smb_GetPacket();
8992 outbufp->ncbp = outncbp;
9000 smb_ResetServerPriority();
9002 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
9005 /* terminate silently if shutdown flag is set */
9006 if (code == WAIT_OBJECT_0) {
9007 if (smbShutdownFlag == 1) {
9008 thrd_SetEvent(smb_ServerShutdown[myIdx]);
9014 /* error checking */
9015 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
9017 int abandonIdx = code - WAIT_ABANDONED_0;
9018 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
9021 if (code == WAIT_IO_COMPLETION)
9023 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
9027 if (code == WAIT_TIMEOUT)
9029 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
9032 if (code == WAIT_FAILED)
9034 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
9037 idx_NCB = code - WAIT_OBJECT_0;
9039 /* check idx range! */
9040 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
9042 /* this is fatal - log as much as possible */
9043 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
9044 osi_assertx(0, "invalid index");
9047 ncbp = NCBs[idx_NCB];
9048 idx_session = NCBsessions[idx_NCB];
9049 rc = ncbp->ncb_retcode;
9051 if (rc != NRC_PENDING && rc != NRC_GOODRET)
9052 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
9056 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9060 /* Can this happen? Or is it just my UNIX paranoia? */
9061 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
9066 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
9069 /* Client closed session */
9070 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9072 lock_ObtainMutex(&vcp->mx);
9073 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9074 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9076 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9077 lock_ReleaseMutex(&vcp->mx);
9078 lock_ObtainWrite(&smb_globalLock);
9079 dead_sessions[vcp->session] = TRUE;
9080 lock_ReleaseWrite(&smb_globalLock);
9082 lock_ReleaseMutex(&vcp->mx);
9084 smb_CleanupDeadVC(vcp);
9091 /* Treat as transient error */
9092 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
9095 "dispatch smb recv failed, message incomplete, ncb_length %d",
9098 "SMB message incomplete, "
9099 "length %d", ncbp->ncb_length);
9102 * We used to discard the packet.
9103 * Instead, try handling it normally.
9107 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9111 /* A weird error code. Log it, sleep, and continue. */
9112 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9114 lock_ObtainMutex(&vcp->mx);
9115 if (vcp->errorCount++ > 3) {
9116 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
9117 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9118 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9120 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9121 lock_ReleaseMutex(&vcp->mx);
9122 lock_ObtainWrite(&smb_globalLock);
9123 dead_sessions[vcp->session] = TRUE;
9124 lock_ReleaseWrite(&smb_globalLock);
9126 lock_ReleaseMutex(&vcp->mx);
9128 smb_CleanupDeadVC(vcp);
9134 lock_ReleaseMutex(&vcp->mx);
9138 thrd_SetEvent(SessionEvents[idx_session]);
9144 /* Success, so now dispatch on all the data in the packet */
9146 smb_concurrentCalls++;
9147 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
9148 smb_maxObsConcurrentCalls = smb_concurrentCalls;
9151 * If at this point vcp is NULL (implies that packet was invalid)
9152 * then we are in big trouble. This means either :
9153 * a) we have the wrong NCB.
9154 * b) Netbios screwed up the call.
9155 * c) The VC was already marked dead before we were able to
9157 * Obviously this implies that
9158 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
9159 * lanas[idx_session] != ncbp->ncb_lana_num )
9160 * Either way, we can't do anything with this packet.
9161 * Log, sleep and resume.
9164 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
9168 ncbp->ncb_lana_num);
9170 /* Also log in the trace log. */
9171 osi_Log4(smb_logp, "Server: VCP does not exist!"
9172 "LSNs[idx_session]=[%d],"
9173 "lanas[idx_session]=[%d],"
9174 "ncbp->ncb_lsn=[%d],"
9175 "ncbp->ncb_lana_num=[%d]",
9179 ncbp->ncb_lana_num);
9181 /* thrd_Sleep(1000); Don't bother sleeping */
9182 thrd_SetEvent(SessionEvents[idx_session]);
9183 smb_concurrentCalls--;
9187 smb_SetRequestStartTime();
9189 vcp->errorCount = 0;
9190 bufp = (struct smb_packet *) ncbp->ncb_buffer;
9191 smbp = (smb_t *)bufp->data;
9198 if (smbp->com == 0x1d) {
9199 /* Special handling for Write Raw */
9200 raw_write_cont_t rwc;
9202 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
9203 if (rwc.code == 0) {
9204 EVENT_HANDLE rwevent;
9205 char eventName[MAX_PATH];
9207 snprintf(eventName, MAX_PATH, "smb_Server() rwevent %d", myIdx);
9208 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9209 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9210 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9212 ncbp->ncb_command = NCBRECV | ASYNCH;
9213 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
9214 ncbp->ncb_lana_num = vcp->lana;
9215 ncbp->ncb_buffer = rwc.buf;
9216 ncbp->ncb_length = 65535;
9217 ncbp->ncb_event = rwevent;
9219 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
9220 thrd_CloseHandle(rwevent);
9222 thrd_SetEvent(SessionEvents[idx_session]);
9224 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
9226 else if (smbp->com == 0xa0) {
9228 * Serialize the handling for NT Transact
9231 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
9232 thrd_SetEvent(SessionEvents[idx_session]);
9234 thrd_SetEvent(SessionEvents[idx_session]);
9235 /* TODO: what else needs to be serialized? */
9236 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
9240 __except( smb_ServerExceptionFilter() ) {
9244 smb_concurrentCalls--;
9247 thrd_SetEvent(NCBavails[idx_NCB]);
9252 smb_FreePacket(outbufp);
9254 smb_FreeNCB(outncbp);
9258 * Exception filter for the server threads. If an exception occurs in the
9259 * dispatch routines, which is where exceptions are most common, then do a
9260 * force trace and give control to upstream exception handlers. Useful for
9263 DWORD smb_ServerExceptionFilter(void) {
9264 /* While this is not the best time to do a trace, if it succeeds, then
9265 * we have a trace (assuming tracing was enabled). Otherwise, this should
9266 * throw a second exception.
9268 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
9269 afsd_ForceTrace(TRUE);
9270 buf_ForceTrace(TRUE);
9271 return EXCEPTION_CONTINUE_SEARCH;
9275 * Create a new NCB and associated events, packet buffer, and "space" buffer.
9276 * If the number of server threads is M, and the number of live sessions is
9277 * N, then the number of NCB's in use at any time either waiting for, or
9278 * holding, received messages is M + N, so that is how many NCB's get created.
9280 void InitNCBslot(int idx)
9282 struct smb_packet *bufp;
9283 EVENT_HANDLE retHandle;
9285 char eventName[MAX_PATH];
9287 osi_assertx( idx < (sizeof(NCBs) / sizeof(NCBs[0])), "invalid index" );
9289 NCBs[idx] = smb_GetNCB();
9290 sprintf(eventName,"NCBavails[%d]", idx);
9291 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9292 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9293 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9294 sprintf(eventName,"NCBevents[%d]", idx);
9295 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
9296 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9297 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9298 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
9299 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9300 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9301 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9302 for (i=0; i<smb_NumServerThreads; i++)
9303 NCBreturns[i][idx] = retHandle;
9304 bufp = smb_GetPacket();
9305 bufp->spacep = cm_GetSpace();
9309 /* listen for new connections */
9310 void smb_Listener(void *parmp)
9316 afs_uint32 session, thread;
9317 smb_vc_t *vcp = NULL;
9319 char rname[NCBNAMSZ+1];
9320 char cname[MAX_COMPUTERNAME_LENGTH+1];
9321 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
9322 INT_PTR lana = (INT_PTR) parmp;
9323 char eventName[MAX_PATH];
9324 int bridgeCount = 0;
9325 int nowildCount = 0;
9327 sprintf(eventName,"smb_Listener_lana_%d", (unsigned char)lana);
9328 ListenerShutdown[lana] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9329 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9330 thrd_ResetEvent(ListenerShutdown[lana]);
9332 ncbp = smb_GetNCB();
9334 /* retrieve computer name */
9335 GetComputerName(cname, &cnamelen);
9338 while (smb_ListenerState == SMB_LISTENER_STARTED) {
9339 memset(ncbp, 0, sizeof(NCB));
9342 ncbp->ncb_command = NCBLISTEN;
9343 ncbp->ncb_rto = 0; /* No receive timeout */
9344 ncbp->ncb_sto = 0; /* No send timeout */
9346 /* pad out with spaces instead of null termination */
9347 len = (long)strlen(smb_localNamep);
9348 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9349 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9351 strcpy(ncbp->ncb_callname, "*");
9352 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
9354 ncbp->ncb_lana_num = (UCHAR)lana;
9356 code = Netbios(ncbp);
9358 if (code == NRC_NAMERR) {
9359 /* An smb shutdown or Vista resume must have taken place */
9361 "NCBLISTEN lana=%d failed with NRC_NAMERR.",
9362 ncbp->ncb_lana_num);
9363 afsi_log("NCBLISTEN lana=%d failed with NRC_NAMERR.", ncbp->ncb_lana_num);
9365 if (lock_TryMutex(&smb_StartedLock)) {
9366 lana_list.lana[i] = LANA_INVALID;
9367 lock_ReleaseMutex(&smb_StartedLock);
9370 } else if (code == NRC_BRIDGE || code != 0) {
9371 int lanaRemaining = 0;
9373 if (code == NRC_BRIDGE) {
9374 if (++bridgeCount <= 5) {
9375 afsi_log("NCBLISTEN lana=%d failed with NRC_BRIDGE, retrying ...", ncbp->ncb_lana_num);
9378 } else if (code == NRC_NOWILD) {
9379 if (++nowildCount <= 5) {
9380 afsi_log("NCBLISTEN lana=%d failed with NRC_NOWILD, retrying ...", ncbp->ncb_lana_num);
9382 if (bridgeCount > 0) {
9383 memset(ncbp, 0, sizeof(*ncbp));
9384 ncbp->ncb_command = NCBADDNAME;
9385 ncbp->ncb_lana_num = (UCHAR)lana;
9386 /* pad out with spaces instead of null termination */
9387 len = (long)strlen(smb_localNamep);
9388 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9389 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9390 code = Netbios(ncbp);
9396 while (!lock_TryMutex(&smb_StartedLock)) {
9397 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9403 "NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
9404 ncbp->ncb_lana_num, ncb_error_string(code));
9405 afsi_log("NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
9406 ncbp->ncb_lana_num, ncb_error_string(code));
9408 for (i = 0; i < lana_list.length; i++) {
9409 if (lana_list.lana[i] == lana) {
9410 smb_StopListener(ncbp, lana_list.lana[i], FALSE);
9411 lana_list.lana[i] = LANA_INVALID;
9413 if (lana_list.lana[i] != LANA_INVALID)
9417 if (lanaRemaining == 0) {
9418 cm_VolStatus_Network_Stopped(cm_NetbiosName
9423 smb_ListenerState = SMB_LISTENER_STOPPED;
9424 smb_LANadapter = LANA_INVALID;
9425 lana_list.length = 0;
9427 lock_ReleaseMutex(&smb_StartedLock);
9431 else if (code != 0) {
9432 char tbuffer[AFSPATHMAX];
9434 /* terminate silently if shutdown flag is set */
9435 while (!lock_TryMutex(&smb_StartedLock)) {
9436 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9442 "NCBLISTEN lana=%d failed with code %d [%s]",
9443 ncbp->ncb_lana_num, code, ncb_error_string(code));
9445 "Client exiting due to network failure. Please restart client.\n");
9448 "Client exiting due to network failure. Please restart client.\n"
9449 "NCBLISTEN lana=%d failed with code %d [%s]",
9450 ncbp->ncb_lana_num, code, ncb_error_string(code));
9452 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
9453 MB_OK|MB_SERVICE_NOTIFICATION);
9454 osi_panic(tbuffer, __FILE__, __LINE__);
9456 lock_ReleaseMutex(&smb_StartedLock);
9461 /* a successful packet received. clear bridge error count */
9465 /* check for remote conns */
9466 /* first get remote name and insert null terminator */
9467 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
9468 for (i=NCBNAMSZ; i>0; i--) {
9469 if (rname[i-1] != ' ' && rname[i-1] != 0) {
9475 /* compare with local name */
9477 if (strncmp(rname, cname, NCBNAMSZ) != 0)
9478 flags |= SMB_VCFLAG_REMOTECONN;
9481 lock_ObtainMutex(&smb_ListenerLock);
9483 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
9484 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
9486 /* now ncbp->ncb_lsn is the connection ID */
9487 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
9488 if (vcp->session == 0) {
9489 /* New generation */
9490 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
9493 /* Log session startup */
9495 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9496 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9497 #endif /* NOTSERVICE */
9498 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9499 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9501 if (reportSessionStartups) {
9502 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9505 lock_ObtainMutex(&vcp->mx);
9506 cm_Utf8ToUtf16(rname, -1, vcp->rname, lengthof(vcp->rname));
9507 vcp->flags |= flags;
9508 lock_ReleaseMutex(&vcp->mx);
9510 /* Allocate slot in session arrays */
9511 /* Re-use dead session if possible, otherwise add one more */
9512 /* But don't look at session[0], it is reserved */
9513 lock_ObtainWrite(&smb_globalLock);
9514 for (session = 1; session < numSessions; session++) {
9515 if (dead_sessions[session]) {
9516 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
9517 dead_sessions[session] = FALSE;
9521 lock_ReleaseWrite(&smb_globalLock);
9523 /* We are re-using an existing VC because the lsn and lana
9525 session = vcp->session;
9527 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
9529 /* Log session startup */
9531 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9532 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9533 #endif /* NOTSERVICE */
9534 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9535 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9537 if (reportSessionStartups) {
9538 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9542 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
9543 unsigned long code = CM_ERROR_ALLBUSY;
9544 smb_packet_t * outp = smb_GetPacket();
9545 unsigned char *outWctp;
9548 smb_FormatResponsePacket(vcp, NULL, outp);
9551 if (vcp->flags & SMB_VCFLAG_STATUS32) {
9552 unsigned long NTStatus;
9553 smb_MapNTError(code, &NTStatus);
9554 outWctp = outp->wctp;
9555 smbp = (smb_t *) &outp->data;
9559 smbp->rcls = (unsigned char) (NTStatus & 0xff);
9560 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
9561 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
9562 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
9563 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9565 unsigned short errCode;
9566 unsigned char errClass;
9567 smb_MapCoreError(code, vcp, &errCode, &errClass);
9568 outWctp = outp->wctp;
9569 smbp = (smb_t *) &outp->data;
9573 smbp->errLow = (unsigned char) (errCode & 0xff);
9574 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
9575 smbp->rcls = errClass;
9578 smb_SendPacket(vcp, outp);
9579 smb_FreePacket(outp);
9581 lock_ObtainMutex(&vcp->mx);
9582 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9583 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9585 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9586 lock_ReleaseMutex(&vcp->mx);
9587 lock_ObtainWrite(&smb_globalLock);
9588 dead_sessions[vcp->session] = TRUE;
9589 lock_ReleaseWrite(&smb_globalLock);
9590 smb_CleanupDeadVC(vcp);
9592 lock_ReleaseMutex(&vcp->mx);
9595 /* assert that we do not exceed the maximum number of sessions or NCBs.
9596 * we should probably want to wait for a session to be freed in case
9599 osi_assertx(session < SESSION_MAX - 1, "invalid session");
9600 osi_assertx(numNCBs < NCB_MAX - 1, "invalid numNCBs"); /* if we pass this test we can allocate one more */
9602 lock_ObtainMutex(&vcp->mx);
9603 vcp->session = session;
9604 lock_ReleaseMutex(&vcp->mx);
9605 lock_ObtainWrite(&smb_globalLock);
9606 LSNs[session] = ncbp->ncb_lsn;
9607 lanas[session] = ncbp->ncb_lana_num;
9608 lock_ReleaseWrite(&smb_globalLock);
9610 if (session == numSessions) {
9611 /* Add new NCB for new session */
9612 char eventName[MAX_PATH];
9614 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
9616 InitNCBslot(numNCBs);
9617 lock_ObtainWrite(&smb_globalLock);
9619 lock_ReleaseWrite(&smb_globalLock);
9620 thrd_SetEvent(NCBavails[0]);
9621 thrd_SetEvent(NCBevents[0]);
9622 for (thread = 0; thread < smb_NumServerThreads; thread++)
9623 thrd_SetEvent(NCBreturns[thread][0]);
9624 /* Also add new session event */
9625 sprintf(eventName, "SessionEvents[%d]", session);
9626 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9627 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9628 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9629 lock_ObtainWrite(&smb_globalLock);
9631 lock_ReleaseWrite(&smb_globalLock);
9632 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
9633 thrd_SetEvent(SessionEvents[0]);
9635 thrd_SetEvent(SessionEvents[session]);
9641 lock_ReleaseMutex(&smb_ListenerLock);
9642 } /* dispatch while loop */
9646 thrd_SetEvent(ListenerShutdown[lana]);
9651 configureBackConnectionHostNames(void)
9653 /* On Windows XP SP2, Windows 2003 SP1, and all future Windows operating systems
9654 * there is a restriction on the use of SMB authentication on loopback connections.
9655 * There are two work arounds available:
9657 * (1) We can disable the check for matching host names. This does not
9659 * [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa]
9660 * "DisableLoopbackCheck"=dword:00000001
9662 * (2) We can add the AFS SMB/CIFS service name to an approved list. This
9663 * does require a reboot:
9664 * [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0]
9665 * "BackConnectionHostNames"=multi-sz
9667 * The algorithm will be:
9668 * (1) Check to see if cm_NetbiosName exists in the BackConnectionHostNames list
9669 * (2a) If not, add it to the list. (This will not take effect until the next reboot.)
9670 * (2b1) and check to see if DisableLoopbackCheck is set.
9671 * (2b2) If not set, set the DisableLoopbackCheck value to 0x1
9672 * (2b3) and create HKLM\SOFTWARE\OpenAFS\Client UnsetDisableLoopbackCheck
9673 * (2c) else If cm_NetbiosName exists in the BackConnectionHostNames list,
9674 * check for the UnsetDisableLoopbackCheck value.
9675 * If set, set the DisableLoopbackCheck flag to 0x0
9676 * and delete the UnsetDisableLoopbackCheck value
9678 * Starting in Longhorn Beta 1, an entry in the BackConnectionHostNames value will
9679 * force Windows to use the loopback authentication mechanism for the specified
9682 * Do not permit the "DisableLoopbackCheck" value to be removed within the same
9683 * service session that set it.
9689 DWORD dwSize, dwAllocSize;
9691 PBYTE pHostNames = NULL, pName = NULL;
9692 BOOL bNameFound = FALSE;
9693 static BOOL bLoopbackCheckDisabled = FALSE;
9695 /* BackConnectionHostNames and DisableLoopbackCheck */
9696 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
9697 "SYSTEM\\CurrentControlSet\\Control\\Lsa\\MSV1_0",
9700 &hkMSV10) == ERROR_SUCCESS )
9702 if ((RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0,
9703 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
9704 (dwType == REG_MULTI_SZ))
9706 dwAllocSize += 1 /* in case the source string is not nul terminated */
9707 + (DWORD)strlen(cm_NetbiosName) + 2;
9708 pHostNames = malloc(dwAllocSize);
9709 dwSize = dwAllocSize;
9710 if (RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0, &dwType,
9711 pHostNames, &dwSize) == ERROR_SUCCESS)
9713 for (pName = pHostNames;
9714 (pName - pHostNames < (int) dwSize) && *pName ;
9715 pName += strlen(pName) + 1)
9717 if ( !stricmp(pName, cm_NetbiosName) ) {
9725 if ( !bNameFound ) {
9726 size_t size = strlen(cm_NetbiosName) + 2;
9727 if ( !pHostNames ) {
9728 pHostNames = malloc(size);
9731 StringCbCopyA(pName, size, cm_NetbiosName);
9733 *pName = '\0'; /* add a second nul terminator */
9735 dwType = REG_MULTI_SZ;
9736 dwSize = (DWORD)(pName - pHostNames + 1);
9737 RegSetValueEx( hkMSV10, "BackConnectionHostNames", 0, dwType, pHostNames, dwSize);
9739 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
9740 "SYSTEM\\CurrentControlSet\\Control\\Lsa",
9743 &hkLsa) == ERROR_SUCCESS )
9745 dwSize = sizeof(DWORD);
9746 if ( RegQueryValueEx( hkLsa, "DisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) != ERROR_SUCCESS ||
9749 dwSize = sizeof(DWORD);
9751 RegSetValueEx( hkLsa, "DisableLoopbackCheck", 0, dwType, (LPBYTE)&dwValue, dwSize);
9753 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
9754 AFSREG_CLT_OPENAFS_SUBKEY,
9757 REG_OPTION_NON_VOLATILE,
9761 NULL) == ERROR_SUCCESS) {
9764 dwSize = sizeof(DWORD);
9766 RegSetValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, dwType, (LPBYTE)&dwValue, dwSize);
9767 bLoopbackCheckDisabled = TRUE;
9768 RegCloseKey(hkClient);
9773 } else if (!bLoopbackCheckDisabled) {
9774 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
9775 AFSREG_CLT_OPENAFS_SUBKEY,
9778 REG_OPTION_NON_VOLATILE,
9782 NULL) == ERROR_SUCCESS) {
9784 dwSize = sizeof(DWORD);
9785 if ( RegQueryValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) == ERROR_SUCCESS &&
9787 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
9788 "SYSTEM\\CurrentControlSet\\Control\\Lsa",
9791 &hkLsa) == ERROR_SUCCESS )
9793 RegDeleteValue(hkLsa, "DisableLoopbackCheck");
9797 RegDeleteValue(hkClient, "RemoveDisableLoopbackCheck");
9798 RegCloseKey(hkClient);
9807 RegCloseKey(hkMSV10);
9813 configureExtendedSMBSessionTimeouts(void)
9816 * In a Hot Fix to Windows 2003 SP2, the smb redirector was given the following
9817 * new functionality:
9819 * [HKLM\SYSTEM\CurrentControlSet\Services\LanManWorkstation\Parameters]
9820 * "ReconnectableServers" REG_MULTI_SZ
9821 * "ExtendedSessTimeout" REG_DWORD (seconds)
9822 * "ServersWithExtendedSessTimeout" REG_MULTI_SZ
9824 * These values can be used to prevent the smb redirector from timing out
9825 * smb connection to the afs smb server prematurely.
9829 DWORD dwSize, dwAllocSize;
9831 PBYTE pHostNames = NULL, pName = NULL;
9832 BOOL bNameFound = FALSE;
9834 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
9835 "SYSTEM\\CurrentControlSet\\Services\\LanManWorkstation\\Parameters",
9838 &hkLanMan) == ERROR_SUCCESS )
9840 if ((RegQueryValueEx( hkLanMan, "ReconnectableServers", 0,
9841 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
9842 (dwType == REG_MULTI_SZ))
9844 dwAllocSize += 1 /* in case the source string is not nul terminated */
9845 + (DWORD)strlen(cm_NetbiosName) + 2;
9846 pHostNames = malloc(dwAllocSize);
9847 dwSize = dwAllocSize;
9848 if (RegQueryValueEx( hkLanMan, "ReconnectableServers", 0, &dwType,
9849 pHostNames, &dwSize) == ERROR_SUCCESS)
9851 for (pName = pHostNames;
9852 (pName - pHostNames < (int) dwSize) && *pName ;
9853 pName += strlen(pName) + 1)
9855 if ( !stricmp(pName, cm_NetbiosName) ) {
9863 if ( !bNameFound ) {
9864 size_t size = strlen(cm_NetbiosName) + 2;
9865 if ( !pHostNames ) {
9866 pHostNames = malloc(size);
9869 StringCbCopyA(pName, size, cm_NetbiosName);
9871 *pName = '\0'; /* add a second nul terminator */
9873 dwType = REG_MULTI_SZ;
9874 dwSize = (DWORD)(pName - pHostNames + 1);
9875 RegSetValueEx( hkLanMan, "ReconnectableServers", 0, dwType, pHostNames, dwSize);
9883 if ((RegQueryValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0,
9884 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
9885 (dwType == REG_MULTI_SZ))
9887 dwAllocSize += 1 /* in case the source string is not nul terminated */
9888 + (DWORD)strlen(cm_NetbiosName) + 2;
9889 pHostNames = malloc(dwAllocSize);
9890 dwSize = dwAllocSize;
9891 if (RegQueryValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0, &dwType,
9892 pHostNames, &dwSize) == ERROR_SUCCESS)
9894 for (pName = pHostNames;
9895 (pName - pHostNames < (int) dwSize) && *pName ;
9896 pName += strlen(pName) + 1)
9898 if ( !stricmp(pName, cm_NetbiosName) ) {
9906 if ( !bNameFound ) {
9907 size_t size = strlen(cm_NetbiosName) + 2;
9908 if ( !pHostNames ) {
9909 pHostNames = malloc(size);
9912 StringCbCopyA(pName, size, cm_NetbiosName);
9914 *pName = '\0'; /* add a second nul terminator */
9916 dwType = REG_MULTI_SZ;
9917 dwSize = (DWORD)(pName - pHostNames + 1);
9918 RegSetValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0, dwType, pHostNames, dwSize);
9926 if ((RegQueryValueEx( hkLanMan, "ExtendedSessTimeout", 0,
9927 &dwType, (LPBYTE)&dwValue, &dwAllocSize) != ERROR_SUCCESS) ||
9928 (dwType != REG_DWORD))
9931 dwSize = sizeof(dwValue);
9932 dwValue = 300; /* 5 minutes */
9933 RegSetValueEx( hkLanMan, "ExtendedSessTimeout", 0, dwType, (const BYTE *)&dwValue, dwSize);
9935 RegCloseKey(hkLanMan);
9940 smb_LanAdapterChangeThread(void *param)
9943 * Give the IPAddrDaemon thread a chance
9944 * to block before we trigger.
9947 smb_LanAdapterChange(0);
9950 void smb_SetLanAdapterChangeDetected(void)
9955 lock_ObtainMutex(&smb_StartedLock);
9957 if (!powerStateSuspended) {
9958 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_LanAdapterChangeThread,
9959 NULL, 0, &lpid, "smb_LanAdapterChange");
9960 osi_assertx(phandle != NULL, "smb_LanAdapterChangeThread thread creation failure");
9961 thrd_CloseHandle(phandle);
9964 smb_LanAdapterChangeDetected = 1;
9965 lock_ReleaseMutex(&smb_StartedLock);
9968 void smb_LanAdapterChange(int locked) {
9969 lana_number_t lanaNum;
9971 char NetbiosName[MAX_NB_NAME_LENGTH] = "";
9973 LANA_ENUM temp_list;
9978 afsi_log("smb_LanAdapterChange");
9981 lock_ObtainMutex(&smb_StartedLock);
9983 smb_LanAdapterChangeDetected = 0;
9985 if (!powerStateSuspended &&
9986 SUCCEEDED(lana_GetUncServerNameEx(NetbiosName, &lanaNum, &bGateway,
9987 LANA_NETBIOS_NAME_FULL)) &&
9988 lanaNum != LANA_INVALID && smb_LANadapter != lanaNum) {
9989 if ( isGateway != bGateway ) {
9990 afsi_log("Lan Adapter Change detected (%d != %d): gateway %d != %d",
9991 smb_LANadapter, lanaNum, isGateway, bGateway);
9993 } else if (strcmp(cm_NetbiosName, NetbiosName) ) {
9994 afsi_log("Lan Adapter Change detected (%d != %d): name %s != %s",
9995 smb_LANadapter, lanaNum, cm_NetbiosName, NetbiosName);
9998 NCB *ncbp = smb_GetNCB();
9999 ncbp->ncb_command = NCBENUM;
10000 ncbp->ncb_buffer = (PUCHAR)&temp_list;
10001 ncbp->ncb_length = sizeof(temp_list);
10002 code = Netbios(ncbp);
10004 if (temp_list.length != lana_list.length) {
10005 afsi_log("Lan Adapter Change detected (%d != %d): lan list length changed %d != %d",
10006 smb_LANadapter, lanaNum, temp_list.length, lana_list.length);
10009 for (i=0; i<lana_list.length; i++) {
10010 if ( temp_list.lana[i] != lana_list.lana[i] ) {
10011 afsi_log("Lan Adapter Change detected (%d != %d): lana[%d] %d != %d",
10012 smb_LANadapter, lanaNum, i, temp_list.lana[i], lana_list.lana[i]);
10024 smb_StopListeners(1);
10025 smb_RestartListeners(1);
10028 lock_ReleaseMutex(&smb_StartedLock);
10031 /* initialize Netbios */
10032 int smb_NetbiosInit(int locked)
10035 int i, lana, code, l;
10037 int delname_tried=0;
10039 int lana_found = 0;
10040 lana_number_t lanaNum;
10043 lock_ObtainMutex(&smb_StartedLock);
10045 if (smb_ListenerState != SMB_LISTENER_UNINITIALIZED &&
10046 smb_ListenerState != SMB_LISTENER_STOPPED) {
10049 lock_ReleaseMutex(&smb_StartedLock);
10052 /* setup the NCB system */
10053 ncbp = smb_GetNCB();
10055 /* Call lanahelper to get Netbios name, lan adapter number and gateway flag */
10056 if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
10057 smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
10059 if (smb_LANadapter != LANA_INVALID)
10060 afsi_log("LAN adapter number %d", smb_LANadapter);
10062 afsi_log("LAN adapter number not determined");
10065 afsi_log("Set for gateway service");
10067 afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
10069 /* something went horribly wrong. We can't proceed without a netbios name */
10071 StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
10072 osi_panic(buf, __FILE__, __LINE__);
10075 /* remember the name */
10076 len = (int)strlen(cm_NetbiosName);
10077 if (smb_localNamep)
10078 free(smb_localNamep);
10079 smb_localNamep = malloc(len+1);
10080 strcpy(smb_localNamep, cm_NetbiosName);
10081 afsi_log("smb_localNamep is >%s<", smb_localNamep);
10083 /* Also copy the value to the client character encoded string */
10084 cm_Utf8ToClientString(cm_NetbiosName, -1, cm_NetbiosNameC, MAX_NB_NAME_LENGTH);
10086 if (smb_LANadapter == LANA_INVALID) {
10087 ncbp->ncb_command = NCBENUM;
10088 ncbp->ncb_buffer = (PUCHAR)&lana_list;
10089 ncbp->ncb_length = sizeof(lana_list);
10090 code = Netbios(ncbp);
10092 afsi_log("Netbios NCBENUM error code %d", code);
10093 osi_panic(s, __FILE__, __LINE__);
10097 lana_list.length = 1;
10098 lana_list.lana[0] = smb_LANadapter;
10101 for (i = 0; i < lana_list.length; i++) {
10102 /* reset the adaptor: in Win32, this is required for every process, and
10103 * acts as an init call, not as a real hardware reset.
10105 ncbp->ncb_command = NCBRESET;
10106 ncbp->ncb_callname[0] = 100;
10107 ncbp->ncb_callname[2] = 100;
10108 ncbp->ncb_lana_num = lana_list.lana[i];
10109 code = Netbios(ncbp);
10111 code = ncbp->ncb_retcode;
10113 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
10114 lana_list.lana[i] = LANA_INVALID; /* invalid lana */
10116 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
10120 /* and declare our name so we can receive connections */
10121 memset(ncbp, 0, sizeof(*ncbp));
10122 len=lstrlen(smb_localNamep);
10123 memset(smb_sharename,' ',NCBNAMSZ);
10124 memcpy(smb_sharename,smb_localNamep,len);
10125 afsi_log("lana_list.length %d", lana_list.length);
10127 /* Keep the name so we can unregister it later */
10128 for (l = 0; l < lana_list.length; l++) {
10129 lana = lana_list.lana[l];
10131 ncbp->ncb_command = NCBADDNAME;
10132 ncbp->ncb_lana_num = lana;
10133 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10134 code = Netbios(ncbp);
10136 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
10137 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
10139 char name[NCBNAMSZ+1];
10141 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
10142 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
10146 code = ncbp->ncb_retcode;
10149 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
10152 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
10153 if (code == NRC_BRIDGE) { /* invalid LANA num */
10154 lana_list.lana[l] = LANA_INVALID;
10157 else if (code == NRC_DUPNAME) {
10158 afsi_log("Name already exists; try to delete it");
10159 memset(ncbp, 0, sizeof(*ncbp));
10160 ncbp->ncb_command = NCBDELNAME;
10161 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10162 ncbp->ncb_lana_num = lana;
10163 code = Netbios(ncbp);
10165 code = ncbp->ncb_retcode;
10167 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
10169 if (code != 0 || delname_tried) {
10170 lana_list.lana[l] = LANA_INVALID;
10172 else if (code == 0) {
10173 if (!delname_tried) {
10181 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
10182 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
10186 smb_LANadapter = lana;
10187 lana_found = 1; /* at least one worked */
10191 osi_assertx(lana_list.length >= 0, "empty lana list");
10193 afsi_log("No valid LANA numbers found!");
10194 lana_list.length = 0;
10195 smb_LANadapter = LANA_INVALID;
10196 smb_ListenerState = SMB_LISTENER_STOPPED;
10197 cm_VolStatus_Network_Stopped(cm_NetbiosName
10204 /* we're done with the NCB now */
10207 afsi_log("smb_NetbiosInit smb_LANadapter=%d",smb_LANadapter);
10208 if (lana_list.length > 0)
10209 osi_assert(smb_LANadapter != LANA_INVALID);
10212 lock_ReleaseMutex(&smb_StartedLock);
10214 return (lana_list.length > 0 ? 1 : 0);
10217 void smb_StartListeners(int locked)
10224 lock_ObtainMutex(&smb_StartedLock);
10226 if (smb_ListenerState == SMB_LISTENER_STARTED) {
10228 lock_ReleaseMutex(&smb_StartedLock);
10232 afsi_log("smb_StartListeners");
10233 /* Ensure the AFS Netbios Name is registered to allow loopback access */
10234 configureBackConnectionHostNames();
10236 /* Configure Extended SMB Session Timeouts */
10237 if (msftSMBRedirectorSupportsExtendedTimeouts()) {
10238 afsi_log("Microsoft SMB Redirector supports Extended Timeouts");
10239 configureExtendedSMBSessionTimeouts();
10242 smb_ListenerState = SMB_LISTENER_STARTED;
10243 cm_VolStatus_Network_Started(cm_NetbiosName
10249 for (i = 0; i < lana_list.length; i++) {
10250 if (lana_list.lana[i] == LANA_INVALID)
10252 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
10253 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
10254 osi_assertx(phandle != NULL, "smb_Listener thread creation failure");
10255 thrd_CloseHandle(phandle);
10258 lock_ReleaseMutex(&smb_StartedLock);
10261 void smb_RestartListeners(int locked)
10264 lock_ObtainMutex(&smb_StartedLock);
10266 if (powerStateSuspended)
10267 afsi_log("smb_RestartListeners called while suspended");
10269 if (!powerStateSuspended && smb_ListenerState != SMB_LISTENER_UNINITIALIZED) {
10270 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
10271 if (smb_NetbiosInit(1))
10272 smb_StartListeners(1);
10273 } else if (smb_LanAdapterChangeDetected) {
10274 smb_LanAdapterChange(1);
10278 lock_ReleaseMutex(&smb_StartedLock);
10281 void smb_StopListener(NCB *ncbp, int lana, int wait)
10285 memset(ncbp, 0, sizeof(*ncbp));
10286 ncbp->ncb_command = NCBDELNAME;
10287 ncbp->ncb_lana_num = lana;
10288 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10289 code = Netbios(ncbp);
10291 afsi_log("StopListener: Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
10292 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
10294 /* and then reset the LANA; this will cause the listener threads to exit */
10295 ncbp->ncb_command = NCBRESET;
10296 ncbp->ncb_callname[0] = 100;
10297 ncbp->ncb_callname[2] = 100;
10298 ncbp->ncb_lana_num = lana;
10299 code = Netbios(ncbp);
10301 code = ncbp->ncb_retcode;
10303 afsi_log("StopListener: Netbios NCBRESET lana %d error code %d", lana, code);
10305 afsi_log("StopListener: Netbios NCBRESET lana %d succeeded", lana);
10309 thrd_WaitForSingleObject_Event(ListenerShutdown[lana], INFINITE);
10312 void smb_StopListeners(int locked)
10318 lock_ObtainMutex(&smb_StartedLock);
10320 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
10322 lock_ReleaseMutex(&smb_StartedLock);
10326 afsi_log("smb_StopListeners");
10327 smb_ListenerState = SMB_LISTENER_STOPPED;
10328 cm_VolStatus_Network_Stopped(cm_NetbiosName
10334 ncbp = smb_GetNCB();
10336 /* Unregister the SMB name */
10337 for (l = 0; l < lana_list.length; l++) {
10338 lana = lana_list.lana[l];
10340 if (lana != LANA_INVALID) {
10341 smb_StopListener(ncbp, lana, TRUE);
10343 /* mark the adapter invalid */
10344 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
10348 /* force a re-evaluation of the network adapters */
10349 lana_list.length = 0;
10350 smb_LANadapter = LANA_INVALID;
10353 lock_ReleaseMutex(&smb_StartedLock);
10356 void smb_Init(osi_log_t *logp, int useV3,
10366 EVENT_HANDLE retHandle;
10367 char eventName[MAX_PATH];
10368 int startListeners = 0;
10370 smb_TlsRequestSlot = TlsAlloc();
10372 smb_MBfunc = aMBfunc;
10376 /* Initialize smb_localZero */
10377 myTime.tm_isdst = -1; /* compute whether on DST or not */
10378 myTime.tm_year = 70;
10380 myTime.tm_mday = 1;
10381 myTime.tm_hour = 0;
10384 smb_localZero = mktime(&myTime);
10386 #ifndef USE_NUMERIC_TIME_CONV
10387 /* Initialize kludge-GMT */
10388 smb_CalculateNowTZ();
10389 #endif /* USE_NUMERIC_TIME_CONV */
10390 #ifdef AFS_FREELANCE_CLIENT
10391 /* Make sure the root.afs volume has the correct time */
10392 cm_noteLocalMountPointChange();
10395 /* initialize the remote debugging log */
10398 /* and the global lock */
10399 lock_InitializeRWLock(&smb_globalLock, "smb global lock", LOCK_HIERARCHY_SMB_GLOBAL);
10400 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock", LOCK_HIERARCHY_SMB_RCT_GLOBAL);
10402 /* Raw I/O data structures */
10403 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock", LOCK_HIERARCHY_SMB_RAWBUF);
10405 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock", LOCK_HIERARCHY_SMB_LISTENER);
10406 lock_InitializeMutex(&smb_StartedLock, "smb started lock", LOCK_HIERARCHY_SMB_STARTED);
10408 /* 4 Raw I/O buffers */
10409 smb_RawBufs = calloc(65536,1);
10410 *((char **)smb_RawBufs) = NULL;
10411 for (i=0; i<3; i++) {
10412 char *rawBuf = calloc(65536,1);
10413 *((char **)rawBuf) = smb_RawBufs;
10414 smb_RawBufs = rawBuf;
10417 /* global free lists */
10418 smb_ncbFreeListp = NULL;
10419 smb_packetFreeListp = NULL;
10421 lock_ObtainMutex(&smb_StartedLock);
10422 startListeners = smb_NetbiosInit(1);
10424 /* Initialize listener and server structures */
10426 memset(dead_sessions, 0, sizeof(dead_sessions));
10427 sprintf(eventName, "SessionEvents[0]");
10428 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10429 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10430 afsi_log("Event Object Already Exists: %s", eventName);
10432 smb_NumServerThreads = nThreads;
10433 sprintf(eventName, "NCBavails[0]");
10434 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10435 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10436 afsi_log("Event Object Already Exists: %s", eventName);
10437 sprintf(eventName, "NCBevents[0]");
10438 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10439 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10440 afsi_log("Event Object Already Exists: %s", eventName);
10441 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
10442 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
10443 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10444 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10445 afsi_log("Event Object Already Exists: %s", eventName);
10446 for (i = 0; i < smb_NumServerThreads; i++) {
10447 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
10448 NCBreturns[i][0] = retHandle;
10451 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
10452 for (i = 0; i < smb_NumServerThreads; i++) {
10453 sprintf(eventName, "smb_ServerShutdown[%d]", i);
10454 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10455 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10456 afsi_log("Event Object Already Exists: %s", eventName);
10457 InitNCBslot((int)(i+1));
10459 numNCBs = smb_NumServerThreads + 1;
10461 /* Initialize dispatch table */
10462 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
10463 /* Prepare the table for unknown operations */
10464 for(i=0; i<= SMB_NOPCODES; i++) {
10465 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
10467 /* Fill in the ones we do know */
10468 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
10469 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
10470 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
10471 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
10472 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
10473 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
10474 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
10475 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
10476 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
10477 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
10478 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
10479 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
10480 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
10481 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
10482 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
10483 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
10484 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
10485 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
10486 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
10487 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
10488 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
10489 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10490 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
10491 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
10492 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
10493 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
10494 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
10495 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
10496 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10497 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
10498 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10499 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
10500 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
10501 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
10502 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10503 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
10504 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
10505 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
10506 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
10507 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
10508 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
10509 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
10510 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10511 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
10512 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10513 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
10514 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
10515 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
10516 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
10517 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
10518 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
10519 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
10520 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
10521 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
10522 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
10523 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
10524 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
10525 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
10526 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
10527 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
10528 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
10529 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
10530 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
10531 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
10532 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
10533 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10534 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
10535 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
10536 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
10537 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
10538 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
10539 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
10540 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
10541 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
10543 /* setup tran 2 dispatch table */
10544 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
10545 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
10546 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
10547 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
10548 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
10549 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
10550 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
10551 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
10552 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
10553 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
10554 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
10555 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
10556 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
10557 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
10558 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
10559 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
10560 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
10561 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
10563 /* setup the rap dispatch table */
10564 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
10565 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
10566 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
10567 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
10568 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
10572 /* if we are doing SMB authentication we have register outselves as a logon process */
10573 if (smb_authType != SMB_AUTH_NONE) {
10574 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
10575 LSA_STRING afsProcessName;
10576 LSA_OPERATIONAL_MODE dummy; /*junk*/
10578 afsProcessName.Buffer = "OpenAFSClientDaemon";
10579 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
10580 afsProcessName.MaximumLength = afsProcessName.Length + 1;
10582 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
10584 if (nts == STATUS_SUCCESS) {
10585 LSA_STRING packageName;
10586 /* we are registered. Find out the security package id */
10587 packageName.Buffer = MSV1_0_PACKAGE_NAME;
10588 packageName.Length = (USHORT)strlen(packageName.Buffer);
10589 packageName.MaximumLength = packageName.Length + 1;
10590 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
10591 if (nts == STATUS_SUCCESS) {
10593 * This code forces Windows to authenticate against the Logon Cache
10594 * first instead of attempting to authenticate against the Domain
10595 * Controller. When the Windows logon cache is enabled this improves
10596 * performance by removing the network access and works around a bug
10597 * seen at sites which are using a MIT Kerberos principal to login
10598 * to machines joined to a non-root domain in a multi-domain forest.
10599 * MsV1_0SetProcessOption was added in Windows XP.
10601 PVOID pResponse = NULL;
10602 ULONG cbResponse = 0;
10603 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
10605 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
10606 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
10607 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
10608 OptionsRequest.DisableOptions = FALSE;
10610 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
10613 sizeof(OptionsRequest),
10619 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
10620 osi_Log2(smb_logp, "MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
10623 afsi_log("MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x", nts, ntsEx);
10625 osi_Log0(smb_logp, "MsV1_0SetProcessOption success");
10626 afsi_log("MsV1_0SetProcessOption success");
10628 /* END - code from Larry */
10630 smb_lsaLogonOrigin.Buffer = "OpenAFS";
10631 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
10632 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
10634 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
10636 /* something went wrong. We report the error and revert back to no authentication
10637 because we can't perform any auth requests without a successful lsa handle
10638 or sec package id. */
10639 afsi_log("Reverting to NO SMB AUTH");
10640 smb_authType = SMB_AUTH_NONE;
10643 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
10645 /* something went wrong. We report the error and revert back to no authentication
10646 because we can't perform any auth requests without a successful lsa handle
10647 or sec package id. */
10648 afsi_log("Reverting to NO SMB AUTH");
10649 smb_authType = SMB_AUTH_NONE;
10653 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
10654 * time prevents the failure of authentication when logged into Windows with an
10655 * external Kerberos principal mapped to a local account.
10657 else if ( smb_authType == SMB_AUTH_EXTENDED) {
10658 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
10659 * then the only option is NTLMSSP anyway; so just fallback.
10664 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
10665 if (secBlobLength == 0) {
10666 smb_authType = SMB_AUTH_NTLM;
10667 afsi_log("Reverting to SMB AUTH NTLM");
10676 /* Now get ourselves a domain name. */
10677 /* For now we are using the local computer name as the domain name.
10678 * It is actually the domain for local logins, and we are acting as
10679 * a local SMB server.
10681 bufsize = lengthof(smb_ServerDomainName) - 1;
10682 GetComputerNameW(smb_ServerDomainName, &bufsize);
10683 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
10684 afsi_log("Setting SMB server domain name to [%S]", smb_ServerDomainName);
10687 /* Start listeners, waiters, servers, and daemons */
10688 if (startListeners)
10689 smb_StartListeners(1);
10691 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
10692 NULL, 0, &lpid, "smb_ClientWaiter");
10693 osi_assertx(phandle != NULL, "smb_ClientWaiter thread creation failure");
10694 thrd_CloseHandle(phandle);
10696 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
10697 NULL, 0, &lpid, "smb_ServerWaiter");
10698 osi_assertx(phandle != NULL, "smb_ServerWaiter thread creation failure");
10699 thrd_CloseHandle(phandle);
10701 for (i=0; i<smb_NumServerThreads; i++) {
10702 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
10703 (void *) i, 0, &lpid, "smb_Server");
10704 osi_assertx(phandle != NULL, "smb_Server thread creation failure");
10705 thrd_CloseHandle(phandle);
10708 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
10709 NULL, 0, &lpid, "smb_Daemon");
10710 osi_assertx(phandle != NULL, "smb_Daemon thread creation failure");
10711 thrd_CloseHandle(phandle);
10713 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
10714 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
10715 osi_assertx(phandle != NULL, "smb_WaitingLocksDaemon thread creation failure");
10716 thrd_CloseHandle(phandle);
10718 lock_ReleaseMutex(&smb_StartedLock);
10722 void smb_Shutdown(void)
10729 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
10731 /* setup the NCB system */
10732 ncbp = smb_GetNCB();
10734 /* Block new sessions by setting shutdown flag */
10735 smbShutdownFlag = 1;
10737 /* Hang up all sessions */
10738 memset((char *)ncbp, 0, sizeof(NCB));
10739 for (i = 1; i < numSessions; i++)
10741 if (dead_sessions[i])
10744 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
10745 ncbp->ncb_command = NCBHANGUP;
10746 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
10747 ncbp->ncb_lsn = (UCHAR)LSNs[i];
10748 code = Netbios(ncbp);
10749 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
10750 if (code == 0) code = ncbp->ncb_retcode;
10752 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
10753 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
10757 /* Trigger the shutdown of all SMB threads */
10758 for (i = 0; i < smb_NumServerThreads; i++)
10759 thrd_SetEvent(NCBreturns[i][0]);
10761 thrd_SetEvent(NCBevents[0]);
10762 thrd_SetEvent(SessionEvents[0]);
10763 thrd_SetEvent(NCBavails[0]);
10765 for (i = 0;i < smb_NumServerThreads; i++) {
10766 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
10767 if (code == WAIT_OBJECT_0) {
10770 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
10771 thrd_SetEvent(NCBreturns[i--][0]);
10775 /* Delete Netbios name */
10776 memset((char *)ncbp, 0, sizeof(NCB));
10777 for (i = 0; i < lana_list.length; i++) {
10778 if (lana_list.lana[i] == LANA_INVALID) continue;
10779 ncbp->ncb_command = NCBDELNAME;
10780 ncbp->ncb_lana_num = lana_list.lana[i];
10781 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10782 code = Netbios(ncbp);
10784 code = ncbp->ncb_retcode;
10786 fprintf(stderr, "Shutdown: Netbios NCBDELNAME lana %d error code %d",
10787 ncbp->ncb_lana_num, code);
10792 /* Release the reference counts held by the VCs */
10793 lock_ObtainWrite(&smb_rctLock);
10794 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
10799 if (vcp->magic != SMB_VC_MAGIC)
10800 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
10801 __FILE__, __LINE__);
10803 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10805 if (fidp->scp != NULL) {
10808 lock_ReleaseWrite(&smb_rctLock);
10809 lock_ObtainMutex(&fidp->mx);
10810 if (fidp->scp != NULL) {
10813 lock_ObtainWrite(&scp->rw);
10814 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
10815 lock_ReleaseWrite(&scp->rw);
10816 osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
10817 cm_ReleaseSCache(scp);
10819 lock_ReleaseMutex(&fidp->mx);
10820 lock_ObtainWrite(&smb_rctLock);
10824 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10826 smb_ReleaseVCNoLock(tidp->vcp);
10828 cm_user_t *userp = tidp->userp;
10829 tidp->userp = NULL;
10830 cm_ReleaseUser(userp);
10834 lock_ReleaseWrite(&smb_rctLock);
10836 TlsFree(smb_TlsRequestSlot);
10839 /* Get the UNC \\<servername>\<sharename> prefix. */
10840 char *smb_GetSharename()
10845 /* Make sure we have been properly initialized. */
10846 if (smb_localNamep == NULL)
10849 /* Allocate space for \\<servername>\<sharename>, plus the
10852 len = (strlen(smb_localNamep) + strlen("ALL") + 4) * sizeof(char);
10853 name = malloc(len);
10854 snprintf(name, len, "\\\\%s\\%s", smb_localNamep, "ALL");
10860 void smb_LogPacket(smb_packet_t *packet)
10864 unsigned length, paramlen, datalen, i, j;
10866 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
10868 if (!packet) return;
10870 osi_Log0(smb_logp, "*** SMB packet dump ***");
10872 smbp = (smb_t *) packet->data;
10873 vp = (BYTE *) packet->data;
10875 paramlen = smbp->wct * 2;
10876 datalen = *((WORD *) (smbp->vdata + paramlen));
10877 length = sizeof(*smbp) + paramlen + 1 + datalen;
10879 for (i=0;i < length; i+=16)
10881 memset( buf, ' ', 80 );
10884 itoa( i, buf, 16 );
10886 buf[strlen(buf)] = ' ';
10888 cp = (BYTE*) buf + 7;
10890 for (j=0;j < 16 && (i+j)<length; j++)
10892 *(cp++) = hex[vp[i+j] >> 4];
10893 *(cp++) = hex[vp[i+j] & 0xf];
10903 for (j=0;j < 16 && (i+j)<length;j++)
10905 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
10916 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
10919 osi_Log0(smb_logp, "*** End SMB packet dump ***");
10921 #endif /* LOG_PACKET */
10924 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
10930 smb_username_t *unp;
10931 smb_waitingLockRequest_t *wlrp;
10934 lock_ObtainRead(&smb_rctLock);
10936 sprintf(output, "begin dumping smb_username_t\r\n");
10937 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10938 for (unp = usernamesp; unp; unp=unp->nextp)
10940 cm_ucell_t *ucellp;
10942 sprintf(output, "%s -- smb_unp=0x%p, refCount=%d, cm_userp=0x%p, flags=0x%x, logoff=%u, name=%S, machine=%S\r\n",
10943 cookie, unp, unp->refCount, unp->userp, unp->flags, unp->last_logoff_t,
10944 unp->name ? unp->name : _C("NULL"),
10945 unp->machine ? unp->machine : _C("NULL"));
10946 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10948 sprintf(output, " begin dumping cm_ucell_t\r\n");
10949 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10951 for ( ucellp = unp->userp->cellInfop; ucellp; ucellp = ucellp->nextp ) {
10952 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",
10953 cookie, ucellp, ucellp->cellp, ucellp->flags, ucellp->ticketLen, ucellp->kvno,
10954 ucellp->expirationTime, ucellp->gen,
10956 ucellp->cellp->name);
10957 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10960 sprintf(output, " done dumping cm_ucell_t\r\n");
10961 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10964 sprintf(output, "done dumping smb_username_t\r\n");
10965 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10968 sprintf(output, "begin dumping smb_waitingLockRequest_t\r\n");
10969 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10972 for ( wlrp = smb_allWaitingLocks; wlrp; wlrp = (smb_waitingLockRequest_t *) osi_QNext(&wlrp->q)) {
10973 smb_waitingLock_t *lockp;
10975 sprintf(output, "%s wlrp=0x%p vcp=0x%p, scp=0x%p, type=0x%x, start_t=0x%I64u msTimeout=0x%x\r\n",
10976 cookie, wlrp, wlrp->vcp, wlrp->scp, wlrp->lockType, wlrp->start_t, wlrp->msTimeout);
10977 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10979 sprintf(output, " begin dumping smb_waitingLock_t\r\n");
10980 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10981 for (lockp = wlrp->locks; lockp; lockp = (smb_waitingLock_t *) osi_QNext(&lockp->q)) {
10982 sprintf(output, " %s -- waitlockp=0x%p lockp=0x%p key=0x%I64x offset=0x%I64x length=0x%I64x state=0x%x\r\n",
10983 cookie, lockp, lockp->lockp, lockp->key, lockp->LOffset.QuadPart, lockp->LLength.QuadPart, lockp->state);
10984 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10986 sprintf(output, " done dumping smb_waitingLock_t\r\n");
10987 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10990 sprintf(output, "done dumping smb_waitingLockRequest_t\r\n");
10991 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10993 sprintf(output, "begin dumping smb_vc_t\r\n");
10994 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10996 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
11002 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
11003 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
11004 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11006 sprintf(output, " begin dumping smb_user_t\r\n");
11007 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11008 for (userp = vcp->usersp; userp; userp = userp->nextp) {
11009 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
11010 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
11011 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11013 sprintf(output, " done dumping smb_user_t\r\n");
11014 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11016 sprintf(output, " begin dumping smb_tid_t\r\n");
11017 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11018 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
11019 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",
11020 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
11021 tidp->pathname ? tidp->pathname : _C("NULL"));
11022 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11024 sprintf(output, " done dumping smb_tid_t\r\n");
11025 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11027 sprintf(output, " begin dumping smb_fid_t\r\n");
11028 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11030 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
11032 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",
11033 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
11034 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
11035 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
11036 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11039 sprintf(output, " done dumping smb_fid_t\r\n");
11040 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11043 sprintf(output, "done dumping smb_vc_t\r\n");
11044 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11046 sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
11047 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11049 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
11055 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
11056 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
11057 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11059 sprintf(output, " begin dumping smb_user_t\r\n");
11060 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11061 for (userp = vcp->usersp; userp; userp = userp->nextp) {
11062 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
11063 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
11064 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11066 sprintf(output, " done dumping smb_user_t\r\n");
11067 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11069 sprintf(output, " begin dumping smb_tid_t\r\n");
11070 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11071 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
11072 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",
11073 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
11074 tidp->pathname ? tidp->pathname : _C("NULL"));
11075 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11077 sprintf(output, " done dumping smb_tid_t\r\n");
11078 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11080 sprintf(output, " begin dumping smb_fid_t\r\n");
11081 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11083 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
11085 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",
11086 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
11087 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
11088 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
11089 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11092 sprintf(output, " done dumping smb_fid_t\r\n");
11093 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11096 sprintf(output, "done dumping DEAD smb_vc_t\r\n");
11097 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11100 lock_ReleaseRead(&smb_rctLock);
11104 long smb_IsNetworkStarted(void)
11107 lock_ObtainWrite(&smb_globalLock);
11108 rc = (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);
11109 lock_ReleaseWrite(&smb_globalLock);