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>
17 #include <sys/timeb.h>
30 #include <rx/rx_prototypes.h>
31 #include <WINNT\afsreg.h>
34 #include "lanahelper.h"
36 /* These characters are illegal in Windows filenames */
37 static char *illegalChars = "\\/:*?\"<>|";
38 BOOL isWindows2000 = FALSE;
40 int smbShutdownFlag = 0;
42 int smb_LogoffTokenTransfer;
43 time_t smb_LogoffTransferTimeout;
45 int smb_StoreAnsiFilenames = 0;
47 DWORD last_msg_time = 0;
51 unsigned int sessionGen = 0;
53 extern void afsi_log(char *pattern, ...);
54 extern HANDLE afsi_file;
56 osi_hyper_t hzero = {0, 0};
57 osi_hyper_t hones = {0xFFFFFFFF, -1};
60 osi_rwlock_t smb_globalLock;
61 osi_rwlock_t smb_rctLock;
62 osi_mutex_t smb_ListenerLock;
65 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
68 long smb_maxObsConcurrentCalls=0;
69 long smb_concurrentCalls=0;
71 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
73 smb_packet_t *smb_packetFreeListp;
74 smb_ncb_t *smb_ncbFreeListp;
76 int smb_NumServerThreads;
78 int numNCBs, numSessions, numVCs;
80 int smb_maxVCPerServer;
81 int smb_maxMpxRequests;
83 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
85 ULONG smb_lsaSecPackage;
86 LSA_STRING smb_lsaLogonOrigin;
88 #define NCB_MAX MAXIMUM_WAIT_OBJECTS
89 EVENT_HANDLE NCBavails[NCB_MAX], NCBevents[NCB_MAX];
90 EVENT_HANDLE **NCBreturns;
91 EVENT_HANDLE **NCBShutdown;
92 EVENT_HANDLE *smb_ServerShutdown;
93 DWORD NCBsessions[NCB_MAX];
95 struct smb_packet *bufs[NCB_MAX];
97 #define SESSION_MAX MAXIMUM_WAIT_OBJECTS - 4
98 EVENT_HANDLE SessionEvents[SESSION_MAX];
99 unsigned short LSNs[SESSION_MAX];
100 int lanas[SESSION_MAX];
101 BOOL dead_sessions[SESSION_MAX];
105 osi_mutex_t smb_RawBufLock;
107 #define SMB_RAW_BUFS 4
109 int smb_RawBufSel[SMB_RAW_BUFS];
114 #define SMB_MASKFLAG_TILDE 1
115 #define SMB_MASKFLAG_CASEFOLD 2
117 #define RAWTIMEOUT INFINITE
120 typedef struct raw_write_cont {
133 /* dir search stuff */
134 long smb_dirSearchCounter = 1;
135 smb_dirSearch_t *smb_firstDirSearchp;
136 smb_dirSearch_t *smb_lastDirSearchp;
138 /* hide dot files? */
139 int smb_hideDotFiles;
141 /* global state about V3 protocols */
142 int smb_useV3; /* try to negotiate V3 */
145 static showErrors = 1;
146 /* MessageBox or something like it */
147 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
151 * Time in Unix format of midnight, 1/1/1970 local time.
152 * When added to dosUTime, gives Unix (AFS) time.
154 time_t smb_localZero = 0;
156 #define USE_NUMERIC_TIME_CONV 1
158 #ifndef USE_NUMERIC_TIME_CONV
159 /* Time difference for converting to kludge-GMT */
160 afs_uint32 smb_NowTZ;
161 #endif /* USE_NUMERIC_TIME_CONV */
163 char *smb_localNamep = NULL;
165 smb_vc_t *smb_allVCsp;
166 smb_vc_t *smb_deadVCsp;
168 smb_username_t *usernamesp = NULL;
170 smb_waitingLockRequest_t *smb_allWaitingLocks;
172 DWORD smb_TlsRequestSlot = -1;
175 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
176 NCB *ncbp, raw_write_cont_t *rwcp);
177 void smb_NetbiosInit();
179 #ifndef AFS_WIN95_ENV
180 DWORD smb_ServerExceptionFilter(void);
183 extern char cm_HostName[];
184 extern char cm_confDir[];
188 #define LPTSTR char *
189 #define GetComputerName(str, sizep) \
190 strcpy((str), cm_HostName); \
191 *(sizep) = strlen(cm_HostName)
195 void smb_LogPacket(smb_packet_t *packet);
196 #endif /* LOG_PACKET */
198 char smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = ""; /* domain name */
199 int smb_ServerDomainNameLength = 0;
200 char smb_ServerOS[] = "Windows 5.0"; /* Faux OS String */
201 int smb_ServerOSLength = sizeof(smb_ServerOS);
202 char smb_ServerLanManager[] = "Windows 2000 LAN Manager"; /* Faux LAN Manager string */
203 int smb_ServerLanManagerLength = sizeof(smb_ServerLanManager);
205 /* Faux server GUID. This is never checked. */
206 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
208 void smb_ResetServerPriority()
210 void * p = TlsGetValue(smb_TlsRequestSlot);
213 TlsSetValue(smb_TlsRequestSlot, NULL);
214 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
218 void smb_SetRequestStartTime()
220 time_t * tp = malloc(sizeof(time_t));
224 if (!TlsSetValue(smb_TlsRequestSlot, tp))
229 void smb_UpdateServerPriority()
231 time_t *tp = TlsGetValue(smb_TlsRequestSlot);
234 time_t now = osi_Time();
236 /* Give one priority boost for each 15 seconds */
237 SetThreadPriority(GetCurrentThread(), (now - *tp) / 15);
242 const char * ncb_error_string(int code)
246 case 0x01: s = "llegal buffer length"; break;
247 case 0x03: s = "illegal command"; break;
248 case 0x05: s = "command timed out"; break;
249 case 0x06: s = "message incomplete, issue another command"; break;
250 case 0x07: s = "illegal buffer address"; break;
251 case 0x08: s = "session number out of range"; break;
252 case 0x09: s = "no resource available"; break;
253 case 0x0a: s = "session closed"; break;
254 case 0x0b: s = "command cancelled"; break;
255 case 0x0d: s = "duplicate name"; break;
256 case 0x0e: s = "name table full"; break;
257 case 0x0f: s = "no deletions, name has active sessions"; break;
258 case 0x11: s = "local session table full"; break;
259 case 0x12: s = "remote session table full"; break;
260 case 0x13: s = "illegal name number"; break;
261 case 0x14: s = "no callname"; break;
262 case 0x15: s = "cannot put * in NCB_NAME"; break;
263 case 0x16: s = "name in use on remote adapter"; break;
264 case 0x17: s = "name deleted"; break;
265 case 0x18: s = "session ended abnormally"; break;
266 case 0x19: s = "name conflict detected"; break;
267 case 0x21: s = "interface busy, IRET before retrying"; break;
268 case 0x22: s = "too many commands outstanding, retry later";break;
269 case 0x23: s = "ncb_lana_num field invalid"; break;
270 case 0x24: s = "command completed while cancel occurring "; break;
271 case 0x26: s = "command not valid to cancel"; break;
272 case 0x30: s = "name defined by anther local process"; break;
273 case 0x34: s = "environment undefined. RESET required"; break;
274 case 0x35: s = "required OS resources exhausted"; break;
275 case 0x36: s = "max number of applications exceeded"; break;
276 case 0x37: s = "no saps available for netbios"; break;
277 case 0x38: s = "requested resources are not available"; break;
278 case 0x39: s = "invalid ncb address or length > segment"; break;
279 case 0x3B: s = "invalid NCB DDID"; break;
280 case 0x3C: s = "lock of user area failed"; break;
281 case 0x3f: s = "NETBIOS not loaded"; break;
282 case 0x40: s = "system error"; break;
283 default: s = "unknown error";
289 char * myCrt_Dispatch(int i)
294 return "(00)ReceiveCoreMakeDir";
296 return "(01)ReceiveCoreRemoveDir";
298 return "(02)ReceiveCoreOpen";
300 return "(03)ReceiveCoreCreate";
302 return "(04)ReceiveCoreClose";
304 return "(05)ReceiveCoreFlush";
306 return "(06)ReceiveCoreUnlink";
308 return "(07)ReceiveCoreRename";
310 return "(08)ReceiveCoreGetFileAttributes";
312 return "(09)ReceiveCoreSetFileAttributes";
314 return "(0a)ReceiveCoreRead";
316 return "(0b)ReceiveCoreWrite";
318 return "(0c)ReceiveCoreLockRecord";
320 return "(0d)ReceiveCoreUnlockRecord";
322 return "(0e)SendCoreBadOp";
324 return "(0f)ReceiveCoreCreate";
326 return "(10)ReceiveCoreCheckPath";
328 return "(11)SendCoreBadOp";
330 return "(12)ReceiveCoreSeek";
332 return "(1a)ReceiveCoreReadRaw";
334 return "(1d)ReceiveCoreWriteRawDummy";
336 return "(22)ReceiveV3SetAttributes";
338 return "(23)ReceiveV3GetAttributes";
340 return "(24)ReceiveV3LockingX";
342 return "(25)ReceiveV3Trans";
344 return "(26)ReceiveV3Trans[aux]";
346 return "(29)SendCoreBadOp";
348 return "(2b)ReceiveCoreEcho";
350 return "(2d)ReceiveV3OpenX";
352 return "(2e)ReceiveV3ReadX";
354 return "(2f)ReceiveV3WriteX";
356 return "(32)ReceiveV3Tran2A";
358 return "(33)ReceiveV3Tran2A[aux]";
360 return "(34)ReceiveV3FindClose";
362 return "(35)ReceiveV3FindNotifyClose";
364 return "(70)ReceiveCoreTreeConnect";
366 return "(71)ReceiveCoreTreeDisconnect";
368 return "(72)ReceiveNegotiate";
370 return "(73)ReceiveV3SessionSetupX";
372 return "(74)ReceiveV3UserLogoffX";
374 return "(75)ReceiveV3TreeConnectX";
376 return "(80)ReceiveCoreGetDiskAttributes";
378 return "(81)ReceiveCoreSearchDir";
382 return "(83)FindUnique";
384 return "(84)FindClose";
386 return "(A0)ReceiveNTTransact";
388 return "(A2)ReceiveNTCreateX";
390 return "(A4)ReceiveNTCancel";
392 return "(A5)ReceiveNTRename";
394 return "(C0)OpenPrintFile";
396 return "(C1)WritePrintFile";
398 return "(C2)ClosePrintFile";
400 return "(C3)GetPrintQueue";
402 return "(D8)ReadBulk";
404 return "(D9)WriteBulk";
406 return "(DA)WriteBulkData";
408 return "unknown SMB op";
412 char * myCrt_2Dispatch(int i)
417 return "unknown SMB op-2";
419 return "S(00)CreateFile";
421 return "S(01)FindFirst";
423 return "S(02)FindNext"; /* FindNext */
425 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
429 return "S(05)QueryFileInfo_ReceiveTran2QPathInfo";
431 return "S(06)SetFileInfo_ReceiveTran2SetPathInfo";
433 return "S(07)SetInfoHandle_ReceiveTran2QFileInfo";
435 return "S(08)??_ReceiveTran2SetFileInfo";
437 return "S(09)??_ReceiveTran2FSCTL";
439 return "S(0a)_ReceiveTran2IOCTL";
441 return "S(0b)_ReceiveTran2FindNotifyFirst";
443 return "S(0c)_ReceiveTran2FindNotifyNext";
445 return "S(0d)_ReceiveTran2CreateDirectory";
447 return "S(0e)_ReceiveTran2SessionSetup";
449 return "S(10)_ReceiveTran2GetDfsReferral";
451 return "S(11)_ReceiveTran2ReportDfsInconsistency";
455 char * myCrt_RapDispatch(int i)
460 return "unknown RAP OP";
462 return "RAP(0)NetShareEnum";
464 return "RAP(1)NetShareGetInfo";
466 return "RAP(13)NetServerGetInfo";
468 return "RAP(63)NetWkStaGetInfo";
472 /* scache must be locked */
473 unsigned int smb_Attributes(cm_scache_t *scp)
477 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
478 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
479 scp->fileType == CM_SCACHETYPE_INVALID)
481 attrs = SMB_ATTR_DIRECTORY;
482 #ifdef SPECIAL_FOLDERS
483 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
484 #endif /* SPECIAL_FOLDERS */
485 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
486 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
491 * We used to mark a file RO if it was in an RO volume, but that
492 * turns out to be impolitic in NT. See defect 10007.
495 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
496 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
498 if ((scp->unixModeBits & 0222) == 0)
499 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
505 /* Check if the named file/dir is a dotfile/dotdir */
506 /* String pointed to by lastComp can have leading slashes, but otherwise should have
507 no other patch components */
508 unsigned int smb_IsDotFile(char *lastComp) {
511 /* skip over slashes */
512 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
517 /* nulls, curdir and parent dir doesn't count */
523 if(*(s+1) == '.' && !*(s + 2))
530 static int ExtractBits(WORD bits, short start, short len)
537 num = bits << (16 - end);
538 num = num >> ((16 - end) + start);
544 void ShowUnixTime(char *FuncName, time_t unixTime)
549 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
551 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
552 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
554 int day, month, year, sec, min, hour;
557 day = ExtractBits(wDate, 0, 5);
558 month = ExtractBits(wDate, 5, 4);
559 year = ExtractBits(wDate, 9, 7) + 1980;
561 sec = ExtractBits(wTime, 0, 5);
562 min = ExtractBits(wTime, 5, 6);
563 hour = ExtractBits(wTime, 11, 5);
565 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
566 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
572 /* Determine if we are observing daylight savings time */
573 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
575 TIME_ZONE_INFORMATION timeZoneInformation;
576 SYSTEMTIME utc, local, localDST;
578 /* Get the time zone info. NT uses this to calc if we are in DST. */
579 GetTimeZoneInformation(&timeZoneInformation);
581 /* Return the daylight bias */
582 *pDstBias = timeZoneInformation.DaylightBias;
584 /* Return the bias */
585 *pBias = timeZoneInformation.Bias;
587 /* Now determine if DST is being observed */
589 /* Get the UTC (GMT) time */
592 /* Convert UTC time to local time using the time zone info. If we are
593 observing DST, the calculated local time will include this.
595 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
597 /* Set the daylight bias to 0. The daylight bias is the amount of change
598 * in time that we use for daylight savings time. By setting this to 0
599 * we cause there to be no change in time during daylight savings time.
601 timeZoneInformation.DaylightBias = 0;
603 /* Convert the utc time to local time again, but this time without any
604 adjustment for daylight savings time.
606 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
608 /* If the two times are different, then it means that the localDST that
609 we calculated includes the daylight bias, and therefore we are
610 observing daylight savings time.
612 *pDST = localDST.wHour != local.wHour;
615 /* Determine if we are observing daylight savings time */
616 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
622 *pDstBias = -60; /* where can this be different? */
628 void CompensateForSmbClientLastWriteTimeBugs(afs_uint32 *pLastWriteTime)
630 BOOL dst; /* Will be TRUE if observing DST */
631 LONG dstBias; /* Offset from local time if observing DST */
632 LONG bias; /* Offset from GMT for local time */
635 * This function will adjust the last write time to compensate
636 * for two bugs in the smb client:
638 * 1) During Daylight Savings Time, the LastWriteTime is ahead
639 * in time by the DaylightBias (ignoring the sign - the
640 * DaylightBias is always stored as a negative number). If
641 * the DaylightBias is -60, then the LastWriteTime will be
642 * ahead by 60 minutes.
644 * 2) If the local time zone is a positive offset from GMT, then
645 * the LastWriteTime will be the correct local time plus the
646 * Bias (ignoring the sign - a positive offset from GMT is
647 * always stored as a negative Bias). If the Bias is -120,
648 * then the LastWriteTime will be ahead by 120 minutes.
650 * These bugs can occur at the same time.
653 GetTimeZoneInfo(&dst, &dstBias, &bias);
655 /* First adjust for DST */
657 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
659 /* Now adjust for a positive offset from GMT (a negative bias). */
661 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
664 #ifndef USE_NUMERIC_TIME_CONV
666 * Calculate the difference (in seconds) between local time and GMT.
667 * This enables us to convert file times to kludge-GMT.
673 struct tm gmt_tm, local_tm;
674 int days, hours, minutes, seconds;
677 gmt_tm = *(gmtime(&t));
678 local_tm = *(localtime(&t));
680 days = local_tm.tm_yday - gmt_tm.tm_yday;
681 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour;
682 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
683 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
687 #endif /* USE_NUMERIC_TIME_CONV */
690 #ifdef USE_NUMERIC_TIME_CONV
691 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
693 // Note that LONGLONG is a 64-bit value
696 ll = Int32x32To64(unixTime, 10000000) + 116444736000000000;
697 largeTimep->dwLowDateTime = (DWORD)(ll & 0xFFFFFFFF);
698 largeTimep->dwHighDateTime = (DWORD)(ll >> 32);
701 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
706 time_t ersatz_unixTime;
709 * Must use kludge-GMT instead of real GMT.
710 * kludge-GMT is computed by adding time zone difference to localtime.
713 * ltp = gmtime(&unixTime);
715 ersatz_unixTime = unixTime - smb_NowTZ;
716 ltp = localtime(&ersatz_unixTime);
718 /* if we fail, make up something */
721 localJunk.tm_year = 89 - 20;
722 localJunk.tm_mon = 4;
723 localJunk.tm_mday = 12;
724 localJunk.tm_hour = 0;
725 localJunk.tm_min = 0;
726 localJunk.tm_sec = 0;
729 stm.wYear = ltp->tm_year + 1900;
730 stm.wMonth = ltp->tm_mon + 1;
731 stm.wDayOfWeek = ltp->tm_wday;
732 stm.wDay = ltp->tm_mday;
733 stm.wHour = ltp->tm_hour;
734 stm.wMinute = ltp->tm_min;
735 stm.wSecond = ltp->tm_sec;
736 stm.wMilliseconds = 0;
738 SystemTimeToFileTime(&stm, largeTimep);
740 #endif /* USE_NUMERIC_TIME_CONV */
742 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
744 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
745 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 ??? */
746 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
748 int leap_years = 89; /* leap years betw 1/1/1601 and 1/1/1970 */
750 /* set ft to number of 100ns intervals betw 1/1/1601 and 1/1/1970 GMT */
751 *ft = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years)
753 *ft = LargeIntegerMultiplyByLong(*ft, 60);
754 *ft = LargeIntegerMultiplyByLong(*ft, 10000000);
757 ut = ConvertLongToLargeInteger(unixTime);
758 ut = LargeIntegerMultiplyByLong(ut, 10000000);
759 *ft = LargeIntegerAdd(*ft, ut);
764 #ifdef USE_NUMERIC_TIME_CONV
765 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
767 // Note that LONGLONG is a 64-bit value
770 ll = largeTimep->dwHighDateTime;
772 ll += largeTimep->dwLowDateTime;
774 ll -= 116444736000000000;
777 *unixTimep = (DWORD)ll;
779 #else /* USE_NUMERIC_TIME_CONV */
780 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
786 FileTimeToSystemTime(largeTimep, &stm);
788 lt.tm_year = stm.wYear - 1900;
789 lt.tm_mon = stm.wMonth - 1;
790 lt.tm_wday = stm.wDayOfWeek;
791 lt.tm_mday = stm.wDay;
792 lt.tm_hour = stm.wHour;
793 lt.tm_min = stm.wMinute;
794 lt.tm_sec = stm.wSecond;
797 save_timezone = _timezone;
798 _timezone += smb_NowTZ;
799 *unixTimep = mktime(<);
800 _timezone = save_timezone;
802 #endif /* USE_NUMERIC_TIME_CONV */
804 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
806 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
807 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 GMT? */
808 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
812 /* set to number of 100ns intervals betw 1/1/1601 and 1/1/1970 */
813 a = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years) * 24 * 60);
814 a = LargeIntegerMultiplyByLong(a, 60);
815 a = LargeIntegerMultiplyByLong(a, 10000000);
817 /* subtract it from ft */
818 a = LargeIntegerSubtract(*ft, a);
820 /* divide down to seconds */
821 *unixTimep = LargeIntegerDivideByLong(a, 10000000);
825 void smb_SearchTimeFromUnixTime(afs_uint32 *searchTimep, time_t unixTime)
835 /* if we fail, make up something */
838 localJunk.tm_year = 89 - 20;
839 localJunk.tm_mon = 4;
840 localJunk.tm_mday = 12;
841 localJunk.tm_hour = 0;
842 localJunk.tm_min = 0;
843 localJunk.tm_sec = 0;
846 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
847 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
848 *searchTimep = (dosDate<<16) | dosTime;
851 void smb_UnixTimeFromSearchTime(time_t *unixTimep, afs_uint32 searchTime)
853 unsigned short dosDate;
854 unsigned short dosTime;
857 dosDate = (unsigned short) (searchTime & 0xffff);
858 dosTime = (unsigned short) ((searchTime >> 16) & 0xffff);
860 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
861 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
862 localTm.tm_mday = (dosDate) & 0x1f;
863 localTm.tm_hour = (dosTime>>11) & 0x1f;
864 localTm.tm_min = (dosTime >> 5) & 0x3f;
865 localTm.tm_sec = (dosTime & 0x1f) * 2;
866 localTm.tm_isdst = -1; /* compute whether DST in effect */
868 *unixTimep = mktime(&localTm);
871 void smb_DosUTimeFromUnixTime(afs_uint32 *dosUTimep, time_t unixTime)
873 time_t diff_t = unixTime - smb_localZero;
874 #if defined(DEBUG) && !defined(_USE_32BIT_TIME_T)
875 osi_assert(diff_t < _UI32_MAX);
877 *dosUTimep = (afs_uint32)diff_t;
880 void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
883 *unixTimep = dosTime + smb_localZero;
885 /* dosTime seems to be already adjusted for GMT */
886 *unixTimep = dosTime;
890 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
894 lock_ObtainWrite(&smb_rctLock);
895 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
896 if (vcp->magic != SMB_VC_MAGIC)
897 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
900 if (lsn == vcp->lsn && lana == vcp->lana &&
901 !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
902 smb_HoldVCNoLock(vcp);
906 if (!vcp && (flags & SMB_FLAG_CREATE)) {
907 vcp = malloc(sizeof(*vcp));
908 memset(vcp, 0, sizeof(*vcp));
909 lock_ObtainWrite(&smb_globalLock);
910 vcp->vcID = ++numVCs;
911 lock_ReleaseWrite(&smb_globalLock);
912 vcp->magic = SMB_VC_MAGIC;
913 vcp->refCount = 2; /* smb_allVCsp and caller */
916 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
917 vcp->nextp = smb_allVCsp;
919 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
924 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
925 /* We must obtain a challenge for extended auth
926 * in case the client negotiates smb v3
928 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
929 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
930 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp;
931 ULONG lsaRespSize = 0;
933 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
935 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
942 if (nts != STATUS_SUCCESS)
943 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
944 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
945 osi_assert(nts == STATUS_SUCCESS); /* this had better work! */
947 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
948 LsaFreeReturnBuffer(lsaResp);
951 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
953 if (numVCs >= CM_SESSION_RESERVED) {
954 lock_ObtainWrite(&smb_globalLock);
956 lock_ReleaseWrite(&smb_globalLock);
957 osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
960 lock_ReleaseWrite(&smb_rctLock);
964 int smb_IsStarMask(char *maskp)
969 for(i=0; i<11; i++) {
971 if (tc == '?' || tc == '*' || tc == '>')
977 void smb_ReleaseVCInternal(smb_vc_t *vcp)
984 if (vcp->refCount == 0) {
985 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
986 /* remove VCP from smb_deadVCsp */
987 for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
993 lock_FinalizeMutex(&vcp->mx);
994 memset(vcp,0,sizeof(smb_vc_t));
997 for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
1001 osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
1002 avcp?"not ":"",vcp, vcp->refCount);
1004 GenerateMiniDump(NULL);
1006 /* This is a wrong. However, I suspect that there is an undercount
1007 * and I don't want to release 1.4.1 in a state that will allow
1008 * smb_vc_t objects to be deallocated while still in the
1009 * smb_allVCsp list. The list is supposed to keep a reference
1010 * to the smb_vc_t. Put it back.
1017 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
1019 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
1020 smb_ReleaseVCInternal(vcp);
1023 void smb_ReleaseVC(smb_vc_t *vcp)
1025 lock_ObtainWrite(&smb_rctLock);
1026 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
1027 smb_ReleaseVCInternal(vcp);
1028 lock_ReleaseWrite(&smb_rctLock);
1031 void smb_HoldVCNoLock(smb_vc_t *vcp)
1034 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
1037 void smb_HoldVC(smb_vc_t *vcp)
1039 lock_ObtainWrite(&smb_rctLock);
1041 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
1042 lock_ReleaseWrite(&smb_rctLock);
1045 void smb_CleanupDeadVC(smb_vc_t *vcp)
1047 smb_fid_t *fidpIter;
1048 smb_fid_t *fidpNext;
1050 smb_tid_t *tidpIter;
1051 smb_tid_t *tidpNext;
1053 smb_user_t *uidpIter;
1054 smb_user_t *uidpNext;
1058 lock_ObtainMutex(&vcp->mx);
1059 if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
1060 lock_ReleaseMutex(&vcp->mx);
1061 osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
1064 vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
1065 lock_ReleaseMutex(&vcp->mx);
1066 osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
1068 lock_ObtainWrite(&smb_rctLock);
1069 /* remove VCP from smb_allVCsp */
1070 for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
1071 if ((*vcpp)->magic != SMB_VC_MAGIC)
1072 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
1073 __FILE__, __LINE__);
1076 vcp->nextp = smb_deadVCsp;
1078 /* Hold onto the reference until we are done with this function */
1083 for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
1084 fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
1086 if (fidpIter->delete)
1089 fid = fidpIter->fid;
1090 osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1092 smb_HoldFIDNoLock(fidpIter);
1093 lock_ReleaseWrite(&smb_rctLock);
1095 smb_CloseFID(vcp, fidpIter, NULL, 0);
1096 smb_ReleaseFID(fidpIter);
1098 lock_ObtainWrite(&smb_rctLock);
1099 fidpNext = vcp->fidsp;
1102 for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1103 tidpNext = tidpIter->nextp;
1104 if (tidpIter->delete)
1106 tidpIter->delete = 1;
1108 tid = tidpIter->tid;
1109 osi_Log2(smb_logp, " Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1111 smb_HoldTIDNoLock(tidpIter);
1112 lock_ReleaseWrite(&smb_rctLock);
1114 smb_ReleaseTID(tidpIter);
1116 lock_ObtainWrite(&smb_rctLock);
1117 tidpNext = vcp->tidsp;
1120 for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1121 uidpNext = uidpIter->nextp;
1122 if (uidpIter->delete)
1124 uidpIter->delete = 1;
1126 /* do not add an additional reference count for the smb_user_t
1127 * as the smb_vc_t already is holding a reference */
1128 lock_ReleaseWrite(&smb_rctLock);
1130 smb_ReleaseUID(uidpIter);
1132 lock_ObtainWrite(&smb_rctLock);
1133 uidpNext = vcp->usersp;
1136 /* The vcp is now on the deadVCsp list. We intentionally drop the
1137 * reference so that the refcount can reach 0 and we can delete it */
1138 smb_ReleaseVCNoLock(vcp);
1140 lock_ReleaseWrite(&smb_rctLock);
1141 osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1144 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1148 lock_ObtainWrite(&smb_rctLock);
1149 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1150 if (tid == tidp->tid) {
1155 if (!tidp && (flags & SMB_FLAG_CREATE)) {
1156 tidp = malloc(sizeof(*tidp));
1157 memset(tidp, 0, sizeof(*tidp));
1158 tidp->nextp = vcp->tidsp;
1161 smb_HoldVCNoLock(vcp);
1163 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
1166 lock_ReleaseWrite(&smb_rctLock);
1170 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1175 void smb_ReleaseTID(smb_tid_t *tidp)
1182 lock_ObtainWrite(&smb_rctLock);
1183 osi_assert(tidp->refCount-- > 0);
1184 if (tidp->refCount == 0 && (tidp->delete)) {
1185 ltpp = &tidp->vcp->tidsp;
1186 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1190 osi_assert(tp != NULL);
1192 lock_FinalizeMutex(&tidp->mx);
1193 userp = tidp->userp; /* remember to drop ref later */
1195 smb_ReleaseVCNoLock(tidp->vcp);
1198 lock_ReleaseWrite(&smb_rctLock);
1200 cm_ReleaseUser(userp);
1203 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1205 smb_user_t *uidp = NULL;
1207 lock_ObtainWrite(&smb_rctLock);
1208 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1209 if (uid == uidp->userID) {
1211 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%s]",
1213 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
1217 if (!uidp && (flags & SMB_FLAG_CREATE)) {
1218 uidp = malloc(sizeof(*uidp));
1219 memset(uidp, 0, sizeof(*uidp));
1220 uidp->nextp = vcp->usersp;
1221 uidp->refCount = 2; /* one for the vcp and one for the caller */
1223 smb_HoldVCNoLock(vcp);
1225 lock_InitializeMutex(&uidp->mx, "user_t mutex");
1227 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%s]",
1229 osi_LogSaveString(smb_logp,uidp->unp ? uidp->unp->name : ""));
1231 lock_ReleaseWrite(&smb_rctLock);
1235 smb_username_t *smb_FindUserByName(char *usern, char *machine, afs_uint32 flags)
1237 smb_username_t *unp= NULL;
1239 lock_ObtainWrite(&smb_rctLock);
1240 for(unp = usernamesp; unp; unp = unp->nextp) {
1241 if (stricmp(unp->name, usern) == 0 &&
1242 stricmp(unp->machine, machine) == 0) {
1247 if (!unp && (flags & SMB_FLAG_CREATE)) {
1248 unp = malloc(sizeof(*unp));
1249 memset(unp, 0, sizeof(*unp));
1251 unp->nextp = usernamesp;
1252 unp->name = strdup(usern);
1253 unp->machine = strdup(machine);
1255 lock_InitializeMutex(&unp->mx, "username_t mutex");
1256 if (flags & SMB_FLAG_AFSLOGON)
1257 unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1260 lock_ReleaseWrite(&smb_rctLock);
1264 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
1266 smb_user_t *uidp= NULL;
1268 lock_ObtainWrite(&smb_rctLock);
1269 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1272 if (stricmp(uidp->unp->name, usern) == 0) {
1274 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%s]",
1275 vcp,uidp->userID,osi_LogSaveString(smb_logp,usern));
1280 lock_ReleaseWrite(&smb_rctLock);
1284 void smb_ReleaseUsername(smb_username_t *unp)
1287 smb_username_t **lupp;
1288 cm_user_t *userp = NULL;
1289 time_t now = osi_Time();
1291 lock_ObtainWrite(&smb_rctLock);
1292 osi_assert(unp->refCount-- > 0);
1293 if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1294 (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1296 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1300 osi_assert(up != NULL);
1302 up->nextp = NULL; /* do not remove this */
1303 lock_FinalizeMutex(&unp->mx);
1309 lock_ReleaseWrite(&smb_rctLock);
1312 cm_ReleaseUser(userp);
1316 void smb_HoldUIDNoLock(smb_user_t *uidp)
1321 void smb_ReleaseUID(smb_user_t *uidp)
1325 smb_username_t *unp = NULL;
1327 lock_ObtainWrite(&smb_rctLock);
1328 osi_assert(uidp->refCount-- > 0);
1329 if (uidp->refCount == 0) {
1330 lupp = &uidp->vcp->usersp;
1331 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1335 osi_assert(up != NULL);
1337 lock_FinalizeMutex(&uidp->mx);
1339 smb_ReleaseVCNoLock(uidp->vcp);
1343 lock_ReleaseWrite(&smb_rctLock);
1347 cm_ReleaseUserVCRef(unp->userp);
1348 smb_ReleaseUsername(unp);
1352 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1354 cm_user_t *up = NULL;
1359 lock_ObtainMutex(&uidp->mx);
1361 up = uidp->unp->userp;
1364 lock_ReleaseMutex(&uidp->mx);
1370 /* retrieve a held reference to a user structure corresponding to an incoming
1372 * corresponding release function is cm_ReleaseUser.
1374 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1377 cm_user_t *up = NULL;
1380 smbp = (smb_t *) inp;
1381 uidp = smb_FindUID(vcp, smbp->uid, 0);
1385 up = smb_GetUserFromUID(uidp);
1387 smb_ReleaseUID(uidp);
1392 * Return a pointer to a pathname extracted from a TID structure. The
1393 * TID structure is not held; assume it won't go away.
1395 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1400 tidp = smb_FindTID(vcp, tid, 0);
1404 if (tidp->flags & SMB_TIDFLAG_IPC) {
1405 code = CM_ERROR_TIDIPC;
1406 /* tidp->pathname would be NULL, but that's fine */
1408 *treepath = tidp->pathname;
1409 smb_ReleaseTID(tidp);
1414 /* check to see if we have a chained fid, that is, a fid that comes from an
1415 * OpenAndX message that ran earlier in this packet. In this case, the fid
1416 * field in a read, for example, request, isn't set, since the value is
1417 * supposed to be inherited from the openAndX call.
1419 int smb_ChainFID(int fid, smb_packet_t *inp)
1421 if (inp->fid == 0 || inp->inCount == 0)
1427 /* are we a priv'd user? What does this mean on NT? */
1428 int smb_SUser(cm_user_t *userp)
1433 /* find a file ID. If we pass in 0 we select an unused File ID.
1434 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1435 * smb_fid_t data structure if desired File ID cannot be found.
1437 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1442 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1445 lock_ObtainWrite(&smb_rctLock);
1446 /* figure out if we need to allocate a new file ID */
1449 fid = vcp->fidCounter;
1453 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1454 if (fid == fidp->fid) {
1457 if (fid == 0xFFFF) {
1459 "New FID number wraps on vcp 0x%x", vcp);
1469 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1470 char eventName[MAX_PATH];
1472 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1473 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1474 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1475 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1476 thrd_CloseHandle(event);
1478 if (fid == 0xFFFF) {
1479 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1485 fidp = malloc(sizeof(*fidp));
1486 memset(fidp, 0, sizeof(*fidp));
1487 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1490 smb_HoldVCNoLock(vcp);
1491 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1493 fidp->curr_chunk = fidp->prev_chunk = -2;
1494 fidp->raw_write_event = event;
1496 vcp->fidCounter = fid+1;
1497 if (vcp->fidCounter == 0xFFFF) {
1498 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1500 vcp->fidCounter = 1;
1505 lock_ReleaseWrite(&smb_rctLock);
1509 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1514 void smb_ReleaseFID(smb_fid_t *fidp)
1516 cm_scache_t *scp = NULL;
1517 cm_user_t *userp = NULL;
1518 smb_vc_t *vcp = NULL;
1519 smb_ioctl_t *ioctlp;
1521 lock_ObtainMutex(&fidp->mx);
1522 lock_ObtainWrite(&smb_rctLock);
1523 osi_assert(fidp->refCount-- > 0);
1524 if (fidp->refCount == 0 && (fidp->delete)) {
1527 scp = fidp->scp; /* release after lock is released */
1529 userp = fidp->userp;
1533 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1534 thrd_CloseHandle(fidp->raw_write_event);
1536 /* and see if there is ioctl stuff to free */
1537 ioctlp = fidp->ioctlp;
1540 cm_FreeSpace(ioctlp->prefix);
1541 if (ioctlp->inAllocp)
1542 free(ioctlp->inAllocp);
1543 if (ioctlp->outAllocp)
1544 free(ioctlp->outAllocp);
1547 lock_ReleaseMutex(&fidp->mx);
1548 lock_FinalizeMutex(&fidp->mx);
1552 smb_ReleaseVCNoLock(vcp);
1554 lock_ReleaseMutex(&fidp->mx);
1556 lock_ReleaseWrite(&smb_rctLock);
1558 /* now release the scache structure */
1560 cm_ReleaseSCache(scp);
1563 cm_ReleaseUser(userp);
1567 * Case-insensitive search for one string in another;
1568 * used to find variable names in submount pathnames.
1570 static char *smb_stristr(char *str1, char *str2)
1574 for (cursor = str1; *cursor; cursor++)
1575 if (stricmp(cursor, str2) == 0)
1582 * Substitute a variable value for its name in a submount pathname. Variable
1583 * name has been identified by smb_stristr() and is in substr. Variable name
1584 * length (plus one) is in substr_size. Variable value is in newstr.
1586 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1591 strcpy(temp, substr + substr_size - 1);
1592 strcpy(substr, newstr);
1596 char VNUserName[] = "%USERNAME%";
1597 char VNLCUserName[] = "%LCUSERNAME%";
1598 char VNComputerName[] = "%COMPUTERNAME%";
1599 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1602 /* List available shares */
1603 int smb_ListShares()
1607 char shareBuf[4096];
1615 /*strcpy(shareNameList[num_shares], "all");
1616 strcpy(pathNameList[num_shares++], "/afs");*/
1617 fprintf(stderr, "The following shares are available:\n");
1618 fprintf(stderr, "Share Name (AFS Path)\n");
1619 fprintf(stderr, "---------------------\n");
1620 fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
1623 code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1624 if (code == 0 || code > sizeof(sbmtpath)) return -1;
1626 strcpy(sbmtpath, cm_confDir);
1628 strcat(sbmtpath, "/afsdsbmt.ini");
1629 len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1630 shareBuf, sizeof(shareBuf),
1636 this_share = shareBuf;
1640 /*strcpy(shareNameList[num_shares], this_share);*/
1641 len = GetPrivateProfileString("AFS Submounts", this_share,
1648 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) != 0)
1651 if (*p == '\\') *p = '/'; /* change to / */
1655 fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1656 smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
1659 while (*this_share != 0) this_share++; /* find next NUL */
1660 this_share++; /* skip past the NUL */
1661 } while (*this_share != 0); /* stop at final NUL */
1667 typedef struct smb_findShare_rock {
1671 } smb_findShare_rock_t;
1673 #define SMB_FINDSHARE_EXACT_MATCH 1
1674 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1676 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1680 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1681 if (!strnicmp(dep->name, vrock->shareName, 12)) {
1682 if(!stricmp(dep->name, vrock->shareName))
1683 matchType = SMB_FINDSHARE_EXACT_MATCH;
1685 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1686 if(vrock->match) free(vrock->match);
1687 vrock->match = strdup(dep->name);
1688 vrock->matchType = matchType;
1690 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1691 return CM_ERROR_STOPNOW;
1697 /* find a shareName in the table of submounts */
1698 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1702 char pathName[1024];
1707 char sbmtpath[MAX_PATH];
1712 DWORD allSubmount = 1;
1714 /* if allSubmounts == 0, only return the //mountRoot/all share
1715 * if in fact it has been been created in the subMounts table.
1716 * This is to allow sites that want to restrict access to the
1719 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1720 0, KEY_QUERY_VALUE, &parmKey);
1721 if (code == ERROR_SUCCESS) {
1722 len = sizeof(allSubmount);
1723 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1724 (BYTE *) &allSubmount, &len);
1725 if (code != ERROR_SUCCESS) {
1728 RegCloseKey (parmKey);
1731 if (allSubmount && _stricmp(shareName, "all") == 0) {
1736 /* In case, the all share is disabled we need to still be able
1737 * to handle ioctl requests
1739 if (_stricmp(shareName, "ioctl$") == 0) {
1740 *pathNamep = strdup("/.__ioctl__");
1744 if (_stricmp(shareName, "IPC$") == 0 ||
1745 _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1746 _stricmp(shareName, "DESKTOP.INI") == 0
1753 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1754 0, KEY_QUERY_VALUE, &parmKey);
1755 if (code == ERROR_SUCCESS) {
1756 len = sizeof(pathName);
1757 code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1758 (BYTE *) pathName, &len);
1759 if (code != ERROR_SUCCESS)
1761 RegCloseKey (parmKey);
1766 strcpy(sbmtpath, cm_confDir);
1767 strcat(sbmtpath, "/afsdsbmt.ini");
1768 len = GetPrivateProfileString("AFS Submounts", shareName, "",
1769 pathName, sizeof(pathName), sbmtpath);
1771 if (len != 0 && len != sizeof(pathName) - 1) {
1772 /* We can accept either unix or PC style AFS pathnames. Convert
1773 * Unix-style to PC style here for internal use.
1776 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1777 p += strlen(cm_mountRoot); /* skip mount path */
1780 if (*q == '/') *q = '\\'; /* change to \ */
1786 if (var = smb_stristr(p, VNUserName)) {
1787 if (uidp && uidp->unp)
1788 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1790 smb_subst(p, var, sizeof(VNUserName)," ");
1792 else if (var = smb_stristr(p, VNLCUserName))
1794 if (uidp && uidp->unp)
1795 strcpy(temp, uidp->unp->name);
1799 smb_subst(p, var, sizeof(VNLCUserName), temp);
1801 else if (var = smb_stristr(p, VNComputerName))
1803 sizeTemp = sizeof(temp);
1804 GetComputerName((LPTSTR)temp, &sizeTemp);
1805 smb_subst(p, var, sizeof(VNComputerName), temp);
1807 else if (var = smb_stristr(p, VNLCComputerName))
1809 sizeTemp = sizeof(temp);
1810 GetComputerName((LPTSTR)temp, &sizeTemp);
1812 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1817 *pathNamep = strdup(p);
1822 /* First lookup shareName in root.afs */
1824 smb_findShare_rock_t vrock;
1826 char * p = shareName;
1829 /* attempt to locate a partial match in root.afs. This is because
1830 when using the ANSI RAP calls, the share name is limited to 13 chars
1831 and hence is truncated. Of course we prefer exact matches. */
1833 thyper.HighPart = 0;
1836 vrock.shareName = shareName;
1838 vrock.matchType = 0;
1840 cm_HoldSCache(cm_data.rootSCachep);
1841 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1842 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1843 cm_ReleaseSCache(cm_data.rootSCachep);
1845 if (vrock.matchType) {
1846 sprintf(pathName,"/%s/",vrock.match);
1847 *pathNamep = strdup(strlwr(pathName));
1852 /* if we get here, there was no match for the share in root.afs */
1853 /* so try to create \\<netbiosName>\<cellname> */
1858 /* Get the full name for this cell */
1859 code = cm_SearchCellFile(p, temp, 0, 0);
1860 #ifdef AFS_AFSDB_ENV
1861 if (code && cm_dnsEnabled) {
1863 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1866 /* construct the path */
1868 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1869 *pathNamep = strdup(strlwr(pathName));
1878 /* Client-side offline caching policy types */
1879 #define CSC_POLICY_MANUAL 0
1880 #define CSC_POLICY_DOCUMENTS 1
1881 #define CSC_POLICY_PROGRAMS 2
1882 #define CSC_POLICY_DISABLE 3
1884 int smb_FindShareCSCPolicy(char *shareName)
1890 int retval = CSC_POLICY_MANUAL;
1892 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1893 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1896 REG_OPTION_NON_VOLATILE,
1902 len = sizeof(policy);
1903 if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1905 retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1907 else if (stricmp(policy, "documents") == 0)
1909 retval = CSC_POLICY_DOCUMENTS;
1911 else if (stricmp(policy, "programs") == 0)
1913 retval = CSC_POLICY_PROGRAMS;
1915 else if (stricmp(policy, "disable") == 0)
1917 retval = CSC_POLICY_DISABLE;
1920 RegCloseKey(hkCSCPolicy);
1924 /* find a dir search structure by cookie value, and return it held.
1925 * Must be called with smb_globalLock held.
1927 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
1929 smb_dirSearch_t *dsp;
1931 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1932 if (dsp->cookie == cookie) {
1933 if (dsp != smb_firstDirSearchp) {
1934 /* move to head of LRU queue, too, if we're not already there */
1935 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1936 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
1937 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1938 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1939 if (!smb_lastDirSearchp)
1940 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1942 lock_ObtainMutex(&dsp->mx);
1944 lock_ReleaseMutex(&dsp->mx);
1950 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
1951 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1952 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
1958 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1960 lock_ObtainWrite(&smb_globalLock);
1961 lock_ObtainMutex(&dsp->mx);
1962 dsp->flags |= SMB_DIRSEARCH_DELETE;
1963 if (dsp->scp != NULL) {
1964 lock_ObtainMutex(&dsp->scp->mx);
1965 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1966 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1967 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1968 dsp->scp->bulkStatProgress = hzero;
1970 lock_ReleaseMutex(&dsp->scp->mx);
1972 lock_ReleaseMutex(&dsp->mx);
1973 lock_ReleaseWrite(&smb_globalLock);
1976 /* Must be called with the smb_globalLock held */
1977 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
1979 cm_scache_t *scp = NULL;
1981 lock_ObtainMutex(&dsp->mx);
1982 osi_assert(dsp->refCount-- > 0);
1983 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1984 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1985 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1986 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1987 lock_ReleaseMutex(&dsp->mx);
1988 lock_FinalizeMutex(&dsp->mx);
1992 lock_ReleaseMutex(&dsp->mx);
1994 /* do this now to avoid spurious locking hierarchy creation */
1996 cm_ReleaseSCache(scp);
1999 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
2001 lock_ObtainWrite(&smb_globalLock);
2002 smb_ReleaseDirSearchNoLock(dsp);
2003 lock_ReleaseWrite(&smb_globalLock);
2006 /* find a dir search structure by cookie value, and return it held */
2007 smb_dirSearch_t *smb_FindDirSearch(long cookie)
2009 smb_dirSearch_t *dsp;
2011 lock_ObtainWrite(&smb_globalLock);
2012 dsp = smb_FindDirSearchNoLock(cookie);
2013 lock_ReleaseWrite(&smb_globalLock);
2017 /* GC some dir search entries, in the address space expected by the specific protocol.
2018 * Must be called with smb_globalLock held; release the lock temporarily.
2020 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
2021 void smb_GCDirSearches(int isV3)
2023 smb_dirSearch_t *prevp;
2024 smb_dirSearch_t *tp;
2025 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
2029 victimCount = 0; /* how many have we got so far */
2030 for (tp = smb_lastDirSearchp; tp; tp=prevp) {
2031 /* we'll move tp from queue, so
2034 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
2035 /* if no one is using this guy, and we're either in the new protocol,
2036 * or we're in the old one and this is a small enough ID to be useful
2037 * to the old protocol, GC this guy.
2039 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
2040 /* hold and delete */
2041 lock_ObtainMutex(&tp->mx);
2042 tp->flags |= SMB_DIRSEARCH_DELETE;
2043 lock_ReleaseMutex(&tp->mx);
2044 victimsp[victimCount++] = tp;
2048 /* don't do more than this */
2049 if (victimCount >= SMB_DIRSEARCH_GCMAX)
2053 /* now release them */
2054 for (i = 0; i < victimCount; i++) {
2055 smb_ReleaseDirSearchNoLock(victimsp[i]);
2059 /* function for allocating a dir search entry. We need these to remember enough context
2060 * since we don't get passed the path from call to call during a directory search.
2062 * Returns a held dir search structure, and bumps the reference count on the vnode,
2063 * since it saves a pointer to the vnode.
2065 smb_dirSearch_t *smb_NewDirSearch(int isV3)
2067 smb_dirSearch_t *dsp;
2073 lock_ObtainWrite(&smb_globalLock);
2076 /* what's the biggest ID allowed in this version of the protocol */
2077 maxAllowed = isV3 ? 65535 : 255;
2078 if (smb_dirSearchCounter > maxAllowed)
2079 smb_dirSearchCounter = 1;
2081 start = smb_dirSearchCounter;
2084 /* twice so we have enough tries to find guys we GC after one pass;
2085 * 10 extra is just in case I mis-counted.
2087 if (++counter > 2*maxAllowed+10)
2088 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2090 if (smb_dirSearchCounter > maxAllowed) {
2091 smb_dirSearchCounter = 1;
2093 if (smb_dirSearchCounter == start) {
2095 smb_GCDirSearches(isV3);
2098 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2100 /* don't need to watch for refcount zero and deleted, since
2101 * we haven't dropped the global lock.
2103 lock_ObtainMutex(&dsp->mx);
2105 lock_ReleaseMutex(&dsp->mx);
2106 ++smb_dirSearchCounter;
2110 dsp = malloc(sizeof(*dsp));
2111 memset(dsp, 0, sizeof(*dsp));
2112 dsp->cookie = smb_dirSearchCounter;
2113 ++smb_dirSearchCounter;
2115 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
2116 dsp->lastTime = osi_Time();
2117 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2118 if (!smb_lastDirSearchp)
2119 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2122 lock_ReleaseWrite(&smb_globalLock);
2126 static smb_packet_t *GetPacket(void)
2130 unsigned int npar, seg, tb_sel;
2133 lock_ObtainWrite(&smb_globalLock);
2134 tbp = smb_packetFreeListp;
2136 smb_packetFreeListp = tbp->nextp;
2137 lock_ReleaseWrite(&smb_globalLock);
2140 tbp = calloc(65540,1);
2142 tbp = malloc(sizeof(smb_packet_t));
2144 tbp->magic = SMB_PACKETMAGIC;
2147 tbp->resumeCode = 0;
2153 tbp->ncb_length = 0;
2158 npar = SMB_PACKETSIZE >> 4; /* number of paragraphs */
2161 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
2163 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS memory",
2165 osi_panic("",__FILE__,__LINE__);
2168 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X",
2173 tbp->dos_pkt = (seg * 16) + 0; /* DOS physical address */
2174 tbp->dos_pkt_sel = tb_sel;
2177 osi_assert(tbp->magic == SMB_PACKETMAGIC);
2182 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2186 memcpy(tbp, pkt, sizeof(smb_packet_t));
2187 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2189 smb_HoldVC(tbp->vcp);
2193 static NCB *GetNCB(void)
2198 unsigned int npar, seg, tb_sel;
2201 lock_ObtainWrite(&smb_globalLock);
2202 tbp = smb_ncbFreeListp;
2204 smb_ncbFreeListp = tbp->nextp;
2205 lock_ReleaseWrite(&smb_globalLock);
2208 tbp = calloc(sizeof(*tbp),1);
2210 tbp = malloc(sizeof(*tbp));
2211 npar = (sizeof(NCB)+15) >> 4; /* number of paragraphs */
2214 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
2216 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS mem in GetNCB",
2218 osi_panic("",__FILE__,__LINE__);
2220 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
2225 tbp->dos_ncb = (seg * 16) + 0; /* DOS physical address */
2226 tbp->dos_ncb_sel = tb_sel;
2228 tbp->magic = SMB_NCBMAGIC;
2231 osi_assert(tbp->magic == SMB_NCBMAGIC);
2233 memset(&tbp->ncb, 0, sizeof(NCB));
2236 dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
2241 void smb_FreePacket(smb_packet_t *tbp)
2243 smb_vc_t * vcp = NULL;
2244 osi_assert(tbp->magic == SMB_PACKETMAGIC);
2246 lock_ObtainWrite(&smb_globalLock);
2247 tbp->nextp = smb_packetFreeListp;
2248 smb_packetFreeListp = tbp;
2249 tbp->magic = SMB_PACKETMAGIC;
2253 tbp->resumeCode = 0;
2259 tbp->ncb_length = 0;
2261 lock_ReleaseWrite(&smb_globalLock);
2267 static void FreeNCB(NCB *bufferp)
2271 tbp = (smb_ncb_t *) bufferp;
2272 osi_assert(tbp->magic == SMB_NCBMAGIC);
2274 lock_ObtainWrite(&smb_globalLock);
2275 tbp->nextp = smb_ncbFreeListp;
2276 smb_ncbFreeListp = tbp;
2277 lock_ReleaseWrite(&smb_globalLock);
2280 /* get a ptr to the data part of a packet, and its count */
2281 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2285 unsigned char *afterParmsp;
2287 parmBytes = *smbp->wctp << 1;
2288 afterParmsp = smbp->wctp + parmBytes + 1;
2290 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2291 if (nbytesp) *nbytesp = dataBytes;
2293 /* don't forget to skip the data byte count, since it follows
2294 * the parameters; that's where the "2" comes from below.
2296 return (unsigned char *) (afterParmsp + 2);
2299 /* must set all the returned parameters before playing around with the
2300 * data region, since the data region is located past the end of the
2301 * variable number of parameters.
2303 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2305 unsigned char *afterParmsp;
2307 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2309 *afterParmsp++ = dsize & 0xff;
2310 *afterParmsp = (dsize>>8) & 0xff;
2313 /* return the parm'th parameter in the smbp packet */
2314 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
2317 unsigned char *parmDatap;
2319 parmCount = *smbp->wctp;
2321 if (parm >= parmCount) {
2324 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2325 parm, parmCount, smbp->ncb_length);
2326 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2327 parm, parmCount, smbp->ncb_length);
2329 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2330 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2332 osi_panic(s, __FILE__, __LINE__);
2334 parmDatap = smbp->wctp + (2*parm) + 1;
2336 return parmDatap[0] + (parmDatap[1] << 8);
2339 /* return the parm'th parameter in the smbp packet */
2340 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2343 unsigned char *parmDatap;
2345 parmCount = *smbp->wctp;
2347 if (parm * 2 + offset >= parmCount * 2) {
2350 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2351 parm, offset, parmCount, smbp->ncb_length);
2353 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2354 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2356 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2357 parm, offset, parmCount, smbp->ncb_length);
2358 osi_panic(s, __FILE__, __LINE__);
2360 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2362 return parmDatap[0] + (parmDatap[1] << 8);
2365 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2369 /* make sure we have enough slots */
2370 if (*smbp->wctp <= slot)
2371 *smbp->wctp = slot+1;
2373 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2374 *parmDatap++ = parmValue & 0xff;
2375 *parmDatap = (parmValue>>8) & 0xff;
2378 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2382 /* make sure we have enough slots */
2383 if (*smbp->wctp <= slot)
2384 *smbp->wctp = slot+2;
2386 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2387 *parmDatap++ = parmValue & 0xff;
2388 *parmDatap++ = (parmValue>>8) & 0xff;
2389 *parmDatap++ = (parmValue>>16) & 0xff;
2390 *parmDatap++ = (parmValue>>24) & 0xff;
2393 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2398 /* make sure we have enough slots */
2399 if (*smbp->wctp <= slot)
2400 *smbp->wctp = slot+4;
2402 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2404 *parmDatap++ = *parmValuep++;
2407 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2411 /* make sure we have enough slots */
2412 if (*smbp->wctp <= slot) {
2413 if (smbp->oddByte) {
2415 *smbp->wctp = slot+1;
2420 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2421 *parmDatap++ = parmValue & 0xff;
2424 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2428 lastSlashp = strrchr(inPathp, '\\');
2430 *lastComponentp = lastSlashp;
2433 if (inPathp == lastSlashp)
2435 *outPathp++ = *inPathp++;
2444 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2449 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
2454 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2460 tlen = inp[0] + (inp[1]<<8);
2461 inp += 2; /* skip length field */
2464 *chainpp = inp + tlen;
2473 /* format a packet as a response */
2474 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2479 outp = (smb_t *) op;
2481 /* zero the basic structure through the smb_wct field, and zero the data
2482 * size field, assuming that wct stays zero; otherwise, you have to
2483 * explicitly set the data size field, too.
2485 inSmbp = (smb_t *) inp;
2486 memset(outp, 0, sizeof(smb_t)+2);
2492 outp->com = inSmbp->com;
2493 outp->tid = inSmbp->tid;
2494 outp->pid = inSmbp->pid;
2495 outp->uid = inSmbp->uid;
2496 outp->mid = inSmbp->mid;
2497 outp->res[0] = inSmbp->res[0];
2498 outp->res[1] = inSmbp->res[1];
2499 op->inCom = inSmbp->com;
2501 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
2502 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2504 /* copy fields in generic packet area */
2505 op->wctp = &outp->wct;
2508 /* send a (probably response) packet; vcp tells us to whom to send it.
2509 * we compute the length by looking at wct and bcc fields.
2511 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2528 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2531 memset((char *)ncbp, 0, sizeof(NCB));
2533 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2534 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2535 extra += tp[0] + (tp[1]<<8);
2536 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
2537 extra += 3; /* wct and length fields */
2539 ncbp->ncb_length = extra; /* bytes to send */
2540 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2541 ncbp->ncb_lana_num = vcp->lana;
2542 ncbp->ncb_command = NCBSEND; /* op means send data */
2544 ncbp->ncb_buffer = (char *) inp;/* packet */
2545 code = Netbios(ncbp);
2547 ncbp->ncb_buffer = inp->dos_pkt;/* packet */
2548 ((smb_ncb_t*)ncbp)->orig_pkt = inp;
2550 /* copy header information from virtual to DOS address space */
2551 dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
2552 code = Netbios(ncbp, dos_ncb);
2556 const char * s = ncb_error_string(code);
2557 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2559 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
2562 lock_ObtainMutex(&vcp->mx);
2563 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
2564 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
2566 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2567 lock_ReleaseMutex(&vcp->mx);
2568 lock_ObtainWrite(&smb_globalLock);
2569 dead_sessions[vcp->session] = TRUE;
2570 lock_ReleaseWrite(&smb_globalLock);
2571 smb_CleanupDeadVC(vcp);
2573 lock_ReleaseMutex(&vcp->mx);
2581 void smb_MapNTError(long code, unsigned long *NTStatusp)
2583 unsigned long NTStatus;
2585 /* map CM_ERROR_* errors to NT 32-bit status codes */
2586 /* NT Status codes are listed in ntstatus.h not winerror.h */
2587 if (code == CM_ERROR_NOSUCHCELL) {
2588 NTStatus = 0xC000000FL; /* No such file */
2590 else if (code == CM_ERROR_NOSUCHVOLUME) {
2591 NTStatus = 0xC000000FL; /* No such file */
2593 else if (code == CM_ERROR_TIMEDOUT) {
2595 NTStatus = 0xC00000CFL; /* Sharing Paused */
2597 NTStatus = 0x00000102L; /* Timeout */
2600 else if (code == CM_ERROR_RETRY) {
2601 NTStatus = 0xC000022DL; /* Retry */
2603 else if (code == CM_ERROR_NOACCESS) {
2604 NTStatus = 0xC0000022L; /* Access denied */
2606 else if (code == CM_ERROR_READONLY) {
2607 NTStatus = 0xC00000A2L; /* Write protected */
2609 else if (code == CM_ERROR_NOSUCHFILE) {
2610 NTStatus = 0xC000000FL; /* No such file */
2612 else if (code == CM_ERROR_NOSUCHPATH) {
2613 NTStatus = 0xC000003AL; /* Object path not found */
2615 else if (code == CM_ERROR_TOOBIG) {
2616 NTStatus = 0xC000007BL; /* Invalid image format */
2618 else if (code == CM_ERROR_INVAL) {
2619 NTStatus = 0xC000000DL; /* Invalid parameter */
2621 else if (code == CM_ERROR_BADFD) {
2622 NTStatus = 0xC0000008L; /* Invalid handle */
2624 else if (code == CM_ERROR_BADFDOP) {
2625 NTStatus = 0xC0000022L; /* Access denied */
2627 else if (code == CM_ERROR_EXISTS) {
2628 NTStatus = 0xC0000035L; /* Object name collision */
2630 else if (code == CM_ERROR_NOTEMPTY) {
2631 NTStatus = 0xC0000101L; /* Directory not empty */
2633 else if (code == CM_ERROR_CROSSDEVLINK) {
2634 NTStatus = 0xC00000D4L; /* Not same device */
2636 else if (code == CM_ERROR_NOTDIR) {
2637 NTStatus = 0xC0000103L; /* Not a directory */
2639 else if (code == CM_ERROR_ISDIR) {
2640 NTStatus = 0xC00000BAL; /* File is a directory */
2642 else if (code == CM_ERROR_BADOP) {
2644 /* I have no idea where this comes from */
2645 NTStatus = 0xC09820FFL; /* SMB no support */
2647 NTStatus = 0xC00000BBL; /* Not supported */
2648 #endif /* COMMENT */
2650 else if (code == CM_ERROR_BADSHARENAME) {
2651 NTStatus = 0xC00000CCL; /* Bad network name */
2653 else if (code == CM_ERROR_NOIPC) {
2655 NTStatus = 0xC0000022L; /* Access Denied */
2657 NTStatus = 0xC000013DL; /* Remote Resources */
2660 else if (code == CM_ERROR_CLOCKSKEW) {
2661 NTStatus = 0xC0000133L; /* Time difference at DC */
2663 else if (code == CM_ERROR_BADTID) {
2664 NTStatus = 0xC0982005L; /* SMB bad TID */
2666 else if (code == CM_ERROR_USESTD) {
2667 NTStatus = 0xC09820FBL; /* SMB use standard */
2669 else if (code == CM_ERROR_QUOTA) {
2671 NTStatus = 0xC0000044L; /* Quota exceeded */
2673 NTStatus = 0xC000007FL; /* Disk full */
2676 else if (code == CM_ERROR_SPACE) {
2677 NTStatus = 0xC000007FL; /* Disk full */
2679 else if (code == CM_ERROR_ATSYS) {
2680 NTStatus = 0xC0000033L; /* Object name invalid */
2682 else if (code == CM_ERROR_BADNTFILENAME) {
2683 NTStatus = 0xC0000033L; /* Object name invalid */
2685 else if (code == CM_ERROR_WOULDBLOCK) {
2686 NTStatus = 0xC0000055L; /* Lock not granted */
2688 else if (code == CM_ERROR_SHARING_VIOLATION) {
2689 NTStatus = 0xC0000043L; /* Sharing violation */
2691 else if (code == CM_ERROR_LOCK_CONFLICT) {
2692 NTStatus = 0xC0000054L; /* Lock conflict */
2694 else if (code == CM_ERROR_PARTIALWRITE) {
2695 NTStatus = 0xC000007FL; /* Disk full */
2697 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2698 NTStatus = 0xC0000023L; /* Buffer too small */
2700 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2701 NTStatus = 0xC0000035L; /* Object name collision */
2703 else if (code == CM_ERROR_BADPASSWORD) {
2704 NTStatus = 0xC000006DL; /* unknown username or bad password */
2706 else if (code == CM_ERROR_BADLOGONTYPE) {
2707 NTStatus = 0xC000015BL; /* logon type not granted */
2709 else if (code == CM_ERROR_GSSCONTINUE) {
2710 NTStatus = 0xC0000016L; /* more processing required */
2712 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2714 NTStatus = 0xC0000280L; /* reparse point not resolved */
2716 NTStatus = 0xC0000022L; /* Access Denied */
2719 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2720 NTStatus = 0xC0000257L; /* Path Not Covered */
2723 else if (code == CM_ERROR_ALLBUSY) {
2724 NTStatus = 0xC00000BFL; /* Network Busy */
2726 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
2727 NTStatus = 0xC0000350L; /* Remote Host Down */
2730 /* we do not want to be telling the SMB/CIFS client that
2731 * the AFS Client Service is busy or down.
2733 else if (code == CM_ERROR_ALLBUSY ||
2734 code == CM_ERROR_ALLOFFLINE ||
2735 code == CM_ERROR_ALLDOWN) {
2736 NTStatus = 0xC00000BEL; /* Bad Network Path */
2739 else if (code == RXKADUNKNOWNKEY) {
2740 NTStatus = 0xC0000322L; /* Bad Kerberos key */
2742 NTStatus = 0xC0982001L; /* SMB non-specific error */
2745 *NTStatusp = NTStatus;
2746 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2749 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2750 unsigned char *classp)
2752 unsigned char class;
2753 unsigned short error;
2755 /* map CM_ERROR_* errors to SMB errors */
2756 if (code == CM_ERROR_NOSUCHCELL) {
2758 error = 3; /* bad path */
2760 else if (code == CM_ERROR_NOSUCHVOLUME) {
2762 error = 3; /* bad path */
2764 else if (code == CM_ERROR_TIMEDOUT) {
2766 error = 81; /* server is paused */
2768 else if (code == CM_ERROR_RETRY) {
2769 class = 2; /* shouldn't happen */
2772 else if (code == CM_ERROR_NOACCESS) {
2774 error = 4; /* bad access */
2776 else if (code == CM_ERROR_READONLY) {
2778 error = 19; /* read only */
2780 else if (code == CM_ERROR_NOSUCHFILE) {
2782 error = 2; /* ENOENT! */
2784 else if (code == CM_ERROR_NOSUCHPATH) {
2786 error = 3; /* Bad path */
2788 else if (code == CM_ERROR_TOOBIG) {
2790 error = 11; /* bad format */
2792 else if (code == CM_ERROR_INVAL) {
2793 class = 2; /* server non-specific error code */
2796 else if (code == CM_ERROR_BADFD) {
2798 error = 6; /* invalid file handle */
2800 else if (code == CM_ERROR_BADFDOP) {
2801 class = 1; /* invalid op on FD */
2804 else if (code == CM_ERROR_EXISTS) {
2806 error = 80; /* file already exists */
2808 else if (code == CM_ERROR_NOTEMPTY) {
2810 error = 5; /* delete directory not empty */
2812 else if (code == CM_ERROR_CROSSDEVLINK) {
2814 error = 17; /* EXDEV */
2816 else if (code == CM_ERROR_NOTDIR) {
2817 class = 1; /* bad path */
2820 else if (code == CM_ERROR_ISDIR) {
2821 class = 1; /* access denied; DOS doesn't have a good match */
2824 else if (code == CM_ERROR_BADOP) {
2828 else if (code == CM_ERROR_BADSHARENAME) {
2832 else if (code == CM_ERROR_NOIPC) {
2834 error = 4; /* bad access */
2836 else if (code == CM_ERROR_CLOCKSKEW) {
2837 class = 1; /* invalid function */
2840 else if (code == CM_ERROR_BADTID) {
2844 else if (code == CM_ERROR_USESTD) {
2848 else if (code == CM_ERROR_REMOTECONN) {
2852 else if (code == CM_ERROR_QUOTA) {
2853 if (vcp->flags & SMB_VCFLAG_USEV3) {
2855 error = 39; /* disk full */
2859 error = 5; /* access denied */
2862 else if (code == CM_ERROR_SPACE) {
2863 if (vcp->flags & SMB_VCFLAG_USEV3) {
2865 error = 39; /* disk full */
2869 error = 5; /* access denied */
2872 else if (code == CM_ERROR_PARTIALWRITE) {
2874 error = 39; /* disk full */
2876 else if (code == CM_ERROR_ATSYS) {
2878 error = 2; /* ENOENT */
2880 else if (code == CM_ERROR_WOULDBLOCK) {
2882 error = 33; /* lock conflict */
2884 else if (code == CM_ERROR_LOCK_CONFLICT) {
2886 error = 33; /* lock conflict */
2888 else if (code == CM_ERROR_SHARING_VIOLATION) {
2890 error = 33; /* lock conflict */
2892 else if (code == CM_ERROR_NOFILES) {
2894 error = 18; /* no files in search */
2896 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2898 error = 183; /* Samba uses this */
2900 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2901 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2903 error = 2; /* bad password */
2905 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2907 error = 3; /* bad path */
2916 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2919 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2921 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2922 return CM_ERROR_BADOP;
2925 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2927 unsigned short EchoCount, i;
2928 char *data, *outdata;
2931 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2933 for (i=1; i<=EchoCount; i++) {
2934 data = smb_GetSMBData(inp, &dataSize);
2935 smb_SetSMBParm(outp, 0, i);
2936 smb_SetSMBDataLength(outp, dataSize);
2937 outdata = smb_GetSMBData(outp, NULL);
2938 memcpy(outdata, data, dataSize);
2939 smb_SendPacket(vcp, outp);
2945 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2948 long count, minCount, finalCount;
2953 cm_user_t *userp = NULL;
2957 char *rawBuf = NULL;
2959 dos_ptr rawBuf = NULL;
2966 fd = smb_GetSMBParm(inp, 0);
2967 count = smb_GetSMBParm(inp, 3);
2968 minCount = smb_GetSMBParm(inp, 4);
2969 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2971 if (*inp->wctp == 10) {
2972 /* we were sent a request with 64-bit file offsets */
2973 #ifdef AFS_LARGEFILES
2974 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
2976 if (LargeIntegerLessThanZero(offset)) {
2977 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
2981 if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
2982 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset. Dropping request.");
2985 offset.HighPart = 0;
2989 /* we were sent a request with 32-bit file offsets */
2990 offset.HighPart = 0;
2993 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
2994 fd, offset.HighPart, offset.LowPart, count);
2996 fidp = smb_FindFID(vcp, fd, 0);
3000 pid = ((smb_t *) inp)->pid;
3002 LARGE_INTEGER LOffset, LLength;
3005 key = cm_GenerateKey(vcp->vcID, pid, fd);
3007 LOffset.HighPart = offset.HighPart;
3008 LOffset.LowPart = offset.LowPart;
3009 LLength.HighPart = 0;
3010 LLength.LowPart = count;
3012 lock_ObtainMutex(&fidp->scp->mx);
3013 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
3014 lock_ReleaseMutex(&fidp->scp->mx);
3020 lock_ObtainMutex(&smb_RawBufLock);
3022 /* Get a raw buf, from head of list */
3023 rawBuf = smb_RawBufs;
3025 smb_RawBufs = *(char **)smb_RawBufs;
3027 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
3030 lock_ReleaseMutex(&smb_RawBufLock);
3034 lock_ObtainMutex(&fidp->mx);
3035 if (fidp->flags & SMB_FID_IOCTL)
3037 lock_ReleaseMutex(&fidp->mx);
3039 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
3041 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
3044 /* Give back raw buffer */
3045 lock_ObtainMutex(&smb_RawBufLock);
3047 *((char **) rawBuf) = smb_RawBufs;
3049 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
3052 smb_RawBufs = rawBuf;
3053 lock_ReleaseMutex(&smb_RawBufLock);
3056 smb_ReleaseFID(fidp);
3059 lock_ReleaseMutex(&fidp->mx);
3061 userp = smb_GetUserFromVCP(vcp, inp);
3064 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
3066 /* have to give ReadData flag so it will treat buffer as DOS mem. */
3067 code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
3068 userp, &finalCount, TRUE /* rawFlag */);
3075 cm_ReleaseUser(userp);
3078 smb_ReleaseFID(fidp);
3083 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
3085 memset((char *)ncbp, 0, sizeof(NCB));
3087 ncbp->ncb_length = (unsigned short) finalCount;
3088 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
3089 ncbp->ncb_lana_num = vcp->lana;
3090 ncbp->ncb_command = NCBSEND;
3091 ncbp->ncb_buffer = rawBuf;
3094 code = Netbios(ncbp);
3096 code = Netbios(ncbp, dos_ncb);
3099 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
3102 /* Give back raw buffer */
3103 lock_ObtainMutex(&smb_RawBufLock);
3105 *((char **) rawBuf) = smb_RawBufs;
3107 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
3110 smb_RawBufs = rawBuf;
3111 lock_ReleaseMutex(&smb_RawBufLock);
3117 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3119 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3124 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3126 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3131 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3138 int protoIndex; /* index we're using */
3143 char protocol_array[10][1024]; /* protocol signature of the client */
3144 int caps; /* capabilities */
3147 TIME_ZONE_INFORMATION tzi;
3149 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3152 namep = smb_GetSMBData(inp, &dbytes);
3155 coreProtoIndex = -1; /* not found */
3158 while(namex < dbytes) {
3159 osi_Log1(smb_logp, "Protocol %s",
3160 osi_LogSaveString(smb_logp, namep+1));
3161 strcpy(protocol_array[tcounter], namep+1);
3163 /* namep points at the first protocol, or really, a 0x02
3164 * byte preceding the null-terminated ASCII name.
3166 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3167 coreProtoIndex = tcounter;
3169 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3170 v3ProtoIndex = tcounter;
3172 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3173 NTProtoIndex = tcounter;
3176 /* compute size of protocol entry */
3177 entryLength = (int)strlen(namep+1);
3178 entryLength += 2; /* 0x02 bytes and null termination */
3180 /* advance over this protocol entry */
3181 namex += entryLength;
3182 namep += entryLength;
3183 tcounter++; /* which proto entry we're looking at */
3186 lock_ObtainMutex(&vcp->mx);
3187 if (NTProtoIndex != -1) {
3188 protoIndex = NTProtoIndex;
3189 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3191 else if (v3ProtoIndex != -1) {
3192 protoIndex = v3ProtoIndex;
3193 vcp->flags |= SMB_VCFLAG_USEV3;
3195 else if (coreProtoIndex != -1) {
3196 protoIndex = coreProtoIndex;
3197 vcp->flags |= SMB_VCFLAG_USECORE;
3199 else protoIndex = -1;
3200 lock_ReleaseMutex(&vcp->mx);
3202 if (protoIndex == -1)
3203 return CM_ERROR_INVAL;
3204 else if (NTProtoIndex != -1) {
3205 smb_SetSMBParm(outp, 0, protoIndex);
3206 if (smb_authType != SMB_AUTH_NONE) {
3207 smb_SetSMBParmByte(outp, 1,
3208 NEGOTIATE_SECURITY_USER_LEVEL |
3209 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3211 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3213 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3214 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3215 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3216 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3217 /* The session key is not a well documented field however most clients
3218 * will echo back the session key to the server. Currently we are using
3219 * the same value for all sessions. We should generate a random value
3220 * and store it into the vcp
3222 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3223 smb_SetSMBParm(outp, 8, 1);
3225 * Tried changing the capabilities to support for W2K - defect 117695
3226 * Maybe something else needs to be changed here?
3230 smb_SetSMBParmLong(outp, 9, 0x43fd);
3232 smb_SetSMBParmLong(outp, 9, 0x251);
3235 * 32-bit error codes *
3240 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3242 NTNEGOTIATE_CAPABILITY_DFS |
3244 #ifdef AFS_LARGEFILES
3245 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3247 NTNEGOTIATE_CAPABILITY_NTFIND |
3248 NTNEGOTIATE_CAPABILITY_RAWMODE |
3249 NTNEGOTIATE_CAPABILITY_NTSMB;
3251 if ( smb_authType == SMB_AUTH_EXTENDED )
3252 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3254 smb_SetSMBParmLong(outp, 9, caps);
3256 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3257 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3258 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3260 GetTimeZoneInformation(&tzi);
3261 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3263 if (smb_authType == SMB_AUTH_NTLM) {
3264 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3265 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3266 /* paste in encryption key */
3267 datap = smb_GetSMBData(outp, NULL);
3268 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3269 /* and the faux domain name */
3270 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
3271 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3275 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3277 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3279 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3281 datap = smb_GetSMBData(outp, NULL);
3282 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3285 datap += sizeof(smb_ServerGUID);
3286 memcpy(datap, secBlob, secBlobLength);
3290 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3291 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3294 else if (v3ProtoIndex != -1) {
3295 smb_SetSMBParm(outp, 0, protoIndex);
3297 /* NOTE: Extended authentication cannot be negotiated with v3
3298 * therefore we fail over to NTLM
3300 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3301 smb_SetSMBParm(outp, 1,
3302 NEGOTIATE_SECURITY_USER_LEVEL |
3303 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3305 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3307 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3308 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3309 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3310 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3311 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3312 smb_SetSMBParm(outp, 7, 1);
3314 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3315 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3316 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3318 GetTimeZoneInformation(&tzi);
3319 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3321 /* NOTE: Extended authentication cannot be negotiated with v3
3322 * therefore we fail over to NTLM
3324 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3325 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3326 smb_SetSMBParm(outp, 12, 0); /* resvd */
3327 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3328 datap = smb_GetSMBData(outp, NULL);
3329 /* paste in a new encryption key */
3330 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3331 /* and the faux domain name */
3332 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
3334 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3335 smb_SetSMBParm(outp, 12, 0); /* resvd */
3336 smb_SetSMBDataLength(outp, 0);
3339 else if (coreProtoIndex != -1) { /* not really supported anymore */
3340 smb_SetSMBParm(outp, 0, protoIndex);
3341 smb_SetSMBDataLength(outp, 0);
3346 void smb_CheckVCs(void)
3348 smb_vc_t * vcp, *nextp;
3349 smb_packet_t * outp = GetPacket();
3352 lock_ObtainWrite(&smb_rctLock);
3353 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
3355 if (vcp->magic != SMB_VC_MAGIC)
3356 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
3357 __FILE__, __LINE__);
3361 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD)
3364 smb_HoldVCNoLock(vcp);
3366 smb_HoldVCNoLock(nextp);
3367 smb_FormatResponsePacket(vcp, NULL, outp);
3368 smbp = (smb_t *)outp;
3369 outp->inCom = smbp->com = 0x2b /* Echo */;
3377 smb_SetSMBParm(outp, 0, 0);
3378 smb_SetSMBDataLength(outp, 0);
3379 lock_ReleaseWrite(&smb_rctLock);
3381 smb_SendPacket(vcp, outp);
3383 lock_ObtainWrite(&smb_rctLock);
3384 smb_ReleaseVCNoLock(vcp);
3386 smb_ReleaseVCNoLock(nextp);
3388 lock_ReleaseWrite(&smb_rctLock);
3389 smb_FreePacket(outp);
3392 void smb_Daemon(void *parmp)
3394 afs_uint32 count = 0;
3395 smb_username_t **unpp;
3398 while(smbShutdownFlag == 0) {
3402 if (smbShutdownFlag == 1)
3405 if ((count % 72) == 0) { /* every five minutes */
3407 time_t old_localZero = smb_localZero;
3409 /* Initialize smb_localZero */
3410 myTime.tm_isdst = -1; /* compute whether on DST or not */
3411 myTime.tm_year = 70;
3417 smb_localZero = mktime(&myTime);
3419 #ifndef USE_NUMERIC_TIME_CONV
3420 smb_CalculateNowTZ();
3421 #endif /* USE_NUMERIC_TIME_CONV */
3422 #ifdef AFS_FREELANCE
3423 if ( smb_localZero != old_localZero )
3424 cm_noteLocalMountPointChange();
3430 /* GC smb_username_t objects that will no longer be used */
3432 lock_ObtainWrite(&smb_rctLock);
3433 for ( unpp=&usernamesp; *unpp; ) {
3435 smb_username_t *unp;
3437 lock_ObtainMutex(&(*unpp)->mx);
3438 if ( (*unpp)->refCount > 0 ||
3439 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
3440 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
3442 else if (!smb_LogoffTokenTransfer ||
3443 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
3445 lock_ReleaseMutex(&(*unpp)->mx);
3453 lock_FinalizeMutex(&unp->mx);
3459 lock_ReleaseWrite(&smb_rctLock);
3460 cm_ReleaseUser(userp);
3461 lock_ObtainWrite(&smb_rctLock);
3464 unpp = &(*unpp)->nextp;
3467 lock_ReleaseWrite(&smb_rctLock);
3469 /* XXX GC dir search entries */
3473 void smb_WaitingLocksDaemon()
3475 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3476 smb_waitingLock_t *wl, *wlNext;
3479 smb_packet_t *inp, *outp;
3483 while (smbShutdownFlag == 0) {
3484 lock_ObtainWrite(&smb_globalLock);
3485 nwlRequest = smb_allWaitingLocks;
3486 if (nwlRequest == NULL) {
3487 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
3492 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
3499 lock_ObtainWrite(&smb_globalLock);
3501 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
3503 wlRequest = nwlRequest;
3504 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3505 lock_ReleaseWrite(&smb_globalLock);
3509 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3510 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3513 osi_assert(wl->state != SMB_WAITINGLOCKSTATE_ERROR);
3515 /* wl->state is either _DONE or _WAITING. _ERROR
3516 would no longer be on the queue. */
3517 code = cm_RetryLock( wl->lockp,
3518 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3521 wl->state = SMB_WAITINGLOCKSTATE_DONE;
3522 } else if (code != CM_ERROR_WOULDBLOCK) {
3523 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3528 if (code == CM_ERROR_WOULDBLOCK) {
3531 if (wlRequest->timeRemaining != 0xffffffff
3532 && (wlRequest->timeRemaining -= 1000) < 0)
3544 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
3547 scp = wlRequest->scp;
3551 lock_ObtainMutex(&scp->mx);
3553 for (wl = wlRequest->locks; wl; wl = wlNext) {
3554 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3556 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
3557 wl->LLength, wl->key, NULL, &req);
3559 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3564 lock_ReleaseMutex(&scp->mx);
3568 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
3571 for (wl = wlRequest->locks; wl; wl = wlNext) {
3572 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3573 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3578 vcp = wlRequest->vcp;
3579 inp = wlRequest->inp;
3580 outp = wlRequest->outp;
3582 ncbp->ncb_length = inp->ncb_length;
3583 inp->spacep = cm_GetSpace();
3585 /* Remove waitingLock from list */
3586 lock_ObtainWrite(&smb_globalLock);
3587 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3589 lock_ReleaseWrite(&smb_globalLock);
3591 /* Resume packet processing */
3593 smb_SetSMBDataLength(outp, 0);
3594 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3595 outp->resumeCode = code;
3597 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3600 cm_FreeSpace(inp->spacep);
3601 smb_FreePacket(inp);
3602 smb_FreePacket(outp);
3604 cm_ReleaseSCache(wlRequest->scp);
3607 } while (nwlRequest && smbShutdownFlag == 0);
3612 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3614 osi_Log0(smb_logp, "SMB receive get disk attributes");
3616 smb_SetSMBParm(outp, 0, 32000);
3617 smb_SetSMBParm(outp, 1, 64);
3618 smb_SetSMBParm(outp, 2, 1024);
3619 smb_SetSMBParm(outp, 3, 30000);
3620 smb_SetSMBParm(outp, 4, 0);
3621 smb_SetSMBDataLength(outp, 0);
3625 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3629 unsigned short newTid;
3630 char shareName[256];
3638 osi_Log0(smb_logp, "SMB receive tree connect");
3640 /* parse input parameters */
3641 tp = smb_GetSMBData(inp, NULL);
3642 pathp = smb_ParseASCIIBlock(tp, &tp);
3643 if (smb_StoreAnsiFilenames)
3644 OemToChar(pathp,pathp);
3645 passwordp = smb_ParseASCIIBlock(tp, &tp);
3646 tp = strrchr(pathp, '\\');
3648 return CM_ERROR_BADSMB;
3649 strcpy(shareName, tp+1);
3651 lock_ObtainMutex(&vcp->mx);
3652 newTid = vcp->tidCounter++;
3653 lock_ReleaseMutex(&vcp->mx);
3655 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3656 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3657 userp = smb_GetUserFromUID(uidp);
3658 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3660 smb_ReleaseUID(uidp);
3662 smb_ReleaseTID(tidp);
3663 return CM_ERROR_BADSHARENAME;
3665 lock_ObtainMutex(&tidp->mx);
3666 tidp->userp = userp;
3667 tidp->pathname = sharePath;
3668 lock_ReleaseMutex(&tidp->mx);
3669 smb_ReleaseTID(tidp);
3671 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3672 smb_SetSMBParm(rsp, 1, newTid);
3673 smb_SetSMBDataLength(rsp, 0);
3675 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3679 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3683 if (*inp++ != 0x1) return NULL;
3684 tlen = inp[0] + (inp[1]<<8);
3685 inp += 2; /* skip length field */
3688 *chainpp = inp + tlen;
3691 if (lengthp) *lengthp = tlen;
3696 /* set maskp to the mask part of the incoming path.
3697 * Mask is 11 bytes long (8.3 with the dot elided).
3698 * Returns true if succeeds with a valid name, otherwise it does
3699 * its best, but returns false.
3701 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3709 /* starts off valid */
3712 /* mask starts out all blanks */
3713 memset(maskp, ' ', 11);
3715 /* find last backslash, or use whole thing if there is none */
3716 tp = strrchr(pathp, '\\');
3717 if (!tp) tp = pathp;
3718 else tp++; /* skip slash */
3722 /* names starting with a dot are illegal */
3723 if (*tp == '.') valid8Dot3 = 0;
3727 if (tc == 0) return valid8Dot3;
3728 if (tc == '.' || tc == '"') break;
3729 if (i < 8) *up++ = tc;
3730 else valid8Dot3 = 0;
3733 /* if we get here, tp point after the dot */
3734 up = maskp+8; /* ext goes here */
3741 if (tc == '.' || tc == '"')
3744 /* copy extension if not too long */
3754 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3764 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3766 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3770 /* otherwise, we have a valid 8.3 name; see if we have a match,
3771 * treating '?' as a wildcard in maskp (but not in the file name).
3773 tp1 = umask; /* real name, in mask format */
3774 tp2 = maskp; /* mask, in mask format */
3775 for(i=0; i<11; i++) {
3776 tc1 = *tp1++; /* char from real name */
3777 tc2 = *tp2++; /* char from mask */
3778 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3779 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3782 if (tc2 == '?' && tc1 != ' ')
3789 /* we got a match */
3793 char *smb_FindMask(char *pathp)
3797 tp = strrchr(pathp, '\\'); /* find last slash */
3800 return tp+1; /* skip the slash */
3802 return pathp; /* no slash, return the entire path */
3805 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3807 unsigned char *pathp;
3809 unsigned char mask[11];
3810 unsigned char *statBlockp;
3811 unsigned char initStatBlock[21];
3814 osi_Log0(smb_logp, "SMB receive search volume");
3816 /* pull pathname and stat block out of request */
3817 tp = smb_GetSMBData(inp, NULL);
3818 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3819 osi_assert(pathp != NULL);
3820 if (smb_StoreAnsiFilenames)
3821 OemToChar(pathp,pathp);
3822 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3823 osi_assert(statBlockp != NULL);
3825 statBlockp = initStatBlock;
3829 /* for returning to caller */
3830 smb_Get8Dot3MaskFromPath(mask, pathp);
3832 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3833 tp = smb_GetSMBData(outp, NULL);
3835 *tp++ = 43; /* bytes in a dir entry */
3836 *tp++ = 0; /* high byte in counter */
3838 /* now marshall the dir entry, starting with the search status */
3839 *tp++ = statBlockp[0]; /* Reserved */
3840 memcpy(tp, mask, 11); tp += 11; /* FileName */
3842 /* now pass back server use info, with 1st byte non-zero */
3844 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3846 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3848 *tp++ = 0x8; /* attribute: volume */
3858 /* 4 byte file size */
3864 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3865 memset(tp, ' ', 13);
3868 /* set the length of the data part of the packet to 43 + 3, for the dir
3869 * entry plus the 5 and the length fields.
3871 smb_SetSMBDataLength(outp, 46);
3875 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3876 cm_user_t *userp, cm_req_t *reqp)
3884 smb_dirListPatch_t *patchp;
3885 smb_dirListPatch_t *npatchp;
3887 for (patchp = *dirPatchespp; patchp; patchp =
3888 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3890 dptr = patchp->dptr;
3892 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3894 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3895 *dptr++ = SMB_ATTR_HIDDEN;
3898 lock_ObtainMutex(&scp->mx);
3899 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3900 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3902 lock_ReleaseMutex(&scp->mx);
3903 cm_ReleaseSCache(scp);
3904 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3905 *dptr++ = SMB_ATTR_HIDDEN;
3909 attr = smb_Attributes(scp);
3910 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3911 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3912 attr |= SMB_ATTR_HIDDEN;
3916 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3919 shortTemp = (unsigned short) (dosTime & 0xffff);
3920 *((u_short *)dptr) = shortTemp;
3923 /* and copy out date */
3924 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3925 *((u_short *)dptr) = shortTemp;
3928 /* copy out file length */
3929 *((u_long *)dptr) = scp->length.LowPart;
3931 lock_ReleaseMutex(&scp->mx);
3932 cm_ReleaseSCache(scp);
3935 /* now free the patches */
3936 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3937 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3941 /* and mark the list as empty */
3942 *dirPatchespp = NULL;
3947 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3956 smb_dirListPatch_t *dirListPatchesp;
3957 smb_dirListPatch_t *curPatchp;
3961 osi_hyper_t dirLength;
3962 osi_hyper_t bufferOffset;
3963 osi_hyper_t curOffset;
3965 unsigned char *inCookiep;
3966 smb_dirSearch_t *dsp;
3970 unsigned long clientCookie;
3971 cm_pageHeader_t *pageHeaderp;
3972 cm_user_t *userp = NULL;
3979 long nextEntryCookie;
3980 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3981 char resByte; /* reserved byte from the cookie */
3982 char *op; /* output data ptr */
3983 char *origOp; /* original value of op */
3984 cm_space_t *spacep; /* for pathname buffer */
3995 maxCount = smb_GetSMBParm(inp, 0);
3997 dirListPatchesp = NULL;
3999 caseFold = CM_FLAG_CASEFOLD;
4001 tp = smb_GetSMBData(inp, NULL);
4002 pathp = smb_ParseASCIIBlock(tp, &tp);
4003 if (smb_StoreAnsiFilenames)
4004 OemToChar(pathp,pathp);
4005 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
4007 /* bail out if request looks bad */
4008 if (!tp || !pathp) {
4009 return CM_ERROR_BADSMB;
4012 /* We can handle long names */
4013 if (vcp->flags & SMB_VCFLAG_USENT)
4014 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
4016 /* make sure we got a whole search status */
4017 if (dataLength < 21) {
4018 nextCookie = 0; /* start at the beginning of the dir */
4021 attribute = smb_GetSMBParm(inp, 1);
4023 /* handle volume info in another function */
4024 if (attribute & 0x8)
4025 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
4027 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
4028 maxCount, osi_LogSaveString(smb_logp, pathp));
4030 if (*pathp == 0) { /* null pathp, treat as root dir */
4031 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
4032 return CM_ERROR_NOFILES;
4036 dsp = smb_NewDirSearch(0);
4037 dsp->attribute = attribute;
4038 smb_Get8Dot3MaskFromPath(mask, pathp);
4039 memcpy(dsp->mask, mask, 11);
4041 /* track if this is likely to match a lot of entries */
4042 if (smb_IsStarMask(mask))
4047 /* pull the next cookie value out of the search status block */
4048 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
4049 + (inCookiep[16]<<24);
4050 dsp = smb_FindDirSearch(inCookiep[12]);
4052 /* can't find dir search status; fatal error */
4053 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%s]",
4054 inCookiep[12], nextCookie, osi_LogSaveString(smb_logp, pathp));
4055 return CM_ERROR_BADFD;
4057 attribute = dsp->attribute;
4058 resByte = inCookiep[0];
4060 /* copy out client cookie, in host byte order. Don't bother
4061 * interpreting it, since we're just passing it through, anyway.
4063 memcpy(&clientCookie, &inCookiep[17], 4);
4065 memcpy(mask, dsp->mask, 11);
4067 /* assume we're doing a star match if it has continued for more
4073 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
4074 nextCookie, dsp->cookie, attribute);
4076 userp = smb_GetUserFromVCP(vcp, inp);
4078 /* try to get the vnode for the path name next */
4079 lock_ObtainMutex(&dsp->mx);
4085 spacep = inp->spacep;
4086 smb_StripLastComponent(spacep->data, NULL, pathp);
4087 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4089 lock_ReleaseMutex(&dsp->mx);
4090 cm_ReleaseUser(userp);
4091 smb_DeleteDirSearch(dsp);
4092 smb_ReleaseDirSearch(dsp);
4093 return CM_ERROR_NOFILES;
4095 code = cm_NameI(cm_data.rootSCachep, spacep->data,
4096 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
4099 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4100 cm_ReleaseSCache(scp);
4101 lock_ReleaseMutex(&dsp->mx);
4102 cm_ReleaseUser(userp);
4103 smb_DeleteDirSearch(dsp);
4104 smb_ReleaseDirSearch(dsp);
4105 if ( WANTS_DFS_PATHNAMES(inp) )
4106 return CM_ERROR_PATH_NOT_COVERED;
4108 return CM_ERROR_BADSHARENAME;
4110 #endif /* DFS_SUPPORT */
4113 /* we need one hold for the entry we just stored into,
4114 * and one for our own processing. When we're done with this
4115 * function, we'll drop the one for our own processing.
4116 * We held it once from the namei call, and so we do another hold
4120 lock_ObtainMutex(&scp->mx);
4121 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
4122 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
4123 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
4124 dsp->flags |= SMB_DIRSEARCH_BULKST;
4125 dsp->scp->bulkStatProgress = hzero;
4127 lock_ReleaseMutex(&scp->mx);
4130 lock_ReleaseMutex(&dsp->mx);
4132 cm_ReleaseUser(userp);
4133 smb_DeleteDirSearch(dsp);
4134 smb_ReleaseDirSearch(dsp);
4138 /* reserves space for parameter; we'll adjust it again later to the
4139 * real count of the # of entries we returned once we've actually
4140 * assembled the directory listing.
4142 smb_SetSMBParm(outp, 0, 0);
4144 /* get the directory size */
4145 lock_ObtainMutex(&scp->mx);
4146 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4147 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4149 lock_ReleaseMutex(&scp->mx);
4150 cm_ReleaseSCache(scp);
4151 cm_ReleaseUser(userp);
4152 smb_DeleteDirSearch(dsp);
4153 smb_ReleaseDirSearch(dsp);
4157 dirLength = scp->length;
4159 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4160 curOffset.HighPart = 0;
4161 curOffset.LowPart = nextCookie;
4162 origOp = op = smb_GetSMBData(outp, NULL);
4163 /* and write out the basic header */
4164 *op++ = 5; /* variable block */
4165 op += 2; /* skip vbl block length; we'll fill it in later */
4169 /* make sure that curOffset.LowPart doesn't point to the first
4170 * 32 bytes in the 2nd through last dir page, and that it doesn't
4171 * point at the first 13 32-byte chunks in the first dir page,
4172 * since those are dir and page headers, and don't contain useful
4175 temp = curOffset.LowPart & (2048-1);
4176 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4177 /* we're in the first page */
4178 if (temp < 13*32) temp = 13*32;
4181 /* we're in a later dir page */
4182 if (temp < 32) temp = 32;
4185 /* make sure the low order 5 bits are zero */
4188 /* now put temp bits back ito curOffset.LowPart */
4189 curOffset.LowPart &= ~(2048-1);
4190 curOffset.LowPart |= temp;
4192 /* check if we've returned all the names that will fit in the
4195 if (returnedNames >= maxCount) {
4196 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
4197 returnedNames, maxCount);
4201 /* check if we've passed the dir's EOF */
4202 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
4204 /* see if we can use the bufferp we have now; compute in which page
4205 * the current offset would be, and check whether that's the offset
4206 * of the buffer we have. If not, get the buffer.
4208 thyper.HighPart = curOffset.HighPart;
4209 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4210 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4213 buf_Release(bufferp);
4216 lock_ReleaseMutex(&scp->mx);
4217 lock_ObtainRead(&scp->bufCreateLock);
4218 code = buf_Get(scp, &thyper, &bufferp);
4219 lock_ReleaseRead(&scp->bufCreateLock);
4220 lock_ObtainMutex(&dsp->mx);
4222 /* now, if we're doing a star match, do bulk fetching of all of
4223 * the status info for files in the dir.
4226 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
4227 lock_ObtainMutex(&scp->mx);
4228 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4229 LargeIntegerGreaterThanOrEqualTo(thyper,
4230 scp->bulkStatProgress)) {
4231 /* Don't bulk stat if risking timeout */
4232 int now = GetTickCount();
4233 if (now - req.startTime < 5000) {
4234 scp->bulkStatProgress = thyper;
4235 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4236 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4237 dsp->scp->bulkStatProgress = hzero;
4239 code = cm_TryBulkStat(scp, &thyper, userp, &req);
4242 lock_ObtainMutex(&scp->mx);
4244 lock_ReleaseMutex(&dsp->mx);
4246 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
4250 bufferOffset = thyper;
4252 /* now get the data in the cache */
4254 code = cm_SyncOp(scp, bufferp, userp, &req,
4256 CM_SCACHESYNC_NEEDCALLBACK |
4257 CM_SCACHESYNC_READ);
4259 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
4263 if (cm_HaveBuffer(scp, bufferp, 0)) {
4264 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4268 /* otherwise, load the buffer and try again */
4269 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
4271 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4272 scp, bufferp, code);
4277 buf_Release(bufferp);
4281 } /* if (wrong buffer) ... */
4283 /* now we have the buffer containing the entry we're interested in; copy
4284 * it out if it represents a non-deleted entry.
4286 entryInDir = curOffset.LowPart & (2048-1);
4287 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4289 /* page header will help tell us which entries are free. Page header
4290 * can change more often than once per buffer, since AFS 3 dir page size
4291 * may be less than (but not more than a buffer package buffer.
4293 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
4294 temp &= ~(2048 - 1); /* turn off intra-page bits */
4295 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4297 /* now determine which entry we're looking at in the page. If it is
4298 * free (there's a free bitmap at the start of the dir), we should
4299 * skip these 32 bytes.
4301 slotInPage = (entryInDir & 0x7e0) >> 5;
4302 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
4303 /* this entry is free */
4304 numDirChunks = 1; /* only skip this guy */
4308 tp = bufferp->datap + entryInBuffer;
4309 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4311 /* while we're here, compute the next entry's location, too,
4312 * since we'll need it when writing out the cookie into the dir
4315 * XXXX Probably should do more sanity checking.
4317 numDirChunks = cm_NameEntries(dep->name, NULL);
4319 /* compute the offset of the cookie representing the next entry */
4320 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4322 /* Compute 8.3 name if necessary */
4323 actualName = dep->name;
4324 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
4325 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
4326 actualName = shortName;
4329 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%s)",
4330 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
4331 osi_LogSaveString(smb_logp, actualName));
4333 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
4334 /* this is one of the entries to use: it is not deleted
4335 * and it matches the star pattern we're looking for.
4338 /* Eliminate entries that don't match requested
4341 /* no hidden files */
4342 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
4343 osi_Log0(smb_logp, "SMB search dir skipping hidden");
4347 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4349 /* We have already done the cm_TryBulkStat above */
4350 fid.cell = scp->fid.cell;
4351 fid.volume = scp->fid.volume;
4352 fid.vnode = ntohl(dep->fid.vnode);
4353 fid.unique = ntohl(dep->fid.unique);
4354 fileType = cm_FindFileType(&fid);
4355 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
4356 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
4358 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4359 fileType == CM_SCACHETYPE_DFSLINK ||
4360 fileType == CM_SCACHETYPE_INVALID)
4361 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
4366 memcpy(op, mask, 11); op += 11;
4367 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
4368 *op++ = (char)(nextEntryCookie & 0xff);
4369 *op++ = (char)((nextEntryCookie>>8) & 0xff);
4370 *op++ = (char)((nextEntryCookie>>16) & 0xff);
4371 *op++ = (char)((nextEntryCookie>>24) & 0xff);
4372 memcpy(op, &clientCookie, 4); op += 4;
4374 /* now we emit the attribute. This is sort of tricky,
4375 * since we need to really stat the file to find out
4376 * what type of entry we've got. Right now, we're
4377 * copying out data from a buffer, while holding the
4378 * scp locked, so it isn't really convenient to stat
4379 * something now. We'll put in a place holder now,
4380 * and make a second pass before returning this to get
4381 * the real attributes. So, we just skip the data for
4382 * now, and adjust it later. We allocate a patch
4383 * record to make it easy to find this point later.
4384 * The replay will happen at a time when it is safe to
4385 * unlock the directory.
4387 curPatchp = malloc(sizeof(*curPatchp));
4388 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
4389 curPatchp->dptr = op;
4390 curPatchp->fid.cell = scp->fid.cell;
4391 curPatchp->fid.volume = scp->fid.volume;
4392 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4393 curPatchp->fid.unique = ntohl(dep->fid.unique);
4395 /* do hidden attribute here since name won't be around when applying
4399 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
4400 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4402 curPatchp->flags = 0;
4404 op += 9; /* skip attr, time, date and size */
4406 /* zero out name area. The spec says to pad with
4407 * spaces, but Samba doesn't, and neither do we.
4411 /* finally, we get to copy out the name; we know that
4412 * it fits in 8.3 or the pattern wouldn't match, but it
4413 * never hurts to be sure.
4415 strncpy(op, actualName, 13);
4416 if (smb_StoreAnsiFilenames)
4419 /* Uppercase if requested by client */
4420 if (!KNOWS_LONG_NAMES(inp))
4425 /* now, adjust the # of entries copied */
4427 } /* if we're including this name */
4430 /* and adjust curOffset to be where the new cookie is */
4431 thyper.HighPart = 0;
4432 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4433 curOffset = LargeIntegerAdd(thyper, curOffset);
4434 } /* while copying data for dir listing */
4436 /* release the mutex */
4437 lock_ReleaseMutex(&scp->mx);
4438 if (bufferp) buf_Release(bufferp);
4440 /* apply and free last set of patches; if not doing a star match, this
4441 * will be empty, but better safe (and freeing everything) than sorry.
4443 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
4445 /* special return code for unsuccessful search */
4446 if (code == 0 && dataLength < 21 && returnedNames == 0)
4447 code = CM_ERROR_NOFILES;
4449 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
4450 returnedNames, code);
4453 smb_DeleteDirSearch(dsp);
4454 smb_ReleaseDirSearch(dsp);
4455 cm_ReleaseSCache(scp);
4456 cm_ReleaseUser(userp);
4460 /* finalize the output buffer */
4461 smb_SetSMBParm(outp, 0, returnedNames);
4462 temp = (long) (op - origOp);
4463 smb_SetSMBDataLength(outp, temp);
4465 /* the data area is a variable block, which has a 5 (already there)
4466 * followed by the length of the # of data bytes. We now know this to
4467 * be "temp," although that includes the 3 bytes of vbl block header.
4468 * Deduct for them and fill in the length field.
4470 temp -= 3; /* deduct vbl block info */
4471 osi_assert(temp == (43 * returnedNames));
4472 origOp[1] = (char)(temp & 0xff);
4473 origOp[2] = (char)((temp>>8) & 0xff);
4474 if (returnedNames == 0)
4475 smb_DeleteDirSearch(dsp);
4476 smb_ReleaseDirSearch(dsp);
4477 cm_ReleaseSCache(scp);
4478 cm_ReleaseUser(userp);
4482 /* verify that this is a valid path to a directory. I don't know why they
4483 * don't use the get file attributes call.
4485 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4489 cm_scache_t *rootScp;
4490 cm_scache_t *newScp;
4499 pathp = smb_GetSMBData(inp, NULL);
4500 pathp = smb_ParseASCIIBlock(pathp, NULL);
4502 return CM_ERROR_BADFD;
4503 if (smb_StoreAnsiFilenames)
4504 OemToChar(pathp,pathp);
4505 osi_Log1(smb_logp, "SMB receive check path %s",
4506 osi_LogSaveString(smb_logp, pathp));
4508 rootScp = cm_data.rootSCachep;
4510 userp = smb_GetUserFromVCP(vcp, inp);
4512 caseFold = CM_FLAG_CASEFOLD;
4514 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4516 cm_ReleaseUser(userp);
4517 return CM_ERROR_NOSUCHPATH;
4519 code = cm_NameI(rootScp, pathp,
4520 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
4521 userp, tidPathp, &req, &newScp);
4524 cm_ReleaseUser(userp);
4529 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4530 cm_ReleaseSCache(newScp);
4531 cm_ReleaseUser(userp);
4532 if ( WANTS_DFS_PATHNAMES(inp) )
4533 return CM_ERROR_PATH_NOT_COVERED;
4535 return CM_ERROR_BADSHARENAME;
4537 #endif /* DFS_SUPPORT */
4539 /* now lock the vnode with a callback; returns with newScp locked */
4540 lock_ObtainMutex(&newScp->mx);
4541 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
4542 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4543 if (code && code != CM_ERROR_NOACCESS) {
4544 lock_ReleaseMutex(&newScp->mx);
4545 cm_ReleaseSCache(newScp);
4546 cm_ReleaseUser(userp);
4550 attrs = smb_Attributes(newScp);
4552 if (!(attrs & SMB_ATTR_DIRECTORY))
4553 code = CM_ERROR_NOTDIR;
4555 lock_ReleaseMutex(&newScp->mx);
4557 cm_ReleaseSCache(newScp);
4558 cm_ReleaseUser(userp);
4562 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4566 cm_scache_t *rootScp;
4567 unsigned short attribute;
4569 cm_scache_t *newScp;
4578 /* decode basic attributes we're passed */
4579 attribute = smb_GetSMBParm(inp, 0);
4580 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4582 pathp = smb_GetSMBData(inp, NULL);
4583 pathp = smb_ParseASCIIBlock(pathp, NULL);
4585 return CM_ERROR_BADSMB;
4586 if (smb_StoreAnsiFilenames)
4587 OemToChar(pathp,pathp);
4589 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
4590 dosTime, attribute);
4592 rootScp = cm_data.rootSCachep;
4594 userp = smb_GetUserFromVCP(vcp, inp);
4596 caseFold = CM_FLAG_CASEFOLD;
4598 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4600 cm_ReleaseUser(userp);
4601 return CM_ERROR_NOSUCHFILE;
4603 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4604 tidPathp, &req, &newScp);
4607 cm_ReleaseUser(userp);
4612 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4613 cm_ReleaseSCache(newScp);
4614 cm_ReleaseUser(userp);
4615 if ( WANTS_DFS_PATHNAMES(inp) )
4616 return CM_ERROR_PATH_NOT_COVERED;
4618 return CM_ERROR_BADSHARENAME;
4620 #endif /* DFS_SUPPORT */
4622 /* now lock the vnode with a callback; returns with newScp locked; we
4623 * need the current status to determine what the new status is, in some
4626 lock_ObtainMutex(&newScp->mx);
4627 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4628 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4630 lock_ReleaseMutex(&newScp->mx);
4631 cm_ReleaseSCache(newScp);
4632 cm_ReleaseUser(userp);
4636 /* Check for RO volume */
4637 if (newScp->flags & CM_SCACHEFLAG_RO) {
4638 lock_ReleaseMutex(&newScp->mx);
4639 cm_ReleaseSCache(newScp);
4640 cm_ReleaseUser(userp);
4641 return CM_ERROR_READONLY;
4644 /* prepare for setattr call */
4647 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
4648 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
4650 if ((newScp->unixModeBits & 0222) && (attribute & 1) != 0) {
4651 /* we're told to make a writable file read-only */
4652 attr.unixModeBits = newScp->unixModeBits & ~0222;
4653 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4655 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & 1) == 0) {
4656 /* we're told to make a read-only file writable */
4657 attr.unixModeBits = newScp->unixModeBits | 0222;
4658 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4660 lock_ReleaseMutex(&newScp->mx);
4662 /* now call setattr */
4664 code = cm_SetAttr(newScp, &attr, userp, &req);
4668 cm_ReleaseSCache(newScp);
4669 cm_ReleaseUser(userp);
4674 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4678 cm_scache_t *rootScp;
4679 cm_scache_t *newScp, *dscp;
4691 pathp = smb_GetSMBData(inp, NULL);
4692 pathp = smb_ParseASCIIBlock(pathp, NULL);
4694 return CM_ERROR_BADSMB;
4696 if (*pathp == 0) /* null path */
4699 if (smb_StoreAnsiFilenames)
4700 OemToChar(pathp,pathp);
4702 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
4703 osi_LogSaveString(smb_logp, pathp));
4705 rootScp = cm_data.rootSCachep;
4707 userp = smb_GetUserFromVCP(vcp, inp);
4709 /* we shouldn't need this for V3 requests, but we seem to */
4710 caseFold = CM_FLAG_CASEFOLD;
4712 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4714 cm_ReleaseUser(userp);
4715 return CM_ERROR_NOSUCHFILE;
4719 * XXX Strange hack XXX
4721 * As of Patch 5 (16 July 97), we are having the following problem:
4722 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
4723 * requests to look up "desktop.ini" in all the subdirectories.
4724 * This can cause zillions of timeouts looking up non-existent cells
4725 * and volumes, especially in the top-level directory.
4727 * We have not found any way to avoid this or work around it except
4728 * to explicitly ignore the requests for mount points that haven't
4729 * yet been evaluated and for directories that haven't yet been
4732 * We should modify this hack to provide a fake desktop.ini file
4733 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
4735 spacep = inp->spacep;
4736 smb_StripLastComponent(spacep->data, &lastComp, pathp);
4737 #ifndef SPECIAL_FOLDERS
4738 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
4739 code = cm_NameI(rootScp, spacep->data,
4740 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
4741 userp, tidPathp, &req, &dscp);
4744 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4745 if ( WANTS_DFS_PATHNAMES(inp) )
4746 return CM_ERROR_PATH_NOT_COVERED;
4748 return CM_ERROR_BADSHARENAME;
4750 #endif /* DFS_SUPPORT */
4751 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
4752 code = CM_ERROR_NOSUCHFILE;
4753 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
4754 cm_buf_t *bp = buf_Find(dscp, &hzero);
4758 code = CM_ERROR_NOSUCHFILE;
4760 cm_ReleaseSCache(dscp);
4762 cm_ReleaseUser(userp);
4767 #endif /* SPECIAL_FOLDERS */
4769 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4770 tidPathp, &req, &newScp);
4772 cm_ReleaseUser(userp);
4777 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4778 cm_ReleaseSCache(newScp);
4779 cm_ReleaseUser(userp);
4780 if ( WANTS_DFS_PATHNAMES(inp) )
4781 return CM_ERROR_PATH_NOT_COVERED;
4783 return CM_ERROR_BADSHARENAME;
4785 #endif /* DFS_SUPPORT */
4787 /* now lock the vnode with a callback; returns with newScp locked */
4788 lock_ObtainMutex(&newScp->mx);
4789 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4790 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4792 lock_ReleaseMutex(&newScp->mx);
4793 cm_ReleaseSCache(newScp);
4794 cm_ReleaseUser(userp);
4799 /* use smb_Attributes instead. Also the fact that a file is
4800 * in a readonly volume doesn't mean it shojuld be marked as RO
4802 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
4803 newScp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
4804 newScp->fileType == CM_SCACHETYPE_INVALID)
4805 attrs = SMB_ATTR_DIRECTORY;
4808 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
4809 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
4811 attrs = smb_Attributes(newScp);
4814 smb_SetSMBParm(outp, 0, attrs);
4816 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
4817 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
4818 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
4819 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
4820 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
4821 smb_SetSMBParm(outp, 5, 0);
4822 smb_SetSMBParm(outp, 6, 0);
4823 smb_SetSMBParm(outp, 7, 0);
4824 smb_SetSMBParm(outp, 8, 0);
4825 smb_SetSMBParm(outp, 9, 0);
4826 smb_SetSMBDataLength(outp, 0);
4827 lock_ReleaseMutex(&newScp->mx);
4829 cm_ReleaseSCache(newScp);
4830 cm_ReleaseUser(userp);
4835 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4839 osi_Log0(smb_logp, "SMB receive tree disconnect");
4841 /* find the tree and free it */
4842 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
4844 lock_ObtainWrite(&smb_rctLock);
4846 lock_ReleaseWrite(&smb_rctLock);
4847 smb_ReleaseTID(tidp);
4853 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4871 pathp = smb_GetSMBData(inp, NULL);
4872 pathp = smb_ParseASCIIBlock(pathp, NULL);
4873 if (smb_StoreAnsiFilenames)
4874 OemToChar(pathp,pathp);
4876 osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
4878 #ifdef DEBUG_VERBOSE
4882 hexpath = osi_HexifyString( pathp );
4883 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
4888 share = smb_GetSMBParm(inp, 0);
4889 attribute = smb_GetSMBParm(inp, 1);
4891 spacep = inp->spacep;
4892 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4893 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4894 /* special case magic file name for receiving IOCTL requests
4895 * (since IOCTL calls themselves aren't getting through).
4897 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4898 smb_SetupIoctlFid(fidp, spacep);
4899 smb_SetSMBParm(outp, 0, fidp->fid);
4900 smb_SetSMBParm(outp, 1, 0); /* attrs */
4901 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
4902 smb_SetSMBParm(outp, 3, 0);
4903 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
4904 smb_SetSMBParm(outp, 5, 0x7fff);
4905 /* pass the open mode back */
4906 smb_SetSMBParm(outp, 6, (share & 0xf));
4907 smb_SetSMBDataLength(outp, 0);
4908 smb_ReleaseFID(fidp);
4912 userp = smb_GetUserFromVCP(vcp, inp);
4914 caseFold = CM_FLAG_CASEFOLD;
4916 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4918 cm_ReleaseUser(userp);
4919 return CM_ERROR_NOSUCHPATH;
4921 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4922 tidPathp, &req, &scp);
4925 cm_ReleaseUser(userp);
4930 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4931 cm_ReleaseSCache(scp);
4932 cm_ReleaseUser(userp);
4933 if ( WANTS_DFS_PATHNAMES(inp) )
4934 return CM_ERROR_PATH_NOT_COVERED;
4936 return CM_ERROR_BADSHARENAME;
4938 #endif /* DFS_SUPPORT */
4940 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
4942 cm_ReleaseSCache(scp);
4943 cm_ReleaseUser(userp);
4947 /* don't need callback to check file type, since file types never
4948 * change, and namei and cm_Lookup all stat the object at least once on
4949 * a successful return.
4951 if (scp->fileType != CM_SCACHETYPE_FILE) {
4952 cm_ReleaseSCache(scp);
4953 cm_ReleaseUser(userp);
4954 return CM_ERROR_ISDIR;
4957 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4960 /* save a pointer to the vnode */
4964 fidp->userp = userp;
4966 lock_ObtainMutex(&fidp->mx);
4967 if ((share & 0xf) == 0)
4968 fidp->flags |= SMB_FID_OPENREAD;
4969 else if ((share & 0xf) == 1)
4970 fidp->flags |= SMB_FID_OPENWRITE;
4972 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
4973 lock_ReleaseMutex(&fidp->mx);
4975 lock_ObtainMutex(&scp->mx);
4976 smb_SetSMBParm(outp, 0, fidp->fid);
4977 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
4978 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4979 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
4980 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
4981 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
4982 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
4983 /* pass the open mode back; XXXX add access checks */
4984 smb_SetSMBParm(outp, 6, (share & 0xf));
4985 smb_SetSMBDataLength(outp, 0);
4986 lock_ReleaseMutex(&scp->mx);
4989 cm_Open(scp, 0, userp);
4991 /* send and free packet */
4992 smb_ReleaseFID(fidp);
4993 cm_ReleaseUser(userp);
4994 /* don't release scp, since we've squirreled away the pointer in the fid struct */
4998 typedef struct smb_unlinkRock {
5003 char *maskp; /* pointer to the star pattern */
5008 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5011 smb_unlinkRock_t *rockp;
5019 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5020 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5021 caseFold |= CM_FLAG_8DOT3;
5023 matchName = dep->name;
5024 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
5026 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5027 !cm_Is8Dot3(dep->name)) {
5028 cm_Gen8Dot3Name(dep, shortName, NULL);
5029 matchName = shortName;
5030 /* 8.3 matches are always case insensitive */
5031 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
5034 osi_Log1(smb_logp, "Unlinking %s",
5035 osi_LogSaveString(smb_logp, matchName));
5036 code = cm_Unlink(dscp, dep->name, rockp->userp, rockp->reqp);
5037 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5038 smb_NotifyChange(FILE_ACTION_REMOVED,
5039 FILE_NOTIFY_CHANGE_FILE_NAME,
5040 dscp, dep->name, NULL, TRUE);
5044 /* If we made a case sensitive exact match, we might as well quit now. */
5045 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
5046 code = CM_ERROR_STOPNOW;
5054 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5063 smb_unlinkRock_t rock;
5072 attribute = smb_GetSMBParm(inp, 0);
5074 tp = smb_GetSMBData(inp, NULL);
5075 pathp = smb_ParseASCIIBlock(tp, &tp);
5076 if (smb_StoreAnsiFilenames)
5077 OemToChar(pathp,pathp);
5079 osi_Log1(smb_logp, "SMB receive unlink %s",
5080 osi_LogSaveString(smb_logp, pathp));
5082 spacep = inp->spacep;
5083 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5085 userp = smb_GetUserFromVCP(vcp, inp);
5087 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5089 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5091 cm_ReleaseUser(userp);
5092 return CM_ERROR_NOSUCHPATH;
5094 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
5097 cm_ReleaseUser(userp);
5102 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5103 cm_ReleaseSCache(dscp);
5104 cm_ReleaseUser(userp);
5105 if ( WANTS_DFS_PATHNAMES(inp) )
5106 return CM_ERROR_PATH_NOT_COVERED;
5108 return CM_ERROR_BADSHARENAME;
5110 #endif /* DFS_SUPPORT */
5112 /* otherwise, scp points to the parent directory. */
5119 rock.maskp = smb_FindMask(pathp);
5120 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5123 thyper.HighPart = 0;
5129 /* Now, if we aren't dealing with a wildcard match, we first try an exact
5130 * match. If that fails, we do a case insensitve match.
5132 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
5133 !smb_IsStarMask(rock.maskp)) {
5134 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5137 thyper.HighPart = 0;
5138 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5143 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5145 if (code == CM_ERROR_STOPNOW)
5148 cm_ReleaseUser(userp);
5150 cm_ReleaseSCache(dscp);
5152 if (code == 0 && !rock.any)
5153 code = CM_ERROR_NOSUCHFILE;
5157 typedef struct smb_renameRock {
5158 cm_scache_t *odscp; /* old dir */
5159 cm_scache_t *ndscp; /* new dir */
5160 cm_user_t *userp; /* user */
5161 cm_req_t *reqp; /* request struct */
5162 smb_vc_t *vcp; /* virtual circuit */
5163 char *maskp; /* pointer to star pattern of old file name */
5164 int flags; /* tilde, casefold, etc */
5165 char *newNamep; /* ptr to the new file's name */
5168 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5171 smb_renameRock_t *rockp;
5176 rockp = (smb_renameRock_t *) vrockp;
5178 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5179 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5180 caseFold |= CM_FLAG_8DOT3;
5182 match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
5184 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5185 !cm_Is8Dot3(dep->name)) {
5186 cm_Gen8Dot3Name(dep, shortName, NULL);
5187 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
5190 code = cm_Rename(rockp->odscp, dep->name,
5191 rockp->ndscp, rockp->newNamep, rockp->userp,
5193 /* if the call worked, stop doing the search now, since we
5194 * really only want to rename one file.
5197 code = CM_ERROR_STOPNOW;
5206 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, int attrs)
5209 cm_space_t *spacep = NULL;
5210 smb_renameRock_t rock;
5211 cm_scache_t *oldDscp = NULL;
5212 cm_scache_t *newDscp = NULL;
5213 cm_scache_t *tmpscp= NULL;
5214 cm_scache_t *tmpscp2 = NULL;
5224 userp = smb_GetUserFromVCP(vcp, inp);
5225 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5227 cm_ReleaseUser(userp);
5228 return CM_ERROR_NOSUCHPATH;
5232 spacep = inp->spacep;
5233 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5235 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5236 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5237 userp, tidPathp, &req, &oldDscp);
5239 cm_ReleaseUser(userp);
5244 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5245 cm_ReleaseSCache(oldDscp);
5246 cm_ReleaseUser(userp);
5247 if ( WANTS_DFS_PATHNAMES(inp) )
5248 return CM_ERROR_PATH_NOT_COVERED;
5250 return CM_ERROR_BADSHARENAME;
5252 #endif /* DFS_SUPPORT */
5254 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5255 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5256 userp, tidPathp, &req, &newDscp);
5259 cm_ReleaseSCache(oldDscp);
5260 cm_ReleaseUser(userp);
5265 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5266 cm_ReleaseSCache(oldDscp);
5267 cm_ReleaseSCache(newDscp);
5268 cm_ReleaseUser(userp);
5269 if ( WANTS_DFS_PATHNAMES(inp) )
5270 return CM_ERROR_PATH_NOT_COVERED;
5272 return CM_ERROR_BADSHARENAME;
5274 #endif /* DFS_SUPPORT */
5277 /* otherwise, oldDscp and newDscp point to the corresponding directories.
5278 * next, get the component names, and lower case them.
5281 /* handle the old name first */
5283 oldLastNamep = oldPathp;
5287 /* and handle the new name, too */
5289 newLastNamep = newPathp;
5293 /* TODO: The old name could be a wildcard. The new name must not be */
5295 /* do the vnode call */
5296 rock.odscp = oldDscp;
5297 rock.ndscp = newDscp;
5301 rock.maskp = oldLastNamep;
5302 rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5303 rock.newNamep = newLastNamep;
5305 /* Check if the file already exists; if so return error */
5306 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5307 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
5308 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5309 osi_LogSaveString(afsd_logp, newLastNamep));
5311 /* Check if the old and the new names differ only in case. If so return
5312 * success, else return CM_ERROR_EXISTS
5314 if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
5316 /* This would be a success only if the old file is *as same as* the new file */
5317 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
5319 if (tmpscp == tmpscp2)
5322 code = CM_ERROR_EXISTS;
5323 cm_ReleaseSCache(tmpscp2);
5326 code = CM_ERROR_NOSUCHFILE;
5329 /* file exist, do not rename, also fixes move */
5330 osi_Log0(smb_logp, "Can't rename. Target already exists");
5331 code = CM_ERROR_EXISTS;
5335 cm_ReleaseSCache(tmpscp);
5336 cm_ReleaseSCache(newDscp);
5337 cm_ReleaseSCache(oldDscp);
5338 cm_ReleaseUser(userp);
5342 /* Now search the directory for the pattern, and do the appropriate rename when found */
5343 thyper.LowPart = 0; /* search dir from here */
5344 thyper.HighPart = 0;
5346 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5347 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
5349 if (code == CM_ERROR_STOPNOW)
5352 code = CM_ERROR_NOSUCHFILE;
5354 /* Handle Change Notification */
5356 * Being lazy, not distinguishing between files and dirs in this
5357 * filter, since we'd have to do a lookup.
5359 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
5360 if (oldDscp == newDscp) {
5361 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5362 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5363 filter, oldDscp, oldLastNamep,
5364 newLastNamep, TRUE);
5366 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5367 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5368 filter, oldDscp, oldLastNamep,
5370 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5371 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
5372 filter, newDscp, newLastNamep,
5377 cm_ReleaseSCache(tmpscp);
5378 cm_ReleaseUser(userp);
5379 cm_ReleaseSCache(oldDscp);
5380 cm_ReleaseSCache(newDscp);
5385 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
5388 cm_space_t *spacep = NULL;
5389 cm_scache_t *oldDscp = NULL;
5390 cm_scache_t *newDscp = NULL;
5391 cm_scache_t *tmpscp= NULL;
5392 cm_scache_t *tmpscp2 = NULL;
5393 cm_scache_t *sscp = NULL;
5402 userp = smb_GetUserFromVCP(vcp, inp);
5404 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5406 cm_ReleaseUser(userp);
5407 return CM_ERROR_NOSUCHPATH;
5412 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5414 spacep = inp->spacep;
5415 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5417 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5418 userp, tidPathp, &req, &oldDscp);
5420 cm_ReleaseUser(userp);
5425 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5426 cm_ReleaseSCache(oldDscp);
5427 cm_ReleaseUser(userp);
5428 if ( WANTS_DFS_PATHNAMES(inp) )
5429 return CM_ERROR_PATH_NOT_COVERED;
5431 return CM_ERROR_BADSHARENAME;
5433 #endif /* DFS_SUPPORT */
5435 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5436 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5437 userp, tidPathp, &req, &newDscp);
5439 cm_ReleaseSCache(oldDscp);
5440 cm_ReleaseUser(userp);
5445 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5446 cm_ReleaseSCache(newDscp);
5447 cm_ReleaseSCache(oldDscp);
5448 cm_ReleaseUser(userp);
5449 if ( WANTS_DFS_PATHNAMES(inp) )
5450 return CM_ERROR_PATH_NOT_COVERED;
5452 return CM_ERROR_BADSHARENAME;
5454 #endif /* DFS_SUPPORT */
5456 /* Now, although we did two lookups for the two directories (because the same
5457 * directory can be referenced through different paths), we only allow hard links
5458 * within the same directory. */
5459 if (oldDscp != newDscp) {
5460 cm_ReleaseSCache(oldDscp);
5461 cm_ReleaseSCache(newDscp);
5462 cm_ReleaseUser(userp);
5463 return CM_ERROR_CROSSDEVLINK;
5466 /* handle the old name first */
5468 oldLastNamep = oldPathp;
5472 /* and handle the new name, too */
5474 newLastNamep = newPathp;
5478 /* now lookup the old name */
5479 osi_Log1(smb_logp," looking up [%s]", osi_LogSaveString(smb_logp,oldLastNamep));
5480 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
5482 cm_ReleaseSCache(oldDscp);
5483 cm_ReleaseSCache(newDscp);
5484 cm_ReleaseUser(userp);
5488 /* Check if the file already exists; if so return error */
5489 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5490 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
5491 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5492 osi_LogSaveString(afsd_logp, newLastNamep));
5494 /* if the existing link is to the same file, then we return success */
5496 if(sscp == tmpscp) {
5499 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
5500 code = CM_ERROR_EXISTS;
5505 cm_ReleaseSCache(tmpscp);
5506 cm_ReleaseSCache(sscp);
5507 cm_ReleaseSCache(newDscp);
5508 cm_ReleaseSCache(oldDscp);
5509 cm_ReleaseUser(userp);
5513 /* now create the hardlink */
5514 osi_Log1(smb_logp," Attempting to create new link [%s]", osi_LogSaveString(smb_logp, newLastNamep));
5515 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
5516 osi_Log1(smb_logp," Link returns 0x%x", code);
5518 /* Handle Change Notification */
5520 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
5521 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5522 smb_NotifyChange(FILE_ACTION_ADDED,
5523 filter, newDscp, newLastNamep,
5528 cm_ReleaseSCache(tmpscp);
5529 cm_ReleaseUser(userp);
5530 cm_ReleaseSCache(sscp);
5531 cm_ReleaseSCache(oldDscp);
5532 cm_ReleaseSCache(newDscp);
5537 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5543 tp = smb_GetSMBData(inp, NULL);
5544 oldPathp = smb_ParseASCIIBlock(tp, &tp);
5545 if (smb_StoreAnsiFilenames)
5546 OemToChar(oldPathp,oldPathp);
5547 newPathp = smb_ParseASCIIBlock(tp, &tp);
5548 if (smb_StoreAnsiFilenames)
5549 OemToChar(newPathp,newPathp);
5551 osi_Log2(smb_logp, "smb rename [%s] to [%s]",
5552 osi_LogSaveString(smb_logp, oldPathp),
5553 osi_LogSaveString(smb_logp, newPathp));
5555 return smb_Rename(vcp,inp,oldPathp,newPathp,0);
5560 typedef struct smb_rmdirRock {
5564 char *maskp; /* pointer to the star pattern */
5569 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5572 smb_rmdirRock_t *rockp;
5577 rockp = (smb_rmdirRock_t *) vrockp;
5579 matchName = dep->name;
5580 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
5581 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5583 match = (strcmp(matchName, rockp->maskp) == 0);
5585 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5586 !cm_Is8Dot3(dep->name)) {
5587 cm_Gen8Dot3Name(dep, shortName, NULL);
5588 matchName = shortName;
5589 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5592 osi_Log1(smb_logp, "Removing directory %s",
5593 osi_LogSaveString(smb_logp, matchName));
5594 code = cm_RemoveDir(dscp, dep->name, rockp->userp, rockp->reqp);
5595 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5596 smb_NotifyChange(FILE_ACTION_REMOVED,
5597 FILE_NOTIFY_CHANGE_DIR_NAME,
5598 dscp, dep->name, NULL, TRUE);
5607 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5615 smb_rmdirRock_t rock;
5624 tp = smb_GetSMBData(inp, NULL);
5625 pathp = smb_ParseASCIIBlock(tp, &tp);
5626 if (smb_StoreAnsiFilenames)
5627 OemToChar(pathp,pathp);
5629 spacep = inp->spacep;
5630 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5632 userp = smb_GetUserFromVCP(vcp, inp);
5634 caseFold = CM_FLAG_CASEFOLD;
5636 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5638 cm_ReleaseUser(userp);
5639 return CM_ERROR_NOSUCHPATH;
5641 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5642 userp, tidPathp, &req, &dscp);
5645 cm_ReleaseUser(userp);
5650 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5651 cm_ReleaseSCache(dscp);
5652 cm_ReleaseUser(userp);
5653 if ( WANTS_DFS_PATHNAMES(inp) )
5654 return CM_ERROR_PATH_NOT_COVERED;
5656 return CM_ERROR_BADSHARENAME;
5658 #endif /* DFS_SUPPORT */
5660 /* otherwise, scp points to the parent directory. */
5667 rock.maskp = lastNamep;
5668 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5671 thyper.HighPart = 0;
5675 /* First do a case sensitive match, and if that fails, do a case insensitive match */
5676 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5677 if (code == 0 && !rock.any) {
5679 thyper.HighPart = 0;
5680 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5681 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5684 cm_ReleaseUser(userp);
5686 cm_ReleaseSCache(dscp);
5688 if (code == 0 && !rock.any)
5689 code = CM_ERROR_NOSUCHFILE;
5693 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5703 fid = smb_GetSMBParm(inp, 0);
5705 osi_Log1(smb_logp, "SMB flush fid %d", fid);
5707 fid = smb_ChainFID(fid, inp);
5708 fidp = smb_FindFID(vcp, fid, 0);
5710 return CM_ERROR_BADFD;
5712 lock_ObtainMutex(&fidp->mx);
5713 if (fidp->flags & SMB_FID_IOCTL) {
5714 lock_ReleaseMutex(&fidp->mx);
5715 smb_ReleaseFID(fidp);
5716 return CM_ERROR_BADFD;
5718 lock_ReleaseMutex(&fidp->mx);
5720 userp = smb_GetUserFromVCP(vcp, inp);
5722 lock_ObtainMutex(&fidp->mx);
5723 if (fidp->flags & SMB_FID_OPENWRITE) {
5724 cm_scache_t * scp = fidp->scp;
5726 lock_ReleaseMutex(&fidp->mx);
5727 code = cm_FSync(scp, userp, &req);
5728 cm_ReleaseSCache(scp);
5731 lock_ReleaseMutex(&fidp->mx);
5734 smb_ReleaseFID(fidp);
5736 cm_ReleaseUser(userp);
5741 struct smb_FullNameRock {
5747 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
5751 struct smb_FullNameRock *vrockp;
5753 vrockp = (struct smb_FullNameRock *)rockp;
5755 if (!cm_Is8Dot3(dep->name)) {
5756 cm_Gen8Dot3Name(dep, shortName, NULL);
5758 if (cm_stricmp(shortName, vrockp->name) == 0) {
5759 vrockp->fullName = strdup(dep->name);
5760 return CM_ERROR_STOPNOW;
5763 if (cm_stricmp(dep->name, vrockp->name) == 0 &&
5764 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
5765 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
5766 vrockp->fullName = strdup(dep->name);
5767 return CM_ERROR_STOPNOW;
5772 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
5773 char **newPathp, cm_user_t *userp, cm_req_t *reqp)
5775 struct smb_FullNameRock rock;
5781 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
5782 if (code == CM_ERROR_STOPNOW)
5783 *newPathp = rock.fullName;
5785 *newPathp = strdup(pathp);
5788 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
5789 afs_uint32 dosTime) {
5792 cm_scache_t *dscp = fidp->NTopen_dscp;
5793 char *pathp = fidp->NTopen_pathp;
5796 osi_Log3(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d vcp=0x%x)",
5797 fidp, fidp->fid, vcp);
5800 lock_ObtainMutex(&fidp->mx);
5801 if (!fidp->userp && !(fidp->flags & SMB_FID_IOCTL)) {
5802 lock_ReleaseMutex(&fidp->mx);
5803 osi_Log0(smb_logp, " No user specified. Not closing fid");
5804 return CM_ERROR_BADFD;
5807 userp = fidp->userp; /* no hold required since fidp is held
5808 throughout the function */
5809 lock_ReleaseMutex(&fidp->mx);
5814 lock_ObtainWrite(&smb_rctLock);
5816 osi_Log0(smb_logp, " Fid already closed.");
5817 lock_ReleaseWrite(&smb_rctLock);
5818 return CM_ERROR_BADFD;
5821 lock_ReleaseWrite(&smb_rctLock);
5823 lock_ObtainMutex(&fidp->mx);
5824 /* Don't jump the gun on an async raw write */
5825 while (fidp->raw_writers) {
5826 lock_ReleaseMutex(&fidp->mx);
5827 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
5828 lock_ObtainMutex(&fidp->mx);
5835 /* watch for ioctl closes, and read-only opens */
5837 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
5838 == SMB_FID_OPENWRITE) {
5839 if (dosTime != 0 && dosTime != -1) {
5840 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5841 /* This fixes defect 10958 */
5842 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
5843 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
5845 lock_ReleaseMutex(&fidp->mx);
5846 code = cm_FSync(scp, userp, &req);
5847 lock_ObtainMutex(&fidp->mx);
5852 /* unlock any pending locks */
5853 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
5854 scp->fileType == CM_SCACHETYPE_FILE) {
5858 lock_ReleaseMutex(&fidp->mx);
5860 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
5862 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
5863 lock_ObtainMutex(&scp->mx);
5865 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
5866 CM_SCACHESYNC_NEEDCALLBACK
5867 | CM_SCACHESYNC_GETSTATUS
5868 | CM_SCACHESYNC_LOCK);
5872 "smb CoreClose SyncOp failure code 0x%x", tcode);
5873 goto post_syncopdone;
5876 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
5878 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
5882 lock_ReleaseMutex(&scp->mx);
5883 lock_ObtainMutex(&fidp->mx);
5886 if (fidp->flags & SMB_FID_DELONCLOSE) {
5889 lock_ReleaseMutex(&fidp->mx);
5890 smb_FullName(dscp, scp, pathp, &fullPathp, userp, &req);
5891 if (scp->fileType == CM_SCACHETYPE_DIRECTORY) {
5892 code = cm_RemoveDir(dscp, fullPathp, userp, &req);
5893 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5894 smb_NotifyChange(FILE_ACTION_REMOVED,
5895 FILE_NOTIFY_CHANGE_DIR_NAME,
5896 dscp, fullPathp, NULL, TRUE);
5898 code = cm_Unlink(dscp, fullPathp, userp, &req);
5899 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5900 smb_NotifyChange(FILE_ACTION_REMOVED,
5901 FILE_NOTIFY_CHANGE_FILE_NAME,
5902 dscp, fullPathp, NULL, TRUE);
5905 lock_ObtainMutex(&fidp->mx);
5906 fidp->flags &= ~SMB_FID_DELONCLOSE;
5909 /* if this was a newly created file, then clear the creator
5910 * in the stat cache entry. */
5911 if (fidp->flags & SMB_FID_CREATED) {
5912 lock_ObtainMutex(&scp->mx);
5913 if (scp->creator == userp)
5914 scp->creator = NULL;
5915 lock_ReleaseMutex(&scp->mx);
5916 fidp->flags &= ~SMB_FID_CREATED;
5919 if (fidp->flags & SMB_FID_NTOPEN) {
5920 fidp->NTopen_dscp = NULL;
5921 fidp->NTopen_pathp = NULL;
5922 fidp->flags &= ~SMB_FID_NTOPEN;
5924 if (fidp->NTopen_wholepathp) {
5925 free(fidp->NTopen_wholepathp);
5926 fidp->NTopen_wholepathp = NULL;
5928 lock_ReleaseMutex(&fidp->mx);
5931 cm_ReleaseSCache(dscp);
5934 cm_ReleaseSCache(scp);
5942 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5950 fid = smb_GetSMBParm(inp, 0);
5951 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5953 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
5955 fid = smb_ChainFID(fid, inp);
5956 fidp = smb_FindFID(vcp, fid, 0);
5958 return CM_ERROR_BADFD;
5961 userp = smb_GetUserFromVCP(vcp, inp);
5963 code = smb_CloseFID(vcp, fidp, userp, dosTime);
5965 smb_ReleaseFID(fidp);
5966 cm_ReleaseUser(userp);
5971 * smb_ReadData -- common code for Read, Read And X, and Raw Read
5974 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5975 cm_user_t *userp, long *readp)
5977 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5978 cm_user_t *userp, long *readp, int dosflag)
5985 osi_hyper_t fileLength;
5987 osi_hyper_t lastByte;
5988 osi_hyper_t bufferOffset;
5989 long bufIndex, nbytes;
5999 lock_ObtainMutex(&fidp->mx);
6001 lock_ObtainMutex(&scp->mx);
6003 if (offset.HighPart == 0) {
6004 chunk = offset.LowPart >> cm_logChunkSize;
6005 if (chunk != fidp->curr_chunk) {
6006 fidp->prev_chunk = fidp->curr_chunk;
6007 fidp->curr_chunk = chunk;
6009 if (fidp->curr_chunk == fidp->prev_chunk + 1)
6012 lock_ReleaseMutex(&fidp->mx);
6014 /* start by looking up the file's end */
6015 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6016 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6017 if (code) goto done;
6019 /* now we have the entry locked, look up the length */
6020 fileLength = scp->length;
6022 /* adjust count down so that it won't go past EOF */
6023 thyper.LowPart = count;
6024 thyper.HighPart = 0;
6025 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
6027 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6028 /* we'd read past EOF, so just stop at fileLength bytes.
6029 * Start by computing how many bytes remain in the file.
6031 thyper = LargeIntegerSubtract(fileLength, offset);
6033 /* if we are past EOF, read 0 bytes */
6034 if (LargeIntegerLessThanZero(thyper))
6037 count = thyper.LowPart;
6042 /* now, copy the data one buffer at a time,
6043 * until we've filled the request packet
6046 /* if we've copied all the data requested, we're done */
6047 if (count <= 0) break;
6049 /* otherwise, load up a buffer of data */
6050 thyper.HighPart = offset.HighPart;
6051 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6052 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6055 buf_Release(bufferp);
6058 lock_ReleaseMutex(&scp->mx);
6060 lock_ObtainRead(&scp->bufCreateLock);
6061 code = buf_Get(scp, &thyper, &bufferp);
6062 lock_ReleaseRead(&scp->bufCreateLock);
6064 lock_ObtainMutex(&scp->mx);
6065 if (code) goto done;
6066 bufferOffset = thyper;
6068 /* now get the data in the cache */
6070 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6071 CM_SCACHESYNC_NEEDCALLBACK |
6072 CM_SCACHESYNC_READ);
6073 if (code) goto done;
6075 if (cm_HaveBuffer(scp, bufferp, 0)) break;
6077 /* otherwise, load the buffer and try again */
6078 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
6082 buf_Release(bufferp);
6086 } /* if (wrong buffer) ... */
6088 /* now we have the right buffer loaded. Copy out the
6089 * data from here to the user's buffer.
6091 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6093 /* and figure out how many bytes we want from this buffer */
6094 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6095 if (nbytes > count) nbytes = count; /* don't go past EOF */
6097 /* now copy the data */
6100 dosmemput(bufferp->datap + bufIndex, nbytes, (dos_ptr)op);
6103 memcpy(op, bufferp->datap + bufIndex, nbytes);
6105 /* adjust counters, pointers, etc. */
6108 thyper.LowPart = nbytes;
6109 thyper.HighPart = 0;
6110 offset = LargeIntegerAdd(thyper, offset);
6114 lock_ReleaseMutex(&scp->mx);
6116 buf_Release(bufferp);
6118 if (code == 0 && sequential)
6119 cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
6125 * smb_WriteData -- common code for Write and Raw Write
6128 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
6129 cm_user_t *userp, long *writtenp)
6131 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
6132 cm_user_t *userp, long *writtenp, int dosflag)
6139 osi_hyper_t fileLength; /* file's length at start of write */
6140 osi_hyper_t minLength; /* don't read past this */
6141 long nbytes; /* # of bytes to transfer this iteration */
6143 osi_hyper_t thyper; /* hyper tmp variable */
6144 osi_hyper_t bufferOffset;
6145 long bufIndex; /* index in buffer where our data is */
6147 osi_hyper_t writeBackOffset;/* offset of region to write back when
6152 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
6153 fidp->fid, offsetp->LowPart, count);
6163 lock_ObtainMutex(&fidp->mx);
6164 /* make sure we have a writable FD */
6165 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
6166 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
6167 fidp->fid, fidp->flags);
6168 lock_ReleaseMutex(&fidp->mx);
6169 code = CM_ERROR_BADFDOP;
6175 lock_ReleaseMutex(&fidp->mx);
6177 lock_ObtainMutex(&scp->mx);
6178 /* start by looking up the file's end */
6179 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6180 CM_SCACHESYNC_NEEDCALLBACK
6181 | CM_SCACHESYNC_SETSTATUS
6182 | CM_SCACHESYNC_GETSTATUS);
6186 /* now we have the entry locked, look up the length */
6187 fileLength = scp->length;
6188 minLength = fileLength;
6189 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
6190 minLength = scp->serverLength;
6192 /* adjust file length if we extend past EOF */
6193 thyper.LowPart = count;
6194 thyper.HighPart = 0;
6195 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
6196 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6197 /* we'd write past EOF, so extend the file */
6198 scp->mask |= CM_SCACHEMASK_LENGTH;
6199 scp->length = thyper;
6200 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
6202 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
6204 /* now, if the new position (thyper) and the old (offset) are in
6205 * different storeback windows, remember to store back the previous
6206 * storeback window when we're done with the write.
6208 if ((thyper.LowPart & (-cm_chunkSize)) !=
6209 (offset.LowPart & (-cm_chunkSize))) {
6210 /* they're different */
6212 writeBackOffset.HighPart = offset.HighPart;
6213 writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
6218 /* now, copy the data one buffer at a time, until we've filled the
6221 /* if we've copied all the data requested, we're done */
6225 /* handle over quota or out of space */
6226 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
6227 *writtenp = written;
6228 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
6232 /* otherwise, load up a buffer of data */
6233 thyper.HighPart = offset.HighPart;
6234 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6235 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6238 lock_ReleaseMutex(&bufferp->mx);
6239 buf_Release(bufferp);
6242 lock_ReleaseMutex(&scp->mx);
6244 lock_ObtainRead(&scp->bufCreateLock);
6245 code = buf_Get(scp, &thyper, &bufferp);
6246 lock_ReleaseRead(&scp->bufCreateLock);
6248 lock_ObtainMutex(&bufferp->mx);
6249 lock_ObtainMutex(&scp->mx);
6250 if (code) goto done;
6252 bufferOffset = thyper;
6254 /* now get the data in the cache */
6256 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6257 CM_SCACHESYNC_NEEDCALLBACK
6258 | CM_SCACHESYNC_WRITE
6259 | CM_SCACHESYNC_BUFLOCKED);
6263 /* If we're overwriting the entire buffer, or
6264 * if we're writing at or past EOF, mark the
6265 * buffer as current so we don't call
6266 * cm_GetBuffer. This skips the fetch from the
6267 * server in those cases where we're going to
6268 * obliterate all the data in the buffer anyway,
6269 * or in those cases where there is no useful
6270 * data at the server to start with.
6272 * Use minLength instead of scp->length, since
6273 * the latter has already been updated by this
6276 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
6277 || LargeIntegerEqualTo(offset, bufferp->offset)
6278 && (count >= cm_data.buf_blockSize
6279 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
6280 ConvertLongToLargeInteger(count)),
6282 if (count < cm_data.buf_blockSize
6283 && bufferp->dataVersion == -1)
6284 memset(bufferp->datap, 0,
6285 cm_data.buf_blockSize);
6286 bufferp->dataVersion = scp->dataVersion;
6289 if (cm_HaveBuffer(scp, bufferp, 1)) break;
6291 /* otherwise, load the buffer and try again */
6292 lock_ReleaseMutex(&bufferp->mx);
6293 code = cm_GetBuffer(scp, bufferp, NULL, userp,
6295 lock_ReleaseMutex(&scp->mx);
6296 lock_ObtainMutex(&bufferp->mx);
6297 lock_ObtainMutex(&scp->mx);
6301 lock_ReleaseMutex(&bufferp->mx);
6302 buf_Release(bufferp);
6306 } /* if (wrong buffer) ... */
6308 /* now we have the right buffer loaded. Copy out the
6309 * data from here to the user's buffer.
6311 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6313 /* and figure out how many bytes we want from this buffer */
6314 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6316 nbytes = count; /* don't go past end of request */
6318 /* now copy the data */
6321 dosmemget((dos_ptr)op, nbytes, bufferp->datap + bufIndex);
6324 memcpy(bufferp->datap + bufIndex, op, nbytes);
6325 buf_SetDirty(bufferp);
6327 /* and record the last writer */
6328 if (bufferp->userp != userp) {
6331 cm_ReleaseUser(bufferp->userp);
6332 bufferp->userp = userp;
6335 /* adjust counters, pointers, etc. */
6339 thyper.LowPart = nbytes;
6340 thyper.HighPart = 0;
6341 offset = LargeIntegerAdd(thyper, offset);
6345 lock_ReleaseMutex(&scp->mx);
6348 lock_ReleaseMutex(&bufferp->mx);
6349 buf_Release(bufferp);
6352 lock_ObtainMutex(&fidp->mx);
6353 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
6354 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
6355 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
6356 fidp->NTopen_dscp, fidp->NTopen_pathp,
6359 lock_ReleaseMutex(&fidp->mx);
6361 if (code == 0 && doWriteBack) {
6363 lock_ObtainMutex(&scp->mx);
6364 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
6366 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
6367 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
6369 lock_ReleaseMutex(&scp->mx);
6370 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
6371 writeBackOffset.HighPart, cm_chunkSize, 0, userp);
6374 cm_ReleaseSCache(scp);
6376 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
6377 fidp->fid, code, *writtenp);
6381 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6384 long count, written = 0, total_written = 0;
6390 cm_attr_t truncAttr; /* attribute struct used for truncating file */
6392 int inDataBlockCount;
6394 fd = smb_GetSMBParm(inp, 0);
6395 count = smb_GetSMBParm(inp, 1);
6396 offset.HighPart = 0; /* too bad */
6397 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6399 op = smb_GetSMBData(inp, NULL);
6400 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
6402 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
6403 fd, offset.LowPart, count);
6405 fd = smb_ChainFID(fd, inp);
6406 fidp = smb_FindFID(vcp, fd, 0);
6408 return CM_ERROR_BADFD;
6410 lock_ObtainMutex(&fidp->mx);
6411 if (fidp->flags & SMB_FID_IOCTL) {
6412 lock_ReleaseMutex(&fidp->mx);
6413 code = smb_IoctlWrite(fidp, vcp, inp, outp);
6414 smb_ReleaseFID(fidp);
6417 lock_ReleaseMutex(&fidp->mx);
6418 userp = smb_GetUserFromVCP(vcp, inp);
6420 /* special case: 0 bytes transferred means truncate to this position */
6426 truncAttr.mask = CM_ATTRMASK_LENGTH;
6427 truncAttr.length.LowPart = offset.LowPart;
6428 truncAttr.length.HighPart = 0;
6429 lock_ObtainMutex(&fidp->mx);
6430 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
6431 fidp->flags |= SMB_FID_LENGTHSETDONE;
6432 lock_ReleaseMutex(&fidp->mx);
6433 smb_SetSMBParm(outp, 0, /* count */ 0);
6434 smb_SetSMBDataLength(outp, 0);
6440 LARGE_INTEGER LOffset;
6441 LARGE_INTEGER LLength;
6443 pid = ((smb_t *) inp)->pid;
6444 key = cm_GenerateKey(vcp->vcID, pid, fd);
6446 LOffset.HighPart = offset.HighPart;
6447 LOffset.LowPart = offset.LowPart;
6448 LLength.HighPart = 0;
6449 LLength.LowPart = count;
6451 lock_ObtainMutex(&fidp->scp->mx);
6452 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6453 lock_ReleaseMutex(&fidp->scp->mx);
6460 * Work around bug in NT client
6462 * When copying a file, the NT client should first copy the data,
6463 * then copy the last write time. But sometimes the NT client does
6464 * these in the wrong order, so the data copies would inadvertently
6465 * cause the last write time to be overwritten. We try to detect this,
6466 * and don't set client mod time if we think that would go against the
6469 lock_ObtainMutex(&fidp->mx);
6470 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6471 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6472 fidp->scp->clientModTime = time(NULL);
6474 lock_ReleaseMutex(&fidp->mx);
6477 while ( code == 0 && count > 0 ) {
6479 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6481 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
6483 if (code == 0 && written == 0)
6484 code = CM_ERROR_PARTIALWRITE;
6486 offset = LargeIntegerAdd(offset,
6487 ConvertLongToLargeInteger(written));
6489 total_written += written;
6493 /* set the packet data length to 3 bytes for the data block header,
6494 * plus the size of the data.
6496 smb_SetSMBParm(outp, 0, total_written);
6497 smb_SetSMBDataLength(outp, 0);
6500 smb_ReleaseFID(fidp);
6501 cm_ReleaseUser(userp);
6506 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6507 NCB *ncbp, raw_write_cont_t *rwcp)
6520 fd = smb_GetSMBParm(inp, 0);
6521 fidp = smb_FindFID(vcp, fd, 0);
6523 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
6524 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
6526 userp = smb_GetUserFromVCP(vcp, inp);
6530 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
6533 rawBuf = (dos_ptr) rwcp->buf;
6534 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count,
6535 (unsigned char *) rawBuf, userp,
6539 if (rwcp->writeMode & 0x1) { /* synchronous */
6542 smb_FormatResponsePacket(vcp, inp, outp);
6543 op = (smb_t *) outp;
6544 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6545 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
6546 smb_SetSMBDataLength(outp, 0);
6547 smb_SendPacket(vcp, outp);
6548 smb_FreePacket(outp);
6550 else { /* asynchronous */
6551 lock_ObtainMutex(&fidp->mx);
6552 fidp->raw_writers--;
6553 if (fidp->raw_writers == 0)
6554 thrd_SetEvent(fidp->raw_write_event);
6555 lock_ReleaseMutex(&fidp->mx);
6558 /* Give back raw buffer */
6559 lock_ObtainMutex(&smb_RawBufLock);
6561 *((char **)rawBuf) = smb_RawBufs;
6563 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
6565 smb_RawBufs = rawBuf;
6566 lock_ReleaseMutex(&smb_RawBufLock);
6568 smb_ReleaseFID(fidp);
6569 cm_ReleaseUser(userp);
6572 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6577 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
6580 long count, written = 0, total_written = 0;
6587 unsigned short writeMode;
6594 fd = smb_GetSMBParm(inp, 0);
6595 totalCount = smb_GetSMBParm(inp, 1);
6596 count = smb_GetSMBParm(inp, 10);
6597 writeMode = smb_GetSMBParm(inp, 7);
6599 op = (char *) inp->data;
6600 op += smb_GetSMBParm(inp, 11);
6602 offset.HighPart = 0;
6603 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6605 if (*inp->wctp == 14) {
6606 /* we received a 64-bit file offset */
6607 #ifdef AFS_LARGEFILES
6608 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
6610 if (LargeIntegerLessThanZero(offset)) {
6612 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
6613 offset.HighPart, offset.LowPart);
6614 return CM_ERROR_BADSMB;
6617 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
6619 "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files");
6620 return CM_ERROR_BADSMB;
6623 offset.HighPart = 0;
6626 offset.HighPart = 0; /* 32-bit file offset */
6630 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
6631 fd, offset.HighPart, offset.LowPart, count);
6633 " WriteRaw WriteMode 0x%x",
6636 fd = smb_ChainFID(fd, inp);
6637 fidp = smb_FindFID(vcp, fd, 0);
6639 return CM_ERROR_BADFD;
6645 LARGE_INTEGER LOffset;
6646 LARGE_INTEGER LLength;
6648 pid = ((smb_t *) inp)->pid;
6649 key = cm_GenerateKey(vcp->vcID, pid, fd);
6651 LOffset.HighPart = offset.HighPart;
6652 LOffset.LowPart = offset.LowPart;
6653 LLength.HighPart = 0;
6654 LLength.LowPart = count;
6656 lock_ObtainMutex(&fidp->scp->mx);
6657 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6658 lock_ReleaseMutex(&fidp->scp->mx);
6661 smb_ReleaseFID(fidp);
6666 userp = smb_GetUserFromVCP(vcp, inp);
6669 * Work around bug in NT client
6671 * When copying a file, the NT client should first copy the data,
6672 * then copy the last write time. But sometimes the NT client does
6673 * these in the wrong order, so the data copies would inadvertently
6674 * cause the last write time to be overwritten. We try to detect this,
6675 * and don't set client mod time if we think that would go against the
6678 lock_ObtainMutex(&fidp->mx);
6679 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
6680 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6681 fidp->scp->clientModTime = time(NULL);
6683 lock_ReleaseMutex(&fidp->mx);
6686 while ( code == 0 && count > 0 ) {
6688 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6690 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
6692 if (code == 0 && written == 0)
6693 code = CM_ERROR_PARTIALWRITE;
6695 offset = LargeIntegerAdd(offset,
6696 ConvertLongToLargeInteger(written));
6699 total_written += written;
6703 /* Get a raw buffer */
6706 lock_ObtainMutex(&smb_RawBufLock);
6708 /* Get a raw buf, from head of list */
6709 rawBuf = smb_RawBufs;
6711 smb_RawBufs = *(char **)smb_RawBufs;
6713 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
6717 code = CM_ERROR_USESTD;
6719 lock_ReleaseMutex(&smb_RawBufLock);
6722 /* Don't allow a premature Close */
6723 if (code == 0 && (writeMode & 1) == 0) {
6724 lock_ObtainMutex(&fidp->mx);
6725 fidp->raw_writers++;
6726 thrd_ResetEvent(fidp->raw_write_event);
6727 lock_ReleaseMutex(&fidp->mx);
6730 smb_ReleaseFID(fidp);
6731 cm_ReleaseUser(userp);
6734 smb_SetSMBParm(outp, 0, total_written);
6735 smb_SetSMBDataLength(outp, 0);
6736 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6741 offset = LargeIntegerAdd(offset,
6742 ConvertLongToLargeInteger(count));
6746 rwcp->offset.HighPart = offset.HighPart;
6747 rwcp->offset.LowPart = offset.LowPart;
6748 rwcp->count = totalCount - count;
6749 rwcp->writeMode = writeMode;
6750 rwcp->alreadyWritten = total_written;
6752 /* set the packet data length to 3 bytes for the data block header,
6753 * plus the size of the data.
6755 smb_SetSMBParm(outp, 0, 0xffff);
6756 smb_SetSMBDataLength(outp, 0);
6761 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6764 long count, finalCount;
6772 fd = smb_GetSMBParm(inp, 0);
6773 count = smb_GetSMBParm(inp, 1);
6774 offset.HighPart = 0; /* too bad */
6775 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6777 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
6778 fd, offset.LowPart, count);
6780 fd = smb_ChainFID(fd, inp);
6781 fidp = smb_FindFID(vcp, fd, 0);
6783 return CM_ERROR_BADFD;
6785 lock_ObtainMutex(&fidp->mx);
6786 if (fidp->flags & SMB_FID_IOCTL) {
6787 lock_ReleaseMutex(&fidp->mx);
6788 code = smb_IoctlRead(fidp, vcp, inp, outp);
6789 smb_ReleaseFID(fidp);
6792 lock_ReleaseMutex(&fidp->mx);
6795 LARGE_INTEGER LOffset, LLength;
6798 pid = ((smb_t *) inp)->pid;
6799 key = cm_GenerateKey(vcp->vcID, pid, fd);
6801 LOffset.HighPart = 0;
6802 LOffset.LowPart = offset.LowPart;
6803 LLength.HighPart = 0;
6804 LLength.LowPart = count;
6806 lock_ObtainMutex(&fidp->scp->mx);
6807 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
6808 lock_ReleaseMutex(&fidp->scp->mx);
6811 smb_ReleaseFID(fidp);
6815 userp = smb_GetUserFromVCP(vcp, inp);
6817 /* remember this for final results */
6818 smb_SetSMBParm(outp, 0, count);
6819 smb_SetSMBParm(outp, 1, 0);
6820 smb_SetSMBParm(outp, 2, 0);
6821 smb_SetSMBParm(outp, 3, 0);
6822 smb_SetSMBParm(outp, 4, 0);
6824 /* set the packet data length to 3 bytes for the data block header,
6825 * plus the size of the data.
6827 smb_SetSMBDataLength(outp, count+3);
6829 /* get op ptr after putting in the parms, since otherwise we don't
6830 * know where the data really is.
6832 op = smb_GetSMBData(outp, NULL);
6834 /* now emit the data block header: 1 byte of type and 2 bytes of length */
6835 *op++ = 1; /* data block marker */
6836 *op++ = (unsigned char) (count & 0xff);
6837 *op++ = (unsigned char) ((count >> 8) & 0xff);
6840 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6842 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
6845 /* fix some things up */
6846 smb_SetSMBParm(outp, 0, finalCount);
6847 smb_SetSMBDataLength(outp, finalCount+3);
6849 smb_ReleaseFID(fidp);
6851 cm_ReleaseUser(userp);
6855 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6862 cm_scache_t *dscp; /* dir we're dealing with */
6863 cm_scache_t *scp; /* file we're creating */
6865 int initialModeBits;
6875 /* compute initial mode bits based on read-only flag in attributes */
6876 initialModeBits = 0777;
6878 tp = smb_GetSMBData(inp, NULL);
6879 pathp = smb_ParseASCIIBlock(tp, &tp);
6880 if (smb_StoreAnsiFilenames)
6881 OemToChar(pathp,pathp);
6883 if (strcmp(pathp, "\\") == 0)
6884 return CM_ERROR_EXISTS;
6886 spacep = inp->spacep;
6887 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6889 userp = smb_GetUserFromVCP(vcp, inp);
6891 caseFold = CM_FLAG_CASEFOLD;
6893 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6895 cm_ReleaseUser(userp);
6896 return CM_ERROR_NOSUCHPATH;
6899 code = cm_NameI(cm_data.rootSCachep, spacep->data,
6900 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
6901 userp, tidPathp, &req, &dscp);
6904 cm_ReleaseUser(userp);
6909 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6910 cm_ReleaseSCache(dscp);
6911 cm_ReleaseUser(userp);
6912 if ( WANTS_DFS_PATHNAMES(inp) )
6913 return CM_ERROR_PATH_NOT_COVERED;
6915 return CM_ERROR_BADSHARENAME;
6917 #endif /* DFS_SUPPORT */
6919 /* otherwise, scp points to the parent directory. Do a lookup, and
6920 * fail if we find it. Otherwise, we do the create.
6926 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6927 if (scp) cm_ReleaseSCache(scp);
6928 if (code != CM_ERROR_NOSUCHFILE) {
6929 if (code == 0) code = CM_ERROR_EXISTS;
6930 cm_ReleaseSCache(dscp);
6931 cm_ReleaseUser(userp);
6935 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6936 setAttr.clientModTime = time(NULL);
6937 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
6938 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6939 smb_NotifyChange(FILE_ACTION_ADDED,
6940 FILE_NOTIFY_CHANGE_DIR_NAME,
6941 dscp, lastNamep, NULL, TRUE);
6943 /* we don't need this any longer */
6944 cm_ReleaseSCache(dscp);
6947 /* something went wrong creating or truncating the file */
6948 cm_ReleaseUser(userp);
6952 /* otherwise we succeeded */
6953 smb_SetSMBDataLength(outp, 0);
6954 cm_ReleaseUser(userp);
6959 BOOL smb_IsLegalFilename(char *filename)
6962 * Find the longest substring of filename that does not contain
6963 * any of the chars in illegalChars. If that substring is less
6964 * than the length of the whole string, then one or more of the
6965 * illegal chars is in filename.
6967 if (strcspn(filename, illegalChars) < strlen(filename))
6973 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6981 cm_scache_t *dscp; /* dir we're dealing with */
6982 cm_scache_t *scp; /* file we're creating */
6984 int initialModeBits;
6992 int created = 0; /* the file was new */
6997 excl = (inp->inCom == 0x03)? 0 : 1;
6999 attributes = smb_GetSMBParm(inp, 0);
7000 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
7002 /* compute initial mode bits based on read-only flag in attributes */
7003 initialModeBits = 0666;
7004 if (attributes & 1) initialModeBits &= ~0222;
7006 tp = smb_GetSMBData(inp, NULL);
7007 pathp = smb_ParseASCIIBlock(tp, &tp);
7008 if (smb_StoreAnsiFilenames)
7009 OemToChar(pathp,pathp);
7011 spacep = inp->spacep;
7012 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
7014 userp = smb_GetUserFromVCP(vcp, inp);
7016 caseFold = CM_FLAG_CASEFOLD;
7018 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7020 cm_ReleaseUser(userp);
7021 return CM_ERROR_NOSUCHPATH;
7023 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
7024 userp, tidPathp, &req, &dscp);
7027 cm_ReleaseUser(userp);
7032 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7033 cm_ReleaseSCache(dscp);
7034 cm_ReleaseUser(userp);
7035 if ( WANTS_DFS_PATHNAMES(inp) )
7036 return CM_ERROR_PATH_NOT_COVERED;
7038 return CM_ERROR_BADSHARENAME;
7040 #endif /* DFS_SUPPORT */
7042 /* otherwise, scp points to the parent directory. Do a lookup, and
7043 * truncate the file if we find it, otherwise we create the file.
7050 if (!smb_IsLegalFilename(lastNamep))
7051 return CM_ERROR_BADNTFILENAME;
7053 osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
7054 #ifdef DEBUG_VERBOSE
7057 hexp = osi_HexifyString( lastNamep );
7058 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
7063 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
7064 if (code && code != CM_ERROR_NOSUCHFILE) {
7065 cm_ReleaseSCache(dscp);
7066 cm_ReleaseUser(userp);
7070 /* if we get here, if code is 0, the file exists and is represented by
7071 * scp. Otherwise, we have to create it.
7075 /* oops, file shouldn't be there */
7076 cm_ReleaseSCache(dscp);
7077 cm_ReleaseSCache(scp);
7078 cm_ReleaseUser(userp);
7079 return CM_ERROR_EXISTS;
7082 setAttr.mask = CM_ATTRMASK_LENGTH;
7083 setAttr.length.LowPart = 0;
7084 setAttr.length.HighPart = 0;
7085 code = cm_SetAttr(scp, &setAttr, userp, &req);
7088 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7089 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
7090 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7094 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7095 smb_NotifyChange(FILE_ACTION_ADDED,
7096 FILE_NOTIFY_CHANGE_FILE_NAME,
7097 dscp, lastNamep, NULL, TRUE);
7098 } else if (!excl && code == CM_ERROR_EXISTS) {
7099 /* not an exclusive create, and someone else tried
7100 * creating it already, then we open it anyway. We
7101 * don't bother retrying after this, since if this next
7102 * fails, that means that the file was deleted after
7103 * we started this call.
7105 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
7108 setAttr.mask = CM_ATTRMASK_LENGTH;
7109 setAttr.length.LowPart = 0;
7110 setAttr.length.HighPart = 0;
7111 code = cm_SetAttr(scp, &setAttr, userp, &req);
7116 /* we don't need this any longer */
7117 cm_ReleaseSCache(dscp);
7120 /* something went wrong creating or truncating the file */
7121 if (scp) cm_ReleaseSCache(scp);
7122 cm_ReleaseUser(userp);
7126 /* make sure we only open files */
7127 if (scp->fileType != CM_SCACHETYPE_FILE) {
7128 cm_ReleaseSCache(scp);
7129 cm_ReleaseUser(userp);
7130 return CM_ERROR_ISDIR;
7133 /* now all we have to do is open the file itself */
7134 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7139 lock_ObtainMutex(&fidp->mx);
7140 /* always create it open for read/write */
7141 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
7143 /* remember that the file was newly created */
7145 fidp->flags |= SMB_FID_CREATED;
7147 /* save a pointer to the vnode */
7150 fidp->userp = userp;
7151 lock_ReleaseMutex(&fidp->mx);
7153 smb_SetSMBParm(outp, 0, fidp->fid);
7154 smb_SetSMBDataLength(outp, 0);
7156 cm_Open(scp, 0, userp);
7158 smb_ReleaseFID(fidp);
7159 cm_ReleaseUser(userp);
7160 /* leave scp held since we put it in fidp->scp */
7164 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7167 osi_hyper_t new_offset;
7178 fd = smb_GetSMBParm(inp, 0);
7179 whence = smb_GetSMBParm(inp, 1);
7180 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7182 /* try to find the file descriptor */
7183 fd = smb_ChainFID(fd, inp);
7184 fidp = smb_FindFID(vcp, fd, 0);
7187 return CM_ERROR_BADFD;
7189 lock_ObtainMutex(&fidp->mx);
7190 if (fidp->flags & SMB_FID_IOCTL) {
7191 lock_ReleaseMutex(&fidp->mx);
7192 smb_ReleaseFID(fidp);
7193 return CM_ERROR_BADFD;
7195 lock_ReleaseMutex(&fidp->mx);
7197 userp = smb_GetUserFromVCP(vcp, inp);
7199 lock_ObtainMutex(&fidp->mx);
7202 lock_ReleaseMutex(&fidp->mx);
7203 lock_ObtainMutex(&scp->mx);
7204 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7205 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7208 /* offset from current offset */
7209 new_offset = LargeIntegerAdd(fidp->offset,
7210 ConvertLongToLargeInteger(offset));
7212 else if (whence == 2) {
7213 /* offset from current EOF */
7214 new_offset = LargeIntegerAdd(scp->length,
7215 ConvertLongToLargeInteger(offset));
7217 new_offset = ConvertLongToLargeInteger(offset);
7220 fidp->offset = new_offset;
7221 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
7222 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
7223 smb_SetSMBDataLength(outp, 0);
7225 lock_ReleaseMutex(&scp->mx);
7226 smb_ReleaseFID(fidp);
7227 cm_ReleaseSCache(scp);
7228 cm_ReleaseUser(userp);
7232 /* dispatch all of the requests received in a packet. Due to chaining, this may
7233 * be more than one request.
7235 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7236 NCB *ncbp, raw_write_cont_t *rwcp)
7240 unsigned long code = 0;
7241 unsigned char *outWctp;
7242 int nparms; /* # of bytes of parameters */
7244 int nbytes; /* bytes of data, excluding count */
7247 unsigned short errCode;
7248 unsigned long NTStatus;
7250 unsigned char errClass;
7251 unsigned int oldGen;
7252 DWORD oldTime, newTime;
7254 /* get easy pointer to the data */
7255 smbp = (smb_t *) inp->data;
7257 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
7258 /* setup the basic parms for the initial request in the packet */
7259 inp->inCom = smbp->com;
7260 inp->wctp = &smbp->wct;
7262 inp->ncb_length = ncbp->ncb_length;
7267 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
7268 /* log it and discard it */
7270 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
7271 __FILE__, __LINE__, ncbp->ncb_length);
7273 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
7277 /* We are an ongoing op */
7278 thrd_Increment(&ongoingOps);
7280 /* set up response packet for receiving output */
7281 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
7282 smb_FormatResponsePacket(vcp, inp, outp);
7283 outWctp = outp->wctp;
7285 /* Remember session generation number and time */
7286 oldGen = sessionGen;
7287 oldTime = GetTickCount();
7289 while (inp->inCom != 0xff) {
7290 dp = &smb_dispatchTable[inp->inCom];
7292 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
7293 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
7294 code = outp->resumeCode;
7298 /* process each request in the packet; inCom, wctp and inCount
7299 * are already set up.
7301 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
7304 /* now do the dispatch */
7305 /* start by formatting the response record a little, as a default */
7306 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
7308 outWctp[1] = 0xff; /* no operation */
7309 outWctp[2] = 0; /* padding */
7314 /* not a chained request, this is a more reasonable default */
7315 outWctp[0] = 0; /* wct of zero */
7316 outWctp[1] = 0; /* and bcc (word) of zero */
7320 /* once set, stays set. Doesn't matter, since we never chain
7321 * "no response" calls.
7323 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
7327 /* we have a recognized operation */
7329 if (inp->inCom == 0x1d)
7331 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
7333 osi_Log4(smb_logp,"Dispatch %s vcp 0x%p lana %d lsn %d",myCrt_Dispatch(inp->inCom),vcp,vcp->lana,vcp->lsn);
7334 code = (*(dp->procp)) (vcp, inp, outp);
7335 osi_Log4(smb_logp,"Dispatch return code 0x%x vcp 0x%p lana %d lsn %d",code,vcp,vcp->lana,vcp->lsn);
7337 if ( code == CM_ERROR_BADSMB ||
7338 code == CM_ERROR_BADOP )
7340 #endif /* LOG_PACKET */
7343 if (oldGen != sessionGen) {
7344 newTime = GetTickCount();
7346 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
7347 newTime - oldTime, ncbp->ncb_length);
7349 osi_Log2(smb_logp, "Pkt straddled session startup, "
7350 "took %d ms, ncb length %d", newTime - oldTime, ncbp->ncb_length);
7354 /* bad opcode, fail the request, after displaying it */
7355 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
7358 #endif /* LOG_PACKET */
7362 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
7363 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
7364 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
7365 if (code == IDCANCEL)
7369 code = CM_ERROR_BADOP;
7372 /* catastrophic failure: log as much as possible */
7373 if (code == CM_ERROR_BADSMB) {
7375 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
7380 #endif /* LOG_PACKET */
7381 osi_Log1(smb_logp, "Invalid SMB message, length %d",
7384 code = CM_ERROR_INVAL;
7387 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
7388 thrd_Decrement(&ongoingOps);
7393 /* now, if we failed, turn the current response into an empty
7394 * one, and fill in the response packet's error code.
7397 if (vcp->flags & SMB_VCFLAG_STATUS32) {
7398 smb_MapNTError(code, &NTStatus);
7399 outWctp = outp->wctp;
7400 smbp = (smb_t *) &outp->data;
7401 if (code != CM_ERROR_PARTIALWRITE
7402 && code != CM_ERROR_BUFFERTOOSMALL
7403 && code != CM_ERROR_GSSCONTINUE) {
7404 /* nuke wct and bcc. For a partial
7405 * write or an in-process authentication handshake,
7406 * assume they're OK.
7412 smbp->rcls = (unsigned char) (NTStatus & 0xff);
7413 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
7414 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
7415 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
7416 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7420 smb_MapCoreError(code, vcp, &errCode, &errClass);
7421 outWctp = outp->wctp;
7422 smbp = (smb_t *) &outp->data;
7423 if (code != CM_ERROR_PARTIALWRITE) {
7424 /* nuke wct and bcc. For a partial
7425 * write, assume they're OK.
7431 smbp->errLow = (unsigned char) (errCode & 0xff);
7432 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
7433 smbp->rcls = errClass;
7436 } /* error occurred */
7438 /* if we're here, we've finished one request. Look to see if
7439 * this is a chained opcode. If it is, setup things to process
7440 * the chained request, and setup the output buffer to hold the
7441 * chained response. Start by finding the next input record.
7443 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
7444 break; /* not a chained req */
7445 tp = inp->wctp; /* points to start of last request */
7446 /* in a chained request, the first two
7447 * parm fields are required, and are
7448 * AndXCommand/AndXReserved and
7450 if (tp[0] < 2) break;
7451 if (tp[1] == 0xff) break; /* no more chained opcodes */
7453 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
7456 /* and now append the next output request to the end of this
7457 * last request. Begin by finding out where the last response
7458 * ends, since that's where we'll put our new response.
7460 outWctp = outp->wctp; /* ptr to out parameters */
7461 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
7462 nparms = outWctp[0] << 1;
7463 tp = outWctp + nparms + 1; /* now points to bcc field */
7464 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
7465 tp += 2 /* for the count itself */ + nbytes;
7466 /* tp now points to the new output record; go back and patch the
7467 * second parameter (off2) to point to the new record.
7469 temp = (unsigned int)(tp - outp->data);
7470 outWctp[3] = (unsigned char) (temp & 0xff);
7471 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
7472 outWctp[2] = 0; /* padding */
7473 outWctp[1] = inp->inCom; /* next opcode */
7475 /* finally, setup for the next iteration */
7478 } /* while loop over all requests in the packet */
7480 /* now send the output packet, and return */
7482 smb_SendPacket(vcp, outp);
7483 thrd_Decrement(&ongoingOps);
7489 /* Wait for Netbios() calls to return, and make the results available to server
7490 * threads. Note that server threads can't wait on the NCBevents array
7491 * themselves, because NCB events are manual-reset, and the servers would race
7492 * each other to reset them.
7494 void smb_ClientWaiter(void *parmp)
7499 while (smbShutdownFlag == 0) {
7500 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
7502 if (code == WAIT_OBJECT_0)
7505 /* error checking */
7506 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7508 int abandonIdx = code - WAIT_ABANDONED_0;
7509 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7512 if (code == WAIT_IO_COMPLETION)
7514 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
7518 if (code == WAIT_TIMEOUT)
7520 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
7523 if (code == WAIT_FAILED)
7525 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
7528 idx = code - WAIT_OBJECT_0;
7530 /* check idx range! */
7531 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
7533 /* this is fatal - log as much as possible */
7534 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
7538 thrd_ResetEvent(NCBevents[idx]);
7539 thrd_SetEvent(NCBreturns[0][idx]);
7545 * Try to have one NCBRECV request waiting for every live session. Not more
7546 * than one, because if there is more than one, it's hard to handle Write Raw.
7548 void smb_ServerWaiter(void *parmp)
7551 int idx_session, idx_NCB;
7557 while (smbShutdownFlag == 0) {
7559 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
7561 if (code == WAIT_OBJECT_0)
7564 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
7566 int abandonIdx = code - WAIT_ABANDONED_0;
7567 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7570 if (code == WAIT_IO_COMPLETION)
7572 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
7576 if (code == WAIT_TIMEOUT)
7578 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
7581 if (code == WAIT_FAILED)
7583 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
7586 idx_session = code - WAIT_OBJECT_0;
7588 /* check idx range! */
7589 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
7591 /* this is fatal - log as much as possible */
7592 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
7598 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
7600 if (code == WAIT_OBJECT_0) {
7601 if (smbShutdownFlag == 1)
7607 /* error checking */
7608 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7610 int abandonIdx = code - WAIT_ABANDONED_0;
7611 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7614 if (code == WAIT_IO_COMPLETION)
7616 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
7620 if (code == WAIT_TIMEOUT)
7622 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
7625 if (code == WAIT_FAILED)
7627 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
7630 idx_NCB = code - WAIT_OBJECT_0;
7632 /* check idx range! */
7633 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
7635 /* this is fatal - log as much as possible */
7636 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
7640 /* Link them together */
7641 NCBsessions[idx_NCB] = idx_session;
7644 ncbp = NCBs[idx_NCB];
7645 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
7646 ncbp->ncb_command = NCBRECV | ASYNCH;
7647 ncbp->ncb_lana_num = lanas[idx_session];
7649 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
7650 ncbp->ncb_event = NCBevents[idx_NCB];
7651 ncbp->ncb_length = SMB_PACKETSIZE;
7654 ncbp->ncb_buffer = bufs[idx_NCB]->dos_pkt;
7655 ((smb_ncb_t*)ncbp)->orig_pkt = bufs[idx_NCB];
7656 ncbp->ncb_event = NCBreturns[0][idx_NCB];
7657 ncbp->ncb_length = SMB_PACKETSIZE;
7658 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7659 Netbios(ncbp, dos_ncb);
7665 * The top level loop for handling SMB request messages. Each server thread
7666 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
7667 * NCB and buffer for the incoming request are loaned to us.
7669 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
7670 * to immediately send a request for the rest of the data. This must come
7671 * before any other traffic for that session, so we delay setting the session
7672 * event until that data has come in.
7674 void smb_Server(VOID *parmp)
7676 INT_PTR myIdx = (INT_PTR) parmp;
7680 smb_packet_t *outbufp;
7682 int idx_NCB, idx_session;
7684 smb_vc_t *vcp = NULL;
7690 rx_StartClientThread();
7693 outbufp = GetPacket();
7694 outbufp->ncbp = outncbp;
7702 smb_ResetServerPriority();
7704 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
7707 /* terminate silently if shutdown flag is set */
7708 if (code == WAIT_OBJECT_0) {
7709 if (smbShutdownFlag == 1) {
7710 thrd_SetEvent(smb_ServerShutdown[myIdx]);
7716 /* error checking */
7717 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7719 int abandonIdx = code - WAIT_ABANDONED_0;
7720 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
7723 if (code == WAIT_IO_COMPLETION)
7725 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
7729 if (code == WAIT_TIMEOUT)
7731 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
7734 if (code == WAIT_FAILED)
7736 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
7739 idx_NCB = code - WAIT_OBJECT_0;
7741 /* check idx range! */
7742 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
7744 /* this is fatal - log as much as possible */
7745 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
7749 ncbp = NCBs[idx_NCB];
7751 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7753 idx_session = NCBsessions[idx_NCB];
7754 rc = ncbp->ncb_retcode;
7756 if (rc != NRC_PENDING && rc != NRC_GOODRET)
7757 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
7761 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7765 /* Can this happen? Or is it just my UNIX paranoia? */
7766 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
7772 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
7776 /* Client closed session */
7777 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7779 lock_ObtainMutex(&vcp->mx);
7780 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7781 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
7783 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7784 lock_ReleaseMutex(&vcp->mx);
7785 lock_ObtainWrite(&smb_globalLock);
7786 dead_sessions[vcp->session] = TRUE;
7787 lock_ReleaseWrite(&smb_globalLock);
7788 smb_CleanupDeadVC(vcp);
7792 lock_ReleaseMutex(&vcp->mx);
7798 /* Treat as transient error */
7800 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
7804 "dispatch smb recv failed, message incomplete, ncb_length %d",
7807 "SMB message incomplete, "
7808 "length %d", ncbp->ncb_length);
7811 * We used to discard the packet.
7812 * Instead, try handling it normally.
7816 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7820 /* A weird error code. Log it, sleep, and continue. */
7821 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7823 lock_ObtainMutex(&vcp->mx);
7824 if (vcp && vcp->errorCount++ > 3) {
7825 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
7826 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7827 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
7829 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7830 lock_ReleaseMutex(&vcp->mx);
7831 lock_ObtainWrite(&smb_globalLock);
7832 dead_sessions[vcp->session] = TRUE;
7833 lock_ReleaseWrite(&smb_globalLock);
7834 smb_CleanupDeadVC(vcp);
7838 lock_ReleaseMutex(&vcp->mx);
7844 lock_ReleaseMutex(&vcp->mx);
7846 thrd_SetEvent(SessionEvents[idx_session]);
7851 /* Success, so now dispatch on all the data in the packet */
7853 smb_concurrentCalls++;
7854 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
7855 smb_maxObsConcurrentCalls = smb_concurrentCalls;
7858 * If at this point vcp is NULL (implies that packet was invalid)
7859 * then we are in big trouble. This means either :
7860 * a) we have the wrong NCB.
7861 * b) Netbios screwed up the call.
7862 * c) The VC was already marked dead before we were able to
7864 * Obviously this implies that
7865 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
7866 * lanas[idx_session] != ncbp->ncb_lana_num )
7867 * Either way, we can't do anything with this packet.
7868 * Log, sleep and resume.
7871 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
7875 ncbp->ncb_lana_num);
7877 /* Also log in the trace log. */
7878 osi_Log4(smb_logp, "Server: VCP does not exist!"
7879 "LSNs[idx_session]=[%d],"
7880 "lanas[idx_session]=[%d],"
7881 "ncbp->ncb_lsn=[%d],"
7882 "ncbp->ncb_lana_num=[%d]",
7886 ncbp->ncb_lana_num);
7888 /* thrd_Sleep(1000); Don't bother sleeping */
7889 thrd_SetEvent(SessionEvents[idx_session]);
7890 smb_concurrentCalls--;
7894 smb_SetRequestStartTime();
7896 vcp->errorCount = 0;
7897 bufp = (struct smb_packet *) ncbp->ncb_buffer;
7899 bufp = ((smb_ncb_t *) ncbp)->orig_pkt;
7900 /* copy whole packet to virtual memory */
7901 /*fprintf(stderr, "smb_Server: copying dos packet at 0x%x, "
7903 bufp->dos_pkt / 16, bufp);*/
7905 dosmemget(bufp->dos_pkt, ncbp->ncb_length, bufp->data);
7907 smbp = (smb_t *)bufp->data;
7910 #if !defined(DJGPP) && !defined(AFS_WIN32_ENV)
7914 if (smbp->com == 0x1d) {
7915 /* Special handling for Write Raw */
7916 raw_write_cont_t rwc;
7917 EVENT_HANDLE rwevent;
7918 char eventName[MAX_PATH];
7920 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
7921 if (rwc.code == 0) {
7922 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
7923 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7924 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7925 ncbp->ncb_command = NCBRECV | ASYNCH;
7926 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
7927 ncbp->ncb_lana_num = vcp->lana;
7928 ncbp->ncb_buffer = rwc.buf;
7929 ncbp->ncb_length = 65535;
7930 ncbp->ncb_event = rwevent;
7934 Netbios(ncbp, dos_ncb);
7936 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
7937 thrd_CloseHandle(rwevent);
7939 thrd_SetEvent(SessionEvents[idx_session]);
7941 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
7943 else if (smbp->com == 0xa0) {
7945 * Serialize the handling for NT Transact
7948 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7949 thrd_SetEvent(SessionEvents[idx_session]);
7951 thrd_SetEvent(SessionEvents[idx_session]);
7952 /* TODO: what else needs to be serialized? */
7953 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7955 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
7957 __except( smb_ServerExceptionFilter() ) {
7961 smb_concurrentCalls--;
7964 thrd_SetEvent(NCBavails[idx_NCB]);
7971 * Exception filter for the server threads. If an exception occurs in the
7972 * dispatch routines, which is where exceptions are most common, then do a
7973 * force trace and give control to upstream exception handlers. Useful for
7976 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
7977 DWORD smb_ServerExceptionFilter(void) {
7978 /* While this is not the best time to do a trace, if it succeeds, then
7979 * we have a trace (assuming tracing was enabled). Otherwise, this should
7980 * throw a second exception.
7982 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
7983 afsd_ForceTrace(TRUE);
7984 buf_ForceTrace(TRUE);
7985 return EXCEPTION_CONTINUE_SEARCH;
7990 * Create a new NCB and associated events, packet buffer, and "space" buffer.
7991 * If the number of server threads is M, and the number of live sessions is
7992 * N, then the number of NCB's in use at any time either waiting for, or
7993 * holding, received messages is M + N, so that is how many NCB's get created.
7995 void InitNCBslot(int idx)
7997 struct smb_packet *bufp;
7998 EVENT_HANDLE retHandle;
8000 char eventName[MAX_PATH];
8002 osi_assert( idx < (sizeof(NCBs) / sizeof(NCBs[0])) );
8004 NCBs[idx] = GetNCB();
8005 sprintf(eventName,"NCBavails[%d]", idx);
8006 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8007 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8008 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8010 sprintf(eventName,"NCBevents[%d]", idx);
8011 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
8012 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8013 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8015 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
8016 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8017 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8018 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8019 for (i=0; i<smb_NumServerThreads; i++)
8020 NCBreturns[i][idx] = retHandle;
8022 bufp->spacep = cm_GetSpace();
8026 /* listen for new connections */
8027 void smb_Listener(void *parmp)
8033 int session, thread;
8034 smb_vc_t *vcp = NULL;
8036 char rname[NCBNAMSZ+1];
8037 char cname[MAX_COMPUTERNAME_LENGTH+1];
8038 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
8043 INT_PTR lana = (INT_PTR) parmp;
8047 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
8050 /* retrieve computer name */
8051 GetComputerName(cname, &cnamelen);
8055 memset(ncbp, 0, sizeof(NCB));
8058 ncbp->ncb_command = NCBLISTEN;
8059 ncbp->ncb_rto = 0; /* No receive timeout */
8060 ncbp->ncb_sto = 0; /* No send timeout */
8062 /* pad out with spaces instead of null termination */
8063 len = (long)strlen(smb_localNamep);
8064 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
8065 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
8067 strcpy(ncbp->ncb_callname, "*");
8068 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
8070 ncbp->ncb_lana_num = (UCHAR)lana;
8073 code = Netbios(ncbp);
8075 code = Netbios(ncbp, dos_ncb);
8084 /* terminate silently if shutdown flag is set */
8085 if (smbShutdownFlag == 1) {
8094 "NCBLISTEN lana=%d failed with code %d",
8095 ncbp->ncb_lana_num, code);
8097 "Client exiting due to network failure. Please restart client.\n");
8101 "Client exiting due to network failure. Please restart client.\n"
8102 "NCBLISTEN lana=%d failed with code %d",
8103 ncbp->ncb_lana_num, code);
8105 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
8106 MB_OK|MB_SERVICE_NOTIFICATION);
8107 osi_assert(tbuffer);
8110 fprintf(stderr, "NCBLISTEN lana=%d failed with code %d\n",
8111 ncbp->ncb_lana_num, code);
8112 fprintf(stderr, "\nClient exiting due to network failure "
8113 "(possibly due to power-saving mode)\n");
8114 fprintf(stderr, "Please restart client.\n");
8115 afs_exit(AFS_EXITCODE_NETWORK_FAILURE);
8119 /* check for remote conns */
8120 /* first get remote name and insert null terminator */
8121 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
8122 for (i=NCBNAMSZ; i>0; i--) {
8123 if (rname[i-1] != ' ' && rname[i-1] != 0) {
8129 /* compare with local name */
8131 if (strncmp(rname, cname, NCBNAMSZ) != 0)
8132 flags |= SMB_VCFLAG_REMOTECONN;
8135 lock_ObtainMutex(&smb_ListenerLock);
8137 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
8138 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
8140 /* now ncbp->ncb_lsn is the connection ID */
8141 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
8142 if (vcp->session == 0) {
8143 /* New generation */
8144 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
8147 /* Log session startup */
8149 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8150 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8151 #endif /* NOTSERVICE */
8152 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8153 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8155 if (reportSessionStartups) {
8157 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8160 fprintf(stderr, "%s: New session %d starting from host %s\n",
8161 asctime(localtime(&now)), ncbp->ncb_lsn, rname);
8166 lock_ObtainMutex(&vcp->mx);
8167 strcpy(vcp->rname, rname);
8168 vcp->flags |= flags;
8169 lock_ReleaseMutex(&vcp->mx);
8171 /* Allocate slot in session arrays */
8172 /* Re-use dead session if possible, otherwise add one more */
8173 /* But don't look at session[0], it is reserved */
8174 lock_ObtainWrite(&smb_globalLock);
8175 for (session = 1; session < numSessions; session++) {
8176 if (dead_sessions[session]) {
8177 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
8178 dead_sessions[session] = FALSE;
8182 lock_ReleaseWrite(&smb_globalLock);
8184 /* We are re-using an existing VC because the lsn and lana
8186 session = vcp->session;
8188 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
8190 /* Log session startup */
8192 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8193 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8194 #endif /* NOTSERVICE */
8195 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8196 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8198 if (reportSessionStartups) {
8200 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8203 fprintf(stderr, "%s: Re-using session %d starting from host %s\n",
8204 asctime(localtime(&now)), ncbp->ncb_lsn, rname);
8210 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
8211 unsigned long code = CM_ERROR_ALLBUSY;
8212 smb_packet_t * outp = GetPacket();
8213 unsigned char *outWctp;
8216 smb_FormatResponsePacket(vcp, NULL, outp);
8219 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8220 unsigned long NTStatus;
8221 smb_MapNTError(code, &NTStatus);
8222 outWctp = outp->wctp;
8223 smbp = (smb_t *) &outp->data;
8227 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8228 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8229 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8230 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8231 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8233 unsigned short errCode;
8234 unsigned char errClass;
8235 smb_MapCoreError(code, vcp, &errCode, &errClass);
8236 outWctp = outp->wctp;
8237 smbp = (smb_t *) &outp->data;
8241 smbp->errLow = (unsigned char) (errCode & 0xff);
8242 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8243 smbp->rcls = errClass;
8245 smb_SendPacket(vcp, outp);
8246 smb_FreePacket(outp);
8248 lock_ObtainMutex(&vcp->mx);
8249 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8250 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8252 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8253 lock_ReleaseMutex(&vcp->mx);
8254 lock_ObtainWrite(&smb_globalLock);
8255 dead_sessions[vcp->session] = TRUE;
8256 lock_ReleaseWrite(&smb_globalLock);
8257 smb_CleanupDeadVC(vcp);
8259 lock_ReleaseMutex(&vcp->mx);
8262 /* assert that we do not exceed the maximum number of sessions or NCBs.
8263 * we should probably want to wait for a session to be freed in case
8266 osi_assert(session < SESSION_MAX - 1);
8267 osi_assert(numNCBs < NCB_MAX - 1); /* if we pass this test we can allocate one more */
8269 lock_ObtainMutex(&vcp->mx);
8270 vcp->session = session;
8271 lock_ReleaseMutex(&vcp->mx);
8272 lock_ObtainWrite(&smb_globalLock);
8273 LSNs[session] = ncbp->ncb_lsn;
8274 lanas[session] = ncbp->ncb_lana_num;
8275 lock_ReleaseWrite(&smb_globalLock);
8277 if (session == numSessions) {
8278 /* Add new NCB for new session */
8279 char eventName[MAX_PATH];
8281 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
8283 InitNCBslot(numNCBs);
8284 lock_ObtainWrite(&smb_globalLock);
8286 lock_ReleaseWrite(&smb_globalLock);
8287 thrd_SetEvent(NCBavails[0]);
8288 thrd_SetEvent(NCBevents[0]);
8289 for (thread = 0; thread < smb_NumServerThreads; thread++)
8290 thrd_SetEvent(NCBreturns[thread][0]);
8291 /* Also add new session event */
8292 sprintf(eventName, "SessionEvents[%d]", session);
8293 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8294 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8295 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8296 lock_ObtainWrite(&smb_globalLock);
8298 lock_ReleaseWrite(&smb_globalLock);
8299 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
8300 thrd_SetEvent(SessionEvents[0]);
8302 thrd_SetEvent(SessionEvents[session]);
8308 lock_ReleaseMutex(&smb_ListenerLock);
8309 } /* dispatch while loop */
8312 /* initialize Netbios */
8313 void smb_NetbiosInit()
8319 int i, lana, code, l;
8321 int delname_tried=0;
8324 OSVERSIONINFO Version;
8326 /* Get the version of Windows */
8327 memset(&Version, 0x00, sizeof(Version));
8328 Version.dwOSVersionInfoSize = sizeof(Version);
8329 GetVersionEx(&Version);
8331 /* setup the NCB system */
8334 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
8338 if (smb_LANadapter == -1) {
8339 ncbp->ncb_command = NCBENUM;
8340 ncbp->ncb_buffer = (PUCHAR)&lana_list;
8341 ncbp->ncb_length = sizeof(lana_list);
8342 code = Netbios(ncbp);
8344 afsi_log("Netbios NCBENUM error code %d", code);
8345 osi_panic(s, __FILE__, __LINE__);
8349 lana_list.length = 1;
8350 lana_list.lana[0] = smb_LANadapter;
8353 for (i = 0; i < lana_list.length; i++) {
8354 /* reset the adaptor: in Win32, this is required for every process, and
8355 * acts as an init call, not as a real hardware reset.
8357 ncbp->ncb_command = NCBRESET;
8358 ncbp->ncb_callname[0] = 100;
8359 ncbp->ncb_callname[2] = 100;
8360 ncbp->ncb_lana_num = lana_list.lana[i];
8361 code = Netbios(ncbp);
8363 code = ncbp->ncb_retcode;
8365 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
8366 lana_list.lana[i] = 255; /* invalid lana */
8368 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
8372 /* for DJGPP, there is no NCBENUM and NCBRESET is a real reset. so
8373 we will just fake the LANA list */
8374 if (smb_LANadapter == -1) {
8375 for (i = 0; i < 8; i++)
8376 lana_list.lana[i] = i;
8377 lana_list.length = 8;
8380 lana_list.length = 1;
8381 lana_list.lana[0] = smb_LANadapter;
8385 /* and declare our name so we can receive connections */
8386 memset(ncbp, 0, sizeof(*ncbp));
8387 len=lstrlen(smb_localNamep);
8388 memset(smb_sharename,' ',NCBNAMSZ);
8389 memcpy(smb_sharename,smb_localNamep,len);
8390 afsi_log("lana_list.length %d", lana_list.length);
8392 /* Keep the name so we can unregister it later */
8393 for (l = 0; l < lana_list.length; l++) {
8394 lana = lana_list.lana[l];
8396 ncbp->ncb_command = NCBADDNAME;
8397 ncbp->ncb_lana_num = lana;
8398 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8400 code = Netbios(ncbp);
8402 code = Netbios(ncbp, dos_ncb);
8405 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
8406 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
8408 char name[NCBNAMSZ+1];
8410 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
8411 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
8414 if (code == 0) code = ncbp->ncb_retcode;
8416 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
8418 /* we only use one LANA with djgpp */
8419 lana_list.lana[0] = lana;
8420 lana_list.length = 1;
8424 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8425 if (code == NRC_BRIDGE) { /* invalid LANA num */
8426 lana_list.lana[l] = 255;
8429 else if (code == NRC_DUPNAME) {
8430 afsi_log("Name already exists; try to delete it");
8431 memset(ncbp, 0, sizeof(*ncbp));
8432 ncbp->ncb_command = NCBDELNAME;
8433 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8434 ncbp->ncb_lana_num = lana;
8436 code = Netbios(ncbp);
8438 code = Netbios(ncbp, dos_ncb);
8441 code = ncbp->ncb_retcode;
8443 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
8445 if (code != 0 || delname_tried) {
8446 lana_list.lana[l] = 255;
8448 else if (code == 0) {
8449 if (!delname_tried) {
8457 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8458 lana_list.lana[l] = 255; /* invalid lana */
8459 osi_panic(s, __FILE__, __LINE__);
8463 lana_found = 1; /* at least one worked */
8470 osi_assert(lana_list.length >= 0);
8472 osi_panic("No valid LANA numbers found!", __FILE__, __LINE__);
8475 /* we're done with the NCB now */
8479 void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
8496 EVENT_HANDLE retHandle;
8497 char eventName[MAX_PATH];
8499 smb_TlsRequestSlot = TlsAlloc();
8502 smb_MBfunc = aMBfunc;
8506 smb_LANadapter = LANadapt;
8508 /* Initialize smb_localZero */
8509 myTime.tm_isdst = -1; /* compute whether on DST or not */
8510 myTime.tm_year = 70;
8516 smb_localZero = mktime(&myTime);
8518 #ifndef USE_NUMERIC_TIME_CONV
8519 /* Initialize kludge-GMT */
8520 smb_CalculateNowTZ();
8521 #endif /* USE_NUMERIC_TIME_CONV */
8522 #ifdef AFS_FREELANCE_CLIENT
8523 /* Make sure the root.afs volume has the correct time */
8524 cm_noteLocalMountPointChange();
8527 /* initialize the remote debugging log */
8530 /* remember the name */
8531 len = (int)strlen(snamep);
8532 smb_localNamep = malloc(len+1);
8533 strcpy(smb_localNamep, snamep);
8534 afsi_log("smb_localNamep is >%s<", smb_localNamep);
8536 /* and the global lock */
8537 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
8538 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
8540 /* Raw I/O data structures */
8541 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
8543 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
8545 /* 4 Raw I/O buffers */
8547 smb_RawBufs = calloc(65536,1);
8548 *((char **)smb_RawBufs) = NULL;
8549 for (i=0; i<3; i++) {
8550 char *rawBuf = calloc(65536,1);
8551 *((char **)rawBuf) = smb_RawBufs;
8552 smb_RawBufs = rawBuf;
8555 npar = 65536 >> 4; /* number of paragraphs */
8556 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[0]);
8558 afsi_log("Cannot allocate %d paragraphs of DOS memory",
8560 osi_panic("",__FILE__,__LINE__);
8563 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
8566 smb_RawBufs = (seg * 16) + 0; /* DOS physical address */
8568 _farpokel(_dos_ds, smb_RawBufs, NULL);
8569 for (i=0; i<SMB_RAW_BUFS-1; i++) {
8570 npar = 65536 >> 4; /* number of paragraphs */
8571 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[i+1]);
8573 afsi_log("Cannot allocate %d paragraphs of DOS memory",
8575 osi_panic("",__FILE__,__LINE__);
8578 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
8581 rawBuf = (seg * 16) + 0; /* DOS physical address */
8582 /*_farpokel(_dos_ds, smb_RawBufs, smb_RawBufs);*/
8583 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
8584 smb_RawBufs = rawBuf;
8588 /* global free lists */
8589 smb_ncbFreeListp = NULL;
8590 smb_packetFreeListp = NULL;
8594 /* Initialize listener and server structures */
8596 memset(dead_sessions, 0, sizeof(dead_sessions));
8597 sprintf(eventName, "SessionEvents[0]");
8598 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8599 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8600 afsi_log("Event Object Already Exists: %s", eventName);
8602 smb_NumServerThreads = nThreads;
8603 sprintf(eventName, "NCBavails[0]");
8604 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8605 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8606 afsi_log("Event Object Already Exists: %s", eventName);
8607 sprintf(eventName, "NCBevents[0]");
8608 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8609 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8610 afsi_log("Event Object Already Exists: %s", eventName);
8611 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
8612 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
8613 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8614 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8615 afsi_log("Event Object Already Exists: %s", eventName);
8616 for (i = 0; i < smb_NumServerThreads; i++) {
8617 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
8618 NCBreturns[i][0] = retHandle;
8621 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
8622 for (i = 0; i < smb_NumServerThreads; i++) {
8623 sprintf(eventName, "smb_ServerShutdown[%d]", i);
8624 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8625 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8626 afsi_log("Event Object Already Exists: %s", eventName);
8627 InitNCBslot((int)(i+1));
8629 numNCBs = smb_NumServerThreads + 1;
8631 /* Initialize dispatch table */
8632 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
8633 /* Prepare the table for unknown operations */
8634 for(i=0; i<= SMB_NOPCODES; i++) {
8635 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
8637 /* Fill in the ones we do know */
8638 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
8639 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
8640 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
8641 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
8642 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
8643 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
8644 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
8645 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
8646 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
8647 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
8648 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
8649 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
8650 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
8651 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
8652 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
8653 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
8654 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
8655 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
8656 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
8657 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
8658 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
8659 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8660 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
8661 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
8662 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
8663 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
8664 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
8665 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
8666 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8667 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
8668 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8669 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
8670 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
8671 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
8672 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8673 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
8674 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
8675 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
8676 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
8677 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
8678 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
8679 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
8680 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8681 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
8682 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8683 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
8684 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
8685 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
8686 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
8687 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
8688 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
8689 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
8690 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
8691 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
8692 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
8693 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
8694 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
8695 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
8696 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
8697 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
8698 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
8699 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
8700 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
8701 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
8702 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
8703 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8704 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
8705 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
8706 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
8707 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
8708 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
8709 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
8710 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
8711 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
8713 /* setup tran 2 dispatch table */
8714 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
8715 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
8716 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
8717 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
8718 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
8719 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
8720 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
8721 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
8722 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
8723 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
8724 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
8725 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
8726 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
8727 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
8728 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
8729 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
8730 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
8732 /* setup the rap dispatch table */
8733 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
8734 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
8735 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
8736 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
8737 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
8741 /* if we are doing SMB authentication we have register outselves as a logon process */
8742 if (smb_authType != SMB_AUTH_NONE) {
8743 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
8744 LSA_STRING afsProcessName;
8745 LSA_OPERATIONAL_MODE dummy; /*junk*/
8747 afsProcessName.Buffer = "OpenAFSClientDaemon";
8748 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
8749 afsProcessName.MaximumLength = afsProcessName.Length + 1;
8751 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
8753 if (nts == STATUS_SUCCESS) {
8754 LSA_STRING packageName;
8755 /* we are registered. Find out the security package id */
8756 packageName.Buffer = MSV1_0_PACKAGE_NAME;
8757 packageName.Length = (USHORT)strlen(packageName.Buffer);
8758 packageName.MaximumLength = packageName.Length + 1;
8759 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
8760 if (nts == STATUS_SUCCESS) {
8762 * This code forces Windows to authenticate against the Logon Cache
8763 * first instead of attempting to authenticate against the Domain
8764 * Controller. When the Windows logon cache is enabled this improves
8765 * performance by removing the network access and works around a bug
8766 * seen at sites which are using a MIT Kerberos principal to login
8767 * to machines joined to a non-root domain in a multi-domain forest.
8769 PVOID pResponse = NULL;
8770 ULONG cbResponse = 0;
8771 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
8773 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
8774 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
8775 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
8776 OptionsRequest.DisableOptions = FALSE;
8778 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
8781 sizeof(OptionsRequest),
8787 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
8789 sprintf(message,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
8791 OutputDebugString(message);
8794 OutputDebugString("MsV1_0SetProcessOption success");
8795 afsi_log("MsV1_0SetProcessOption success");
8797 /* END - code from Larry */
8799 smb_lsaLogonOrigin.Buffer = "OpenAFS";
8800 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
8801 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
8803 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
8805 /* something went wrong. We report the error and revert back to no authentication
8806 because we can't perform any auth requests without a successful lsa handle
8807 or sec package id. */
8808 afsi_log("Reverting to NO SMB AUTH");
8809 smb_authType = SMB_AUTH_NONE;
8812 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
8814 /* something went wrong. We report the error and revert back to no authentication
8815 because we can't perform any auth requests without a successful lsa handle
8816 or sec package id. */
8817 afsi_log("Reverting to NO SMB AUTH");
8818 smb_authType = SMB_AUTH_NONE;
8822 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
8823 * time prevents the failure of authentication when logged into Windows with an
8824 * external Kerberos principal mapped to a local account.
8826 else if ( smb_authType == SMB_AUTH_EXTENDED) {
8827 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
8828 * then the only option is NTLMSSP anyway; so just fallback.
8833 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
8834 if (secBlobLength == 0) {
8835 smb_authType = SMB_AUTH_NTLM;
8836 afsi_log("Reverting to SMB AUTH NTLM");
8845 /* Now get ourselves a domain name. */
8846 /* For now we are using the local computer name as the domain name.
8847 * It is actually the domain for local logins, and we are acting as
8848 * a local SMB server.
8850 bufsize = sizeof(smb_ServerDomainName) - 1;
8851 GetComputerName(smb_ServerDomainName, &bufsize);
8852 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
8853 afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
8856 /* Start listeners, waiters, servers, and daemons */
8858 for (i = 0; i < lana_list.length; i++) {
8859 if (lana_list.lana[i] == 255)
8861 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
8862 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
8863 osi_assert(phandle != NULL);
8864 thrd_CloseHandle(phandle);
8868 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
8869 NULL, 0, &lpid, "smb_ClientWaiter");
8870 osi_assert(phandle != NULL);
8871 thrd_CloseHandle(phandle);
8874 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
8875 NULL, 0, &lpid, "smb_ServerWaiter");
8876 osi_assert(phandle != NULL);
8877 thrd_CloseHandle(phandle);
8879 for (i=0; i<smb_NumServerThreads; i++) {
8880 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
8881 (void *) i, 0, &lpid, "smb_Server");
8882 osi_assert(phandle != NULL);
8883 thrd_CloseHandle(phandle);
8886 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
8887 NULL, 0, &lpid, "smb_Daemon");
8888 osi_assert(phandle != NULL);
8889 thrd_CloseHandle(phandle);
8891 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
8892 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
8893 osi_assert(phandle != NULL);
8894 thrd_CloseHandle(phandle);
8903 void smb_Shutdown(void)
8913 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
8915 /* setup the NCB system */
8918 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
8921 /* Block new sessions by setting shutdown flag */
8922 smbShutdownFlag = 1;
8924 /* Hang up all sessions */
8925 memset((char *)ncbp, 0, sizeof(NCB));
8926 for (i = 1; i < numSessions; i++)
8928 if (dead_sessions[i])
8931 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8932 ncbp->ncb_command = NCBHANGUP;
8933 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
8934 ncbp->ncb_lsn = (UCHAR)LSNs[i];
8936 code = Netbios(ncbp);
8938 code = Netbios(ncbp, dos_ncb);
8940 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8941 if (code == 0) code = ncbp->ncb_retcode;
8943 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
8944 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
8948 /* Trigger the shutdown of all SMB threads */
8949 for (i = 0; i < smb_NumServerThreads; i++)
8950 thrd_SetEvent(NCBreturns[i][0]);
8952 thrd_SetEvent(NCBevents[0]);
8953 thrd_SetEvent(SessionEvents[0]);
8954 thrd_SetEvent(NCBavails[0]);
8956 for (i = 0;i < smb_NumServerThreads; i++) {
8957 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
8958 if (code == WAIT_OBJECT_0) {
8961 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
8962 thrd_SetEvent(NCBreturns[i--][0]);
8966 /* Delete Netbios name */
8967 memset((char *)ncbp, 0, sizeof(NCB));
8968 for (i = 0; i < lana_list.length; i++) {
8969 if (lana_list.lana[i] == 255) continue;
8970 ncbp->ncb_command = NCBDELNAME;
8971 ncbp->ncb_lana_num = lana_list.lana[i];
8972 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8974 code = Netbios(ncbp);
8976 code = Netbios(ncbp, dos_ncb);
8979 code = ncbp->ncb_retcode;
8981 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
8982 ncbp->ncb_lana_num, code);
8987 /* Release the reference counts held by the VCs */
8988 lock_ObtainWrite(&smb_rctLock);
8989 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
8994 if (vcp->magic != SMB_VC_MAGIC)
8995 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
8996 __FILE__, __LINE__);
8998 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9000 if (fidp->scp != NULL) {
9003 lock_ObtainMutex(&fidp->mx);
9004 if (fidp->scp != NULL) {
9007 cm_ReleaseSCache(scp);
9009 lock_ReleaseMutex(&fidp->mx);
9013 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
9015 smb_ReleaseVCNoLock(tidp->vcp);
9017 cm_user_t *userp = tidp->userp;
9019 lock_ReleaseWrite(&smb_rctLock);
9020 cm_ReleaseUser(userp);
9021 lock_ObtainWrite(&smb_rctLock);
9025 lock_ReleaseWrite(&smb_rctLock);
9027 TlsFree(smb_TlsRequestSlot);
9030 /* Get the UNC \\<servername>\<sharename> prefix. */
9031 char *smb_GetSharename()
9035 /* Make sure we have been properly initialized. */
9036 if (smb_localNamep == NULL)
9039 /* Allocate space for \\<servername>\<sharename>, plus the
9042 name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
9043 sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
9049 void smb_LogPacket(smb_packet_t *packet)
9052 unsigned length, paramlen, datalen, i, j;
9054 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
9056 if (!packet) return;
9058 osi_Log0(smb_logp, "*** SMB packet dump ***");
9060 vp = (BYTE *) packet->data;
9062 datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
9063 length = paramlen + 2 + datalen;
9066 for (i=0;i < length; i+=16)
9068 memset( buf, ' ', 80 );
9073 buf[strlen(buf)] = ' ';
9075 cp = (BYTE*) buf + 7;
9077 for (j=0;j < 16 && (i+j)<length; j++)
9079 *(cp++) = hex[vp[i+j] >> 4];
9080 *(cp++) = hex[vp[i+j] & 0xf];
9090 for (j=0;j < 16 && (i+j)<length;j++)
9092 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
9103 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
9106 osi_Log0(smb_logp, "*** End SMB packet dump ***");
9108 #endif /* LOG_PACKET */
9111 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
9119 lock_ObtainRead(&smb_rctLock);
9121 sprintf(output, "begin dumping smb_vc_t\n");
9122 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9124 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
9128 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
9129 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9130 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9132 sprintf(output, "begin dumping smb_fid_t\n");
9133 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9135 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9137 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",
9138 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9139 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
9140 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
9141 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9144 sprintf(output, "done dumping smb_fid_t\n");
9145 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9148 sprintf(output, "done dumping smb_vc_t\n");
9149 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9151 sprintf(output, "begin dumping DEAD smb_vc_t\n");
9152 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9154 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
9158 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
9159 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9160 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9162 sprintf(output, "begin dumping smb_fid_t\n");
9163 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9165 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9167 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",
9168 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9169 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
9170 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
9171 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9174 sprintf(output, "done dumping smb_fid_t\n");
9175 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9178 sprintf(output, "done dumping DEAD smb_vc_t\n");
9179 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9181 sprintf(output, "begin dumping DEAD smb_vc_t\n");
9182 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9184 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
9188 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
9189 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9190 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9192 sprintf(output, "begin dumping smb_fid_t\n");
9193 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9195 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9197 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",
9198 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9199 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
9200 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
9201 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9204 sprintf(output, "done dumping smb_fid_t\n");
9205 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9208 sprintf(output, "done dumping DEAD smb_vc_t\n");
9209 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9212 lock_ReleaseRead(&smb_rctLock);