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>
25 #include <rx/rx_prototypes.h>
26 #include <WINNT\afsreg.h>
29 #include "lanahelper.h"
31 /* These characters are illegal in Windows filenames */
32 static char *illegalChars = "\\/:*?\"<>|";
34 int smbShutdownFlag = 0;
36 int smb_LogoffTokenTransfer;
37 time_t smb_LogoffTransferTimeout;
39 int smb_StoreAnsiFilenames = 0;
41 DWORD last_msg_time = 0;
45 unsigned int sessionGen = 0;
47 extern void afsi_log(char *pattern, ...);
48 extern HANDLE afsi_file;
50 osi_hyper_t hzero = {0, 0};
51 osi_hyper_t hones = {0xFFFFFFFF, -1};
54 osi_rwlock_t smb_globalLock;
55 osi_rwlock_t smb_rctLock;
56 osi_mutex_t smb_ListenerLock;
59 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
62 long smb_maxObsConcurrentCalls=0;
63 long smb_concurrentCalls=0;
65 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
67 smb_packet_t *smb_packetFreeListp;
68 smb_ncb_t *smb_ncbFreeListp;
70 int smb_NumServerThreads;
72 int numNCBs, numSessions, numVCs;
74 int smb_maxVCPerServer;
75 int smb_maxMpxRequests;
77 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
79 ULONG smb_lsaSecPackage;
80 LSA_STRING smb_lsaLogonOrigin;
82 #define NCB_MAX MAXIMUM_WAIT_OBJECTS
83 EVENT_HANDLE NCBavails[NCB_MAX], NCBevents[NCB_MAX];
84 EVENT_HANDLE **NCBreturns;
85 EVENT_HANDLE **NCBShutdown;
86 EVENT_HANDLE *smb_ServerShutdown;
87 DWORD NCBsessions[NCB_MAX];
89 struct smb_packet *bufs[NCB_MAX];
91 #define SESSION_MAX MAXIMUM_WAIT_OBJECTS - 4
92 EVENT_HANDLE SessionEvents[SESSION_MAX];
93 unsigned short LSNs[SESSION_MAX];
94 int lanas[SESSION_MAX];
95 BOOL dead_sessions[SESSION_MAX];
99 osi_mutex_t smb_RawBufLock;
102 #define SMB_MASKFLAG_TILDE 1
103 #define SMB_MASKFLAG_CASEFOLD 2
105 #define RAWTIMEOUT INFINITE
108 typedef struct raw_write_cont {
117 /* dir search stuff */
118 long smb_dirSearchCounter = 1;
119 smb_dirSearch_t *smb_firstDirSearchp;
120 smb_dirSearch_t *smb_lastDirSearchp;
122 /* hide dot files? */
123 int smb_hideDotFiles;
125 /* global state about V3 protocols */
126 int smb_useV3; /* try to negotiate V3 */
128 static showErrors = 0;
129 /* MessageBox or something like it */
130 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
133 * Time in Unix format of midnight, 1/1/1970 local time.
134 * When added to dosUTime, gives Unix (AFS) time.
136 time_t smb_localZero = 0;
138 #define USE_NUMERIC_TIME_CONV 1
140 #ifndef USE_NUMERIC_TIME_CONV
141 /* Time difference for converting to kludge-GMT */
142 afs_uint32 smb_NowTZ;
143 #endif /* USE_NUMERIC_TIME_CONV */
145 char *smb_localNamep = NULL;
147 smb_vc_t *smb_allVCsp;
148 smb_vc_t *smb_deadVCsp;
150 smb_username_t *usernamesp = NULL;
152 smb_waitingLockRequest_t *smb_allWaitingLocks;
154 DWORD smb_TlsRequestSlot = -1;
157 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
158 NCB *ncbp, raw_write_cont_t *rwcp);
159 void smb_NetbiosInit();
162 void smb_LogPacket(smb_packet_t *packet);
163 #endif /* LOG_PACKET */
165 char smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = ""; /* domain name */
166 int smb_ServerDomainNameLength = 0;
167 char smb_ServerOS[] = "Windows 5.0"; /* Faux OS String */
168 int smb_ServerOSLength = sizeof(smb_ServerOS);
169 char smb_ServerLanManager[] = "Windows 2000 LAN Manager"; /* Faux LAN Manager string */
170 int smb_ServerLanManagerLength = sizeof(smb_ServerLanManager);
172 /* Faux server GUID. This is never checked. */
173 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
175 void smb_ResetServerPriority()
177 void * p = TlsGetValue(smb_TlsRequestSlot);
180 TlsSetValue(smb_TlsRequestSlot, NULL);
181 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
185 void smb_SetRequestStartTime()
187 time_t * tp = TlsGetValue(smb_TlsRequestSlot);
189 tp = malloc(sizeof(time_t));
193 if (!TlsSetValue(smb_TlsRequestSlot, tp))
198 void smb_UpdateServerPriority()
200 time_t *tp = TlsGetValue(smb_TlsRequestSlot);
203 time_t now = osi_Time();
205 /* Give one priority boost for each 15 seconds */
206 SetThreadPriority(GetCurrentThread(), (now - *tp) / 15);
211 const char * ncb_error_string(int code)
215 case 0x01: s = "llegal buffer length"; break;
216 case 0x03: s = "illegal command"; break;
217 case 0x05: s = "command timed out"; break;
218 case 0x06: s = "message incomplete, issue another command"; break;
219 case 0x07: s = "illegal buffer address"; break;
220 case 0x08: s = "session number out of range"; break;
221 case 0x09: s = "no resource available"; break;
222 case 0x0a: s = "session closed"; break;
223 case 0x0b: s = "command cancelled"; break;
224 case 0x0d: s = "duplicate name"; break;
225 case 0x0e: s = "name table full"; break;
226 case 0x0f: s = "no deletions, name has active sessions"; break;
227 case 0x11: s = "local session table full"; break;
228 case 0x12: s = "remote session table full"; break;
229 case 0x13: s = "illegal name number"; break;
230 case 0x14: s = "no callname"; break;
231 case 0x15: s = "cannot put * in NCB_NAME"; break;
232 case 0x16: s = "name in use on remote adapter"; break;
233 case 0x17: s = "name deleted"; break;
234 case 0x18: s = "session ended abnormally"; break;
235 case 0x19: s = "name conflict detected"; break;
236 case 0x21: s = "interface busy, IRET before retrying"; break;
237 case 0x22: s = "too many commands outstanding, retry later";break;
238 case 0x23: s = "ncb_lana_num field invalid"; break;
239 case 0x24: s = "command completed while cancel occurring "; break;
240 case 0x26: s = "command not valid to cancel"; break;
241 case 0x30: s = "name defined by anther local process"; break;
242 case 0x34: s = "environment undefined. RESET required"; break;
243 case 0x35: s = "required OS resources exhausted"; break;
244 case 0x36: s = "max number of applications exceeded"; break;
245 case 0x37: s = "no saps available for netbios"; break;
246 case 0x38: s = "requested resources are not available"; break;
247 case 0x39: s = "invalid ncb address or length > segment"; break;
248 case 0x3B: s = "invalid NCB DDID"; break;
249 case 0x3C: s = "lock of user area failed"; break;
250 case 0x3f: s = "NETBIOS not loaded"; break;
251 case 0x40: s = "system error"; break;
252 default: s = "unknown error";
258 char * myCrt_Dispatch(int i)
263 return "(00)ReceiveCoreMakeDir";
265 return "(01)ReceiveCoreRemoveDir";
267 return "(02)ReceiveCoreOpen";
269 return "(03)ReceiveCoreCreate";
271 return "(04)ReceiveCoreClose";
273 return "(05)ReceiveCoreFlush";
275 return "(06)ReceiveCoreUnlink";
277 return "(07)ReceiveCoreRename";
279 return "(08)ReceiveCoreGetFileAttributes";
281 return "(09)ReceiveCoreSetFileAttributes";
283 return "(0a)ReceiveCoreRead";
285 return "(0b)ReceiveCoreWrite";
287 return "(0c)ReceiveCoreLockRecord";
289 return "(0d)ReceiveCoreUnlockRecord";
291 return "(0e)SendCoreBadOp";
293 return "(0f)ReceiveCoreCreate";
295 return "(10)ReceiveCoreCheckPath";
297 return "(11)SendCoreBadOp";
299 return "(12)ReceiveCoreSeek";
301 return "(1a)ReceiveCoreReadRaw";
303 return "(1d)ReceiveCoreWriteRawDummy";
305 return "(22)ReceiveV3SetAttributes";
307 return "(23)ReceiveV3GetAttributes";
309 return "(24)ReceiveV3LockingX";
311 return "(25)ReceiveV3Trans";
313 return "(26)ReceiveV3Trans[aux]";
315 return "(29)SendCoreBadOp";
317 return "(2b)ReceiveCoreEcho";
319 return "(2d)ReceiveV3OpenX";
321 return "(2e)ReceiveV3ReadX";
323 return "(2f)ReceiveV3WriteX";
325 return "(32)ReceiveV3Tran2A";
327 return "(33)ReceiveV3Tran2A[aux]";
329 return "(34)ReceiveV3FindClose";
331 return "(35)ReceiveV3FindNotifyClose";
333 return "(70)ReceiveCoreTreeConnect";
335 return "(71)ReceiveCoreTreeDisconnect";
337 return "(72)ReceiveNegotiate";
339 return "(73)ReceiveV3SessionSetupX";
341 return "(74)ReceiveV3UserLogoffX";
343 return "(75)ReceiveV3TreeConnectX";
345 return "(80)ReceiveCoreGetDiskAttributes";
347 return "(81)ReceiveCoreSearchDir";
351 return "(83)FindUnique";
353 return "(84)FindClose";
355 return "(A0)ReceiveNTTransact";
357 return "(A2)ReceiveNTCreateX";
359 return "(A4)ReceiveNTCancel";
361 return "(A5)ReceiveNTRename";
363 return "(C0)OpenPrintFile";
365 return "(C1)WritePrintFile";
367 return "(C2)ClosePrintFile";
369 return "(C3)GetPrintQueue";
371 return "(D8)ReadBulk";
373 return "(D9)WriteBulk";
375 return "(DA)WriteBulkData";
377 return "unknown SMB op";
381 char * myCrt_2Dispatch(int i)
386 return "unknown SMB op-2";
388 return "S(00)CreateFile_ReceiveTran2Open";
390 return "S(01)FindFirst_ReceiveTran2SearchDir";
392 return "S(02)FindNext_ReceiveTran2SearchDir"; /* FindNext */
394 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
396 return "S(04)SetFileSystem_ReceiveTran2SetFSInfo";
398 return "S(05)QueryPathInfo_ReceiveTran2QPathInfo";
400 return "S(06)SetPathInfo_ReceiveTran2SetPathInfo";
402 return "S(07)QueryFileInfo_ReceiveTran2QFileInfo";
404 return "S(08)SetFileInfo_ReceiveTran2SetFileInfo";
406 return "S(09)_ReceiveTran2FSCTL";
408 return "S(0a)_ReceiveTran2IOCTL";
410 return "S(0b)_ReceiveTran2FindNotifyFirst";
412 return "S(0c)_ReceiveTran2FindNotifyNext";
414 return "S(0d)_ReceiveTran2CreateDirectory";
416 return "S(0e)_ReceiveTran2SessionSetup";
418 return "S(0f)_QueryFileSystemInformationFid";
420 return "S(10)_ReceiveTran2GetDfsReferral";
422 return "S(11)_ReceiveTran2ReportDfsInconsistency";
426 char * myCrt_RapDispatch(int i)
431 return "unknown RAP OP";
433 return "RAP(0)NetShareEnum";
435 return "RAP(1)NetShareGetInfo";
437 return "RAP(13)NetServerGetInfo";
439 return "RAP(63)NetWkStaGetInfo";
443 /* scache must be locked */
444 unsigned int smb_Attributes(cm_scache_t *scp)
448 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
449 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
450 scp->fileType == CM_SCACHETYPE_INVALID)
452 attrs = SMB_ATTR_DIRECTORY;
453 #ifdef SPECIAL_FOLDERS
454 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
455 #endif /* SPECIAL_FOLDERS */
456 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
457 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
462 * We used to mark a file RO if it was in an RO volume, but that
463 * turns out to be impolitic in NT. See defect 10007.
466 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
467 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
469 if ((scp->unixModeBits & 0222) == 0)
470 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
476 /* Check if the named file/dir is a dotfile/dotdir */
477 /* String pointed to by lastComp can have leading slashes, but otherwise should have
478 no other patch components */
479 unsigned int smb_IsDotFile(char *lastComp) {
482 /* skip over slashes */
483 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
488 /* nulls, curdir and parent dir doesn't count */
494 if(*(s+1) == '.' && !*(s + 2))
501 static int ExtractBits(WORD bits, short start, short len)
508 num = bits << (16 - end);
509 num = num >> ((16 - end) + start);
514 void ShowUnixTime(char *FuncName, time_t unixTime)
519 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
521 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
522 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
524 int day, month, year, sec, min, hour;
527 day = ExtractBits(wDate, 0, 5);
528 month = ExtractBits(wDate, 5, 4);
529 year = ExtractBits(wDate, 9, 7) + 1980;
531 sec = ExtractBits(wTime, 0, 5);
532 min = ExtractBits(wTime, 5, 6);
533 hour = ExtractBits(wTime, 11, 5);
535 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
536 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
540 /* Determine if we are observing daylight savings time */
541 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
543 TIME_ZONE_INFORMATION timeZoneInformation;
544 SYSTEMTIME utc, local, localDST;
546 /* Get the time zone info. NT uses this to calc if we are in DST. */
547 GetTimeZoneInformation(&timeZoneInformation);
549 /* Return the daylight bias */
550 *pDstBias = timeZoneInformation.DaylightBias;
552 /* Return the bias */
553 *pBias = timeZoneInformation.Bias;
555 /* Now determine if DST is being observed */
557 /* Get the UTC (GMT) time */
560 /* Convert UTC time to local time using the time zone info. If we are
561 observing DST, the calculated local time will include this.
563 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
565 /* Set the daylight bias to 0. The daylight bias is the amount of change
566 * in time that we use for daylight savings time. By setting this to 0
567 * we cause there to be no change in time during daylight savings time.
569 timeZoneInformation.DaylightBias = 0;
571 /* Convert the utc time to local time again, but this time without any
572 adjustment for daylight savings time.
574 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
576 /* If the two times are different, then it means that the localDST that
577 we calculated includes the daylight bias, and therefore we are
578 observing daylight savings time.
580 *pDST = localDST.wHour != local.wHour;
584 void CompensateForSmbClientLastWriteTimeBugs(afs_uint32 *pLastWriteTime)
586 BOOL dst; /* Will be TRUE if observing DST */
587 LONG dstBias; /* Offset from local time if observing DST */
588 LONG bias; /* Offset from GMT for local time */
591 * This function will adjust the last write time to compensate
592 * for two bugs in the smb client:
594 * 1) During Daylight Savings Time, the LastWriteTime is ahead
595 * in time by the DaylightBias (ignoring the sign - the
596 * DaylightBias is always stored as a negative number). If
597 * the DaylightBias is -60, then the LastWriteTime will be
598 * ahead by 60 minutes.
600 * 2) If the local time zone is a positive offset from GMT, then
601 * the LastWriteTime will be the correct local time plus the
602 * Bias (ignoring the sign - a positive offset from GMT is
603 * always stored as a negative Bias). If the Bias is -120,
604 * then the LastWriteTime will be ahead by 120 minutes.
606 * These bugs can occur at the same time.
609 GetTimeZoneInfo(&dst, &dstBias, &bias);
611 /* First adjust for DST */
613 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
615 /* Now adjust for a positive offset from GMT (a negative bias). */
617 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
620 #ifndef USE_NUMERIC_TIME_CONV
622 * Calculate the difference (in seconds) between local time and GMT.
623 * This enables us to convert file times to kludge-GMT.
629 struct tm gmt_tm, local_tm;
630 int days, hours, minutes, seconds;
633 gmt_tm = *(gmtime(&t));
634 local_tm = *(localtime(&t));
636 days = local_tm.tm_yday - gmt_tm.tm_yday;
637 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour;
638 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
639 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
643 #endif /* USE_NUMERIC_TIME_CONV */
645 #ifdef USE_NUMERIC_TIME_CONV
646 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
648 // Note that LONGLONG is a 64-bit value
651 ll = Int32x32To64(unixTime, 10000000) + 116444736000000000;
652 largeTimep->dwLowDateTime = (DWORD)(ll & 0xFFFFFFFF);
653 largeTimep->dwHighDateTime = (DWORD)(ll >> 32);
656 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
661 time_t ersatz_unixTime;
664 * Must use kludge-GMT instead of real GMT.
665 * kludge-GMT is computed by adding time zone difference to localtime.
668 * ltp = gmtime(&unixTime);
670 ersatz_unixTime = unixTime - smb_NowTZ;
671 ltp = localtime(&ersatz_unixTime);
673 /* if we fail, make up something */
676 localJunk.tm_year = 89 - 20;
677 localJunk.tm_mon = 4;
678 localJunk.tm_mday = 12;
679 localJunk.tm_hour = 0;
680 localJunk.tm_min = 0;
681 localJunk.tm_sec = 0;
684 stm.wYear = ltp->tm_year + 1900;
685 stm.wMonth = ltp->tm_mon + 1;
686 stm.wDayOfWeek = ltp->tm_wday;
687 stm.wDay = ltp->tm_mday;
688 stm.wHour = ltp->tm_hour;
689 stm.wMinute = ltp->tm_min;
690 stm.wSecond = ltp->tm_sec;
691 stm.wMilliseconds = 0;
693 SystemTimeToFileTime(&stm, largeTimep);
695 #endif /* USE_NUMERIC_TIME_CONV */
697 #ifdef USE_NUMERIC_TIME_CONV
698 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
700 // Note that LONGLONG is a 64-bit value
703 ll = largeTimep->dwHighDateTime;
705 ll += largeTimep->dwLowDateTime;
707 ll -= 116444736000000000;
710 *unixTimep = (DWORD)ll;
712 #else /* USE_NUMERIC_TIME_CONV */
713 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
719 FileTimeToSystemTime(largeTimep, &stm);
721 lt.tm_year = stm.wYear - 1900;
722 lt.tm_mon = stm.wMonth - 1;
723 lt.tm_wday = stm.wDayOfWeek;
724 lt.tm_mday = stm.wDay;
725 lt.tm_hour = stm.wHour;
726 lt.tm_min = stm.wMinute;
727 lt.tm_sec = stm.wSecond;
730 save_timezone = _timezone;
731 _timezone += smb_NowTZ;
732 *unixTimep = mktime(<);
733 _timezone = save_timezone;
735 #endif /* USE_NUMERIC_TIME_CONV */
737 void smb_SearchTimeFromUnixTime(afs_uint32 *searchTimep, time_t unixTime)
747 /* if we fail, make up something */
750 localJunk.tm_year = 89 - 20;
751 localJunk.tm_mon = 4;
752 localJunk.tm_mday = 12;
753 localJunk.tm_hour = 0;
754 localJunk.tm_min = 0;
755 localJunk.tm_sec = 0;
758 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
759 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
760 *searchTimep = (dosDate<<16) | dosTime;
763 void smb_UnixTimeFromSearchTime(time_t *unixTimep, afs_uint32 searchTime)
765 unsigned short dosDate;
766 unsigned short dosTime;
769 dosDate = (unsigned short) (searchTime & 0xffff);
770 dosTime = (unsigned short) ((searchTime >> 16) & 0xffff);
772 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
773 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
774 localTm.tm_mday = (dosDate) & 0x1f;
775 localTm.tm_hour = (dosTime>>11) & 0x1f;
776 localTm.tm_min = (dosTime >> 5) & 0x3f;
777 localTm.tm_sec = (dosTime & 0x1f) * 2;
778 localTm.tm_isdst = -1; /* compute whether DST in effect */
780 *unixTimep = mktime(&localTm);
783 void smb_DosUTimeFromUnixTime(afs_uint32 *dosUTimep, time_t unixTime)
785 time_t diff_t = unixTime - smb_localZero;
786 #if defined(DEBUG) && !defined(_USE_32BIT_TIME_T)
787 osi_assert(diff_t < _UI32_MAX);
789 *dosUTimep = (afs_uint32)diff_t;
792 void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
794 *unixTimep = dosTime + smb_localZero;
797 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
801 lock_ObtainWrite(&smb_globalLock); /* for numVCs */
802 lock_ObtainWrite(&smb_rctLock);
803 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
804 if (vcp->magic != SMB_VC_MAGIC)
805 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
808 if (lsn == vcp->lsn && lana == vcp->lana &&
809 !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
810 smb_HoldVCNoLock(vcp);
814 if (!vcp && (flags & SMB_FLAG_CREATE)) {
815 vcp = malloc(sizeof(*vcp));
816 memset(vcp, 0, sizeof(*vcp));
817 vcp->vcID = ++numVCs;
818 vcp->magic = SMB_VC_MAGIC;
819 vcp->refCount = 2; /* smb_allVCsp and caller */
822 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
823 vcp->nextp = smb_allVCsp;
825 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
830 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
831 /* We must obtain a challenge for extended auth
832 * in case the client negotiates smb v3
834 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
835 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
836 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp;
837 ULONG lsaRespSize = 0;
839 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
841 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
848 if (nts != STATUS_SUCCESS)
849 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
850 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
851 osi_assert(nts == STATUS_SUCCESS); /* this had better work! */
853 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
854 LsaFreeReturnBuffer(lsaResp);
857 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
859 if (numVCs >= CM_SESSION_RESERVED) {
861 osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
864 lock_ReleaseWrite(&smb_rctLock);
865 lock_ReleaseWrite(&smb_globalLock);
869 int smb_IsStarMask(char *maskp)
874 for(i=0; i<11; i++) {
876 if (tc == '?' || tc == '*' || tc == '>')
882 void smb_ReleaseVCInternal(smb_vc_t *vcp)
889 if (vcp->refCount == 0) {
890 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
891 /* remove VCP from smb_deadVCsp */
892 for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
898 lock_FinalizeMutex(&vcp->mx);
899 memset(vcp,0,sizeof(smb_vc_t));
902 for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
906 osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
907 avcp?"not ":"",vcp, vcp->refCount);
909 GenerateMiniDump(NULL);
911 /* This is a wrong. However, I suspect that there is an undercount
912 * and I don't want to release 1.4.1 in a state that will allow
913 * smb_vc_t objects to be deallocated while still in the
914 * smb_allVCsp list. The list is supposed to keep a reference
915 * to the smb_vc_t. Put it back.
922 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
924 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
925 smb_ReleaseVCInternal(vcp);
928 void smb_ReleaseVC(smb_vc_t *vcp)
930 lock_ObtainWrite(&smb_rctLock);
931 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
932 smb_ReleaseVCInternal(vcp);
933 lock_ReleaseWrite(&smb_rctLock);
936 void smb_HoldVCNoLock(smb_vc_t *vcp)
939 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
942 void smb_HoldVC(smb_vc_t *vcp)
944 lock_ObtainWrite(&smb_rctLock);
946 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
947 lock_ReleaseWrite(&smb_rctLock);
950 void smb_CleanupDeadVC(smb_vc_t *vcp)
958 smb_user_t *uidpIter;
959 smb_user_t *uidpNext;
963 lock_ObtainMutex(&vcp->mx);
964 if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
965 lock_ReleaseMutex(&vcp->mx);
966 osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
969 vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
970 lock_ReleaseMutex(&vcp->mx);
971 osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
973 lock_ObtainWrite(&smb_rctLock);
974 /* remove VCP from smb_allVCsp */
975 for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
976 if ((*vcpp)->magic != SMB_VC_MAGIC)
977 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
981 vcp->nextp = smb_deadVCsp;
983 /* Hold onto the reference until we are done with this function */
988 for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
989 fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
991 if (fidpIter->delete)
995 osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
997 smb_HoldFIDNoLock(fidpIter);
998 lock_ReleaseWrite(&smb_rctLock);
1000 smb_CloseFID(vcp, fidpIter, NULL, 0);
1001 smb_ReleaseFID(fidpIter);
1003 lock_ObtainWrite(&smb_rctLock);
1004 fidpNext = vcp->fidsp;
1007 for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1008 tidpNext = tidpIter->nextp;
1009 if (tidpIter->delete)
1011 tidpIter->delete = 1;
1013 tid = tidpIter->tid;
1014 osi_Log2(smb_logp, " Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1016 smb_HoldTIDNoLock(tidpIter);
1017 lock_ReleaseWrite(&smb_rctLock);
1019 smb_ReleaseTID(tidpIter);
1021 lock_ObtainWrite(&smb_rctLock);
1022 tidpNext = vcp->tidsp;
1025 for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1026 uidpNext = uidpIter->nextp;
1027 if (uidpIter->delete)
1029 uidpIter->delete = 1;
1031 /* do not add an additional reference count for the smb_user_t
1032 * as the smb_vc_t already is holding a reference */
1033 lock_ReleaseWrite(&smb_rctLock);
1035 smb_ReleaseUID(uidpIter);
1037 lock_ObtainWrite(&smb_rctLock);
1038 uidpNext = vcp->usersp;
1041 /* The vcp is now on the deadVCsp list. We intentionally drop the
1042 * reference so that the refcount can reach 0 and we can delete it */
1043 smb_ReleaseVCNoLock(vcp);
1045 lock_ReleaseWrite(&smb_rctLock);
1046 osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1049 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1053 lock_ObtainWrite(&smb_rctLock);
1055 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1056 if (tidp->refCount == 0 && tidp->delete) {
1058 lock_ReleaseWrite(&smb_rctLock);
1059 smb_ReleaseTID(tidp);
1060 lock_ObtainWrite(&smb_rctLock);
1064 if (tid == tidp->tid) {
1069 if (!tidp && (flags & SMB_FLAG_CREATE)) {
1070 tidp = malloc(sizeof(*tidp));
1071 memset(tidp, 0, sizeof(*tidp));
1072 tidp->nextp = vcp->tidsp;
1075 smb_HoldVCNoLock(vcp);
1077 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
1080 lock_ReleaseWrite(&smb_rctLock);
1084 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1089 void smb_ReleaseTID(smb_tid_t *tidp)
1096 lock_ObtainWrite(&smb_rctLock);
1097 osi_assert(tidp->refCount-- > 0);
1098 if (tidp->refCount == 0 && (tidp->delete)) {
1099 ltpp = &tidp->vcp->tidsp;
1100 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1104 osi_assert(tp != NULL);
1106 lock_FinalizeMutex(&tidp->mx);
1107 userp = tidp->userp; /* remember to drop ref later */
1109 smb_ReleaseVCNoLock(tidp->vcp);
1112 lock_ReleaseWrite(&smb_rctLock);
1114 cm_ReleaseUser(userp);
1117 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1119 smb_user_t *uidp = NULL;
1121 lock_ObtainWrite(&smb_rctLock);
1122 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1123 if (uid == uidp->userID) {
1125 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%s]",
1127 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
1131 if (!uidp && (flags & SMB_FLAG_CREATE)) {
1132 uidp = malloc(sizeof(*uidp));
1133 memset(uidp, 0, sizeof(*uidp));
1134 uidp->nextp = vcp->usersp;
1135 uidp->refCount = 2; /* one for the vcp and one for the caller */
1137 smb_HoldVCNoLock(vcp);
1139 lock_InitializeMutex(&uidp->mx, "user_t mutex");
1141 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%s]",
1143 osi_LogSaveString(smb_logp,uidp->unp ? uidp->unp->name : ""));
1145 lock_ReleaseWrite(&smb_rctLock);
1149 smb_username_t *smb_FindUserByName(char *usern, char *machine, afs_uint32 flags)
1151 smb_username_t *unp= NULL;
1153 lock_ObtainWrite(&smb_rctLock);
1154 for(unp = usernamesp; unp; unp = unp->nextp) {
1155 if (stricmp(unp->name, usern) == 0 &&
1156 stricmp(unp->machine, machine) == 0) {
1161 if (!unp && (flags & SMB_FLAG_CREATE)) {
1162 unp = malloc(sizeof(*unp));
1163 memset(unp, 0, sizeof(*unp));
1165 unp->nextp = usernamesp;
1166 unp->name = strdup(usern);
1167 unp->machine = strdup(machine);
1169 lock_InitializeMutex(&unp->mx, "username_t mutex");
1170 if (flags & SMB_FLAG_AFSLOGON)
1171 unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1174 lock_ReleaseWrite(&smb_rctLock);
1178 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
1180 smb_user_t *uidp= NULL;
1182 lock_ObtainWrite(&smb_rctLock);
1183 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1186 if (stricmp(uidp->unp->name, usern) == 0) {
1188 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%s]",
1189 vcp,uidp->userID,osi_LogSaveString(smb_logp,usern));
1194 lock_ReleaseWrite(&smb_rctLock);
1198 void smb_ReleaseUsername(smb_username_t *unp)
1201 smb_username_t **lupp;
1202 cm_user_t *userp = NULL;
1203 time_t now = osi_Time();
1205 lock_ObtainWrite(&smb_rctLock);
1206 osi_assert(unp->refCount-- > 0);
1207 if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1208 (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1210 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1214 osi_assert(up != NULL);
1216 up->nextp = NULL; /* do not remove this */
1217 lock_FinalizeMutex(&unp->mx);
1223 lock_ReleaseWrite(&smb_rctLock);
1226 cm_ReleaseUser(userp);
1230 void smb_HoldUIDNoLock(smb_user_t *uidp)
1235 void smb_ReleaseUID(smb_user_t *uidp)
1239 smb_username_t *unp = NULL;
1241 lock_ObtainWrite(&smb_rctLock);
1242 osi_assert(uidp->refCount-- > 0);
1243 if (uidp->refCount == 0) {
1244 lupp = &uidp->vcp->usersp;
1245 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1249 osi_assert(up != NULL);
1251 lock_FinalizeMutex(&uidp->mx);
1253 smb_ReleaseVCNoLock(uidp->vcp);
1257 lock_ReleaseWrite(&smb_rctLock);
1261 cm_ReleaseUserVCRef(unp->userp);
1262 smb_ReleaseUsername(unp);
1266 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1268 cm_user_t *up = NULL;
1273 lock_ObtainMutex(&uidp->mx);
1275 up = uidp->unp->userp;
1278 lock_ReleaseMutex(&uidp->mx);
1284 /* retrieve a held reference to a user structure corresponding to an incoming
1286 * corresponding release function is cm_ReleaseUser.
1288 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1291 cm_user_t *up = NULL;
1294 smbp = (smb_t *) inp;
1295 uidp = smb_FindUID(vcp, smbp->uid, 0);
1299 up = smb_GetUserFromUID(uidp);
1301 smb_ReleaseUID(uidp);
1306 * Return a pointer to a pathname extracted from a TID structure. The
1307 * TID structure is not held; assume it won't go away.
1309 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1314 tidp = smb_FindTID(vcp, tid, 0);
1318 if (tidp->flags & SMB_TIDFLAG_IPC) {
1319 code = CM_ERROR_TIDIPC;
1320 /* tidp->pathname would be NULL, but that's fine */
1322 *treepath = tidp->pathname;
1323 smb_ReleaseTID(tidp);
1328 /* check to see if we have a chained fid, that is, a fid that comes from an
1329 * OpenAndX message that ran earlier in this packet. In this case, the fid
1330 * field in a read, for example, request, isn't set, since the value is
1331 * supposed to be inherited from the openAndX call.
1333 int smb_ChainFID(int fid, smb_packet_t *inp)
1335 if (inp->fid == 0 || inp->inCount == 0)
1341 /* are we a priv'd user? What does this mean on NT? */
1342 int smb_SUser(cm_user_t *userp)
1347 /* find a file ID. If we pass in 0 we select an unused File ID.
1348 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1349 * smb_fid_t data structure if desired File ID cannot be found.
1351 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1356 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1359 lock_ObtainWrite(&smb_rctLock);
1360 /* figure out if we need to allocate a new file ID */
1363 fid = vcp->fidCounter;
1367 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1368 if (fidp->refCount == 0 && fidp->delete) {
1370 lock_ReleaseWrite(&smb_rctLock);
1371 smb_ReleaseFID(fidp);
1372 lock_ObtainWrite(&smb_rctLock);
1375 if (fid == fidp->fid) {
1378 if (fid == 0xFFFF) {
1380 "New FID number wraps on vcp 0x%x", vcp);
1390 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1391 char eventName[MAX_PATH];
1393 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1394 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1395 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1396 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1397 thrd_CloseHandle(event);
1399 if (fid == 0xFFFF) {
1400 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1406 fidp = malloc(sizeof(*fidp));
1407 memset(fidp, 0, sizeof(*fidp));
1408 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1411 smb_HoldVCNoLock(vcp);
1412 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1414 fidp->curr_chunk = fidp->prev_chunk = -2;
1415 fidp->raw_write_event = event;
1417 vcp->fidCounter = fid+1;
1418 if (vcp->fidCounter == 0xFFFF) {
1419 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1421 vcp->fidCounter = 1;
1426 lock_ReleaseWrite(&smb_rctLock);
1430 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1432 smb_fid_t *fidp = NULL;
1438 lock_ObtainWrite(&smb_rctLock);
1439 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1440 if (scp == fidp->scp) {
1445 lock_ReleaseWrite(&smb_rctLock);
1449 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1454 void smb_ReleaseFID(smb_fid_t *fidp)
1456 cm_scache_t *scp = NULL;
1457 cm_user_t *userp = NULL;
1458 smb_vc_t *vcp = NULL;
1459 smb_ioctl_t *ioctlp;
1461 lock_ObtainMutex(&fidp->mx);
1462 lock_ObtainWrite(&smb_rctLock);
1463 osi_assert(fidp->refCount-- > 0);
1464 if (fidp->refCount == 0 && (fidp->delete)) {
1467 scp = fidp->scp; /* release after lock is released */
1469 lock_ObtainMutex(&scp->mx);
1470 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1471 lock_ReleaseMutex(&scp->mx);
1472 osi_Log2(afsd_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1475 userp = fidp->userp;
1479 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1480 thrd_CloseHandle(fidp->raw_write_event);
1482 /* and see if there is ioctl stuff to free */
1483 ioctlp = fidp->ioctlp;
1486 cm_FreeSpace(ioctlp->prefix);
1487 if (ioctlp->inAllocp)
1488 free(ioctlp->inAllocp);
1489 if (ioctlp->outAllocp)
1490 free(ioctlp->outAllocp);
1493 lock_ReleaseMutex(&fidp->mx);
1494 lock_FinalizeMutex(&fidp->mx);
1498 smb_ReleaseVCNoLock(vcp);
1500 lock_ReleaseMutex(&fidp->mx);
1502 lock_ReleaseWrite(&smb_rctLock);
1504 /* now release the scache structure */
1506 cm_ReleaseSCache(scp);
1509 cm_ReleaseUser(userp);
1513 * Case-insensitive search for one string in another;
1514 * used to find variable names in submount pathnames.
1516 static char *smb_stristr(char *str1, char *str2)
1520 for (cursor = str1; *cursor; cursor++)
1521 if (stricmp(cursor, str2) == 0)
1528 * Substitute a variable value for its name in a submount pathname. Variable
1529 * name has been identified by smb_stristr() and is in substr. Variable name
1530 * length (plus one) is in substr_size. Variable value is in newstr.
1532 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1537 strcpy(temp, substr + substr_size - 1);
1538 strcpy(substr, newstr);
1542 char VNUserName[] = "%USERNAME%";
1543 char VNLCUserName[] = "%LCUSERNAME%";
1544 char VNComputerName[] = "%COMPUTERNAME%";
1545 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1548 typedef struct smb_findShare_rock {
1552 } smb_findShare_rock_t;
1554 #define SMB_FINDSHARE_EXACT_MATCH 1
1555 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1557 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1561 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1562 if (!strnicmp(dep->name, vrock->shareName, 12)) {
1563 if(!stricmp(dep->name, vrock->shareName))
1564 matchType = SMB_FINDSHARE_EXACT_MATCH;
1566 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1567 if(vrock->match) free(vrock->match);
1568 vrock->match = strdup(dep->name);
1569 vrock->matchType = matchType;
1571 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1572 return CM_ERROR_STOPNOW;
1578 /* find a shareName in the table of submounts */
1579 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1583 char pathName[1024];
1590 DWORD allSubmount = 1;
1592 /* if allSubmounts == 0, only return the //mountRoot/all share
1593 * if in fact it has been been created in the subMounts table.
1594 * This is to allow sites that want to restrict access to the
1597 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1598 0, KEY_QUERY_VALUE, &parmKey);
1599 if (code == ERROR_SUCCESS) {
1600 len = sizeof(allSubmount);
1601 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1602 (BYTE *) &allSubmount, &len);
1603 if (code != ERROR_SUCCESS) {
1606 RegCloseKey (parmKey);
1609 if (allSubmount && _stricmp(shareName, "all") == 0) {
1614 /* In case, the all share is disabled we need to still be able
1615 * to handle ioctl requests
1617 if (_stricmp(shareName, "ioctl$") == 0) {
1618 *pathNamep = strdup("/.__ioctl__");
1622 if (_stricmp(shareName, "IPC$") == 0 ||
1623 _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1624 _stricmp(shareName, "DESKTOP.INI") == 0
1630 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1631 0, KEY_QUERY_VALUE, &parmKey);
1632 if (code == ERROR_SUCCESS) {
1633 len = sizeof(pathName);
1634 code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1635 (BYTE *) pathName, &len);
1636 if (code != ERROR_SUCCESS)
1638 RegCloseKey (parmKey);
1642 if (len != 0 && len != sizeof(pathName) - 1) {
1643 /* We can accept either unix or PC style AFS pathnames. Convert
1644 * Unix-style to PC style here for internal use.
1647 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1648 p += strlen(cm_mountRoot); /* skip mount path */
1651 if (*q == '/') *q = '\\'; /* change to \ */
1657 if (var = smb_stristr(p, VNUserName)) {
1658 if (uidp && uidp->unp)
1659 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1661 smb_subst(p, var, sizeof(VNUserName)," ");
1663 else if (var = smb_stristr(p, VNLCUserName))
1665 if (uidp && uidp->unp)
1666 strcpy(temp, uidp->unp->name);
1670 smb_subst(p, var, sizeof(VNLCUserName), temp);
1672 else if (var = smb_stristr(p, VNComputerName))
1674 sizeTemp = sizeof(temp);
1675 GetComputerName((LPTSTR)temp, &sizeTemp);
1676 smb_subst(p, var, sizeof(VNComputerName), temp);
1678 else if (var = smb_stristr(p, VNLCComputerName))
1680 sizeTemp = sizeof(temp);
1681 GetComputerName((LPTSTR)temp, &sizeTemp);
1683 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1688 *pathNamep = strdup(p);
1693 /* First lookup shareName in root.afs */
1695 smb_findShare_rock_t vrock;
1697 char * p = shareName;
1700 /* attempt to locate a partial match in root.afs. This is because
1701 when using the ANSI RAP calls, the share name is limited to 13 chars
1702 and hence is truncated. Of course we prefer exact matches. */
1704 thyper.HighPart = 0;
1707 vrock.shareName = shareName;
1709 vrock.matchType = 0;
1711 cm_HoldSCache(cm_data.rootSCachep);
1712 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1713 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1714 cm_ReleaseSCache(cm_data.rootSCachep);
1716 if (vrock.matchType) {
1717 sprintf(pathName,"/%s/",vrock.match);
1718 *pathNamep = strdup(strlwr(pathName));
1723 /* if we get here, there was no match for the share in root.afs */
1724 /* so try to create \\<netbiosName>\<cellname> */
1729 /* Get the full name for this cell */
1730 code = cm_SearchCellFile(p, temp, 0, 0);
1731 #ifdef AFS_AFSDB_ENV
1732 if (code && cm_dnsEnabled) {
1734 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1737 /* construct the path */
1739 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1740 *pathNamep = strdup(strlwr(pathName));
1749 /* Client-side offline caching policy types */
1750 #define CSC_POLICY_MANUAL 0
1751 #define CSC_POLICY_DOCUMENTS 1
1752 #define CSC_POLICY_PROGRAMS 2
1753 #define CSC_POLICY_DISABLE 3
1755 int smb_FindShareCSCPolicy(char *shareName)
1761 int retval = CSC_POLICY_MANUAL;
1763 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1764 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1767 REG_OPTION_NON_VOLATILE,
1773 len = sizeof(policy);
1774 if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1776 retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1778 else if (stricmp(policy, "documents") == 0)
1780 retval = CSC_POLICY_DOCUMENTS;
1782 else if (stricmp(policy, "programs") == 0)
1784 retval = CSC_POLICY_PROGRAMS;
1786 else if (stricmp(policy, "disable") == 0)
1788 retval = CSC_POLICY_DISABLE;
1791 RegCloseKey(hkCSCPolicy);
1795 /* find a dir search structure by cookie value, and return it held.
1796 * Must be called with smb_globalLock held.
1798 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
1800 smb_dirSearch_t *dsp;
1802 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1803 if (dsp->cookie == cookie) {
1804 if (dsp != smb_firstDirSearchp) {
1805 /* move to head of LRU queue, too, if we're not already there */
1806 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1807 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
1808 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1809 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1810 if (!smb_lastDirSearchp)
1811 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1813 lock_ObtainMutex(&dsp->mx);
1815 lock_ReleaseMutex(&dsp->mx);
1821 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
1822 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1823 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
1829 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1831 lock_ObtainWrite(&smb_globalLock);
1832 lock_ObtainMutex(&dsp->mx);
1833 dsp->flags |= SMB_DIRSEARCH_DELETE;
1834 if (dsp->scp != NULL) {
1835 lock_ObtainMutex(&dsp->scp->mx);
1836 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1837 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1838 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1839 dsp->scp->bulkStatProgress = hzero;
1841 lock_ReleaseMutex(&dsp->scp->mx);
1843 lock_ReleaseMutex(&dsp->mx);
1844 lock_ReleaseWrite(&smb_globalLock);
1847 /* Must be called with the smb_globalLock held */
1848 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
1850 cm_scache_t *scp = NULL;
1852 lock_ObtainMutex(&dsp->mx);
1853 osi_assert(dsp->refCount-- > 0);
1854 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1855 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1856 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1857 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1858 lock_ReleaseMutex(&dsp->mx);
1859 lock_FinalizeMutex(&dsp->mx);
1861 osi_Log2(afsd_logp,"smb_ReleaseDirSearch dsp 0x%p scp 0x%p", dsp, scp);
1864 lock_ReleaseMutex(&dsp->mx);
1866 /* do this now to avoid spurious locking hierarchy creation */
1868 cm_ReleaseSCache(scp);
1871 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1873 lock_ObtainWrite(&smb_globalLock);
1874 smb_ReleaseDirSearchNoLock(dsp);
1875 lock_ReleaseWrite(&smb_globalLock);
1878 /* find a dir search structure by cookie value, and return it held */
1879 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1881 smb_dirSearch_t *dsp;
1883 lock_ObtainWrite(&smb_globalLock);
1884 dsp = smb_FindDirSearchNoLock(cookie);
1885 lock_ReleaseWrite(&smb_globalLock);
1889 /* GC some dir search entries, in the address space expected by the specific protocol.
1890 * Must be called with smb_globalLock held; release the lock temporarily.
1892 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
1893 void smb_GCDirSearches(int isV3)
1895 smb_dirSearch_t *prevp;
1896 smb_dirSearch_t *tp;
1897 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1901 victimCount = 0; /* how many have we got so far */
1902 for (tp = smb_lastDirSearchp; tp; tp=prevp) {
1903 /* we'll move tp from queue, so
1906 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
1907 /* if no one is using this guy, and we're either in the new protocol,
1908 * or we're in the old one and this is a small enough ID to be useful
1909 * to the old protocol, GC this guy.
1911 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1912 /* hold and delete */
1913 lock_ObtainMutex(&tp->mx);
1914 tp->flags |= SMB_DIRSEARCH_DELETE;
1915 lock_ReleaseMutex(&tp->mx);
1916 victimsp[victimCount++] = tp;
1920 /* don't do more than this */
1921 if (victimCount >= SMB_DIRSEARCH_GCMAX)
1925 /* now release them */
1926 for (i = 0; i < victimCount; i++) {
1927 smb_ReleaseDirSearchNoLock(victimsp[i]);
1931 /* function for allocating a dir search entry. We need these to remember enough context
1932 * since we don't get passed the path from call to call during a directory search.
1934 * Returns a held dir search structure, and bumps the reference count on the vnode,
1935 * since it saves a pointer to the vnode.
1937 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1939 smb_dirSearch_t *dsp;
1945 lock_ObtainWrite(&smb_globalLock);
1948 /* what's the biggest ID allowed in this version of the protocol */
1949 maxAllowed = isV3 ? 65535 : 255;
1950 if (smb_dirSearchCounter > maxAllowed)
1951 smb_dirSearchCounter = 1;
1953 start = smb_dirSearchCounter;
1956 /* twice so we have enough tries to find guys we GC after one pass;
1957 * 10 extra is just in case I mis-counted.
1959 if (++counter > 2*maxAllowed+10)
1960 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
1962 if (smb_dirSearchCounter > maxAllowed) {
1963 smb_dirSearchCounter = 1;
1965 if (smb_dirSearchCounter == start) {
1967 smb_GCDirSearches(isV3);
1970 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
1972 /* don't need to watch for refcount zero and deleted, since
1973 * we haven't dropped the global lock.
1975 lock_ObtainMutex(&dsp->mx);
1977 lock_ReleaseMutex(&dsp->mx);
1978 ++smb_dirSearchCounter;
1982 dsp = malloc(sizeof(*dsp));
1983 memset(dsp, 0, sizeof(*dsp));
1984 dsp->cookie = smb_dirSearchCounter;
1985 ++smb_dirSearchCounter;
1987 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
1988 dsp->lastTime = osi_Time();
1989 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1990 if (!smb_lastDirSearchp)
1991 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1994 lock_ReleaseWrite(&smb_globalLock);
1998 static smb_packet_t *GetPacket(void)
2002 lock_ObtainWrite(&smb_globalLock);
2003 tbp = smb_packetFreeListp;
2005 smb_packetFreeListp = tbp->nextp;
2006 lock_ReleaseWrite(&smb_globalLock);
2008 tbp = calloc(65540,1);
2009 tbp->magic = SMB_PACKETMAGIC;
2012 tbp->resumeCode = 0;
2018 tbp->ncb_length = 0;
2023 osi_assert(tbp->magic == SMB_PACKETMAGIC);
2028 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2032 memcpy(tbp, pkt, sizeof(smb_packet_t));
2033 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2035 smb_HoldVC(tbp->vcp);
2039 static NCB *GetNCB(void)
2044 lock_ObtainWrite(&smb_globalLock);
2045 tbp = smb_ncbFreeListp;
2047 smb_ncbFreeListp = tbp->nextp;
2048 lock_ReleaseWrite(&smb_globalLock);
2050 tbp = calloc(sizeof(*tbp),1);
2051 tbp->magic = SMB_NCBMAGIC;
2054 osi_assert(tbp->magic == SMB_NCBMAGIC);
2056 memset(&tbp->ncb, 0, sizeof(NCB));
2061 void smb_FreePacket(smb_packet_t *tbp)
2063 smb_vc_t * vcp = NULL;
2064 osi_assert(tbp->magic == SMB_PACKETMAGIC);
2066 lock_ObtainWrite(&smb_globalLock);
2067 tbp->nextp = smb_packetFreeListp;
2068 smb_packetFreeListp = tbp;
2069 tbp->magic = SMB_PACKETMAGIC;
2073 tbp->resumeCode = 0;
2079 tbp->ncb_length = 0;
2081 lock_ReleaseWrite(&smb_globalLock);
2087 static void FreeNCB(NCB *bufferp)
2091 tbp = (smb_ncb_t *) bufferp;
2092 osi_assert(tbp->magic == SMB_NCBMAGIC);
2094 lock_ObtainWrite(&smb_globalLock);
2095 tbp->nextp = smb_ncbFreeListp;
2096 smb_ncbFreeListp = tbp;
2097 lock_ReleaseWrite(&smb_globalLock);
2100 /* get a ptr to the data part of a packet, and its count */
2101 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2105 unsigned char *afterParmsp;
2107 parmBytes = *smbp->wctp << 1;
2108 afterParmsp = smbp->wctp + parmBytes + 1;
2110 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2111 if (nbytesp) *nbytesp = dataBytes;
2113 /* don't forget to skip the data byte count, since it follows
2114 * the parameters; that's where the "2" comes from below.
2116 return (unsigned char *) (afterParmsp + 2);
2119 /* must set all the returned parameters before playing around with the
2120 * data region, since the data region is located past the end of the
2121 * variable number of parameters.
2123 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2125 unsigned char *afterParmsp;
2127 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2129 *afterParmsp++ = dsize & 0xff;
2130 *afterParmsp = (dsize>>8) & 0xff;
2133 /* return the parm'th parameter in the smbp packet */
2134 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
2137 unsigned char *parmDatap;
2139 parmCount = *smbp->wctp;
2141 if (parm >= parmCount) {
2144 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2145 parm, parmCount, smbp->ncb_length);
2146 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2147 parm, parmCount, smbp->ncb_length);
2148 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2149 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2150 osi_panic(s, __FILE__, __LINE__);
2152 parmDatap = smbp->wctp + (2*parm) + 1;
2154 return parmDatap[0] + (parmDatap[1] << 8);
2157 /* return the parm'th parameter in the smbp packet */
2158 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2161 unsigned char *parmDatap;
2163 parmCount = *smbp->wctp;
2165 if (parm + 1 >= parmCount) {
2168 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2169 parm, parmCount, smbp->ncb_length);
2170 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2171 parm, parmCount, smbp->ncb_length);
2172 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2173 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2174 osi_panic(s, __FILE__, __LINE__);
2176 parmDatap = smbp->wctp + (2*parm) + 1;
2178 return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2181 /* return the parm'th parameter in the smbp packet */
2182 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2185 unsigned char *parmDatap;
2187 parmCount = *smbp->wctp;
2189 if (parm * 2 + offset >= parmCount * 2) {
2192 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2193 parm, offset, parmCount, smbp->ncb_length);
2194 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2195 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2196 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2197 parm, offset, parmCount, smbp->ncb_length);
2198 osi_panic(s, __FILE__, __LINE__);
2200 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2202 return parmDatap[0] + (parmDatap[1] << 8);
2205 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2209 /* make sure we have enough slots */
2210 if (*smbp->wctp <= slot)
2211 *smbp->wctp = slot+1;
2213 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2214 *parmDatap++ = parmValue & 0xff;
2215 *parmDatap = (parmValue>>8) & 0xff;
2218 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2222 /* make sure we have enough slots */
2223 if (*smbp->wctp <= slot)
2224 *smbp->wctp = slot+2;
2226 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2227 *parmDatap++ = parmValue & 0xff;
2228 *parmDatap++ = (parmValue>>8) & 0xff;
2229 *parmDatap++ = (parmValue>>16) & 0xff;
2230 *parmDatap = (parmValue>>24) & 0xff;
2233 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2238 /* make sure we have enough slots */
2239 if (*smbp->wctp <= slot)
2240 *smbp->wctp = slot+4;
2242 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2244 *parmDatap++ = *parmValuep++;
2247 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2251 /* make sure we have enough slots */
2252 if (*smbp->wctp <= slot) {
2253 if (smbp->oddByte) {
2255 *smbp->wctp = slot+1;
2260 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2261 *parmDatap++ = parmValue & 0xff;
2264 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2268 lastSlashp = strrchr(inPathp, '\\');
2270 *lastComponentp = lastSlashp;
2273 if (inPathp == lastSlashp)
2275 *outPathp++ = *inPathp++;
2284 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2289 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
2294 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2300 tlen = inp[0] + (inp[1]<<8);
2301 inp += 2; /* skip length field */
2304 *chainpp = inp + tlen;
2313 /* format a packet as a response */
2314 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2319 outp = (smb_t *) op;
2321 /* zero the basic structure through the smb_wct field, and zero the data
2322 * size field, assuming that wct stays zero; otherwise, you have to
2323 * explicitly set the data size field, too.
2325 inSmbp = (smb_t *) inp;
2326 memset(outp, 0, sizeof(smb_t)+2);
2332 outp->com = inSmbp->com;
2333 outp->tid = inSmbp->tid;
2334 outp->pid = inSmbp->pid;
2335 outp->uid = inSmbp->uid;
2336 outp->mid = inSmbp->mid;
2337 outp->res[0] = inSmbp->res[0];
2338 outp->res[1] = inSmbp->res[1];
2339 op->inCom = inSmbp->com;
2341 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
2342 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2344 /* copy fields in generic packet area */
2345 op->wctp = &outp->wct;
2348 /* send a (probably response) packet; vcp tells us to whom to send it.
2349 * we compute the length by looking at wct and bcc fields.
2351 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2365 memset((char *)ncbp, 0, sizeof(NCB));
2367 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2368 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2369 extra += tp[0] + (tp[1]<<8);
2370 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
2371 extra += 3; /* wct and length fields */
2373 ncbp->ncb_length = extra; /* bytes to send */
2374 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2375 ncbp->ncb_lana_num = vcp->lana;
2376 ncbp->ncb_command = NCBSEND; /* op means send data */
2377 ncbp->ncb_buffer = (char *) inp;/* packet */
2378 code = Netbios(ncbp);
2381 const char * s = ncb_error_string(code);
2382 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2383 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
2385 lock_ObtainMutex(&vcp->mx);
2386 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
2387 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
2389 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2390 lock_ReleaseMutex(&vcp->mx);
2391 lock_ObtainWrite(&smb_globalLock);
2392 dead_sessions[vcp->session] = TRUE;
2393 lock_ReleaseWrite(&smb_globalLock);
2394 smb_CleanupDeadVC(vcp);
2396 lock_ReleaseMutex(&vcp->mx);
2404 void smb_MapNTError(long code, unsigned long *NTStatusp)
2406 unsigned long NTStatus;
2408 /* map CM_ERROR_* errors to NT 32-bit status codes */
2409 /* NT Status codes are listed in ntstatus.h not winerror.h */
2410 if (code == CM_ERROR_NOSUCHCELL) {
2411 NTStatus = 0xC000000FL; /* No such file */
2413 else if (code == CM_ERROR_NOSUCHVOLUME) {
2414 NTStatus = 0xC000000FL; /* No such file */
2416 else if (code == CM_ERROR_TIMEDOUT) {
2418 NTStatus = 0xC00000CFL; /* Sharing Paused */
2420 NTStatus = 0x00000102L; /* Timeout */
2423 else if (code == CM_ERROR_RETRY) {
2424 NTStatus = 0xC000022DL; /* Retry */
2426 else if (code == CM_ERROR_NOACCESS) {
2427 NTStatus = 0xC0000022L; /* Access denied */
2429 else if (code == CM_ERROR_READONLY) {
2430 NTStatus = 0xC00000A2L; /* Write protected */
2432 else if (code == CM_ERROR_NOSUCHFILE) {
2433 NTStatus = 0xC000000FL; /* No such file */
2435 else if (code == CM_ERROR_NOSUCHPATH) {
2436 NTStatus = 0xC000003AL; /* Object path not found */
2438 else if (code == CM_ERROR_TOOBIG) {
2439 NTStatus = 0xC000007BL; /* Invalid image format */
2441 else if (code == CM_ERROR_INVAL) {
2442 NTStatus = 0xC000000DL; /* Invalid parameter */
2444 else if (code == CM_ERROR_BADFD) {
2445 NTStatus = 0xC0000008L; /* Invalid handle */
2447 else if (code == CM_ERROR_BADFDOP) {
2448 NTStatus = 0xC0000022L; /* Access denied */
2450 else if (code == CM_ERROR_EXISTS) {
2451 NTStatus = 0xC0000035L; /* Object name collision */
2453 else if (code == CM_ERROR_NOTEMPTY) {
2454 NTStatus = 0xC0000101L; /* Directory not empty */
2456 else if (code == CM_ERROR_CROSSDEVLINK) {
2457 NTStatus = 0xC00000D4L; /* Not same device */
2459 else if (code == CM_ERROR_NOTDIR) {
2460 NTStatus = 0xC0000103L; /* Not a directory */
2462 else if (code == CM_ERROR_ISDIR) {
2463 NTStatus = 0xC00000BAL; /* File is a directory */
2465 else if (code == CM_ERROR_BADOP) {
2467 /* I have no idea where this comes from */
2468 NTStatus = 0xC09820FFL; /* SMB no support */
2470 NTStatus = 0xC00000BBL; /* Not supported */
2471 #endif /* COMMENT */
2473 else if (code == CM_ERROR_BADSHARENAME) {
2474 NTStatus = 0xC00000CCL; /* Bad network name */
2476 else if (code == CM_ERROR_NOIPC) {
2478 NTStatus = 0xC0000022L; /* Access Denied */
2480 NTStatus = 0xC000013DL; /* Remote Resources */
2483 else if (code == CM_ERROR_CLOCKSKEW) {
2484 NTStatus = 0xC0000133L; /* Time difference at DC */
2486 else if (code == CM_ERROR_BADTID) {
2487 NTStatus = 0xC0982005L; /* SMB bad TID */
2489 else if (code == CM_ERROR_USESTD) {
2490 NTStatus = 0xC09820FBL; /* SMB use standard */
2492 else if (code == CM_ERROR_QUOTA) {
2494 NTStatus = 0xC0000044L; /* Quota exceeded */
2496 NTStatus = 0xC000007FL; /* Disk full */
2499 else if (code == CM_ERROR_SPACE) {
2500 NTStatus = 0xC000007FL; /* Disk full */
2502 else if (code == CM_ERROR_ATSYS) {
2503 NTStatus = 0xC0000033L; /* Object name invalid */
2505 else if (code == CM_ERROR_BADNTFILENAME) {
2506 NTStatus = 0xC0000033L; /* Object name invalid */
2508 else if (code == CM_ERROR_WOULDBLOCK) {
2509 NTStatus = 0xC0000055L; /* Lock not granted */
2511 else if (code == CM_ERROR_SHARING_VIOLATION) {
2512 NTStatus = 0xC0000043L; /* Sharing violation */
2514 else if (code == CM_ERROR_LOCK_CONFLICT) {
2515 NTStatus = 0xC0000054L; /* Lock conflict */
2517 else if (code == CM_ERROR_PARTIALWRITE) {
2518 NTStatus = 0xC000007FL; /* Disk full */
2520 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2521 NTStatus = 0xC0000023L; /* Buffer too small */
2523 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2524 NTStatus = 0xC0000035L; /* Object name collision */
2526 else if (code == CM_ERROR_BADPASSWORD) {
2527 NTStatus = 0xC000006DL; /* unknown username or bad password */
2529 else if (code == CM_ERROR_BADLOGONTYPE) {
2530 NTStatus = 0xC000015BL; /* logon type not granted */
2532 else if (code == CM_ERROR_GSSCONTINUE) {
2533 NTStatus = 0xC0000016L; /* more processing required */
2535 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2537 NTStatus = 0xC0000280L; /* reparse point not resolved */
2539 NTStatus = 0xC0000022L; /* Access Denied */
2542 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2543 NTStatus = 0xC0000257L; /* Path Not Covered */
2546 else if (code == CM_ERROR_ALLBUSY) {
2547 NTStatus = 0xC00000BFL; /* Network Busy */
2549 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
2550 NTStatus = 0xC0000350L; /* Remote Host Down */
2553 /* we do not want to be telling the SMB/CIFS client that
2554 * the AFS Client Service is busy or down.
2556 else if (code == CM_ERROR_ALLBUSY ||
2557 code == CM_ERROR_ALLOFFLINE ||
2558 code == CM_ERROR_ALLDOWN) {
2559 NTStatus = 0xC00000BEL; /* Bad Network Path */
2562 else if (code == RXKADUNKNOWNKEY) {
2563 NTStatus = 0xC0000322L; /* Bad Kerberos key */
2565 NTStatus = 0xC0982001L; /* SMB non-specific error */
2568 *NTStatusp = NTStatus;
2569 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2572 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2573 unsigned char *classp)
2575 unsigned char class;
2576 unsigned short error;
2578 /* map CM_ERROR_* errors to SMB errors */
2579 if (code == CM_ERROR_NOSUCHCELL) {
2581 error = 3; /* bad path */
2583 else if (code == CM_ERROR_NOSUCHVOLUME) {
2585 error = 3; /* bad path */
2587 else if (code == CM_ERROR_TIMEDOUT) {
2589 error = 81; /* server is paused */
2591 else if (code == CM_ERROR_RETRY) {
2592 class = 2; /* shouldn't happen */
2595 else if (code == CM_ERROR_NOACCESS) {
2597 error = 4; /* bad access */
2599 else if (code == CM_ERROR_READONLY) {
2601 error = 19; /* read only */
2603 else if (code == CM_ERROR_NOSUCHFILE) {
2605 error = 2; /* ENOENT! */
2607 else if (code == CM_ERROR_NOSUCHPATH) {
2609 error = 3; /* Bad path */
2611 else if (code == CM_ERROR_TOOBIG) {
2613 error = 11; /* bad format */
2615 else if (code == CM_ERROR_INVAL) {
2616 class = 2; /* server non-specific error code */
2619 else if (code == CM_ERROR_BADFD) {
2621 error = 6; /* invalid file handle */
2623 else if (code == CM_ERROR_BADFDOP) {
2624 class = 1; /* invalid op on FD */
2627 else if (code == CM_ERROR_EXISTS) {
2629 error = 80; /* file already exists */
2631 else if (code == CM_ERROR_NOTEMPTY) {
2633 error = 5; /* delete directory not empty */
2635 else if (code == CM_ERROR_CROSSDEVLINK) {
2637 error = 17; /* EXDEV */
2639 else if (code == CM_ERROR_NOTDIR) {
2640 class = 1; /* bad path */
2643 else if (code == CM_ERROR_ISDIR) {
2644 class = 1; /* access denied; DOS doesn't have a good match */
2647 else if (code == CM_ERROR_BADOP) {
2651 else if (code == CM_ERROR_BADSHARENAME) {
2655 else if (code == CM_ERROR_NOIPC) {
2657 error = 4; /* bad access */
2659 else if (code == CM_ERROR_CLOCKSKEW) {
2660 class = 1; /* invalid function */
2663 else if (code == CM_ERROR_BADTID) {
2667 else if (code == CM_ERROR_USESTD) {
2671 else if (code == CM_ERROR_REMOTECONN) {
2675 else if (code == CM_ERROR_QUOTA) {
2676 if (vcp->flags & SMB_VCFLAG_USEV3) {
2678 error = 39; /* disk full */
2682 error = 5; /* access denied */
2685 else if (code == CM_ERROR_SPACE) {
2686 if (vcp->flags & SMB_VCFLAG_USEV3) {
2688 error = 39; /* disk full */
2692 error = 5; /* access denied */
2695 else if (code == CM_ERROR_PARTIALWRITE) {
2697 error = 39; /* disk full */
2699 else if (code == CM_ERROR_ATSYS) {
2701 error = 2; /* ENOENT */
2703 else if (code == CM_ERROR_WOULDBLOCK) {
2705 error = 33; /* lock conflict */
2707 else if (code == CM_ERROR_LOCK_CONFLICT) {
2709 error = 33; /* lock conflict */
2711 else if (code == CM_ERROR_SHARING_VIOLATION) {
2713 error = 33; /* lock conflict */
2715 else if (code == CM_ERROR_NOFILES) {
2717 error = 18; /* no files in search */
2719 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2721 error = 183; /* Samba uses this */
2723 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2724 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2726 error = 2; /* bad password */
2728 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2730 error = 3; /* bad path */
2739 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2742 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2744 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2745 return CM_ERROR_BADOP;
2748 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2750 unsigned short EchoCount, i;
2751 char *data, *outdata;
2754 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2756 for (i=1; i<=EchoCount; i++) {
2757 data = smb_GetSMBData(inp, &dataSize);
2758 smb_SetSMBParm(outp, 0, i);
2759 smb_SetSMBDataLength(outp, dataSize);
2760 outdata = smb_GetSMBData(outp, NULL);
2761 memcpy(outdata, data, dataSize);
2762 smb_SendPacket(vcp, outp);
2768 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2771 long count, minCount, finalCount;
2776 cm_user_t *userp = NULL;
2779 char *rawBuf = NULL;
2784 fd = smb_GetSMBParm(inp, 0);
2785 count = smb_GetSMBParm(inp, 3);
2786 minCount = smb_GetSMBParm(inp, 4);
2787 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2789 if (*inp->wctp == 10) {
2790 /* we were sent a request with 64-bit file offsets */
2791 #ifdef AFS_LARGEFILES
2792 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
2794 if (LargeIntegerLessThanZero(offset)) {
2795 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
2799 if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
2800 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset. Dropping request.");
2803 offset.HighPart = 0;
2807 /* we were sent a request with 32-bit file offsets */
2808 offset.HighPart = 0;
2811 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
2812 fd, offset.HighPart, offset.LowPart, count);
2814 fidp = smb_FindFID(vcp, fd, 0);
2818 pid = ((smb_t *) inp)->pid;
2820 LARGE_INTEGER LOffset, LLength;
2823 key = cm_GenerateKey(vcp->vcID, pid, fd);
2825 LOffset.HighPart = offset.HighPart;
2826 LOffset.LowPart = offset.LowPart;
2827 LLength.HighPart = 0;
2828 LLength.LowPart = count;
2830 lock_ObtainMutex(&fidp->scp->mx);
2831 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
2832 lock_ReleaseMutex(&fidp->scp->mx);
2838 lock_ObtainMutex(&smb_RawBufLock);
2840 /* Get a raw buf, from head of list */
2841 rawBuf = smb_RawBufs;
2842 smb_RawBufs = *(char **)smb_RawBufs;
2844 lock_ReleaseMutex(&smb_RawBufLock);
2848 lock_ObtainMutex(&fidp->mx);
2849 if (fidp->flags & SMB_FID_IOCTL)
2851 lock_ReleaseMutex(&fidp->mx);
2852 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2854 /* Give back raw buffer */
2855 lock_ObtainMutex(&smb_RawBufLock);
2856 *((char **) rawBuf) = smb_RawBufs;
2858 smb_RawBufs = rawBuf;
2859 lock_ReleaseMutex(&smb_RawBufLock);
2862 smb_ReleaseFID(fidp);
2865 lock_ReleaseMutex(&fidp->mx);
2867 userp = smb_GetUserFromVCP(vcp, inp);
2869 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2875 cm_ReleaseUser(userp);
2878 smb_ReleaseFID(fidp);
2882 memset((char *)ncbp, 0, sizeof(NCB));
2884 ncbp->ncb_length = (unsigned short) finalCount;
2885 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2886 ncbp->ncb_lana_num = vcp->lana;
2887 ncbp->ncb_command = NCBSEND;
2888 ncbp->ncb_buffer = rawBuf;
2890 code = Netbios(ncbp);
2892 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2895 /* Give back raw buffer */
2896 lock_ObtainMutex(&smb_RawBufLock);
2897 *((char **) rawBuf) = smb_RawBufs;
2899 smb_RawBufs = rawBuf;
2900 lock_ReleaseMutex(&smb_RawBufLock);
2906 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2908 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
2913 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2915 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
2920 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2927 int VistaProtoIndex;
2928 int protoIndex; /* index we're using */
2933 char protocol_array[10][1024]; /* protocol signature of the client */
2934 int caps; /* capabilities */
2937 TIME_ZONE_INFORMATION tzi;
2939 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2942 namep = smb_GetSMBData(inp, &dbytes);
2945 coreProtoIndex = -1; /* not found */
2948 VistaProtoIndex = -1;
2949 while(namex < dbytes) {
2950 osi_Log1(smb_logp, "Protocol %s",
2951 osi_LogSaveString(smb_logp, namep+1));
2952 strcpy(protocol_array[tcounter], namep+1);
2954 /* namep points at the first protocol, or really, a 0x02
2955 * byte preceding the null-terminated ASCII name.
2957 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2958 coreProtoIndex = tcounter;
2960 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2961 v3ProtoIndex = tcounter;
2963 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
2964 NTProtoIndex = tcounter;
2966 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
2967 VistaProtoIndex = tcounter;
2970 /* compute size of protocol entry */
2971 entryLength = (int)strlen(namep+1);
2972 entryLength += 2; /* 0x02 bytes and null termination */
2974 /* advance over this protocol entry */
2975 namex += entryLength;
2976 namep += entryLength;
2977 tcounter++; /* which proto entry we're looking at */
2980 lock_ObtainMutex(&vcp->mx);
2982 if (VistaProtoIndex != -1) {
2983 protoIndex = VistaProtoIndex;
2984 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2987 if (NTProtoIndex != -1) {
2988 protoIndex = NTProtoIndex;
2989 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2991 else if (v3ProtoIndex != -1) {
2992 protoIndex = v3ProtoIndex;
2993 vcp->flags |= SMB_VCFLAG_USEV3;
2995 else if (coreProtoIndex != -1) {
2996 protoIndex = coreProtoIndex;
2997 vcp->flags |= SMB_VCFLAG_USECORE;
2999 else protoIndex = -1;
3000 lock_ReleaseMutex(&vcp->mx);
3002 if (protoIndex == -1)
3003 return CM_ERROR_INVAL;
3004 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3005 smb_SetSMBParm(outp, 0, protoIndex);
3006 if (smb_authType != SMB_AUTH_NONE) {
3007 smb_SetSMBParmByte(outp, 1,
3008 NEGOTIATE_SECURITY_USER_LEVEL |
3009 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3011 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3013 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3014 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3015 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3016 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3017 /* The session key is not a well documented field however most clients
3018 * will echo back the session key to the server. Currently we are using
3019 * the same value for all sessions. We should generate a random value
3020 * and store it into the vcp
3022 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3023 smb_SetSMBParm(outp, 8, 1);
3025 * Tried changing the capabilities to support for W2K - defect 117695
3026 * Maybe something else needs to be changed here?
3030 smb_SetSMBParmLong(outp, 9, 0x43fd);
3032 smb_SetSMBParmLong(outp, 9, 0x251);
3035 * 32-bit error codes *
3040 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3042 NTNEGOTIATE_CAPABILITY_DFS |
3044 #ifdef AFS_LARGEFILES
3045 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3047 NTNEGOTIATE_CAPABILITY_NTFIND |
3048 NTNEGOTIATE_CAPABILITY_RAWMODE |
3049 NTNEGOTIATE_CAPABILITY_NTSMB;
3051 if ( smb_authType == SMB_AUTH_EXTENDED )
3052 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3054 smb_SetSMBParmLong(outp, 9, caps);
3056 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3057 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3058 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3060 GetTimeZoneInformation(&tzi);
3061 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3063 if (smb_authType == SMB_AUTH_NTLM) {
3064 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3065 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3066 /* paste in encryption key */
3067 datap = smb_GetSMBData(outp, NULL);
3068 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3069 /* and the faux domain name */
3070 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
3071 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3075 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3077 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3079 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3081 datap = smb_GetSMBData(outp, NULL);
3082 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3085 datap += sizeof(smb_ServerGUID);
3086 memcpy(datap, secBlob, secBlobLength);
3090 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3091 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3094 else if (v3ProtoIndex != -1) {
3095 smb_SetSMBParm(outp, 0, protoIndex);
3097 /* NOTE: Extended authentication cannot be negotiated with v3
3098 * therefore we fail over to NTLM
3100 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3101 smb_SetSMBParm(outp, 1,
3102 NEGOTIATE_SECURITY_USER_LEVEL |
3103 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3105 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3107 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3108 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3109 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3110 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3111 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3112 smb_SetSMBParm(outp, 7, 1);
3114 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3115 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3116 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3118 GetTimeZoneInformation(&tzi);
3119 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3121 /* NOTE: Extended authentication cannot be negotiated with v3
3122 * therefore we fail over to NTLM
3124 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3125 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3126 smb_SetSMBParm(outp, 12, 0); /* resvd */
3127 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3128 datap = smb_GetSMBData(outp, NULL);
3129 /* paste in a new encryption key */
3130 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3131 /* and the faux domain name */
3132 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
3134 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3135 smb_SetSMBParm(outp, 12, 0); /* resvd */
3136 smb_SetSMBDataLength(outp, 0);
3139 else if (coreProtoIndex != -1) { /* not really supported anymore */
3140 smb_SetSMBParm(outp, 0, protoIndex);
3141 smb_SetSMBDataLength(outp, 0);
3146 void smb_CheckVCs(void)
3148 smb_vc_t * vcp, *nextp;
3149 smb_packet_t * outp = GetPacket();
3152 lock_ObtainWrite(&smb_rctLock);
3153 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
3155 if (vcp->magic != SMB_VC_MAGIC)
3156 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
3157 __FILE__, __LINE__);
3161 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD)
3164 smb_HoldVCNoLock(vcp);
3166 smb_HoldVCNoLock(nextp);
3167 smb_FormatResponsePacket(vcp, NULL, outp);
3168 smbp = (smb_t *)outp;
3169 outp->inCom = smbp->com = 0x2b /* Echo */;
3177 smb_SetSMBParm(outp, 0, 0);
3178 smb_SetSMBDataLength(outp, 0);
3179 lock_ReleaseWrite(&smb_rctLock);
3181 smb_SendPacket(vcp, outp);
3183 lock_ObtainWrite(&smb_rctLock);
3184 smb_ReleaseVCNoLock(vcp);
3186 smb_ReleaseVCNoLock(nextp);
3188 lock_ReleaseWrite(&smb_rctLock);
3189 smb_FreePacket(outp);
3192 void smb_Daemon(void *parmp)
3194 afs_uint32 count = 0;
3195 smb_username_t **unpp;
3198 while(smbShutdownFlag == 0) {
3202 if (smbShutdownFlag == 1)
3205 if ((count % 72) == 0) { /* every five minutes */
3207 time_t old_localZero = smb_localZero;
3209 /* Initialize smb_localZero */
3210 myTime.tm_isdst = -1; /* compute whether on DST or not */
3211 myTime.tm_year = 70;
3217 smb_localZero = mktime(&myTime);
3219 #ifndef USE_NUMERIC_TIME_CONV
3220 smb_CalculateNowTZ();
3221 #endif /* USE_NUMERIC_TIME_CONV */
3222 #ifdef AFS_FREELANCE
3223 if ( smb_localZero != old_localZero )
3224 cm_noteLocalMountPointChange();
3230 /* GC smb_username_t objects that will no longer be used */
3232 lock_ObtainWrite(&smb_rctLock);
3233 for ( unpp=&usernamesp; *unpp; ) {
3235 smb_username_t *unp;
3237 lock_ObtainMutex(&(*unpp)->mx);
3238 if ( (*unpp)->refCount > 0 ||
3239 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
3240 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
3242 else if (!smb_LogoffTokenTransfer ||
3243 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
3245 lock_ReleaseMutex(&(*unpp)->mx);
3253 lock_FinalizeMutex(&unp->mx);
3259 lock_ReleaseWrite(&smb_rctLock);
3260 cm_ReleaseUser(userp);
3261 lock_ObtainWrite(&smb_rctLock);
3264 unpp = &(*unpp)->nextp;
3267 lock_ReleaseWrite(&smb_rctLock);
3269 /* XXX GC dir search entries */
3273 void smb_WaitingLocksDaemon()
3275 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3276 smb_waitingLock_t *wl, *wlNext;
3279 smb_packet_t *inp, *outp;
3283 while (smbShutdownFlag == 0) {
3284 lock_ObtainWrite(&smb_globalLock);
3285 nwlRequest = smb_allWaitingLocks;
3286 if (nwlRequest == NULL) {
3287 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
3292 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
3299 lock_ObtainWrite(&smb_globalLock);
3301 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
3303 wlRequest = nwlRequest;
3304 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3305 lock_ReleaseWrite(&smb_globalLock);
3309 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3310 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3313 osi_assert(wl->state != SMB_WAITINGLOCKSTATE_ERROR);
3315 /* wl->state is either _DONE or _WAITING. _ERROR
3316 would no longer be on the queue. */
3317 code = cm_RetryLock( wl->lockp,
3318 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3321 wl->state = SMB_WAITINGLOCKSTATE_DONE;
3322 } else if (code != CM_ERROR_WOULDBLOCK) {
3323 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3328 if (code == CM_ERROR_WOULDBLOCK) {
3331 if (wlRequest->timeRemaining != 0xffffffff
3332 && (wlRequest->timeRemaining -= 1000) < 0)
3344 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
3347 scp = wlRequest->scp;
3348 osi_Log2(afsd_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
3352 lock_ObtainMutex(&scp->mx);
3354 for (wl = wlRequest->locks; wl; wl = wlNext) {
3355 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3357 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
3358 wl->LLength, wl->key, NULL, &req);
3360 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3365 lock_ReleaseMutex(&scp->mx);
3369 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
3372 for (wl = wlRequest->locks; wl; wl = wlNext) {
3373 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3374 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3379 vcp = wlRequest->vcp;
3380 inp = wlRequest->inp;
3381 outp = wlRequest->outp;
3383 ncbp->ncb_length = inp->ncb_length;
3384 inp->spacep = cm_GetSpace();
3386 /* Remove waitingLock from list */
3387 lock_ObtainWrite(&smb_globalLock);
3388 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3390 lock_ReleaseWrite(&smb_globalLock);
3392 /* Resume packet processing */
3394 smb_SetSMBDataLength(outp, 0);
3395 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3396 outp->resumeCode = code;
3398 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3401 cm_FreeSpace(inp->spacep);
3402 smb_FreePacket(inp);
3403 smb_FreePacket(outp);
3405 cm_ReleaseSCache(wlRequest->scp);
3408 } while (nwlRequest && smbShutdownFlag == 0);
3413 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3415 osi_Log0(smb_logp, "SMB receive get disk attributes");
3417 smb_SetSMBParm(outp, 0, 32000);
3418 smb_SetSMBParm(outp, 1, 64);
3419 smb_SetSMBParm(outp, 2, 1024);
3420 smb_SetSMBParm(outp, 3, 30000);
3421 smb_SetSMBParm(outp, 4, 0);
3422 smb_SetSMBDataLength(outp, 0);
3426 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3430 unsigned short newTid;
3431 char shareName[256];
3439 osi_Log0(smb_logp, "SMB receive tree connect");
3441 /* parse input parameters */
3442 tp = smb_GetSMBData(inp, NULL);
3443 pathp = smb_ParseASCIIBlock(tp, &tp);
3444 if (smb_StoreAnsiFilenames)
3445 OemToChar(pathp,pathp);
3446 passwordp = smb_ParseASCIIBlock(tp, &tp);
3447 tp = strrchr(pathp, '\\');
3449 return CM_ERROR_BADSMB;
3450 strcpy(shareName, tp+1);
3452 lock_ObtainMutex(&vcp->mx);
3453 newTid = vcp->tidCounter++;
3454 lock_ReleaseMutex(&vcp->mx);
3456 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3457 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3458 userp = smb_GetUserFromUID(uidp);
3459 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3461 smb_ReleaseUID(uidp);
3463 smb_ReleaseTID(tidp);
3464 return CM_ERROR_BADSHARENAME;
3466 lock_ObtainMutex(&tidp->mx);
3467 tidp->userp = userp;
3468 tidp->pathname = sharePath;
3469 lock_ReleaseMutex(&tidp->mx);
3470 smb_ReleaseTID(tidp);
3472 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3473 smb_SetSMBParm(rsp, 1, newTid);
3474 smb_SetSMBDataLength(rsp, 0);
3476 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3480 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3484 if (*inp++ != 0x1) return NULL;
3485 tlen = inp[0] + (inp[1]<<8);
3486 inp += 2; /* skip length field */
3489 *chainpp = inp + tlen;
3492 if (lengthp) *lengthp = tlen;
3497 /* set maskp to the mask part of the incoming path.
3498 * Mask is 11 bytes long (8.3 with the dot elided).
3499 * Returns true if succeeds with a valid name, otherwise it does
3500 * its best, but returns false.
3502 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3510 /* starts off valid */
3513 /* mask starts out all blanks */
3514 memset(maskp, ' ', 11);
3516 /* find last backslash, or use whole thing if there is none */
3517 tp = strrchr(pathp, '\\');
3518 if (!tp) tp = pathp;
3519 else tp++; /* skip slash */
3523 /* names starting with a dot are illegal */
3524 if (*tp == '.') valid8Dot3 = 0;
3528 if (tc == 0) return valid8Dot3;
3529 if (tc == '.' || tc == '"') break;
3530 if (i < 8) *up++ = tc;
3531 else valid8Dot3 = 0;
3534 /* if we get here, tp point after the dot */
3535 up = maskp+8; /* ext goes here */
3542 if (tc == '.' || tc == '"')
3545 /* copy extension if not too long */
3555 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3565 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3567 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3571 /* otherwise, we have a valid 8.3 name; see if we have a match,
3572 * treating '?' as a wildcard in maskp (but not in the file name).
3574 tp1 = umask; /* real name, in mask format */
3575 tp2 = maskp; /* mask, in mask format */
3576 for(i=0; i<11; i++) {
3577 tc1 = *tp1++; /* char from real name */
3578 tc2 = *tp2++; /* char from mask */
3579 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3580 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3583 if (tc2 == '?' && tc1 != ' ')
3590 /* we got a match */
3594 char *smb_FindMask(char *pathp)
3598 tp = strrchr(pathp, '\\'); /* find last slash */
3601 return tp+1; /* skip the slash */
3603 return pathp; /* no slash, return the entire path */
3606 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3608 unsigned char *pathp;
3610 unsigned char mask[11];
3611 unsigned char *statBlockp;
3612 unsigned char initStatBlock[21];
3615 osi_Log0(smb_logp, "SMB receive search volume");
3617 /* pull pathname and stat block out of request */
3618 tp = smb_GetSMBData(inp, NULL);
3619 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3620 osi_assert(pathp != NULL);
3621 if (smb_StoreAnsiFilenames)
3622 OemToChar(pathp,pathp);
3623 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3624 osi_assert(statBlockp != NULL);
3626 statBlockp = initStatBlock;
3630 /* for returning to caller */
3631 smb_Get8Dot3MaskFromPath(mask, pathp);
3633 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3634 tp = smb_GetSMBData(outp, NULL);
3636 *tp++ = 43; /* bytes in a dir entry */
3637 *tp++ = 0; /* high byte in counter */
3639 /* now marshall the dir entry, starting with the search status */
3640 *tp++ = statBlockp[0]; /* Reserved */
3641 memcpy(tp, mask, 11); tp += 11; /* FileName */
3643 /* now pass back server use info, with 1st byte non-zero */
3645 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3647 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3649 *tp++ = 0x8; /* attribute: volume */
3659 /* 4 byte file size */
3665 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3666 memset(tp, ' ', 13);
3669 /* set the length of the data part of the packet to 43 + 3, for the dir
3670 * entry plus the 5 and the length fields.
3672 smb_SetSMBDataLength(outp, 46);
3676 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3677 cm_user_t *userp, cm_req_t *reqp)
3685 smb_dirListPatch_t *patchp;
3686 smb_dirListPatch_t *npatchp;
3688 for (patchp = *dirPatchespp; patchp; patchp =
3689 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3691 dptr = patchp->dptr;
3693 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3695 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3696 *dptr++ = SMB_ATTR_HIDDEN;
3699 lock_ObtainMutex(&scp->mx);
3700 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3701 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3703 lock_ReleaseMutex(&scp->mx);
3704 cm_ReleaseSCache(scp);
3705 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3706 *dptr++ = SMB_ATTR_HIDDEN;
3710 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3712 attr = smb_Attributes(scp);
3713 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3714 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3715 attr |= SMB_ATTR_HIDDEN;
3719 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3722 shortTemp = (unsigned short) (dosTime & 0xffff);
3723 *((u_short *)dptr) = shortTemp;
3726 /* and copy out date */
3727 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3728 *((u_short *)dptr) = shortTemp;
3731 /* copy out file length */
3732 *((u_long *)dptr) = scp->length.LowPart;
3734 lock_ReleaseMutex(&scp->mx);
3735 cm_ReleaseSCache(scp);
3738 /* now free the patches */
3739 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3740 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3744 /* and mark the list as empty */
3745 *dirPatchespp = NULL;
3750 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3759 smb_dirListPatch_t *dirListPatchesp;
3760 smb_dirListPatch_t *curPatchp;
3764 osi_hyper_t dirLength;
3765 osi_hyper_t bufferOffset;
3766 osi_hyper_t curOffset;
3768 unsigned char *inCookiep;
3769 smb_dirSearch_t *dsp;
3773 unsigned long clientCookie;
3774 cm_pageHeader_t *pageHeaderp;
3775 cm_user_t *userp = NULL;
3782 long nextEntryCookie;
3783 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3784 char resByte; /* reserved byte from the cookie */
3785 char *op; /* output data ptr */
3786 char *origOp; /* original value of op */
3787 cm_space_t *spacep; /* for pathname buffer */
3798 maxCount = smb_GetSMBParm(inp, 0);
3800 dirListPatchesp = NULL;
3802 caseFold = CM_FLAG_CASEFOLD;
3804 tp = smb_GetSMBData(inp, NULL);
3805 pathp = smb_ParseASCIIBlock(tp, &tp);
3806 if (smb_StoreAnsiFilenames)
3807 OemToChar(pathp,pathp);
3808 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3810 /* bail out if request looks bad */
3811 if (!tp || !pathp) {
3812 return CM_ERROR_BADSMB;
3815 /* We can handle long names */
3816 if (vcp->flags & SMB_VCFLAG_USENT)
3817 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
3819 /* make sure we got a whole search status */
3820 if (dataLength < 21) {
3821 nextCookie = 0; /* start at the beginning of the dir */
3824 attribute = smb_GetSMBParm(inp, 1);
3826 /* handle volume info in another function */
3827 if (attribute & 0x8)
3828 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3830 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3831 maxCount, osi_LogSaveString(smb_logp, pathp));
3833 if (*pathp == 0) { /* null pathp, treat as root dir */
3834 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
3835 return CM_ERROR_NOFILES;
3839 dsp = smb_NewDirSearch(0);
3840 dsp->attribute = attribute;
3841 smb_Get8Dot3MaskFromPath(mask, pathp);
3842 memcpy(dsp->mask, mask, 11);
3844 /* track if this is likely to match a lot of entries */
3845 if (smb_IsStarMask(mask))
3850 /* pull the next cookie value out of the search status block */
3851 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3852 + (inCookiep[16]<<24);
3853 dsp = smb_FindDirSearch(inCookiep[12]);
3855 /* can't find dir search status; fatal error */
3856 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%s]",
3857 inCookiep[12], nextCookie, osi_LogSaveString(smb_logp, pathp));
3858 return CM_ERROR_BADFD;
3860 attribute = dsp->attribute;
3861 resByte = inCookiep[0];
3863 /* copy out client cookie, in host byte order. Don't bother
3864 * interpreting it, since we're just passing it through, anyway.
3866 memcpy(&clientCookie, &inCookiep[17], 4);
3868 memcpy(mask, dsp->mask, 11);
3870 /* assume we're doing a star match if it has continued for more
3876 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
3877 nextCookie, dsp->cookie, attribute);
3879 userp = smb_GetUserFromVCP(vcp, inp);
3881 /* try to get the vnode for the path name next */
3882 lock_ObtainMutex(&dsp->mx);
3885 osi_Log2(afsd_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
3889 spacep = inp->spacep;
3890 smb_StripLastComponent(spacep->data, NULL, pathp);
3891 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3893 lock_ReleaseMutex(&dsp->mx);
3894 cm_ReleaseUser(userp);
3895 smb_DeleteDirSearch(dsp);
3896 smb_ReleaseDirSearch(dsp);
3897 return CM_ERROR_NOFILES;
3899 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3900 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3903 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3904 cm_ReleaseSCache(scp);
3905 lock_ReleaseMutex(&dsp->mx);
3906 cm_ReleaseUser(userp);
3907 smb_DeleteDirSearch(dsp);
3908 smb_ReleaseDirSearch(dsp);
3909 if ( WANTS_DFS_PATHNAMES(inp) )
3910 return CM_ERROR_PATH_NOT_COVERED;
3912 return CM_ERROR_BADSHARENAME;
3914 #endif /* DFS_SUPPORT */
3917 osi_Log2(afsd_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
3918 /* we need one hold for the entry we just stored into,
3919 * and one for our own processing. When we're done with this
3920 * function, we'll drop the one for our own processing.
3921 * We held it once from the namei call, and so we do another hold
3925 lock_ObtainMutex(&scp->mx);
3926 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3927 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3928 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3929 dsp->flags |= SMB_DIRSEARCH_BULKST;
3930 dsp->scp->bulkStatProgress = hzero;
3932 lock_ReleaseMutex(&scp->mx);
3935 lock_ReleaseMutex(&dsp->mx);
3937 cm_ReleaseUser(userp);
3938 smb_DeleteDirSearch(dsp);
3939 smb_ReleaseDirSearch(dsp);
3943 /* reserves space for parameter; we'll adjust it again later to the
3944 * real count of the # of entries we returned once we've actually
3945 * assembled the directory listing.
3947 smb_SetSMBParm(outp, 0, 0);
3949 /* get the directory size */
3950 lock_ObtainMutex(&scp->mx);
3951 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3952 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3954 lock_ReleaseMutex(&scp->mx);
3955 cm_ReleaseSCache(scp);
3956 cm_ReleaseUser(userp);
3957 smb_DeleteDirSearch(dsp);
3958 smb_ReleaseDirSearch(dsp);
3962 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3964 dirLength = scp->length;
3966 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3967 curOffset.HighPart = 0;
3968 curOffset.LowPart = nextCookie;
3969 origOp = op = smb_GetSMBData(outp, NULL);
3970 /* and write out the basic header */
3971 *op++ = 5; /* variable block */
3972 op += 2; /* skip vbl block length; we'll fill it in later */
3976 /* make sure that curOffset.LowPart doesn't point to the first
3977 * 32 bytes in the 2nd through last dir page, and that it doesn't
3978 * point at the first 13 32-byte chunks in the first dir page,
3979 * since those are dir and page headers, and don't contain useful
3982 temp = curOffset.LowPart & (2048-1);
3983 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3984 /* we're in the first page */
3985 if (temp < 13*32) temp = 13*32;
3988 /* we're in a later dir page */
3989 if (temp < 32) temp = 32;
3992 /* make sure the low order 5 bits are zero */
3995 /* now put temp bits back ito curOffset.LowPart */
3996 curOffset.LowPart &= ~(2048-1);
3997 curOffset.LowPart |= temp;
3999 /* check if we've returned all the names that will fit in the
4002 if (returnedNames >= maxCount) {
4003 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
4004 returnedNames, maxCount);
4008 /* check if we've passed the dir's EOF */
4009 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
4011 /* see if we can use the bufferp we have now; compute in which page
4012 * the current offset would be, and check whether that's the offset
4013 * of the buffer we have. If not, get the buffer.
4015 thyper.HighPart = curOffset.HighPart;
4016 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4017 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4020 buf_Release(bufferp);
4023 lock_ReleaseMutex(&scp->mx);
4024 lock_ObtainRead(&scp->bufCreateLock);
4025 code = buf_Get(scp, &thyper, &bufferp);
4026 lock_ReleaseRead(&scp->bufCreateLock);
4027 lock_ObtainMutex(&dsp->mx);
4029 /* now, if we're doing a star match, do bulk fetching of all of
4030 * the status info for files in the dir.
4033 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
4034 lock_ObtainMutex(&scp->mx);
4035 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4036 LargeIntegerGreaterThanOrEqualTo(thyper,
4037 scp->bulkStatProgress)) {
4038 /* Don't bulk stat if risking timeout */
4039 int now = GetTickCount();
4040 if (now - req.startTime > RDRtimeout) {
4041 scp->bulkStatProgress = thyper;
4042 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4043 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4044 dsp->scp->bulkStatProgress = hzero;
4046 code = cm_TryBulkStat(scp, &thyper, userp, &req);
4049 lock_ObtainMutex(&scp->mx);
4051 lock_ReleaseMutex(&dsp->mx);
4053 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
4057 bufferOffset = thyper;
4059 /* now get the data in the cache */
4061 code = cm_SyncOp(scp, bufferp, userp, &req,
4063 CM_SCACHESYNC_NEEDCALLBACK |
4064 CM_SCACHESYNC_READ);
4066 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
4070 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
4072 if (cm_HaveBuffer(scp, bufferp, 0)) {
4073 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4077 /* otherwise, load the buffer and try again */
4078 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
4080 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4081 scp, bufferp, code);
4086 buf_Release(bufferp);
4090 } /* if (wrong buffer) ... */
4092 /* now we have the buffer containing the entry we're interested in; copy
4093 * it out if it represents a non-deleted entry.
4095 entryInDir = curOffset.LowPart & (2048-1);
4096 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4098 /* page header will help tell us which entries are free. Page header
4099 * can change more often than once per buffer, since AFS 3 dir page size
4100 * may be less than (but not more than a buffer package buffer.
4102 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
4103 temp &= ~(2048 - 1); /* turn off intra-page bits */
4104 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4106 /* now determine which entry we're looking at in the page. If it is
4107 * free (there's a free bitmap at the start of the dir), we should
4108 * skip these 32 bytes.
4110 slotInPage = (entryInDir & 0x7e0) >> 5;
4111 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
4112 /* this entry is free */
4113 numDirChunks = 1; /* only skip this guy */
4117 tp = bufferp->datap + entryInBuffer;
4118 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4120 /* while we're here, compute the next entry's location, too,
4121 * since we'll need it when writing out the cookie into the dir
4124 * XXXX Probably should do more sanity checking.
4126 numDirChunks = cm_NameEntries(dep->name, NULL);
4128 /* compute the offset of the cookie representing the next entry */
4129 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4131 /* Compute 8.3 name if necessary */
4132 actualName = dep->name;
4133 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
4134 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
4135 actualName = shortName;
4138 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%s)",
4139 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
4140 osi_LogSaveString(smb_logp, actualName));
4142 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
4143 /* this is one of the entries to use: it is not deleted
4144 * and it matches the star pattern we're looking for.
4147 /* Eliminate entries that don't match requested
4150 /* no hidden files */
4151 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
4152 osi_Log0(smb_logp, "SMB search dir skipping hidden");
4156 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4158 /* We have already done the cm_TryBulkStat above */
4159 fid.cell = scp->fid.cell;
4160 fid.volume = scp->fid.volume;
4161 fid.vnode = ntohl(dep->fid.vnode);
4162 fid.unique = ntohl(dep->fid.unique);
4163 fileType = cm_FindFileType(&fid);
4164 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
4165 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
4167 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4168 fileType == CM_SCACHETYPE_DFSLINK ||
4169 fileType == CM_SCACHETYPE_INVALID)
4170 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
4175 memcpy(op, mask, 11); op += 11;
4176 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
4177 *op++ = (char)(nextEntryCookie & 0xff);
4178 *op++ = (char)((nextEntryCookie>>8) & 0xff);
4179 *op++ = (char)((nextEntryCookie>>16) & 0xff);
4180 *op++ = (char)((nextEntryCookie>>24) & 0xff);
4181 memcpy(op, &clientCookie, 4); op += 4;
4183 /* now we emit the attribute. This is sort of tricky,
4184 * since we need to really stat the file to find out
4185 * what type of entry we've got. Right now, we're
4186 * copying out data from a buffer, while holding the
4187 * scp locked, so it isn't really convenient to stat
4188 * something now. We'll put in a place holder now,
4189 * and make a second pass before returning this to get
4190 * the real attributes. So, we just skip the data for
4191 * now, and adjust it later. We allocate a patch
4192 * record to make it easy to find this point later.
4193 * The replay will happen at a time when it is safe to
4194 * unlock the directory.
4196 curPatchp = malloc(sizeof(*curPatchp));
4197 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
4198 curPatchp->dptr = op;
4199 curPatchp->fid.cell = scp->fid.cell;
4200 curPatchp->fid.volume = scp->fid.volume;
4201 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4202 curPatchp->fid.unique = ntohl(dep->fid.unique);
4204 /* do hidden attribute here since name won't be around when applying
4208 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
4209 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4211 curPatchp->flags = 0;
4213 op += 9; /* skip attr, time, date and size */
4215 /* zero out name area. The spec says to pad with
4216 * spaces, but Samba doesn't, and neither do we.
4220 /* finally, we get to copy out the name; we know that
4221 * it fits in 8.3 or the pattern wouldn't match, but it
4222 * never hurts to be sure.
4224 strncpy(op, actualName, 13);
4225 if (smb_StoreAnsiFilenames)
4228 /* Uppercase if requested by client */
4229 if (!KNOWS_LONG_NAMES(inp))
4234 /* now, adjust the # of entries copied */
4236 } /* if we're including this name */
4239 /* and adjust curOffset to be where the new cookie is */
4240 thyper.HighPart = 0;
4241 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4242 curOffset = LargeIntegerAdd(thyper, curOffset);
4243 } /* while copying data for dir listing */
4245 /* release the mutex */
4246 lock_ReleaseMutex(&scp->mx);
4248 buf_Release(bufferp);
4252 /* apply and free last set of patches; if not doing a star match, this
4253 * will be empty, but better safe (and freeing everything) than sorry.
4255 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
4257 /* special return code for unsuccessful search */
4258 if (code == 0 && dataLength < 21 && returnedNames == 0)
4259 code = CM_ERROR_NOFILES;
4261 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
4262 returnedNames, code);
4265 smb_DeleteDirSearch(dsp);
4266 smb_ReleaseDirSearch(dsp);
4267 cm_ReleaseSCache(scp);
4268 cm_ReleaseUser(userp);
4272 /* finalize the output buffer */
4273 smb_SetSMBParm(outp, 0, returnedNames);
4274 temp = (long) (op - origOp);
4275 smb_SetSMBDataLength(outp, temp);
4277 /* the data area is a variable block, which has a 5 (already there)
4278 * followed by the length of the # of data bytes. We now know this to
4279 * be "temp," although that includes the 3 bytes of vbl block header.
4280 * Deduct for them and fill in the length field.
4282 temp -= 3; /* deduct vbl block info */
4283 osi_assert(temp == (43 * returnedNames));
4284 origOp[1] = (char)(temp & 0xff);
4285 origOp[2] = (char)((temp>>8) & 0xff);
4286 if (returnedNames == 0)
4287 smb_DeleteDirSearch(dsp);
4288 smb_ReleaseDirSearch(dsp);
4289 cm_ReleaseSCache(scp);
4290 cm_ReleaseUser(userp);
4294 /* verify that this is a valid path to a directory. I don't know why they
4295 * don't use the get file attributes call.
4297 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4301 cm_scache_t *rootScp;
4302 cm_scache_t *newScp;
4311 pathp = smb_GetSMBData(inp, NULL);
4312 pathp = smb_ParseASCIIBlock(pathp, NULL);
4314 return CM_ERROR_BADFD;
4315 if (smb_StoreAnsiFilenames)
4316 OemToChar(pathp,pathp);
4317 osi_Log1(smb_logp, "SMB receive check path %s",
4318 osi_LogSaveString(smb_logp, pathp));
4320 rootScp = cm_data.rootSCachep;
4322 userp = smb_GetUserFromVCP(vcp, inp);
4324 caseFold = CM_FLAG_CASEFOLD;
4326 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4328 cm_ReleaseUser(userp);
4329 return CM_ERROR_NOSUCHPATH;
4331 code = cm_NameI(rootScp, pathp,
4332 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
4333 userp, tidPathp, &req, &newScp);
4336 cm_ReleaseUser(userp);
4341 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4342 cm_ReleaseSCache(newScp);
4343 cm_ReleaseUser(userp);
4344 if ( WANTS_DFS_PATHNAMES(inp) )
4345 return CM_ERROR_PATH_NOT_COVERED;
4347 return CM_ERROR_BADSHARENAME;
4349 #endif /* DFS_SUPPORT */
4351 /* now lock the vnode with a callback; returns with newScp locked */
4352 lock_ObtainMutex(&newScp->mx);
4353 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
4354 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4356 if (code != CM_ERROR_NOACCESS) {
4357 lock_ReleaseMutex(&newScp->mx);
4358 cm_ReleaseSCache(newScp);
4359 cm_ReleaseUser(userp);
4363 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4366 attrs = smb_Attributes(newScp);
4368 if (!(attrs & SMB_ATTR_DIRECTORY))
4369 code = CM_ERROR_NOTDIR;
4371 lock_ReleaseMutex(&newScp->mx);
4373 cm_ReleaseSCache(newScp);
4374 cm_ReleaseUser(userp);
4378 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4382 cm_scache_t *rootScp;
4383 unsigned short attribute;
4385 cm_scache_t *newScp;
4394 /* decode basic attributes we're passed */
4395 attribute = smb_GetSMBParm(inp, 0);
4396 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4398 pathp = smb_GetSMBData(inp, NULL);
4399 pathp = smb_ParseASCIIBlock(pathp, NULL);
4401 return CM_ERROR_BADSMB;
4402 if (smb_StoreAnsiFilenames)
4403 OemToChar(pathp,pathp);
4405 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
4406 dosTime, attribute);
4408 rootScp = cm_data.rootSCachep;
4410 userp = smb_GetUserFromVCP(vcp, inp);
4412 caseFold = CM_FLAG_CASEFOLD;
4414 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4416 cm_ReleaseUser(userp);
4417 return CM_ERROR_NOSUCHFILE;
4419 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4420 tidPathp, &req, &newScp);
4423 cm_ReleaseUser(userp);
4428 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4429 cm_ReleaseSCache(newScp);
4430 cm_ReleaseUser(userp);
4431 if ( WANTS_DFS_PATHNAMES(inp) )
4432 return CM_ERROR_PATH_NOT_COVERED;
4434 return CM_ERROR_BADSHARENAME;
4436 #endif /* DFS_SUPPORT */
4438 /* now lock the vnode with a callback; returns with newScp locked; we
4439 * need the current status to determine what the new status is, in some
4442 lock_ObtainMutex(&newScp->mx);
4443 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4444 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4446 lock_ReleaseMutex(&newScp->mx);
4447 cm_ReleaseSCache(newScp);
4448 cm_ReleaseUser(userp);
4452 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4454 /* Check for RO volume */
4455 if (newScp->flags & CM_SCACHEFLAG_RO) {
4456 lock_ReleaseMutex(&newScp->mx);
4457 cm_ReleaseSCache(newScp);
4458 cm_ReleaseUser(userp);
4459 return CM_ERROR_READONLY;
4462 /* prepare for setattr call */
4465 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
4466 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
4468 if ((newScp->unixModeBits & 0222) && (attribute & SMB_ATTR_READONLY) != 0) {
4469 /* we're told to make a writable file read-only */
4470 attr.unixModeBits = newScp->unixModeBits & ~0222;
4471 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4473 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
4474 /* we're told to make a read-only file writable */
4475 attr.unixModeBits = newScp->unixModeBits | 0222;
4476 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4478 lock_ReleaseMutex(&newScp->mx);
4480 /* now call setattr */
4482 code = cm_SetAttr(newScp, &attr, userp, &req);
4486 cm_ReleaseSCache(newScp);
4487 cm_ReleaseUser(userp);
4492 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4496 cm_scache_t *rootScp;
4497 cm_scache_t *newScp, *dscp;
4509 pathp = smb_GetSMBData(inp, NULL);
4510 pathp = smb_ParseASCIIBlock(pathp, NULL);
4512 return CM_ERROR_BADSMB;
4514 if (*pathp == 0) /* null path */
4517 if (smb_StoreAnsiFilenames)
4518 OemToChar(pathp,pathp);
4520 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
4521 osi_LogSaveString(smb_logp, pathp));
4523 rootScp = cm_data.rootSCachep;
4525 userp = smb_GetUserFromVCP(vcp, inp);
4527 /* we shouldn't need this for V3 requests, but we seem to */
4528 caseFold = CM_FLAG_CASEFOLD;
4530 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4532 cm_ReleaseUser(userp);
4533 return CM_ERROR_NOSUCHFILE;
4537 * XXX Strange hack XXX
4539 * As of Patch 5 (16 July 97), we are having the following problem:
4540 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
4541 * requests to look up "desktop.ini" in all the subdirectories.
4542 * This can cause zillions of timeouts looking up non-existent cells
4543 * and volumes, especially in the top-level directory.
4545 * We have not found any way to avoid this or work around it except
4546 * to explicitly ignore the requests for mount points that haven't
4547 * yet been evaluated and for directories that haven't yet been
4550 * We should modify this hack to provide a fake desktop.ini file
4551 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
4553 spacep = inp->spacep;
4554 smb_StripLastComponent(spacep->data, &lastComp, pathp);
4555 #ifndef SPECIAL_FOLDERS
4556 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
4557 code = cm_NameI(rootScp, spacep->data,
4558 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
4559 userp, tidPathp, &req, &dscp);
4562 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4563 if ( WANTS_DFS_PATHNAMES(inp) )
4564 return CM_ERROR_PATH_NOT_COVERED;
4566 return CM_ERROR_BADSHARENAME;
4568 #endif /* DFS_SUPPORT */
4569 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
4570 code = CM_ERROR_NOSUCHFILE;
4571 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
4572 cm_buf_t *bp = buf_Find(dscp, &hzero);
4577 code = CM_ERROR_NOSUCHFILE;
4579 cm_ReleaseSCache(dscp);
4581 cm_ReleaseUser(userp);
4586 #endif /* SPECIAL_FOLDERS */
4588 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4589 tidPathp, &req, &newScp);
4591 cm_ReleaseUser(userp);
4596 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4597 cm_ReleaseSCache(newScp);
4598 cm_ReleaseUser(userp);
4599 if ( WANTS_DFS_PATHNAMES(inp) )
4600 return CM_ERROR_PATH_NOT_COVERED;
4602 return CM_ERROR_BADSHARENAME;
4604 #endif /* DFS_SUPPORT */
4606 /* now lock the vnode with a callback; returns with newScp locked */
4607 lock_ObtainMutex(&newScp->mx);
4608 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4609 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4611 lock_ReleaseMutex(&newScp->mx);
4612 cm_ReleaseSCache(newScp);
4613 cm_ReleaseUser(userp);
4617 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4620 /* use smb_Attributes instead. Also the fact that a file is
4621 * in a readonly volume doesn't mean it shojuld be marked as RO
4623 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
4624 newScp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
4625 newScp->fileType == CM_SCACHETYPE_INVALID)
4626 attrs = SMB_ATTR_DIRECTORY;
4629 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
4630 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
4632 attrs = smb_Attributes(newScp);
4635 smb_SetSMBParm(outp, 0, attrs);
4637 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
4638 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
4639 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
4640 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
4641 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
4642 smb_SetSMBParm(outp, 5, 0);
4643 smb_SetSMBParm(outp, 6, 0);
4644 smb_SetSMBParm(outp, 7, 0);
4645 smb_SetSMBParm(outp, 8, 0);
4646 smb_SetSMBParm(outp, 9, 0);
4647 smb_SetSMBDataLength(outp, 0);
4648 lock_ReleaseMutex(&newScp->mx);
4650 cm_ReleaseSCache(newScp);
4651 cm_ReleaseUser(userp);
4656 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4660 osi_Log0(smb_logp, "SMB receive tree disconnect");
4662 /* find the tree and free it */
4663 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
4665 lock_ObtainWrite(&smb_rctLock);
4667 lock_ReleaseWrite(&smb_rctLock);
4668 smb_ReleaseTID(tidp);
4674 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4692 pathp = smb_GetSMBData(inp, NULL);
4693 pathp = smb_ParseASCIIBlock(pathp, NULL);
4694 if (smb_StoreAnsiFilenames)
4695 OemToChar(pathp,pathp);
4697 osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
4699 #ifdef DEBUG_VERBOSE
4703 hexpath = osi_HexifyString( pathp );
4704 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
4709 share = smb_GetSMBParm(inp, 0);
4710 attribute = smb_GetSMBParm(inp, 1);
4712 spacep = inp->spacep;
4713 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4714 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4715 /* special case magic file name for receiving IOCTL requests
4716 * (since IOCTL calls themselves aren't getting through).
4718 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4719 smb_SetupIoctlFid(fidp, spacep);
4720 smb_SetSMBParm(outp, 0, fidp->fid);
4721 smb_SetSMBParm(outp, 1, 0); /* attrs */
4722 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
4723 smb_SetSMBParm(outp, 3, 0);
4724 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
4725 smb_SetSMBParm(outp, 5, 0x7fff);
4726 /* pass the open mode back */
4727 smb_SetSMBParm(outp, 6, (share & 0xf));
4728 smb_SetSMBDataLength(outp, 0);
4729 smb_ReleaseFID(fidp);
4733 userp = smb_GetUserFromVCP(vcp, inp);
4735 caseFold = CM_FLAG_CASEFOLD;
4737 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4739 cm_ReleaseUser(userp);
4740 return CM_ERROR_NOSUCHPATH;
4742 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4743 tidPathp, &req, &scp);
4746 cm_ReleaseUser(userp);
4751 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4752 cm_ReleaseSCache(scp);
4753 cm_ReleaseUser(userp);
4754 if ( WANTS_DFS_PATHNAMES(inp) )
4755 return CM_ERROR_PATH_NOT_COVERED;
4757 return CM_ERROR_BADSHARENAME;
4759 #endif /* DFS_SUPPORT */
4761 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
4763 cm_ReleaseSCache(scp);
4764 cm_ReleaseUser(userp);
4768 /* don't need callback to check file type, since file types never
4769 * change, and namei and cm_Lookup all stat the object at least once on
4770 * a successful return.
4772 if (scp->fileType != CM_SCACHETYPE_FILE) {
4773 cm_ReleaseSCache(scp);
4774 cm_ReleaseUser(userp);
4775 return CM_ERROR_ISDIR;
4778 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4781 /* save a pointer to the vnode */
4783 osi_Log2(afsd_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
4784 lock_ObtainMutex(&scp->mx);
4785 scp->flags |= CM_SCACHEFLAG_SMB_FID;
4786 lock_ReleaseMutex(&scp->mx);
4790 fidp->userp = userp;
4792 lock_ObtainMutex(&fidp->mx);
4793 if ((share & 0xf) == 0)
4794 fidp->flags |= SMB_FID_OPENREAD;
4795 else if ((share & 0xf) == 1)
4796 fidp->flags |= SMB_FID_OPENWRITE;
4798 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
4799 lock_ReleaseMutex(&fidp->mx);
4801 lock_ObtainMutex(&scp->mx);
4802 smb_SetSMBParm(outp, 0, fidp->fid);
4803 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
4804 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4805 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
4806 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
4807 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
4808 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
4809 /* pass the open mode back; XXXX add access checks */
4810 smb_SetSMBParm(outp, 6, (share & 0xf));
4811 smb_SetSMBDataLength(outp, 0);
4812 lock_ReleaseMutex(&scp->mx);
4815 cm_Open(scp, 0, userp);
4817 /* send and free packet */
4818 smb_ReleaseFID(fidp);
4819 cm_ReleaseUser(userp);
4820 /* don't release scp, since we've squirreled away the pointer in the fid struct */
4824 typedef struct smb_unlinkRock {
4829 char *maskp; /* pointer to the star pattern */
4834 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4837 smb_unlinkRock_t *rockp;
4845 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4846 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4847 caseFold |= CM_FLAG_8DOT3;
4849 matchName = dep->name;
4850 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
4852 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4853 !cm_Is8Dot3(dep->name)) {
4854 cm_Gen8Dot3Name(dep, shortName, NULL);
4855 matchName = shortName;
4856 /* 8.3 matches are always case insensitive */
4857 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
4860 osi_Log1(smb_logp, "Unlinking %s",
4861 osi_LogSaveString(smb_logp, matchName));
4862 code = cm_Unlink(dscp, dep->name, rockp->userp, rockp->reqp);
4863 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4864 smb_NotifyChange(FILE_ACTION_REMOVED,
4865 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
4866 dscp, dep->name, NULL, TRUE);
4870 /* If we made a case sensitive exact match, we might as well quit now. */
4871 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
4872 code = CM_ERROR_STOPNOW;
4880 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4889 smb_unlinkRock_t rock;
4898 attribute = smb_GetSMBParm(inp, 0);
4900 tp = smb_GetSMBData(inp, NULL);
4901 pathp = smb_ParseASCIIBlock(tp, &tp);
4902 if (smb_StoreAnsiFilenames)
4903 OemToChar(pathp,pathp);
4905 osi_Log1(smb_logp, "SMB receive unlink %s",
4906 osi_LogSaveString(smb_logp, pathp));
4908 spacep = inp->spacep;
4909 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4911 userp = smb_GetUserFromVCP(vcp, inp);
4913 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4915 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4917 cm_ReleaseUser(userp);
4918 return CM_ERROR_NOSUCHPATH;
4920 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
4923 cm_ReleaseUser(userp);
4928 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4929 cm_ReleaseSCache(dscp);
4930 cm_ReleaseUser(userp);
4931 if ( WANTS_DFS_PATHNAMES(inp) )
4932 return CM_ERROR_PATH_NOT_COVERED;
4934 return CM_ERROR_BADSHARENAME;
4936 #endif /* DFS_SUPPORT */
4938 /* otherwise, scp points to the parent directory. */
4945 rock.maskp = smb_FindMask(pathp);
4946 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4949 thyper.HighPart = 0;
4955 /* Now, if we aren't dealing with a wildcard match, we first try an exact
4956 * match. If that fails, we do a case insensitve match.
4958 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
4959 !smb_IsStarMask(rock.maskp)) {
4960 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4963 thyper.HighPart = 0;
4964 rock.flags |= SMB_MASKFLAG_CASEFOLD;
4969 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4971 if (code == CM_ERROR_STOPNOW)
4974 cm_ReleaseUser(userp);
4976 cm_ReleaseSCache(dscp);
4978 if (code == 0 && !rock.any)
4979 code = CM_ERROR_NOSUCHFILE;
4983 typedef struct smb_renameRock {
4984 cm_scache_t *odscp; /* old dir */
4985 cm_scache_t *ndscp; /* new dir */
4986 cm_user_t *userp; /* user */
4987 cm_req_t *reqp; /* request struct */
4988 smb_vc_t *vcp; /* virtual circuit */
4989 char *maskp; /* pointer to star pattern of old file name */
4990 int flags; /* tilde, casefold, etc */
4991 char *newNamep; /* ptr to the new file's name */
4994 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4997 smb_renameRock_t *rockp;
5002 rockp = (smb_renameRock_t *) vrockp;
5004 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5005 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5006 caseFold |= CM_FLAG_8DOT3;
5008 match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
5010 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5011 !cm_Is8Dot3(dep->name)) {
5012 cm_Gen8Dot3Name(dep, shortName, NULL);
5013 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
5016 code = cm_Rename(rockp->odscp, dep->name,
5017 rockp->ndscp, rockp->newNamep, rockp->userp,
5019 /* if the call worked, stop doing the search now, since we
5020 * really only want to rename one file.
5023 code = CM_ERROR_STOPNOW;
5032 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, int attrs)
5035 cm_space_t *spacep = NULL;
5036 smb_renameRock_t rock;
5037 cm_scache_t *oldDscp = NULL;
5038 cm_scache_t *newDscp = NULL;
5039 cm_scache_t *tmpscp= NULL;
5040 cm_scache_t *tmpscp2 = NULL;
5050 userp = smb_GetUserFromVCP(vcp, inp);
5051 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5053 cm_ReleaseUser(userp);
5054 return CM_ERROR_NOSUCHPATH;
5058 spacep = inp->spacep;
5059 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5061 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5062 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5063 userp, tidPathp, &req, &oldDscp);
5065 cm_ReleaseUser(userp);
5070 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5071 cm_ReleaseSCache(oldDscp);
5072 cm_ReleaseUser(userp);
5073 if ( WANTS_DFS_PATHNAMES(inp) )
5074 return CM_ERROR_PATH_NOT_COVERED;
5076 return CM_ERROR_BADSHARENAME;
5078 #endif /* DFS_SUPPORT */
5080 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5081 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5082 userp, tidPathp, &req, &newDscp);
5085 cm_ReleaseSCache(oldDscp);
5086 cm_ReleaseUser(userp);
5091 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5092 cm_ReleaseSCache(oldDscp);
5093 cm_ReleaseSCache(newDscp);
5094 cm_ReleaseUser(userp);
5095 if ( WANTS_DFS_PATHNAMES(inp) )
5096 return CM_ERROR_PATH_NOT_COVERED;
5098 return CM_ERROR_BADSHARENAME;
5100 #endif /* DFS_SUPPORT */
5103 /* otherwise, oldDscp and newDscp point to the corresponding directories.
5104 * next, get the component names, and lower case them.
5107 /* handle the old name first */
5109 oldLastNamep = oldPathp;
5113 /* and handle the new name, too */
5115 newLastNamep = newPathp;
5119 /* TODO: The old name could be a wildcard. The new name must not be */
5121 /* do the vnode call */
5122 rock.odscp = oldDscp;
5123 rock.ndscp = newDscp;
5127 rock.maskp = oldLastNamep;
5128 rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5129 rock.newNamep = newLastNamep;
5131 /* Check if the file already exists; if so return error */
5132 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5133 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
5134 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5135 osi_LogSaveString(afsd_logp, newLastNamep));
5137 /* Check if the old and the new names differ only in case. If so return
5138 * success, else return CM_ERROR_EXISTS
5140 if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
5142 /* This would be a success only if the old file is *as same as* the new file */
5143 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
5145 if (tmpscp == tmpscp2)
5148 code = CM_ERROR_EXISTS;
5149 cm_ReleaseSCache(tmpscp2);
5152 code = CM_ERROR_NOSUCHFILE;
5155 /* file exist, do not rename, also fixes move */
5156 osi_Log0(smb_logp, "Can't rename. Target already exists");
5157 code = CM_ERROR_EXISTS;
5161 cm_ReleaseSCache(tmpscp);
5162 cm_ReleaseSCache(newDscp);
5163 cm_ReleaseSCache(oldDscp);
5164 cm_ReleaseUser(userp);
5168 /* Now search the directory for the pattern, and do the appropriate rename when found */
5169 thyper.LowPart = 0; /* search dir from here */
5170 thyper.HighPart = 0;
5172 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5173 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
5175 if (code == CM_ERROR_STOPNOW)
5178 code = CM_ERROR_NOSUCHFILE;
5180 /* Handle Change Notification */
5182 * Being lazy, not distinguishing between files and dirs in this
5183 * filter, since we'd have to do a lookup.
5185 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
5186 if (oldDscp == newDscp) {
5187 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5188 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5189 filter, oldDscp, oldLastNamep,
5190 newLastNamep, TRUE);
5192 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5193 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5194 filter, oldDscp, oldLastNamep,
5196 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5197 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
5198 filter, newDscp, newLastNamep,
5203 cm_ReleaseSCache(tmpscp);
5204 cm_ReleaseUser(userp);
5205 cm_ReleaseSCache(oldDscp);
5206 cm_ReleaseSCache(newDscp);
5211 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
5214 cm_space_t *spacep = NULL;
5215 cm_scache_t *oldDscp = NULL;
5216 cm_scache_t *newDscp = NULL;
5217 cm_scache_t *tmpscp= NULL;
5218 cm_scache_t *tmpscp2 = NULL;
5219 cm_scache_t *sscp = NULL;
5228 userp = smb_GetUserFromVCP(vcp, inp);
5230 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5232 cm_ReleaseUser(userp);
5233 return CM_ERROR_NOSUCHPATH;
5238 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5240 spacep = inp->spacep;
5241 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5243 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5244 userp, tidPathp, &req, &oldDscp);
5246 cm_ReleaseUser(userp);
5251 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5252 cm_ReleaseSCache(oldDscp);
5253 cm_ReleaseUser(userp);
5254 if ( WANTS_DFS_PATHNAMES(inp) )
5255 return CM_ERROR_PATH_NOT_COVERED;
5257 return CM_ERROR_BADSHARENAME;
5259 #endif /* DFS_SUPPORT */
5261 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5262 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5263 userp, tidPathp, &req, &newDscp);
5265 cm_ReleaseSCache(oldDscp);
5266 cm_ReleaseUser(userp);
5271 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5272 cm_ReleaseSCache(newDscp);
5273 cm_ReleaseSCache(oldDscp);
5274 cm_ReleaseUser(userp);
5275 if ( WANTS_DFS_PATHNAMES(inp) )
5276 return CM_ERROR_PATH_NOT_COVERED;
5278 return CM_ERROR_BADSHARENAME;
5280 #endif /* DFS_SUPPORT */
5282 /* Now, although we did two lookups for the two directories (because the same
5283 * directory can be referenced through different paths), we only allow hard links
5284 * within the same directory. */
5285 if (oldDscp != newDscp) {
5286 cm_ReleaseSCache(oldDscp);
5287 cm_ReleaseSCache(newDscp);
5288 cm_ReleaseUser(userp);
5289 return CM_ERROR_CROSSDEVLINK;
5292 /* handle the old name first */
5294 oldLastNamep = oldPathp;
5298 /* and handle the new name, too */
5300 newLastNamep = newPathp;
5304 /* now lookup the old name */
5305 osi_Log1(smb_logp," looking up [%s]", osi_LogSaveString(smb_logp,oldLastNamep));
5306 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
5308 cm_ReleaseSCache(oldDscp);
5309 cm_ReleaseSCache(newDscp);
5310 cm_ReleaseUser(userp);
5314 /* Check if the file already exists; if so return error */
5315 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5316 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
5317 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5318 osi_LogSaveString(afsd_logp, newLastNamep));
5320 /* if the existing link is to the same file, then we return success */
5322 if(sscp == tmpscp) {
5325 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
5326 code = CM_ERROR_EXISTS;
5331 cm_ReleaseSCache(tmpscp);
5332 cm_ReleaseSCache(sscp);
5333 cm_ReleaseSCache(newDscp);
5334 cm_ReleaseSCache(oldDscp);
5335 cm_ReleaseUser(userp);
5339 /* now create the hardlink */
5340 osi_Log1(smb_logp," Attempting to create new link [%s]", osi_LogSaveString(smb_logp, newLastNamep));
5341 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
5342 osi_Log1(smb_logp," Link returns 0x%x", code);
5344 /* Handle Change Notification */
5346 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
5347 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5348 smb_NotifyChange(FILE_ACTION_ADDED,
5349 filter, newDscp, newLastNamep,
5354 cm_ReleaseSCache(tmpscp);
5355 cm_ReleaseUser(userp);
5356 cm_ReleaseSCache(sscp);
5357 cm_ReleaseSCache(oldDscp);
5358 cm_ReleaseSCache(newDscp);
5363 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5369 tp = smb_GetSMBData(inp, NULL);
5370 oldPathp = smb_ParseASCIIBlock(tp, &tp);
5371 if (smb_StoreAnsiFilenames)
5372 OemToChar(oldPathp,oldPathp);
5373 newPathp = smb_ParseASCIIBlock(tp, &tp);
5374 if (smb_StoreAnsiFilenames)
5375 OemToChar(newPathp,newPathp);
5377 osi_Log2(smb_logp, "smb rename [%s] to [%s]",
5378 osi_LogSaveString(smb_logp, oldPathp),
5379 osi_LogSaveString(smb_logp, newPathp));
5381 return smb_Rename(vcp,inp,oldPathp,newPathp,0);
5386 typedef struct smb_rmdirRock {
5390 char *maskp; /* pointer to the star pattern */
5395 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5398 smb_rmdirRock_t *rockp;
5403 rockp = (smb_rmdirRock_t *) vrockp;
5405 matchName = dep->name;
5406 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
5407 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5409 match = (strcmp(matchName, rockp->maskp) == 0);
5411 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5412 !cm_Is8Dot3(dep->name)) {
5413 cm_Gen8Dot3Name(dep, shortName, NULL);
5414 matchName = shortName;
5415 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5418 osi_Log1(smb_logp, "Removing directory %s",
5419 osi_LogSaveString(smb_logp, matchName));
5420 code = cm_RemoveDir(dscp, dep->name, rockp->userp, rockp->reqp);
5421 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5422 smb_NotifyChange(FILE_ACTION_REMOVED,
5423 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
5424 dscp, dep->name, NULL, TRUE);
5433 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5441 smb_rmdirRock_t rock;
5450 tp = smb_GetSMBData(inp, NULL);
5451 pathp = smb_ParseASCIIBlock(tp, &tp);
5452 if (smb_StoreAnsiFilenames)
5453 OemToChar(pathp,pathp);
5455 spacep = inp->spacep;
5456 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5458 userp = smb_GetUserFromVCP(vcp, inp);
5460 caseFold = CM_FLAG_CASEFOLD;
5462 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5464 cm_ReleaseUser(userp);
5465 return CM_ERROR_NOSUCHPATH;
5467 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5468 userp, tidPathp, &req, &dscp);
5471 cm_ReleaseUser(userp);
5476 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5477 cm_ReleaseSCache(dscp);
5478 cm_ReleaseUser(userp);
5479 if ( WANTS_DFS_PATHNAMES(inp) )
5480 return CM_ERROR_PATH_NOT_COVERED;
5482 return CM_ERROR_BADSHARENAME;
5484 #endif /* DFS_SUPPORT */
5486 /* otherwise, scp points to the parent directory. */
5493 rock.maskp = lastNamep;
5494 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5497 thyper.HighPart = 0;
5501 /* First do a case sensitive match, and if that fails, do a case insensitive match */
5502 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5503 if (code == 0 && !rock.any) {
5505 thyper.HighPart = 0;
5506 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5507 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5510 cm_ReleaseUser(userp);
5512 cm_ReleaseSCache(dscp);
5514 if (code == 0 && !rock.any)
5515 code = CM_ERROR_NOSUCHFILE;
5519 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5529 fid = smb_GetSMBParm(inp, 0);
5531 osi_Log1(smb_logp, "SMB flush fid %d", fid);
5533 fid = smb_ChainFID(fid, inp);
5534 fidp = smb_FindFID(vcp, fid, 0);
5536 return CM_ERROR_BADFD;
5538 lock_ObtainMutex(&fidp->mx);
5539 if (fidp->flags & SMB_FID_IOCTL) {
5540 lock_ReleaseMutex(&fidp->mx);
5541 smb_ReleaseFID(fidp);
5542 return CM_ERROR_BADFD;
5544 lock_ReleaseMutex(&fidp->mx);
5546 userp = smb_GetUserFromVCP(vcp, inp);
5548 lock_ObtainMutex(&fidp->mx);
5549 if (fidp->flags & SMB_FID_OPENWRITE) {
5550 cm_scache_t * scp = fidp->scp;
5552 lock_ReleaseMutex(&fidp->mx);
5553 code = cm_FSync(scp, userp, &req);
5554 cm_ReleaseSCache(scp);
5557 lock_ReleaseMutex(&fidp->mx);
5560 smb_ReleaseFID(fidp);
5562 cm_ReleaseUser(userp);
5567 struct smb_FullNameRock {
5573 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
5577 struct smb_FullNameRock *vrockp;
5579 vrockp = (struct smb_FullNameRock *)rockp;
5581 if (!cm_Is8Dot3(dep->name)) {
5582 cm_Gen8Dot3Name(dep, shortName, NULL);
5584 if (cm_stricmp(shortName, vrockp->name) == 0) {
5585 vrockp->fullName = strdup(dep->name);
5586 return CM_ERROR_STOPNOW;
5589 if (cm_stricmp(dep->name, vrockp->name) == 0 &&
5590 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
5591 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
5592 vrockp->fullName = strdup(dep->name);
5593 return CM_ERROR_STOPNOW;
5598 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
5599 char **newPathp, cm_user_t *userp, cm_req_t *reqp)
5601 struct smb_FullNameRock rock;
5607 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
5608 if (code == CM_ERROR_STOPNOW)
5609 *newPathp = rock.fullName;
5611 *newPathp = strdup(pathp);
5614 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
5615 afs_uint32 dosTime) {
5618 cm_scache_t *dscp = fidp->NTopen_dscp;
5619 char *pathp = fidp->NTopen_pathp;
5620 cm_scache_t * scp = fidp->scp;
5622 int nullcreator = 0;
5624 osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
5625 fidp, fidp->fid, scp, vcp);
5628 lock_ObtainMutex(&fidp->mx);
5629 if (!fidp->userp && !(fidp->flags & SMB_FID_IOCTL)) {
5630 lock_ReleaseMutex(&fidp->mx);
5631 osi_Log0(smb_logp, " No user specified. Not closing fid");
5632 return CM_ERROR_BADFD;
5635 userp = fidp->userp; /* no hold required since fidp is held
5636 throughout the function */
5637 lock_ReleaseMutex(&fidp->mx);
5642 lock_ObtainWrite(&smb_rctLock);
5644 osi_Log0(smb_logp, " Fid already closed.");
5645 lock_ReleaseWrite(&smb_rctLock);
5646 return CM_ERROR_BADFD;
5649 lock_ReleaseWrite(&smb_rctLock);
5651 lock_ObtainMutex(&fidp->mx);
5652 /* Don't jump the gun on an async raw write */
5653 while (fidp->raw_writers) {
5654 lock_ReleaseMutex(&fidp->mx);
5655 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
5656 lock_ObtainMutex(&fidp->mx);
5659 /* watch for ioctl closes, and read-only opens */
5661 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
5662 == SMB_FID_OPENWRITE) {
5663 if (dosTime != 0 && dosTime != -1) {
5664 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5665 /* This fixes defect 10958 */
5666 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
5667 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
5669 lock_ReleaseMutex(&fidp->mx);
5670 code = cm_FSync(scp, userp, &req);
5671 lock_ObtainMutex(&fidp->mx);
5676 /* unlock any pending locks */
5677 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
5678 scp->fileType == CM_SCACHETYPE_FILE) {
5682 lock_ReleaseMutex(&fidp->mx);
5684 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
5686 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
5687 lock_ObtainMutex(&scp->mx);
5689 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
5690 CM_SCACHESYNC_NEEDCALLBACK
5691 | CM_SCACHESYNC_GETSTATUS
5692 | CM_SCACHESYNC_LOCK);
5696 "smb CoreClose SyncOp failure code 0x%x", tcode);
5697 goto post_syncopdone;
5700 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
5702 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
5706 lock_ReleaseMutex(&scp->mx);
5707 lock_ObtainMutex(&fidp->mx);
5710 if (fidp->flags & SMB_FID_DELONCLOSE) {
5713 lock_ReleaseMutex(&fidp->mx);
5714 smb_FullName(dscp, scp, pathp, &fullPathp, userp, &req);
5715 if (scp->fileType == CM_SCACHETYPE_DIRECTORY) {
5716 code = cm_RemoveDir(dscp, fullPathp, userp, &req);
5719 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5720 smb_NotifyChange(FILE_ACTION_REMOVED,
5721 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
5722 dscp, fullPathp, NULL, TRUE);
5725 code = cm_Unlink(dscp, fullPathp, userp, &req);
5728 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5729 smb_NotifyChange(FILE_ACTION_REMOVED,
5730 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5731 dscp, fullPathp, NULL, TRUE);
5735 lock_ObtainMutex(&fidp->mx);
5736 fidp->flags &= ~SMB_FID_DELONCLOSE;
5739 /* if this was a newly created file, then clear the creator
5740 * in the stat cache entry. */
5741 if (fidp->flags & SMB_FID_CREATED) {
5743 fidp->flags &= ~SMB_FID_CREATED;
5746 if (fidp->flags & SMB_FID_NTOPEN) {
5747 fidp->NTopen_dscp = NULL;
5748 fidp->NTopen_pathp = NULL;
5749 fidp->flags &= ~SMB_FID_NTOPEN;
5751 if (fidp->NTopen_wholepathp) {
5752 free(fidp->NTopen_wholepathp);
5753 fidp->NTopen_wholepathp = NULL;
5757 lock_ReleaseMutex(&fidp->mx);
5760 cm_ReleaseSCache(dscp);
5763 if (deleted || nullcreator) {
5764 lock_ObtainMutex(&scp->mx);
5765 if (nullcreator && scp->creator == userp)
5766 scp->creator = NULL;
5768 scp->flags |= CM_SCACHEFLAG_DELETED;
5769 lock_ReleaseMutex(&scp->mx);
5771 lock_ObtainMutex(&scp->mx);
5772 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
5773 lock_ReleaseMutex(&scp->mx);
5774 cm_ReleaseSCache(scp);
5783 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5791 fid = smb_GetSMBParm(inp, 0);
5792 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5794 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
5796 fid = smb_ChainFID(fid, inp);
5797 fidp = smb_FindFID(vcp, fid, 0);
5799 return CM_ERROR_BADFD;
5802 userp = smb_GetUserFromVCP(vcp, inp);
5804 code = smb_CloseFID(vcp, fidp, userp, dosTime);
5806 smb_ReleaseFID(fidp);
5807 cm_ReleaseUser(userp);
5812 * smb_ReadData -- common code for Read, Read And X, and Raw Read
5814 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5815 cm_user_t *userp, long *readp)
5821 osi_hyper_t fileLength;
5823 osi_hyper_t lastByte;
5824 osi_hyper_t bufferOffset;
5825 long bufIndex, nbytes;
5827 int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
5835 lock_ObtainMutex(&fidp->mx);
5838 lock_ObtainMutex(&scp->mx);
5840 if (offset.HighPart == 0) {
5841 chunk = offset.LowPart >> cm_logChunkSize;
5842 if (chunk != fidp->curr_chunk) {
5843 fidp->prev_chunk = fidp->curr_chunk;
5844 fidp->curr_chunk = chunk;
5846 if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
5849 lock_ReleaseMutex(&fidp->mx);
5851 /* start by looking up the file's end */
5852 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5853 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5857 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5859 /* now we have the entry locked, look up the length */
5860 fileLength = scp->length;
5862 /* adjust count down so that it won't go past EOF */
5863 thyper.LowPart = count;
5864 thyper.HighPart = 0;
5865 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
5867 if (LargeIntegerGreaterThan(thyper, fileLength)) {
5868 /* we'd read past EOF, so just stop at fileLength bytes.
5869 * Start by computing how many bytes remain in the file.
5871 thyper = LargeIntegerSubtract(fileLength, offset);
5873 /* if we are past EOF, read 0 bytes */
5874 if (LargeIntegerLessThanZero(thyper))
5877 count = thyper.LowPart;
5882 /* now, copy the data one buffer at a time,
5883 * until we've filled the request packet
5886 /* if we've copied all the data requested, we're done */
5887 if (count <= 0) break;
5889 /* otherwise, load up a buffer of data */
5890 thyper.HighPart = offset.HighPart;
5891 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
5892 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5895 buf_Release(bufferp);
5898 lock_ReleaseMutex(&scp->mx);
5900 lock_ObtainRead(&scp->bufCreateLock);
5901 code = buf_Get(scp, &thyper, &bufferp);
5902 lock_ReleaseRead(&scp->bufCreateLock);
5904 lock_ObtainMutex(&scp->mx);
5905 if (code) goto done;
5906 bufferOffset = thyper;
5908 /* now get the data in the cache */
5910 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
5911 CM_SCACHESYNC_NEEDCALLBACK |
5912 CM_SCACHESYNC_READ);
5916 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5918 if (cm_HaveBuffer(scp, bufferp, 0)) break;
5920 /* otherwise, load the buffer and try again */
5921 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
5925 buf_Release(bufferp);
5929 } /* if (wrong buffer) ... */
5931 /* now we have the right buffer loaded. Copy out the
5932 * data from here to the user's buffer.
5934 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
5936 /* and figure out how many bytes we want from this buffer */
5937 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
5938 if (nbytes > count) nbytes = count; /* don't go past EOF */
5940 /* now copy the data */
5941 memcpy(op, bufferp->datap + bufIndex, nbytes);
5943 /* adjust counters, pointers, etc. */
5946 thyper.LowPart = nbytes;
5947 thyper.HighPart = 0;
5948 offset = LargeIntegerAdd(thyper, offset);
5952 lock_ReleaseMutex(&scp->mx);
5954 buf_Release(bufferp);
5956 if (code == 0 && sequential)
5957 cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
5959 cm_ReleaseSCache(scp);
5965 * smb_WriteData -- common code for Write and Raw Write
5967 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5968 cm_user_t *userp, long *writtenp)
5974 osi_hyper_t fileLength; /* file's length at start of write */
5975 osi_hyper_t minLength; /* don't read past this */
5976 long nbytes; /* # of bytes to transfer this iteration */
5978 osi_hyper_t thyper; /* hyper tmp variable */
5979 osi_hyper_t bufferOffset;
5980 long bufIndex; /* index in buffer where our data is */
5982 osi_hyper_t writeBackOffset;/* offset of region to write back when
5987 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
5988 fidp->fid, offsetp->LowPart, count);
5998 lock_ObtainMutex(&fidp->mx);
5999 /* make sure we have a writable FD */
6000 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
6001 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
6002 fidp->fid, fidp->flags);
6003 lock_ReleaseMutex(&fidp->mx);
6004 code = CM_ERROR_BADFDOP;
6010 lock_ReleaseMutex(&fidp->mx);
6012 lock_ObtainMutex(&scp->mx);
6013 /* start by looking up the file's end */
6014 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6015 CM_SCACHESYNC_NEEDCALLBACK
6016 | CM_SCACHESYNC_SETSTATUS
6017 | CM_SCACHESYNC_GETSTATUS);
6021 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
6023 /* now we have the entry locked, look up the length */
6024 fileLength = scp->length;
6025 minLength = fileLength;
6026 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
6027 minLength = scp->serverLength;
6029 /* adjust file length if we extend past EOF */
6030 thyper.LowPart = count;
6031 thyper.HighPart = 0;
6032 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
6033 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6034 /* we'd write past EOF, so extend the file */
6035 scp->mask |= CM_SCACHEMASK_LENGTH;
6036 scp->length = thyper;
6037 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
6039 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
6041 /* now, if the new position (thyper) and the old (offset) are in
6042 * different storeback windows, remember to store back the previous
6043 * storeback window when we're done with the write.
6045 if ((thyper.LowPart & (-cm_chunkSize)) !=
6046 (offset.LowPart & (-cm_chunkSize))) {
6047 /* they're different */
6049 writeBackOffset.HighPart = offset.HighPart;
6050 writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
6055 /* now, copy the data one buffer at a time, until we've filled the
6058 /* if we've copied all the data requested, we're done */
6062 /* handle over quota or out of space */
6063 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
6064 *writtenp = written;
6065 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
6069 /* otherwise, load up a buffer of data */
6070 thyper.HighPart = offset.HighPart;
6071 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6072 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6075 lock_ReleaseMutex(&bufferp->mx);
6076 buf_Release(bufferp);
6079 lock_ReleaseMutex(&scp->mx);
6081 lock_ObtainRead(&scp->bufCreateLock);
6082 code = buf_Get(scp, &thyper, &bufferp);
6083 lock_ReleaseRead(&scp->bufCreateLock);
6085 lock_ObtainMutex(&bufferp->mx);
6086 lock_ObtainMutex(&scp->mx);
6087 if (code) goto done;
6089 bufferOffset = thyper;
6091 /* now get the data in the cache */
6093 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6094 CM_SCACHESYNC_NEEDCALLBACK
6095 | CM_SCACHESYNC_WRITE
6096 | CM_SCACHESYNC_BUFLOCKED);
6100 cm_SyncOpDone(scp, bufferp,
6101 CM_SCACHESYNC_NEEDCALLBACK
6102 | CM_SCACHESYNC_WRITE
6103 | CM_SCACHESYNC_BUFLOCKED);
6105 /* If we're overwriting the entire buffer, or
6106 * if we're writing at or past EOF, mark the
6107 * buffer as current so we don't call
6108 * cm_GetBuffer. This skips the fetch from the
6109 * server in those cases where we're going to
6110 * obliterate all the data in the buffer anyway,
6111 * or in those cases where there is no useful
6112 * data at the server to start with.
6114 * Use minLength instead of scp->length, since
6115 * the latter has already been updated by this
6118 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
6119 || LargeIntegerEqualTo(offset, bufferp->offset)
6120 && (count >= cm_data.buf_blockSize
6121 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
6122 ConvertLongToLargeInteger(count)),
6124 if (count < cm_data.buf_blockSize
6125 && bufferp->dataVersion == -1)
6126 memset(bufferp->datap, 0,
6127 cm_data.buf_blockSize);
6128 bufferp->dataVersion = scp->dataVersion;
6131 if (cm_HaveBuffer(scp, bufferp, 1)) break;
6133 /* otherwise, load the buffer and try again */
6134 lock_ReleaseMutex(&bufferp->mx);
6135 code = cm_GetBuffer(scp, bufferp, NULL, userp,
6137 lock_ReleaseMutex(&scp->mx);
6138 lock_ObtainMutex(&bufferp->mx);
6139 lock_ObtainMutex(&scp->mx);
6143 lock_ReleaseMutex(&bufferp->mx);
6144 buf_Release(bufferp);
6148 } /* if (wrong buffer) ... */
6150 /* now we have the right buffer loaded. Copy out the
6151 * data from here to the user's buffer.
6153 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6155 /* and figure out how many bytes we want from this buffer */
6156 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6158 nbytes = count; /* don't go past end of request */
6160 /* now copy the data */
6161 memcpy(bufferp->datap + bufIndex, op, nbytes);
6162 buf_SetDirty(bufferp);
6164 /* and record the last writer */
6165 if (bufferp->userp != userp) {
6168 cm_ReleaseUser(bufferp->userp);
6169 bufferp->userp = userp;
6172 /* adjust counters, pointers, etc. */
6176 thyper.LowPart = nbytes;
6177 thyper.HighPart = 0;
6178 offset = LargeIntegerAdd(thyper, offset);
6182 lock_ReleaseMutex(&scp->mx);
6185 lock_ReleaseMutex(&bufferp->mx);
6186 buf_Release(bufferp);
6189 lock_ObtainMutex(&fidp->mx);
6190 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
6191 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
6192 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
6193 fidp->NTopen_dscp, fidp->NTopen_pathp,
6196 lock_ReleaseMutex(&fidp->mx);
6198 if (code == 0 && doWriteBack) {
6200 lock_ObtainMutex(&scp->mx);
6201 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
6203 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
6204 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
6206 lock_ReleaseMutex(&scp->mx);
6207 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
6208 writeBackOffset.HighPart, cm_chunkSize, 0, userp);
6209 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
6212 cm_ReleaseSCache(scp);
6214 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
6215 fidp->fid, code, *writtenp);
6219 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6222 unsigned short count;
6224 unsigned short hint;
6225 long written = 0, total_written = 0;
6230 cm_attr_t truncAttr; /* attribute struct used for truncating file */
6232 int inDataBlockCount;
6234 fd = smb_GetSMBParm(inp, 0);
6235 count = smb_GetSMBParm(inp, 1);
6236 offset.HighPart = 0; /* too bad */
6237 offset.LowPart = smb_GetSMBParmLong(inp, 2);
6238 hint = smb_GetSMBParm(inp, 4);
6240 op = smb_GetSMBData(inp, NULL);
6241 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
6243 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
6244 fd, offset.LowPart, count);
6246 fd = smb_ChainFID(fd, inp);
6247 fidp = smb_FindFID(vcp, fd, 0);
6249 osi_Log0(smb_logp, "smb_ReceiveCoreWrite fid not found");
6250 return CM_ERROR_BADFD;
6253 lock_ObtainMutex(&fidp->mx);
6254 if (fidp->flags & SMB_FID_IOCTL) {
6255 lock_ReleaseMutex(&fidp->mx);
6256 code = smb_IoctlWrite(fidp, vcp, inp, outp);
6257 smb_ReleaseFID(fidp);
6258 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
6261 lock_ReleaseMutex(&fidp->mx);
6262 userp = smb_GetUserFromVCP(vcp, inp);
6266 LARGE_INTEGER LOffset;
6267 LARGE_INTEGER LLength;
6269 pid = ((smb_t *) inp)->pid;
6270 key = cm_GenerateKey(vcp->vcID, pid, fd);
6272 LOffset.HighPart = offset.HighPart;
6273 LOffset.LowPart = offset.LowPart;
6274 LLength.HighPart = 0;
6275 LLength.LowPart = count;
6277 lock_ObtainMutex(&fidp->scp->mx);
6278 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6279 lock_ReleaseMutex(&fidp->scp->mx);
6282 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
6287 /* special case: 0 bytes transferred means truncate to this position */
6291 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
6295 truncAttr.mask = CM_ATTRMASK_LENGTH;
6296 truncAttr.length.LowPart = offset.LowPart;
6297 truncAttr.length.HighPart = 0;
6298 lock_ObtainMutex(&fidp->mx);
6299 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
6300 fidp->flags |= SMB_FID_LENGTHSETDONE;
6301 lock_ReleaseMutex(&fidp->mx);
6302 smb_SetSMBParm(outp, 0, 0 /* count */);
6303 smb_SetSMBDataLength(outp, 0);
6308 * Work around bug in NT client
6310 * When copying a file, the NT client should first copy the data,
6311 * then copy the last write time. But sometimes the NT client does
6312 * these in the wrong order, so the data copies would inadvertently
6313 * cause the last write time to be overwritten. We try to detect this,
6314 * and don't set client mod time if we think that would go against the
6317 lock_ObtainMutex(&fidp->mx);
6318 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6319 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6320 fidp->scp->clientModTime = time(NULL);
6322 lock_ReleaseMutex(&fidp->mx);
6325 while ( code == 0 && count > 0 ) {
6326 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6327 if (code == 0 && written == 0)
6328 code = CM_ERROR_PARTIALWRITE;
6330 offset = LargeIntegerAdd(offset,
6331 ConvertLongToLargeInteger(written));
6333 total_written += written;
6337 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
6338 total_written, code);
6340 /* set the packet data length to 3 bytes for the data block header,
6341 * plus the size of the data.
6343 smb_SetSMBParm(outp, 0, total_written);
6344 smb_SetSMBParmLong(outp, 1, offset.LowPart);
6345 smb_SetSMBParm(outp, 3, hint);
6346 smb_SetSMBDataLength(outp, 0);
6349 smb_ReleaseFID(fidp);
6350 cm_ReleaseUser(userp);
6355 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6356 NCB *ncbp, raw_write_cont_t *rwcp)
6365 fd = smb_GetSMBParm(inp, 0);
6366 fidp = smb_FindFID(vcp, fd, 0);
6368 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
6369 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
6371 userp = smb_GetUserFromVCP(vcp, inp);
6374 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
6376 if (rwcp->writeMode & 0x1) { /* synchronous */
6379 smb_FormatResponsePacket(vcp, inp, outp);
6380 op = (smb_t *) outp;
6381 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6382 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
6383 smb_SetSMBDataLength(outp, 0);
6384 smb_SendPacket(vcp, outp);
6385 smb_FreePacket(outp);
6387 else { /* asynchronous */
6388 lock_ObtainMutex(&fidp->mx);
6389 fidp->raw_writers--;
6390 if (fidp->raw_writers == 0)
6391 thrd_SetEvent(fidp->raw_write_event);
6392 lock_ReleaseMutex(&fidp->mx);
6395 /* Give back raw buffer */
6396 lock_ObtainMutex(&smb_RawBufLock);
6397 *((char **)rawBuf) = smb_RawBufs;
6398 smb_RawBufs = rawBuf;
6399 lock_ReleaseMutex(&smb_RawBufLock);
6401 smb_ReleaseFID(fidp);
6402 cm_ReleaseUser(userp);
6405 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6410 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
6413 long count, written = 0, total_written = 0;
6420 unsigned short writeMode;
6422 fd = smb_GetSMBParm(inp, 0);
6423 totalCount = smb_GetSMBParm(inp, 1);
6424 count = smb_GetSMBParm(inp, 10);
6425 writeMode = smb_GetSMBParm(inp, 7);
6427 op = (char *) inp->data;
6428 op += smb_GetSMBParm(inp, 11);
6430 offset.HighPart = 0;
6431 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6433 if (*inp->wctp == 14) {
6434 /* we received a 64-bit file offset */
6435 #ifdef AFS_LARGEFILES
6436 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
6438 if (LargeIntegerLessThanZero(offset)) {
6440 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
6441 offset.HighPart, offset.LowPart);
6442 return CM_ERROR_BADSMB;
6445 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
6447 "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files");
6448 return CM_ERROR_BADSMB;
6451 offset.HighPart = 0;
6454 offset.HighPart = 0; /* 32-bit file offset */
6458 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
6459 fd, offset.HighPart, offset.LowPart, count);
6461 " WriteRaw WriteMode 0x%x",
6464 fd = smb_ChainFID(fd, inp);
6465 fidp = smb_FindFID(vcp, fd, 0);
6467 return CM_ERROR_BADFD;
6473 LARGE_INTEGER LOffset;
6474 LARGE_INTEGER LLength;
6476 pid = ((smb_t *) inp)->pid;
6477 key = cm_GenerateKey(vcp->vcID, pid, fd);
6479 LOffset.HighPart = offset.HighPart;
6480 LOffset.LowPart = offset.LowPart;
6481 LLength.HighPart = 0;
6482 LLength.LowPart = count;
6484 lock_ObtainMutex(&fidp->scp->mx);
6485 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6486 lock_ReleaseMutex(&fidp->scp->mx);
6489 smb_ReleaseFID(fidp);
6494 userp = smb_GetUserFromVCP(vcp, inp);
6497 * Work around bug in NT client
6499 * When copying a file, the NT client should first copy the data,
6500 * then copy the last write time. But sometimes the NT client does
6501 * these in the wrong order, so the data copies would inadvertently
6502 * cause the last write time to be overwritten. We try to detect this,
6503 * and don't set client mod time if we think that would go against the
6506 lock_ObtainMutex(&fidp->mx);
6507 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
6508 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6509 fidp->scp->clientModTime = time(NULL);
6511 lock_ReleaseMutex(&fidp->mx);
6514 while ( code == 0 && count > 0 ) {
6515 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6516 if (code == 0 && written == 0)
6517 code = CM_ERROR_PARTIALWRITE;
6519 offset = LargeIntegerAdd(offset,
6520 ConvertLongToLargeInteger(written));
6523 total_written += written;
6527 /* Get a raw buffer */
6530 lock_ObtainMutex(&smb_RawBufLock);
6532 /* Get a raw buf, from head of list */
6533 rawBuf = smb_RawBufs;
6534 smb_RawBufs = *(char **)smb_RawBufs;
6537 code = CM_ERROR_USESTD;
6539 lock_ReleaseMutex(&smb_RawBufLock);
6542 /* Don't allow a premature Close */
6543 if (code == 0 && (writeMode & 1) == 0) {
6544 lock_ObtainMutex(&fidp->mx);
6545 fidp->raw_writers++;
6546 thrd_ResetEvent(fidp->raw_write_event);
6547 lock_ReleaseMutex(&fidp->mx);
6550 smb_ReleaseFID(fidp);
6551 cm_ReleaseUser(userp);
6554 smb_SetSMBParm(outp, 0, total_written);
6555 smb_SetSMBDataLength(outp, 0);
6556 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6561 offset = LargeIntegerAdd(offset,
6562 ConvertLongToLargeInteger(count));
6566 rwcp->offset.HighPart = offset.HighPart;
6567 rwcp->offset.LowPart = offset.LowPart;
6568 rwcp->count = totalCount - count;
6569 rwcp->writeMode = writeMode;
6570 rwcp->alreadyWritten = total_written;
6572 /* set the packet data length to 3 bytes for the data block header,
6573 * plus the size of the data.
6575 smb_SetSMBParm(outp, 0, 0xffff);
6576 smb_SetSMBDataLength(outp, 0);
6581 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6584 long count, finalCount;
6592 fd = smb_GetSMBParm(inp, 0);
6593 count = smb_GetSMBParm(inp, 1);
6594 offset.HighPart = 0; /* too bad */
6595 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6597 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
6598 fd, offset.LowPart, count);
6600 fd = smb_ChainFID(fd, inp);
6601 fidp = smb_FindFID(vcp, fd, 0);
6603 return CM_ERROR_BADFD;
6605 lock_ObtainMutex(&fidp->mx);
6606 if (fidp->flags & SMB_FID_IOCTL) {
6607 lock_ReleaseMutex(&fidp->mx);
6608 code = smb_IoctlRead(fidp, vcp, inp, outp);
6609 smb_ReleaseFID(fidp);
6612 lock_ReleaseMutex(&fidp->mx);
6615 LARGE_INTEGER LOffset, LLength;
6618 pid = ((smb_t *) inp)->pid;
6619 key = cm_GenerateKey(vcp->vcID, pid, fd);
6621 LOffset.HighPart = 0;
6622 LOffset.LowPart = offset.LowPart;
6623 LLength.HighPart = 0;
6624 LLength.LowPart = count;
6626 lock_ObtainMutex(&fidp->scp->mx);
6627 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
6628 lock_ReleaseMutex(&fidp->scp->mx);
6631 smb_ReleaseFID(fidp);
6635 userp = smb_GetUserFromVCP(vcp, inp);
6637 /* remember this for final results */
6638 smb_SetSMBParm(outp, 0, count);
6639 smb_SetSMBParm(outp, 1, 0);
6640 smb_SetSMBParm(outp, 2, 0);
6641 smb_SetSMBParm(outp, 3, 0);
6642 smb_SetSMBParm(outp, 4, 0);
6644 /* set the packet data length to 3 bytes for the data block header,
6645 * plus the size of the data.
6647 smb_SetSMBDataLength(outp, count+3);
6649 /* get op ptr after putting in the parms, since otherwise we don't
6650 * know where the data really is.
6652 op = smb_GetSMBData(outp, NULL);
6654 /* now emit the data block header: 1 byte of type and 2 bytes of length */
6655 *op++ = 1; /* data block marker */
6656 *op++ = (unsigned char) (count & 0xff);
6657 *op++ = (unsigned char) ((count >> 8) & 0xff);
6659 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6661 /* fix some things up */
6662 smb_SetSMBParm(outp, 0, finalCount);
6663 smb_SetSMBDataLength(outp, finalCount+3);
6665 smb_ReleaseFID(fidp);
6667 cm_ReleaseUser(userp);
6671 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6678 cm_scache_t *dscp; /* dir we're dealing with */
6679 cm_scache_t *scp; /* file we're creating */
6681 int initialModeBits;
6691 /* compute initial mode bits based on read-only flag in attributes */
6692 initialModeBits = 0777;
6694 tp = smb_GetSMBData(inp, NULL);
6695 pathp = smb_ParseASCIIBlock(tp, &tp);
6696 if (smb_StoreAnsiFilenames)
6697 OemToChar(pathp,pathp);
6699 if (strcmp(pathp, "\\") == 0)
6700 return CM_ERROR_EXISTS;
6702 spacep = inp->spacep;
6703 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6705 userp = smb_GetUserFromVCP(vcp, inp);
6707 caseFold = CM_FLAG_CASEFOLD;
6709 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6711 cm_ReleaseUser(userp);
6712 return CM_ERROR_NOSUCHPATH;
6715 code = cm_NameI(cm_data.rootSCachep, spacep->data,
6716 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
6717 userp, tidPathp, &req, &dscp);
6720 cm_ReleaseUser(userp);
6725 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6726 cm_ReleaseSCache(dscp);
6727 cm_ReleaseUser(userp);
6728 if ( WANTS_DFS_PATHNAMES(inp) )
6729 return CM_ERROR_PATH_NOT_COVERED;
6731 return CM_ERROR_BADSHARENAME;
6733 #endif /* DFS_SUPPORT */
6735 /* otherwise, scp points to the parent directory. Do a lookup, and
6736 * fail if we find it. Otherwise, we do the create.
6742 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6743 if (scp) cm_ReleaseSCache(scp);
6744 if (code != CM_ERROR_NOSUCHFILE) {
6745 if (code == 0) code = CM_ERROR_EXISTS;
6746 cm_ReleaseSCache(dscp);
6747 cm_ReleaseUser(userp);
6751 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6752 setAttr.clientModTime = time(NULL);
6753 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
6754 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6755 smb_NotifyChange(FILE_ACTION_ADDED,
6756 FILE_NOTIFY_CHANGE_DIR_NAME,
6757 dscp, lastNamep, NULL, TRUE);
6759 /* we don't need this any longer */
6760 cm_ReleaseSCache(dscp);
6763 /* something went wrong creating or truncating the file */
6764 cm_ReleaseUser(userp);
6768 /* otherwise we succeeded */
6769 smb_SetSMBDataLength(outp, 0);
6770 cm_ReleaseUser(userp);
6775 BOOL smb_IsLegalFilename(char *filename)
6778 * Find the longest substring of filename that does not contain
6779 * any of the chars in illegalChars. If that substring is less
6780 * than the length of the whole string, then one or more of the
6781 * illegal chars is in filename.
6783 if (strcspn(filename, illegalChars) < strlen(filename))
6789 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6797 cm_scache_t *dscp; /* dir we're dealing with */
6798 cm_scache_t *scp; /* file we're creating */
6800 int initialModeBits;
6808 int created = 0; /* the file was new */
6813 excl = (inp->inCom == 0x03)? 0 : 1;
6815 attributes = smb_GetSMBParm(inp, 0);
6816 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6818 /* compute initial mode bits based on read-only flag in attributes */
6819 initialModeBits = 0666;
6820 if (attributes & SMB_ATTR_READONLY)
6821 initialModeBits &= ~0222;
6823 tp = smb_GetSMBData(inp, NULL);
6824 pathp = smb_ParseASCIIBlock(tp, &tp);
6825 if (smb_StoreAnsiFilenames)
6826 OemToChar(pathp,pathp);
6828 spacep = inp->spacep;
6829 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6831 userp = smb_GetUserFromVCP(vcp, inp);
6833 caseFold = CM_FLAG_CASEFOLD;
6835 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6837 cm_ReleaseUser(userp);
6838 return CM_ERROR_NOSUCHPATH;
6840 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
6841 userp, tidPathp, &req, &dscp);
6844 cm_ReleaseUser(userp);
6849 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6850 cm_ReleaseSCache(dscp);
6851 cm_ReleaseUser(userp);
6852 if ( WANTS_DFS_PATHNAMES(inp) )
6853 return CM_ERROR_PATH_NOT_COVERED;
6855 return CM_ERROR_BADSHARENAME;
6857 #endif /* DFS_SUPPORT */
6859 /* otherwise, scp points to the parent directory. Do a lookup, and
6860 * truncate the file if we find it, otherwise we create the file.
6867 if (!smb_IsLegalFilename(lastNamep))
6868 return CM_ERROR_BADNTFILENAME;
6870 osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
6871 #ifdef DEBUG_VERBOSE
6874 hexp = osi_HexifyString( lastNamep );
6875 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
6880 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6881 if (code && code != CM_ERROR_NOSUCHFILE) {
6882 cm_ReleaseSCache(dscp);
6883 cm_ReleaseUser(userp);
6887 /* if we get here, if code is 0, the file exists and is represented by
6888 * scp. Otherwise, we have to create it.
6892 /* oops, file shouldn't be there */
6893 cm_ReleaseSCache(dscp);
6894 cm_ReleaseSCache(scp);
6895 cm_ReleaseUser(userp);
6896 return CM_ERROR_EXISTS;
6899 setAttr.mask = CM_ATTRMASK_LENGTH;
6900 setAttr.length.LowPart = 0;
6901 setAttr.length.HighPart = 0;
6902 code = cm_SetAttr(scp, &setAttr, userp, &req);
6905 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6906 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
6907 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
6911 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6912 smb_NotifyChange(FILE_ACTION_ADDED,
6913 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6914 dscp, lastNamep, NULL, TRUE);
6915 } else if (!excl && code == CM_ERROR_EXISTS) {
6916 /* not an exclusive create, and someone else tried
6917 * creating it already, then we open it anyway. We
6918 * don't bother retrying after this, since if this next
6919 * fails, that means that the file was deleted after
6920 * we started this call.
6922 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
6925 setAttr.mask = CM_ATTRMASK_LENGTH;
6926 setAttr.length.LowPart = 0;
6927 setAttr.length.HighPart = 0;
6928 code = cm_SetAttr(scp, &setAttr, userp, &req);
6933 /* we don't need this any longer */
6934 cm_ReleaseSCache(dscp);
6937 /* something went wrong creating or truncating the file */
6938 if (scp) cm_ReleaseSCache(scp);
6939 cm_ReleaseUser(userp);
6943 /* make sure we only open files */
6944 if (scp->fileType != CM_SCACHETYPE_FILE) {
6945 cm_ReleaseSCache(scp);
6946 cm_ReleaseUser(userp);
6947 return CM_ERROR_ISDIR;
6950 /* now all we have to do is open the file itself */
6951 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6956 lock_ObtainMutex(&fidp->mx);
6957 /* always create it open for read/write */
6958 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
6960 /* remember that the file was newly created */
6962 fidp->flags |= SMB_FID_CREATED;
6964 osi_Log2(afsd_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
6966 /* save a pointer to the vnode */
6968 lock_ObtainMutex(&scp->mx);
6969 scp->flags |= CM_SCACHEFLAG_SMB_FID;
6970 lock_ReleaseMutex(&scp->mx);
6973 fidp->userp = userp;
6974 lock_ReleaseMutex(&fidp->mx);
6976 smb_SetSMBParm(outp, 0, fidp->fid);
6977 smb_SetSMBDataLength(outp, 0);
6979 cm_Open(scp, 0, userp);
6981 smb_ReleaseFID(fidp);
6982 cm_ReleaseUser(userp);
6983 /* leave scp held since we put it in fidp->scp */
6987 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6990 osi_hyper_t new_offset;
7001 fd = smb_GetSMBParm(inp, 0);
7002 whence = smb_GetSMBParm(inp, 1);
7003 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7005 /* try to find the file descriptor */
7006 fd = smb_ChainFID(fd, inp);
7007 fidp = smb_FindFID(vcp, fd, 0);
7010 return CM_ERROR_BADFD;
7012 lock_ObtainMutex(&fidp->mx);
7013 if (fidp->flags & SMB_FID_IOCTL) {
7014 lock_ReleaseMutex(&fidp->mx);
7015 smb_ReleaseFID(fidp);
7016 return CM_ERROR_BADFD;
7018 lock_ReleaseMutex(&fidp->mx);
7020 userp = smb_GetUserFromVCP(vcp, inp);
7022 lock_ObtainMutex(&fidp->mx);
7025 lock_ReleaseMutex(&fidp->mx);
7026 lock_ObtainMutex(&scp->mx);
7027 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7028 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7030 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7032 /* offset from current offset */
7033 new_offset = LargeIntegerAdd(fidp->offset,
7034 ConvertLongToLargeInteger(offset));
7036 else if (whence == 2) {
7037 /* offset from current EOF */
7038 new_offset = LargeIntegerAdd(scp->length,
7039 ConvertLongToLargeInteger(offset));
7041 new_offset = ConvertLongToLargeInteger(offset);
7044 fidp->offset = new_offset;
7045 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
7046 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
7047 smb_SetSMBDataLength(outp, 0);
7049 lock_ReleaseMutex(&scp->mx);
7050 smb_ReleaseFID(fidp);
7051 cm_ReleaseSCache(scp);
7052 cm_ReleaseUser(userp);
7056 /* dispatch all of the requests received in a packet. Due to chaining, this may
7057 * be more than one request.
7059 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7060 NCB *ncbp, raw_write_cont_t *rwcp)
7064 unsigned long code = 0;
7065 unsigned char *outWctp;
7066 int nparms; /* # of bytes of parameters */
7068 int nbytes; /* bytes of data, excluding count */
7071 unsigned short errCode;
7072 unsigned long NTStatus;
7074 unsigned char errClass;
7075 unsigned int oldGen;
7076 DWORD oldTime, newTime;
7078 /* get easy pointer to the data */
7079 smbp = (smb_t *) inp->data;
7081 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
7082 /* setup the basic parms for the initial request in the packet */
7083 inp->inCom = smbp->com;
7084 inp->wctp = &smbp->wct;
7086 inp->ncb_length = ncbp->ncb_length;
7091 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
7092 /* log it and discard it */
7093 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
7094 __FILE__, __LINE__, ncbp->ncb_length);
7095 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
7099 /* We are an ongoing op */
7100 thrd_Increment(&ongoingOps);
7102 /* set up response packet for receiving output */
7103 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
7104 smb_FormatResponsePacket(vcp, inp, outp);
7105 outWctp = outp->wctp;
7107 /* Remember session generation number and time */
7108 oldGen = sessionGen;
7109 oldTime = GetTickCount();
7111 while (inp->inCom != 0xff) {
7112 dp = &smb_dispatchTable[inp->inCom];
7114 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
7115 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
7116 code = outp->resumeCode;
7120 /* process each request in the packet; inCom, wctp and inCount
7121 * are already set up.
7123 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
7126 /* now do the dispatch */
7127 /* start by formatting the response record a little, as a default */
7128 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
7130 outWctp[1] = 0xff; /* no operation */
7131 outWctp[2] = 0; /* padding */
7136 /* not a chained request, this is a more reasonable default */
7137 outWctp[0] = 0; /* wct of zero */
7138 outWctp[1] = 0; /* and bcc (word) of zero */
7142 /* once set, stays set. Doesn't matter, since we never chain
7143 * "no response" calls.
7145 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
7149 /* we have a recognized operation */
7151 if (inp->inCom == 0x1d)
7153 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
7155 osi_Log4(smb_logp,"Dispatch %s vcp 0x%p lana %d lsn %d",myCrt_Dispatch(inp->inCom),vcp,vcp->lana,vcp->lsn);
7156 code = (*(dp->procp)) (vcp, inp, outp);
7157 osi_Log4(smb_logp,"Dispatch return code 0x%x vcp 0x%p lana %d lsn %d",code,vcp,vcp->lana,vcp->lsn);
7159 if ( code == CM_ERROR_BADSMB ||
7160 code == CM_ERROR_BADOP )
7162 #endif /* LOG_PACKET */
7165 if (oldGen != sessionGen) {
7166 newTime = GetTickCount();
7167 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
7168 newTime - oldTime, ncbp->ncb_length);
7169 osi_Log2(smb_logp, "Pkt straddled session startup, "
7170 "took %d ms, ncb length %d", newTime - oldTime, ncbp->ncb_length);
7174 /* bad opcode, fail the request, after displaying it */
7175 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
7178 #endif /* LOG_PACKET */
7181 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
7182 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
7183 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
7184 if (code == IDCANCEL)
7187 code = CM_ERROR_BADOP;
7190 /* catastrophic failure: log as much as possible */
7191 if (code == CM_ERROR_BADSMB) {
7192 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
7196 #endif /* LOG_PACKET */
7197 osi_Log1(smb_logp, "Invalid SMB message, length %d",
7200 code = CM_ERROR_INVAL;
7203 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
7204 thrd_Decrement(&ongoingOps);
7209 /* now, if we failed, turn the current response into an empty
7210 * one, and fill in the response packet's error code.
7213 if (vcp->flags & SMB_VCFLAG_STATUS32) {
7214 smb_MapNTError(code, &NTStatus);
7215 outWctp = outp->wctp;
7216 smbp = (smb_t *) &outp->data;
7217 if (code != CM_ERROR_PARTIALWRITE
7218 && code != CM_ERROR_BUFFERTOOSMALL
7219 && code != CM_ERROR_GSSCONTINUE) {
7220 /* nuke wct and bcc. For a partial
7221 * write or an in-process authentication handshake,
7222 * assume they're OK.
7228 smbp->rcls = (unsigned char) (NTStatus & 0xff);
7229 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
7230 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
7231 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
7232 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7236 smb_MapCoreError(code, vcp, &errCode, &errClass);
7237 outWctp = outp->wctp;
7238 smbp = (smb_t *) &outp->data;
7239 if (code != CM_ERROR_PARTIALWRITE) {
7240 /* nuke wct and bcc. For a partial
7241 * write, assume they're OK.
7247 smbp->errLow = (unsigned char) (errCode & 0xff);
7248 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
7249 smbp->rcls = errClass;
7252 } /* error occurred */
7254 /* if we're here, we've finished one request. Look to see if
7255 * this is a chained opcode. If it is, setup things to process
7256 * the chained request, and setup the output buffer to hold the
7257 * chained response. Start by finding the next input record.
7259 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
7260 break; /* not a chained req */
7261 tp = inp->wctp; /* points to start of last request */
7262 /* in a chained request, the first two
7263 * parm fields are required, and are
7264 * AndXCommand/AndXReserved and
7266 if (tp[0] < 2) break;
7267 if (tp[1] == 0xff) break; /* no more chained opcodes */
7269 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
7272 /* and now append the next output request to the end of this
7273 * last request. Begin by finding out where the last response
7274 * ends, since that's where we'll put our new response.
7276 outWctp = outp->wctp; /* ptr to out parameters */
7277 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
7278 nparms = outWctp[0] << 1;
7279 tp = outWctp + nparms + 1; /* now points to bcc field */
7280 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
7281 tp += 2 /* for the count itself */ + nbytes;
7282 /* tp now points to the new output record; go back and patch the
7283 * second parameter (off2) to point to the new record.
7285 temp = (unsigned int)(tp - outp->data);
7286 outWctp[3] = (unsigned char) (temp & 0xff);
7287 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
7288 outWctp[2] = 0; /* padding */
7289 outWctp[1] = inp->inCom; /* next opcode */
7291 /* finally, setup for the next iteration */
7294 } /* while loop over all requests in the packet */
7296 /* now send the output packet, and return */
7298 smb_SendPacket(vcp, outp);
7299 thrd_Decrement(&ongoingOps);
7304 /* Wait for Netbios() calls to return, and make the results available to server
7305 * threads. Note that server threads can't wait on the NCBevents array
7306 * themselves, because NCB events are manual-reset, and the servers would race
7307 * each other to reset them.
7309 void smb_ClientWaiter(void *parmp)
7314 while (smbShutdownFlag == 0) {
7315 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
7317 if (code == WAIT_OBJECT_0)
7320 /* error checking */
7321 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7323 int abandonIdx = code - WAIT_ABANDONED_0;
7324 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7327 if (code == WAIT_IO_COMPLETION)
7329 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
7333 if (code == WAIT_TIMEOUT)
7335 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
7338 if (code == WAIT_FAILED)
7340 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
7343 idx = code - WAIT_OBJECT_0;
7345 /* check idx range! */
7346 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
7348 /* this is fatal - log as much as possible */
7349 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
7353 thrd_ResetEvent(NCBevents[idx]);
7354 thrd_SetEvent(NCBreturns[0][idx]);
7359 * Try to have one NCBRECV request waiting for every live session. Not more
7360 * than one, because if there is more than one, it's hard to handle Write Raw.
7362 void smb_ServerWaiter(void *parmp)
7365 int idx_session, idx_NCB;
7368 while (smbShutdownFlag == 0) {
7370 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
7372 if (code == WAIT_OBJECT_0)
7375 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
7377 int abandonIdx = code - WAIT_ABANDONED_0;
7378 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7381 if (code == WAIT_IO_COMPLETION)
7383 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
7387 if (code == WAIT_TIMEOUT)
7389 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
7392 if (code == WAIT_FAILED)
7394 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
7397 idx_session = code - WAIT_OBJECT_0;
7399 /* check idx range! */
7400 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
7402 /* this is fatal - log as much as possible */
7403 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
7409 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
7411 if (code == WAIT_OBJECT_0) {
7412 if (smbShutdownFlag == 1)
7418 /* error checking */
7419 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7421 int abandonIdx = code - WAIT_ABANDONED_0;
7422 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7425 if (code == WAIT_IO_COMPLETION)
7427 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
7431 if (code == WAIT_TIMEOUT)
7433 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
7436 if (code == WAIT_FAILED)
7438 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
7441 idx_NCB = code - WAIT_OBJECT_0;
7443 /* check idx range! */
7444 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
7446 /* this is fatal - log as much as possible */
7447 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
7451 /* Link them together */
7452 NCBsessions[idx_NCB] = idx_session;
7455 ncbp = NCBs[idx_NCB];
7456 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
7457 ncbp->ncb_command = NCBRECV | ASYNCH;
7458 ncbp->ncb_lana_num = lanas[idx_session];
7459 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
7460 ncbp->ncb_event = NCBevents[idx_NCB];
7461 ncbp->ncb_length = SMB_PACKETSIZE;
7467 * The top level loop for handling SMB request messages. Each server thread
7468 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
7469 * NCB and buffer for the incoming request are loaned to us.
7471 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
7472 * to immediately send a request for the rest of the data. This must come
7473 * before any other traffic for that session, so we delay setting the session
7474 * event until that data has come in.
7476 void smb_Server(VOID *parmp)
7478 INT_PTR myIdx = (INT_PTR) parmp;
7482 smb_packet_t *outbufp;
7484 int idx_NCB, idx_session;
7486 smb_vc_t *vcp = NULL;
7489 rx_StartClientThread();
7492 outbufp = GetPacket();
7493 outbufp->ncbp = outncbp;
7501 smb_ResetServerPriority();
7503 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
7506 /* terminate silently if shutdown flag is set */
7507 if (code == WAIT_OBJECT_0) {
7508 if (smbShutdownFlag == 1) {
7509 thrd_SetEvent(smb_ServerShutdown[myIdx]);
7515 /* error checking */
7516 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7518 int abandonIdx = code - WAIT_ABANDONED_0;
7519 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
7522 if (code == WAIT_IO_COMPLETION)
7524 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
7528 if (code == WAIT_TIMEOUT)
7530 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
7533 if (code == WAIT_FAILED)
7535 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
7538 idx_NCB = code - WAIT_OBJECT_0;
7540 /* check idx range! */
7541 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
7543 /* this is fatal - log as much as possible */
7544 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
7548 ncbp = NCBs[idx_NCB];
7549 idx_session = NCBsessions[idx_NCB];
7550 rc = ncbp->ncb_retcode;
7552 if (rc != NRC_PENDING && rc != NRC_GOODRET)
7553 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
7557 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7561 /* Can this happen? Or is it just my UNIX paranoia? */
7562 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
7567 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
7570 /* Client closed session */
7571 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7573 lock_ObtainMutex(&vcp->mx);
7574 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7575 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
7577 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7578 lock_ReleaseMutex(&vcp->mx);
7579 lock_ObtainWrite(&smb_globalLock);
7580 dead_sessions[vcp->session] = TRUE;
7581 lock_ReleaseWrite(&smb_globalLock);
7582 smb_CleanupDeadVC(vcp);
7586 lock_ReleaseMutex(&vcp->mx);
7592 /* Treat as transient error */
7593 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
7596 "dispatch smb recv failed, message incomplete, ncb_length %d",
7599 "SMB message incomplete, "
7600 "length %d", ncbp->ncb_length);
7603 * We used to discard the packet.
7604 * Instead, try handling it normally.
7608 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7612 /* A weird error code. Log it, sleep, and continue. */
7613 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7615 lock_ObtainMutex(&vcp->mx);
7616 if (vcp && vcp->errorCount++ > 3) {
7617 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
7618 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7619 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
7621 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7622 lock_ReleaseMutex(&vcp->mx);
7623 lock_ObtainWrite(&smb_globalLock);
7624 dead_sessions[vcp->session] = TRUE;
7625 lock_ReleaseWrite(&smb_globalLock);
7626 smb_CleanupDeadVC(vcp);
7630 lock_ReleaseMutex(&vcp->mx);
7636 lock_ReleaseMutex(&vcp->mx);
7638 thrd_SetEvent(SessionEvents[idx_session]);
7643 /* Success, so now dispatch on all the data in the packet */
7645 smb_concurrentCalls++;
7646 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
7647 smb_maxObsConcurrentCalls = smb_concurrentCalls;
7650 * If at this point vcp is NULL (implies that packet was invalid)
7651 * then we are in big trouble. This means either :
7652 * a) we have the wrong NCB.
7653 * b) Netbios screwed up the call.
7654 * c) The VC was already marked dead before we were able to
7656 * Obviously this implies that
7657 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
7658 * lanas[idx_session] != ncbp->ncb_lana_num )
7659 * Either way, we can't do anything with this packet.
7660 * Log, sleep and resume.
7663 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
7667 ncbp->ncb_lana_num);
7669 /* Also log in the trace log. */
7670 osi_Log4(smb_logp, "Server: VCP does not exist!"
7671 "LSNs[idx_session]=[%d],"
7672 "lanas[idx_session]=[%d],"
7673 "ncbp->ncb_lsn=[%d],"
7674 "ncbp->ncb_lana_num=[%d]",
7678 ncbp->ncb_lana_num);
7680 /* thrd_Sleep(1000); Don't bother sleeping */
7681 thrd_SetEvent(SessionEvents[idx_session]);
7682 smb_concurrentCalls--;
7686 smb_SetRequestStartTime();
7688 vcp->errorCount = 0;
7689 bufp = (struct smb_packet *) ncbp->ncb_buffer;
7690 smbp = (smb_t *)bufp->data;
7695 if (smbp->com == 0x1d) {
7696 /* Special handling for Write Raw */
7697 raw_write_cont_t rwc;
7698 EVENT_HANDLE rwevent;
7699 char eventName[MAX_PATH];
7701 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
7702 if (rwc.code == 0) {
7703 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
7704 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7705 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7706 ncbp->ncb_command = NCBRECV | ASYNCH;
7707 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
7708 ncbp->ncb_lana_num = vcp->lana;
7709 ncbp->ncb_buffer = rwc.buf;
7710 ncbp->ncb_length = 65535;
7711 ncbp->ncb_event = rwevent;
7713 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
7714 thrd_CloseHandle(rwevent);
7716 thrd_SetEvent(SessionEvents[idx_session]);
7718 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
7720 else if (smbp->com == 0xa0) {
7722 * Serialize the handling for NT Transact
7725 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7726 thrd_SetEvent(SessionEvents[idx_session]);
7728 thrd_SetEvent(SessionEvents[idx_session]);
7729 /* TODO: what else needs to be serialized? */
7730 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7733 __except( smb_ServerExceptionFilter() ) {
7736 smb_concurrentCalls--;
7739 thrd_SetEvent(NCBavails[idx_NCB]);
7746 * Exception filter for the server threads. If an exception occurs in the
7747 * dispatch routines, which is where exceptions are most common, then do a
7748 * force trace and give control to upstream exception handlers. Useful for
7751 DWORD smb_ServerExceptionFilter(void) {
7752 /* While this is not the best time to do a trace, if it succeeds, then
7753 * we have a trace (assuming tracing was enabled). Otherwise, this should
7754 * throw a second exception.
7756 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
7757 afsd_ForceTrace(TRUE);
7758 buf_ForceTrace(TRUE);
7759 return EXCEPTION_CONTINUE_SEARCH;
7763 * Create a new NCB and associated events, packet buffer, and "space" buffer.
7764 * If the number of server threads is M, and the number of live sessions is
7765 * N, then the number of NCB's in use at any time either waiting for, or
7766 * holding, received messages is M + N, so that is how many NCB's get created.
7768 void InitNCBslot(int idx)
7770 struct smb_packet *bufp;
7771 EVENT_HANDLE retHandle;
7773 char eventName[MAX_PATH];
7775 osi_assert( idx < (sizeof(NCBs) / sizeof(NCBs[0])) );
7777 NCBs[idx] = GetNCB();
7778 sprintf(eventName,"NCBavails[%d]", idx);
7779 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7780 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7781 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7782 sprintf(eventName,"NCBevents[%d]", idx);
7783 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
7784 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7785 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7786 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
7787 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7788 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7789 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7790 for (i=0; i<smb_NumServerThreads; i++)
7791 NCBreturns[i][idx] = retHandle;
7793 bufp->spacep = cm_GetSpace();
7797 /* listen for new connections */
7798 void smb_Listener(void *parmp)
7804 int session, thread;
7805 smb_vc_t *vcp = NULL;
7807 char rname[NCBNAMSZ+1];
7808 char cname[MAX_COMPUTERNAME_LENGTH+1];
7809 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
7810 INT_PTR lana = (INT_PTR) parmp;
7814 /* retrieve computer name */
7815 GetComputerName(cname, &cnamelen);
7819 memset(ncbp, 0, sizeof(NCB));
7822 ncbp->ncb_command = NCBLISTEN;
7823 ncbp->ncb_rto = 0; /* No receive timeout */
7824 ncbp->ncb_sto = 0; /* No send timeout */
7826 /* pad out with spaces instead of null termination */
7827 len = (long)strlen(smb_localNamep);
7828 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
7829 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
7831 strcpy(ncbp->ncb_callname, "*");
7832 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
7834 ncbp->ncb_lana_num = (UCHAR)lana;
7836 code = Netbios(ncbp);
7842 /* terminate silently if shutdown flag is set */
7843 if (smbShutdownFlag == 1) {
7848 "NCBLISTEN lana=%d failed with code %d",
7849 ncbp->ncb_lana_num, code);
7851 "Client exiting due to network failure. Please restart client.\n");
7854 "Client exiting due to network failure. Please restart client.\n"
7855 "NCBLISTEN lana=%d failed with code %d",
7856 ncbp->ncb_lana_num, code);
7858 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
7859 MB_OK|MB_SERVICE_NOTIFICATION);
7860 osi_panic(tbuffer, __FILE__, __LINE__);
7863 /* check for remote conns */
7864 /* first get remote name and insert null terminator */
7865 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
7866 for (i=NCBNAMSZ; i>0; i--) {
7867 if (rname[i-1] != ' ' && rname[i-1] != 0) {
7873 /* compare with local name */
7875 if (strncmp(rname, cname, NCBNAMSZ) != 0)
7876 flags |= SMB_VCFLAG_REMOTECONN;
7879 lock_ObtainMutex(&smb_ListenerLock);
7881 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
7882 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
7884 /* now ncbp->ncb_lsn is the connection ID */
7885 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
7886 if (vcp->session == 0) {
7887 /* New generation */
7888 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
7891 /* Log session startup */
7893 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
7894 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
7895 #endif /* NOTSERVICE */
7896 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
7897 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
7899 if (reportSessionStartups) {
7900 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
7903 lock_ObtainMutex(&vcp->mx);
7904 strcpy(vcp->rname, rname);
7905 vcp->flags |= flags;
7906 lock_ReleaseMutex(&vcp->mx);
7908 /* Allocate slot in session arrays */
7909 /* Re-use dead session if possible, otherwise add one more */
7910 /* But don't look at session[0], it is reserved */
7911 lock_ObtainWrite(&smb_globalLock);
7912 for (session = 1; session < numSessions; session++) {
7913 if (dead_sessions[session]) {
7914 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
7915 dead_sessions[session] = FALSE;
7919 lock_ReleaseWrite(&smb_globalLock);
7921 /* We are re-using an existing VC because the lsn and lana
7923 session = vcp->session;
7925 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
7927 /* Log session startup */
7929 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
7930 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
7931 #endif /* NOTSERVICE */
7932 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
7933 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
7935 if (reportSessionStartups) {
7936 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
7940 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
7941 unsigned long code = CM_ERROR_ALLBUSY;
7942 smb_packet_t * outp = GetPacket();
7943 unsigned char *outWctp;
7946 smb_FormatResponsePacket(vcp, NULL, outp);
7949 if (vcp->flags & SMB_VCFLAG_STATUS32) {
7950 unsigned long NTStatus;
7951 smb_MapNTError(code, &NTStatus);
7952 outWctp = outp->wctp;
7953 smbp = (smb_t *) &outp->data;
7957 smbp->rcls = (unsigned char) (NTStatus & 0xff);
7958 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
7959 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
7960 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
7961 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7963 unsigned short errCode;
7964 unsigned char errClass;
7965 smb_MapCoreError(code, vcp, &errCode, &errClass);
7966 outWctp = outp->wctp;
7967 smbp = (smb_t *) &outp->data;
7971 smbp->errLow = (unsigned char) (errCode & 0xff);
7972 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
7973 smbp->rcls = errClass;
7975 smb_SendPacket(vcp, outp);
7976 smb_FreePacket(outp);
7978 lock_ObtainMutex(&vcp->mx);
7979 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7980 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
7982 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7983 lock_ReleaseMutex(&vcp->mx);
7984 lock_ObtainWrite(&smb_globalLock);
7985 dead_sessions[vcp->session] = TRUE;
7986 lock_ReleaseWrite(&smb_globalLock);
7987 smb_CleanupDeadVC(vcp);
7989 lock_ReleaseMutex(&vcp->mx);
7992 /* assert that we do not exceed the maximum number of sessions or NCBs.
7993 * we should probably want to wait for a session to be freed in case
7996 osi_assert(session < SESSION_MAX - 1);
7997 osi_assert(numNCBs < NCB_MAX - 1); /* if we pass this test we can allocate one more */
7999 lock_ObtainMutex(&vcp->mx);
8000 vcp->session = session;
8001 lock_ReleaseMutex(&vcp->mx);
8002 lock_ObtainWrite(&smb_globalLock);
8003 LSNs[session] = ncbp->ncb_lsn;
8004 lanas[session] = ncbp->ncb_lana_num;
8005 lock_ReleaseWrite(&smb_globalLock);
8007 if (session == numSessions) {
8008 /* Add new NCB for new session */
8009 char eventName[MAX_PATH];
8011 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
8013 InitNCBslot(numNCBs);
8014 lock_ObtainWrite(&smb_globalLock);
8016 lock_ReleaseWrite(&smb_globalLock);
8017 thrd_SetEvent(NCBavails[0]);
8018 thrd_SetEvent(NCBevents[0]);
8019 for (thread = 0; thread < smb_NumServerThreads; thread++)
8020 thrd_SetEvent(NCBreturns[thread][0]);
8021 /* Also add new session event */
8022 sprintf(eventName, "SessionEvents[%d]", session);
8023 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8024 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8025 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8026 lock_ObtainWrite(&smb_globalLock);
8028 lock_ReleaseWrite(&smb_globalLock);
8029 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
8030 thrd_SetEvent(SessionEvents[0]);
8032 thrd_SetEvent(SessionEvents[session]);
8038 lock_ReleaseMutex(&smb_ListenerLock);
8039 } /* dispatch while loop */
8042 /* initialize Netbios */
8043 void smb_NetbiosInit()
8046 int i, lana, code, l;
8048 int delname_tried=0;
8051 OSVERSIONINFO Version;
8053 /* Get the version of Windows */
8054 memset(&Version, 0x00, sizeof(Version));
8055 Version.dwOSVersionInfoSize = sizeof(Version);
8056 GetVersionEx(&Version);
8058 /* setup the NCB system */
8061 if (smb_LANadapter == -1) {
8062 ncbp->ncb_command = NCBENUM;
8063 ncbp->ncb_buffer = (PUCHAR)&lana_list;
8064 ncbp->ncb_length = sizeof(lana_list);
8065 code = Netbios(ncbp);
8067 afsi_log("Netbios NCBENUM error code %d", code);
8068 osi_panic(s, __FILE__, __LINE__);
8072 lana_list.length = 1;
8073 lana_list.lana[0] = smb_LANadapter;
8076 for (i = 0; i < lana_list.length; i++) {
8077 /* reset the adaptor: in Win32, this is required for every process, and
8078 * acts as an init call, not as a real hardware reset.
8080 ncbp->ncb_command = NCBRESET;
8081 ncbp->ncb_callname[0] = 100;
8082 ncbp->ncb_callname[2] = 100;
8083 ncbp->ncb_lana_num = lana_list.lana[i];
8084 code = Netbios(ncbp);
8086 code = ncbp->ncb_retcode;
8088 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
8089 lana_list.lana[i] = 255; /* invalid lana */
8091 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
8095 /* and declare our name so we can receive connections */
8096 memset(ncbp, 0, sizeof(*ncbp));
8097 len=lstrlen(smb_localNamep);
8098 memset(smb_sharename,' ',NCBNAMSZ);
8099 memcpy(smb_sharename,smb_localNamep,len);
8100 afsi_log("lana_list.length %d", lana_list.length);
8102 /* Keep the name so we can unregister it later */
8103 for (l = 0; l < lana_list.length; l++) {
8104 lana = lana_list.lana[l];
8106 ncbp->ncb_command = NCBADDNAME;
8107 ncbp->ncb_lana_num = lana;
8108 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8109 code = Netbios(ncbp);
8111 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
8112 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
8114 char name[NCBNAMSZ+1];
8116 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
8117 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
8120 if (code == 0) code = ncbp->ncb_retcode;
8122 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
8125 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8126 if (code == NRC_BRIDGE) { /* invalid LANA num */
8127 lana_list.lana[l] = 255;
8130 else if (code == NRC_DUPNAME) {
8131 afsi_log("Name already exists; try to delete it");
8132 memset(ncbp, 0, sizeof(*ncbp));
8133 ncbp->ncb_command = NCBDELNAME;
8134 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8135 ncbp->ncb_lana_num = lana;
8136 code = Netbios(ncbp);
8138 code = ncbp->ncb_retcode;
8140 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
8142 if (code != 0 || delname_tried) {
8143 lana_list.lana[l] = 255;
8145 else if (code == 0) {
8146 if (!delname_tried) {
8154 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8155 lana_list.lana[l] = 255; /* invalid lana */
8156 osi_panic(s, __FILE__, __LINE__);
8160 lana_found = 1; /* at least one worked */
8164 osi_assert(lana_list.length >= 0);
8166 osi_panic("No valid LANA numbers found!", __FILE__, __LINE__);
8169 /* we're done with the NCB now */
8173 void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
8184 EVENT_HANDLE retHandle;
8185 char eventName[MAX_PATH];
8187 smb_TlsRequestSlot = TlsAlloc();
8189 smb_MBfunc = aMBfunc;
8192 smb_LANadapter = LANadapt;
8194 /* Initialize smb_localZero */
8195 myTime.tm_isdst = -1; /* compute whether on DST or not */
8196 myTime.tm_year = 70;
8202 smb_localZero = mktime(&myTime);
8204 #ifndef USE_NUMERIC_TIME_CONV
8205 /* Initialize kludge-GMT */
8206 smb_CalculateNowTZ();
8207 #endif /* USE_NUMERIC_TIME_CONV */
8208 #ifdef AFS_FREELANCE_CLIENT
8209 /* Make sure the root.afs volume has the correct time */
8210 cm_noteLocalMountPointChange();
8213 /* initialize the remote debugging log */
8216 /* remember the name */
8217 len = (int)strlen(snamep);
8218 smb_localNamep = malloc(len+1);
8219 strcpy(smb_localNamep, snamep);
8220 afsi_log("smb_localNamep is >%s<", smb_localNamep);
8222 /* and the global lock */
8223 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
8224 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
8226 /* Raw I/O data structures */
8227 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
8229 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
8231 /* 4 Raw I/O buffers */
8232 smb_RawBufs = calloc(65536,1);
8233 *((char **)smb_RawBufs) = NULL;
8234 for (i=0; i<3; i++) {
8235 char *rawBuf = calloc(65536,1);
8236 *((char **)rawBuf) = smb_RawBufs;
8237 smb_RawBufs = rawBuf;
8240 /* global free lists */
8241 smb_ncbFreeListp = NULL;
8242 smb_packetFreeListp = NULL;
8246 /* Initialize listener and server structures */
8248 memset(dead_sessions, 0, sizeof(dead_sessions));
8249 sprintf(eventName, "SessionEvents[0]");
8250 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8251 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8252 afsi_log("Event Object Already Exists: %s", eventName);
8254 smb_NumServerThreads = nThreads;
8255 sprintf(eventName, "NCBavails[0]");
8256 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8257 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8258 afsi_log("Event Object Already Exists: %s", eventName);
8259 sprintf(eventName, "NCBevents[0]");
8260 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8261 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8262 afsi_log("Event Object Already Exists: %s", eventName);
8263 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
8264 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
8265 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8266 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8267 afsi_log("Event Object Already Exists: %s", eventName);
8268 for (i = 0; i < smb_NumServerThreads; i++) {
8269 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
8270 NCBreturns[i][0] = retHandle;
8273 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
8274 for (i = 0; i < smb_NumServerThreads; i++) {
8275 sprintf(eventName, "smb_ServerShutdown[%d]", i);
8276 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8277 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8278 afsi_log("Event Object Already Exists: %s", eventName);
8279 InitNCBslot((int)(i+1));
8281 numNCBs = smb_NumServerThreads + 1;
8283 /* Initialize dispatch table */
8284 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
8285 /* Prepare the table for unknown operations */
8286 for(i=0; i<= SMB_NOPCODES; i++) {
8287 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
8289 /* Fill in the ones we do know */
8290 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
8291 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
8292 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
8293 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
8294 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
8295 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
8296 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
8297 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
8298 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
8299 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
8300 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
8301 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
8302 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
8303 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
8304 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
8305 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
8306 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
8307 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
8308 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
8309 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
8310 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
8311 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8312 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
8313 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
8314 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
8315 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
8316 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
8317 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
8318 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8319 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
8320 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8321 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
8322 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
8323 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
8324 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8325 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
8326 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
8327 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
8328 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
8329 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
8330 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
8331 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
8332 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8333 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
8334 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8335 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
8336 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
8337 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
8338 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
8339 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
8340 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
8341 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
8342 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
8343 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
8344 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
8345 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
8346 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
8347 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
8348 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
8349 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
8350 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
8351 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
8352 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
8353 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
8354 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
8355 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8356 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
8357 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
8358 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
8359 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
8360 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
8361 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
8362 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
8363 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
8365 /* setup tran 2 dispatch table */
8366 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
8367 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
8368 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
8369 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
8370 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
8371 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
8372 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
8373 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
8374 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
8375 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
8376 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
8377 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
8378 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
8379 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
8380 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
8381 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
8382 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
8383 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
8385 /* setup the rap dispatch table */
8386 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
8387 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
8388 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
8389 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
8390 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
8394 /* if we are doing SMB authentication we have register outselves as a logon process */
8395 if (smb_authType != SMB_AUTH_NONE) {
8396 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
8397 LSA_STRING afsProcessName;
8398 LSA_OPERATIONAL_MODE dummy; /*junk*/
8400 afsProcessName.Buffer = "OpenAFSClientDaemon";
8401 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
8402 afsProcessName.MaximumLength = afsProcessName.Length + 1;
8404 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
8406 if (nts == STATUS_SUCCESS) {
8407 LSA_STRING packageName;
8408 /* we are registered. Find out the security package id */
8409 packageName.Buffer = MSV1_0_PACKAGE_NAME;
8410 packageName.Length = (USHORT)strlen(packageName.Buffer);
8411 packageName.MaximumLength = packageName.Length + 1;
8412 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
8413 if (nts == STATUS_SUCCESS) {
8415 * This code forces Windows to authenticate against the Logon Cache
8416 * first instead of attempting to authenticate against the Domain
8417 * Controller. When the Windows logon cache is enabled this improves
8418 * performance by removing the network access and works around a bug
8419 * seen at sites which are using a MIT Kerberos principal to login
8420 * to machines joined to a non-root domain in a multi-domain forest.
8422 PVOID pResponse = NULL;
8423 ULONG cbResponse = 0;
8424 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
8426 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
8427 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
8428 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
8429 OptionsRequest.DisableOptions = FALSE;
8431 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
8434 sizeof(OptionsRequest),
8440 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
8442 sprintf(message,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
8444 OutputDebugString(message);
8447 OutputDebugString("MsV1_0SetProcessOption success");
8448 afsi_log("MsV1_0SetProcessOption success");
8450 /* END - code from Larry */
8452 smb_lsaLogonOrigin.Buffer = "OpenAFS";
8453 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
8454 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
8456 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
8458 /* something went wrong. We report the error and revert back to no authentication
8459 because we can't perform any auth requests without a successful lsa handle
8460 or sec package id. */
8461 afsi_log("Reverting to NO SMB AUTH");
8462 smb_authType = SMB_AUTH_NONE;
8465 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
8467 /* something went wrong. We report the error and revert back to no authentication
8468 because we can't perform any auth requests without a successful lsa handle
8469 or sec package id. */
8470 afsi_log("Reverting to NO SMB AUTH");
8471 smb_authType = SMB_AUTH_NONE;
8475 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
8476 * time prevents the failure of authentication when logged into Windows with an
8477 * external Kerberos principal mapped to a local account.
8479 else if ( smb_authType == SMB_AUTH_EXTENDED) {
8480 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
8481 * then the only option is NTLMSSP anyway; so just fallback.
8486 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
8487 if (secBlobLength == 0) {
8488 smb_authType = SMB_AUTH_NTLM;
8489 afsi_log("Reverting to SMB AUTH NTLM");
8498 /* Now get ourselves a domain name. */
8499 /* For now we are using the local computer name as the domain name.
8500 * It is actually the domain for local logins, and we are acting as
8501 * a local SMB server.
8503 bufsize = sizeof(smb_ServerDomainName) - 1;
8504 GetComputerName(smb_ServerDomainName, &bufsize);
8505 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
8506 afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
8509 /* Start listeners, waiters, servers, and daemons */
8511 for (i = 0; i < lana_list.length; i++) {
8512 if (lana_list.lana[i] == 255)
8514 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
8515 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
8516 osi_assert(phandle != NULL);
8517 thrd_CloseHandle(phandle);
8520 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
8521 NULL, 0, &lpid, "smb_ClientWaiter");
8522 osi_assert(phandle != NULL);
8523 thrd_CloseHandle(phandle);
8525 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
8526 NULL, 0, &lpid, "smb_ServerWaiter");
8527 osi_assert(phandle != NULL);
8528 thrd_CloseHandle(phandle);
8530 for (i=0; i<smb_NumServerThreads; i++) {
8531 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
8532 (void *) i, 0, &lpid, "smb_Server");
8533 osi_assert(phandle != NULL);
8534 thrd_CloseHandle(phandle);
8537 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
8538 NULL, 0, &lpid, "smb_Daemon");
8539 osi_assert(phandle != NULL);
8540 thrd_CloseHandle(phandle);
8542 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
8543 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
8544 osi_assert(phandle != NULL);
8545 thrd_CloseHandle(phandle);
8550 void smb_Shutdown(void)
8557 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
8559 /* setup the NCB system */
8562 /* Block new sessions by setting shutdown flag */
8563 smbShutdownFlag = 1;
8565 /* Hang up all sessions */
8566 memset((char *)ncbp, 0, sizeof(NCB));
8567 for (i = 1; i < numSessions; i++)
8569 if (dead_sessions[i])
8572 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8573 ncbp->ncb_command = NCBHANGUP;
8574 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
8575 ncbp->ncb_lsn = (UCHAR)LSNs[i];
8576 code = Netbios(ncbp);
8577 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8578 if (code == 0) code = ncbp->ncb_retcode;
8580 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
8581 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
8585 /* Trigger the shutdown of all SMB threads */
8586 for (i = 0; i < smb_NumServerThreads; i++)
8587 thrd_SetEvent(NCBreturns[i][0]);
8589 thrd_SetEvent(NCBevents[0]);
8590 thrd_SetEvent(SessionEvents[0]);
8591 thrd_SetEvent(NCBavails[0]);
8593 for (i = 0;i < smb_NumServerThreads; i++) {
8594 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
8595 if (code == WAIT_OBJECT_0) {
8598 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
8599 thrd_SetEvent(NCBreturns[i--][0]);
8603 /* Delete Netbios name */
8604 memset((char *)ncbp, 0, sizeof(NCB));
8605 for (i = 0; i < lana_list.length; i++) {
8606 if (lana_list.lana[i] == 255) continue;
8607 ncbp->ncb_command = NCBDELNAME;
8608 ncbp->ncb_lana_num = lana_list.lana[i];
8609 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8610 code = Netbios(ncbp);
8612 code = ncbp->ncb_retcode;
8614 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
8615 ncbp->ncb_lana_num, code);
8620 /* Release the reference counts held by the VCs */
8621 lock_ObtainWrite(&smb_rctLock);
8622 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
8627 if (vcp->magic != SMB_VC_MAGIC)
8628 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
8629 __FILE__, __LINE__);
8631 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8633 if (fidp->scp != NULL) {
8636 lock_ObtainMutex(&fidp->mx);
8637 if (fidp->scp != NULL) {
8640 lock_ObtainMutex(&scp->mx);
8641 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
8642 lock_ReleaseMutex(&scp->mx);
8643 osi_Log2(afsd_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
8644 cm_ReleaseSCache(scp);
8646 lock_ReleaseMutex(&fidp->mx);
8650 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
8652 smb_ReleaseVCNoLock(tidp->vcp);
8654 cm_user_t *userp = tidp->userp;
8656 lock_ReleaseWrite(&smb_rctLock);
8657 cm_ReleaseUser(userp);
8658 lock_ObtainWrite(&smb_rctLock);
8662 lock_ReleaseWrite(&smb_rctLock);
8664 TlsFree(smb_TlsRequestSlot);
8667 /* Get the UNC \\<servername>\<sharename> prefix. */
8668 char *smb_GetSharename()
8672 /* Make sure we have been properly initialized. */
8673 if (smb_localNamep == NULL)
8676 /* Allocate space for \\<servername>\<sharename>, plus the
8679 name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
8680 sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
8686 void smb_LogPacket(smb_packet_t *packet)
8689 unsigned length, paramlen, datalen, i, j;
8691 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
8693 if (!packet) return;
8695 osi_Log0(smb_logp, "*** SMB packet dump ***");
8697 vp = (BYTE *) packet->data;
8699 datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
8700 length = paramlen + 2 + datalen;
8703 for (i=0;i < length; i+=16)
8705 memset( buf, ' ', 80 );
8710 buf[strlen(buf)] = ' ';
8712 cp = (BYTE*) buf + 7;
8714 for (j=0;j < 16 && (i+j)<length; j++)
8716 *(cp++) = hex[vp[i+j] >> 4];
8717 *(cp++) = hex[vp[i+j] & 0xf];
8727 for (j=0;j < 16 && (i+j)<length;j++)
8729 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
8740 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
8743 osi_Log0(smb_logp, "*** End SMB packet dump ***");
8745 #endif /* LOG_PACKET */
8748 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
8756 lock_ObtainRead(&smb_rctLock);
8758 sprintf(output, "begin dumping smb_vc_t\n");
8759 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8761 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
8765 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
8766 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
8767 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8769 sprintf(output, "begin dumping smb_fid_t\n");
8770 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8772 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8774 sprintf(output, "%s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, ioctlp=0x%p, NTopen_pathp=%s, NTopen_wholepathp=%s\n",
8775 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
8776 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
8777 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
8778 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8781 sprintf(output, "done dumping smb_fid_t\n");
8782 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8785 sprintf(output, "done dumping smb_vc_t\n");
8786 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8788 sprintf(output, "begin dumping DEAD smb_vc_t\n");
8789 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8791 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
8795 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
8796 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
8797 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8799 sprintf(output, "begin dumping smb_fid_t\n");
8800 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8802 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8804 sprintf(output, "%s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, ioctlp=0x%p, NTopen_pathp=%s, NTopen_wholepathp=%s\n",
8805 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
8806 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
8807 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
8808 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8811 sprintf(output, "done dumping smb_fid_t\n");
8812 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8815 sprintf(output, "done dumping DEAD smb_vc_t\n");
8816 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8818 sprintf(output, "begin dumping DEAD smb_vc_t\n");
8819 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8821 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
8825 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
8826 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
8827 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8829 sprintf(output, "begin dumping smb_fid_t\n");
8830 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8832 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8834 sprintf(output, "%s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, ioctlp=0x%p, NTopen_pathp=%s, NTopen_wholepathp=%s\n",
8835 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
8836 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
8837 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
8838 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8841 sprintf(output, "done dumping smb_fid_t\n");
8842 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8845 sprintf(output, "done dumping DEAD smb_vc_t\n");
8846 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8849 lock_ReleaseRead(&smb_rctLock);