smb-rap-20040720
[openafs.git] / src / WINNT / afsd / smb.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
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
8  */
9
10 //#define NOSERVICE 1
11
12 #include <afs/param.h>
13 #include <afs/stds.h>
14
15 #ifndef DJGPP
16 #include <windows.h>
17 #else
18 #include <sys/timeb.h>
19 #include <tzfile.h>
20 #endif /* !DJGPP */
21 #include <stddef.h>
22 #include <stdlib.h>
23 #include <malloc.h>
24 #include <string.h>
25 #include <stdio.h>
26 #include <time.h>
27
28 #include <osi.h>
29 #include <ntstatus.h>
30
31 #include "afsd.h"
32
33 #include "smb.h"
34 #include "lanahelper.h"
35
36 /* These characters are illegal in Windows filenames */
37 static char *illegalChars = "\\/:*?\"<>|";
38 BOOL isWindows2000 = FALSE;
39
40 smb_vc_t *dead_vcp = NULL;
41 smb_vc_t *active_vcp = NULL;
42
43 /* TODO; logout mechanism needs to be thread-safe */
44 char *loggedOutName = NULL;
45 smb_user_t *loggedOutUserp = NULL;
46 unsigned long loggedOutTime;
47 int loggedOut = 0;
48 int smbShutdownFlag = 0;
49
50 int smb_LogoffTokenTransfer;
51 unsigned long smb_LogoffTransferTimeout;
52
53 DWORD last_msg_time = 0;
54
55 long ongoingOps = 0;
56
57 unsigned int sessionGen = 0;
58
59 extern void afsi_log(char *pattern, ...);
60 extern HANDLE afsi_file;
61
62 osi_hyper_t hzero = {0, 0};
63 osi_hyper_t hones = {0xFFFFFFFF, -1};
64
65 osi_log_t *  smb_logp;
66 osi_rwlock_t smb_globalLock;
67 osi_rwlock_t smb_rctLock;
68 osi_mutex_t  smb_ListenerLock;
69  
70 char smb_LANadapter;
71 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
72
73 /* for debugging */
74 long smb_maxObsConcurrentCalls=0;
75 long smb_concurrentCalls=0;
76
77 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
78
79 smb_packet_t *smb_packetFreeListp;
80 smb_ncb_t *smb_ncbFreeListp;
81
82 int smb_NumServerThreads;
83
84 int numNCBs, numSessions, numVCs;
85
86 int smb_maxVCPerServer;
87 int smb_maxMpxRequests;
88
89 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
90 HANDLE smb_lsaHandle;
91 ULONG smb_lsaSecPackage;
92 LSA_STRING smb_lsaLogonOrigin;
93
94 #define NCBmax MAXIMUM_WAIT_OBJECTS
95 EVENT_HANDLE NCBavails[NCBmax], NCBevents[NCBmax];
96 EVENT_HANDLE **NCBreturns;
97 DWORD NCBsessions[NCBmax];
98 NCB *NCBs[NCBmax];
99 struct smb_packet *bufs[NCBmax];
100
101 #define Sessionmax MAXIMUM_WAIT_OBJECTS
102 EVENT_HANDLE SessionEvents[Sessionmax];
103 unsigned short LSNs[Sessionmax];
104 int lanas[Sessionmax];
105 BOOL dead_sessions[Sessionmax];
106 LANA_ENUM lana_list;
107
108 /* for raw I/O */
109 osi_mutex_t smb_RawBufLock;
110 #ifdef DJGPP
111 #define SMB_RAW_BUFS 4
112 dos_ptr smb_RawBufs;
113 int smb_RawBufSel[SMB_RAW_BUFS];
114 #else
115 char *smb_RawBufs;
116 #endif /* DJGPP */
117
118 #define SMB_MASKFLAG_TILDE 1
119 #define SMB_MASKFLAG_CASEFOLD 2
120
121 #define RAWTIMEOUT INFINITE
122
123 /* for raw write */
124 typedef struct raw_write_cont {
125         long code;
126         osi_hyper_t offset;
127         long count;
128 #ifndef DJGPP
129         char *buf;
130 #else
131         dos_ptr buf;
132 #endif /* DJGPP */
133         int writeMode;
134         long alreadyWritten;
135 } raw_write_cont_t;
136
137 /* dir search stuff */
138 long smb_dirSearchCounter = 1;
139 smb_dirSearch_t *smb_firstDirSearchp;
140 smb_dirSearch_t *smb_lastDirSearchp;
141
142 /* hide dot files? */
143 int smb_hideDotFiles;
144
145 /* global state about V3 protocols */
146 int smb_useV3;          /* try to negotiate V3 */
147
148 #ifndef DJGPP
149 static showErrors = 1;
150 /* MessageBox or something like it */
151 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
152 extern HANDLE WaitToTerminate;
153 #endif /* DJGPP */
154
155 /* GMT time info:
156  * Time in Unix format of midnight, 1/1/1970 local time.
157  * When added to dosUTime, gives Unix (AFS) time.
158  */
159 long smb_localZero;
160
161 /* Time difference for converting to kludge-GMT */
162 int smb_NowTZ;
163
164 char *smb_localNamep = NULL;
165
166 smb_vc_t *smb_allVCsp;
167
168 smb_username_t *usernamesp = NULL;
169
170 smb_waitingLock_t *smb_allWaitingLocks;
171
172 /* forward decl */
173 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
174                                                 NCB *ncbp, raw_write_cont_t *rwcp);
175 void smb_NetbiosInit();
176 #ifdef DJGPP
177 #ifndef AFS_WIN95_ENV
178 DWORD smb_ServerExceptionFilter(void);
179 #endif
180
181 extern char cm_HostName[];
182 extern char cm_confDir[];
183 #endif
184
185 #ifdef DJGPP
186 #define LPTSTR char *
187 #define GetComputerName(str, sizep) \
188        strcpy((str), cm_HostName); \
189        *(sizep) = strlen(cm_HostName)
190 #endif /* DJGPP */
191
192 extern char AFSConfigKeyName[];
193
194 char smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = ""; /* domain name */
195 int smb_ServerDomainNameLength = 0;
196 char smb_ServerOS[] = "Windows 5.0"; /* Faux OS String */
197 int smb_ServerOSLength = sizeof(smb_ServerOS);
198 char smb_ServerLanManager[] = "Windows 2000 LAN Manager"; /* Faux LAN Manager string */
199 int smb_ServerLanManagerLength = sizeof(smb_ServerLanManager);
200
201 /* Faux server GUID. This is never checked. */
202 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
203
204 /*
205  * Demo expiration
206  *
207  * To build an expiring version, comment out the definition of NOEXPIRE,
208  * and set the definition of EXPIREDATE to the desired value.
209  */
210 #define NOEXPIRE 1
211 #define EXPIREDATE 834000000            /* Wed Jun 5 1996 */
212
213
214 char * myCrt_Dispatch(int i)
215 {
216         switch (i)
217         {
218         default:
219                 return "unknown SMB op";
220         case 0x00:
221                 return "(00)ReceiveCoreMakeDir";
222         case 0x01:
223                 return "(01)ReceiveCoreRemoveDir";
224         case 0x02:
225                 return "(02)ReceiveCoreOpen";
226         case 0x03:
227                 return "(03)ReceiveCoreCreate";
228         case 0x04:
229                 return "(04)ReceiveCoreClose";
230         case 0x05:
231                 return "(05)ReceiveCoreFlush";
232         case 0x06:
233                 return "(06)ReceiveCoreUnlink";
234         case 0x07:
235                 return "(07)ReceiveCoreRename";
236         case 0x08:
237                 return "(08)ReceiveCoreGetFileAttributes";
238         case 0x09:
239                 return "(09)ReceiveCoreSetFileAttributes";
240         case 0x0a:
241                 return "(0a)ReceiveCoreRead";
242         case 0x0b:
243                 return "(0b)ReceiveCoreWrite";
244         case 0x0c:
245                 return "(0c)ReceiveCoreLockRecord";
246         case 0x0d:
247                 return "(0d)ReceiveCoreUnlockRecord";
248         case 0x0e:
249                 return "(0e)SendCoreBadOp";
250         case 0x0f:
251                 return "(0f)ReceiveCoreCreate";
252         case 0x10:
253                 return "(10)ReceiveCoreCheckPath";
254         case 0x11:
255                 return "(11)SendCoreBadOp";
256         case 0x12:
257                 return "(12)ReceiveCoreSeek";
258         case 0x1a:
259                 return "(1a)ReceiveCoreReadRaw";
260         case 0x1d:
261                 return "(1d)ReceiveCoreWriteRawDummy";
262         case 0x22:
263                 return "(22)ReceiveV3SetAttributes";
264         case 0x23:
265                 return "(23)ReceiveV3GetAttributes";
266         case 0x24:
267                 return "(24)ReceiveV3LockingX";
268         case 0x25:
269                 return "(25)ReceiveV3Trans";
270         case 0x26:
271                 return "(26)ReceiveV3Trans[aux]";
272         case 0x29:
273                 return "(29)SendCoreBadOp";
274         case 0x2b:
275                 return "(2b)ReceiveCoreEcho";
276         case 0x2d:
277                 return "(2d)ReceiveV3OpenX";
278         case 0x2e:
279                 return "(2e)ReceiveV3ReadX";
280         case 0x32:
281                 return "(32)ReceiveV3Tran2A";
282         case 0x33:
283                 return "(33)ReceiveV3Tran2A[aux]";
284         case 0x34:
285                 return "(34)ReceiveV3FindClose";
286         case 0x35:
287                 return "(35)ReceiveV3FindNotifyClose";
288         case 0x70:
289                 return "(70)ReceiveCoreTreeConnect";
290         case 0x71:
291                 return "(71)ReceiveCoreTreeDisconnect";
292         case 0x72:
293                 return "(72)ReceiveNegotiate";
294         case 0x73:
295                 return "(73)ReceiveV3SessionSetupX";
296         case 0x74:
297                 return "(74)ReceiveV3UserLogoffX";
298         case 0x75:
299                 return "(75)ReceiveV3TreeConnectX";
300         case 0x80:
301                 return "(80)ReceiveCoreGetDiskAttributes";
302         case 0x81:
303                 return "(81)ReceiveCoreSearchDir";
304         case 0xA0:
305                 return "(A0)ReceiveNTTransact";
306         case 0xA2:
307                 return "(A2)ReceiveNTCreateX";
308         case 0xA4:
309                 return "(A4)ReceiveNTCancel";
310         case 0xc0:
311                 return "(c0)SendCoreBadOp";
312         case 0xc1:
313                 return "(c1)SendCoreBadOp";
314         case 0xc2:
315                 return "(c2)SendCoreBadOp";
316         case 0xc3:
317                 return "(c3)SendCoreBadOp";
318         }
319 }
320
321 char * myCrt_2Dispatch(int i)
322 {
323         switch (i)
324         {
325         default:
326                 return "unknown SMB op-2";
327         case 0:
328                 return "S(00)CreateFile";
329         case 1:
330                 return "S(01)FindFirst";
331         case 2:
332                 return "S(02)FindNext"; /* FindNext */
333         case 3:
334                 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
335         case 4:
336                 return "S(04)??";
337         case 5:
338                 return "S(05)QueryFileInfo_ReceiveTran2QPathInfo";
339         case 6:
340                 return "S(06)SetFileInfo_ReceiveTran2SetPathInfo";
341         case 7:
342                 return "S(07)SetInfoHandle_ReceiveTran2QFileInfo";
343         case 8:
344                 return "S(08)??_ReceiveTran2SetFileInfo";
345         case 9:
346                 return "S(09)??_ReceiveTran2FSCTL";
347         case 10:
348                 return "S(0a)_ReceiveTran2IOCTL";
349         case 11:
350                 return "S(0b)_ReceiveTran2FindNotifyFirst";
351         case 12:
352                 return "S(0c)_ReceiveTran2FindNotifyNext";
353         case 13:
354                 return "S(0d)CreateDirectory_ReceiveTran2MKDir";
355         }
356 }
357
358 char * myCrt_RapDispatch(int i)
359 {
360         switch(i)
361         {
362         default:
363                 return "unknown RAP OP";
364         case 0:
365                 return "RAP(0)NetShareEnum";
366         case 1:
367                 return "RAP(1)NetShareGetInfo";
368         case 13:
369                 return "RAP(13)NetServerGetInfo";
370         case 63:
371                 return "RAP(63)NetWkStaGetInfo";
372         }
373 }
374
375 /* scache must be locked */
376 unsigned int smb_Attributes(cm_scache_t *scp)
377 {
378         unsigned int attrs;
379
380         if (scp->fileType == CM_SCACHETYPE_DIRECTORY
381                 || scp->fileType == CM_SCACHETYPE_MOUNTPOINT)
382                 attrs = SMB_ATTR_DIRECTORY;
383         else
384                 attrs = 0;
385
386         /*
387          * We used to mark a file RO if it was in an RO volume, but that
388          * turns out to be impolitic in NT.  See defect 10007.
389          */
390 #ifdef notdef
391         if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
392 #endif
393         if ((scp->unixModeBits & 0222) == 0)
394                 attrs |= SMB_ATTR_READONLY;     /* turn on read-only flag */
395
396         return attrs;
397 }
398
399 /* Check if the named file/dir is a dotfile/dotdir */
400 /* String pointed to by lastComp can have leading slashes, but otherwise should have
401    no other patch components */
402 unsigned int smb_IsDotFile(char *lastComp) {
403         char *s;
404         if(lastComp) {
405                 /* skip over slashes */
406         for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
407         }
408         else
409                 return 0;
410
411     /* nulls, curdir and parent dir doesn't count */
412         if(!*s) return 0;
413         if(*s == '.') {
414                 if(!*(s + 1)) return 0;
415                 if(*(s+1) == '.' && !*(s + 2)) return 0;
416                 return 1;
417         }
418         return 0;
419 }
420
421 static int ExtractBits(WORD bits, short start, short len)
422 {
423         int end;
424         WORD num;
425
426         end = start + len;
427         
428         num = bits << (16 - end);
429         num = num >> ((16 - end) + start);
430
431         return (int)num;
432 }
433
434 #ifndef DJGPP
435 void ShowUnixTime(char *FuncName, long unixTime)
436 {
437         FILETIME ft;
438         WORD wDate, wTime;
439
440         smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
441                 
442         if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
443                 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
444         else {
445                 int day, month, year, sec, min, hour;
446                 char msg[256];
447
448                 day = ExtractBits(wDate, 0, 5);
449                 month = ExtractBits(wDate, 5, 4);
450                 year = ExtractBits(wDate, 9, 7) + 1980;
451
452                 sec = ExtractBits(wTime, 0, 5);
453                 min = ExtractBits(wTime, 5, 6);
454                 hour = ExtractBits(wTime, 11, 5);
455
456                 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
457                 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
458         }
459 }
460 #endif /* DJGPP */
461
462 #ifndef DJGPP
463 /* Determine if we are observing daylight savings time */
464 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
465 {
466         TIME_ZONE_INFORMATION timeZoneInformation;
467         SYSTEMTIME utc, local, localDST;
468
469         /* Get the time zone info. NT uses this to calc if we are in DST. */
470         GetTimeZoneInformation(&timeZoneInformation);
471  
472         /* Return the daylight bias */
473         *pDstBias = timeZoneInformation.DaylightBias;
474
475         /* Return the bias */
476         *pBias = timeZoneInformation.Bias;
477
478         /* Now determine if DST is being observed */
479
480         /* Get the UTC (GMT) time */
481         GetSystemTime(&utc);
482
483         /* Convert UTC time to local time using the time zone info.  If we are
484            observing DST, the calculated local time will include this. 
485         */
486         SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
487
488         /* Set the daylight bias to 0.  The daylight bias is the amount of change
489            in time that we use for daylight savings time.  By setting this to 0
490            we cause there to be no change in time during daylight savings time. 
491         */
492         timeZoneInformation.DaylightBias = 0;
493
494         /* Convert the utc time to local time again, but this time without any
495            adjustment for daylight savings time. 
496         */
497         SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
498
499         /* If the two times are different, then it means that the localDST that
500            we calculated includes the daylight bias, and therefore we are
501            observing daylight savings time.
502         */
503         *pDST = localDST.wHour != local.wHour;
504 }
505 #else
506 /* Determine if we are observing daylight savings time */
507 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
508 {
509         struct timeb t;
510
511         ftime(&t);
512         *pDST = t.dstflag;
513         *pDstBias = -60;    /* where can this be different? */
514         *pBias = t.timezone;
515 }
516 #endif /* DJGPP */
517  
518
519 void CompensateForSmbClientLastWriteTimeBugs(long *pLastWriteTime)
520 {
521         BOOL dst;       /* Will be TRUE if observing DST */
522         LONG dstBias;   /* Offset from local time if observing DST */
523         LONG bias;      /* Offset from GMT for local time */
524
525         /*
526          * This function will adjust the last write time to compensate
527          * for two bugs in the smb client:
528          *
529          *    1) During Daylight Savings Time, the LastWriteTime is ahead
530          *       in time by the DaylightBias (ignoring the sign - the
531          *       DaylightBias is always stored as a negative number).  If
532          *       the DaylightBias is -60, then the LastWriteTime will be
533          *       ahead by 60 minutes.
534          *
535          *    2) If the local time zone is a positive offset from GMT, then
536          *       the LastWriteTime will be the correct local time plus the
537          *       Bias (ignoring the sign - a positive offset from GMT is
538          *       always stored as a negative Bias).  If the Bias is -120,
539          *       then the LastWriteTime will be ahead by 120 minutes.
540          *
541          *    These bugs can occur at the same time.
542          */
543
544         GetTimeZoneInfo(&dst, &dstBias, &bias);
545
546         /* First adjust for DST */
547         if (dst)
548                 *pLastWriteTime -= (-dstBias * 60);     /* Convert dstBias to seconds */
549
550         /* Now adjust for a positive offset from GMT (a negative bias). */
551         if (bias < 0)
552                 *pLastWriteTime -= (-bias * 60);        /* Convert bias to seconds */
553 }               
554
555 /*
556  * Calculate the difference (in seconds) between local time and GMT.
557  * This enables us to convert file times to kludge-GMT.
558  */
559 static void
560 smb_CalculateNowTZ()
561 {
562         time_t t;
563         struct tm gmt_tm, local_tm;
564         int days, hours, minutes, seconds;
565
566         t = time(NULL);
567         gmt_tm = *(gmtime(&t));
568         local_tm = *(localtime(&t));
569
570         days = local_tm.tm_yday - gmt_tm.tm_yday;
571         hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour
572 #ifdef COMMENT
573         /* There is a problem with DST immediately after the time change
574          * which may continue to exist until the machine is rebooted
575          */
576         - (local_tm.tm_isdst ? 1 : 0)
577 #endif /* COMMENT */
578         ;
579         minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
580         seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
581
582         smb_NowTZ = seconds;
583 }
584
585 #ifndef DJGPP
586 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, long unixTime)
587 {
588         struct tm *ltp;
589         SYSTEMTIME stm;
590         struct tm localJunk;
591         long ersatz_unixTime;
592
593         /*
594          * Must use kludge-GMT instead of real GMT.
595          * kludge-GMT is computed by adding time zone difference to localtime.
596          *
597          * real GMT would be:
598          * ltp = gmtime(&unixTime);
599          */
600         ersatz_unixTime = unixTime - smb_NowTZ;
601         ltp = localtime(&ersatz_unixTime);
602
603         /* if we fail, make up something */
604         if (!ltp) {
605                 ltp = &localJunk;
606                 localJunk.tm_year = 89 - 20;
607                 localJunk.tm_mon = 4;
608                 localJunk.tm_mday = 12;
609                 localJunk.tm_hour = 0;
610                 localJunk.tm_min = 0;
611                 localJunk.tm_sec = 0;
612         }
613
614         stm.wYear = ltp->tm_year + 1900;
615         stm.wMonth = ltp->tm_mon + 1;
616         stm.wDayOfWeek = ltp->tm_wday;
617         stm.wDay = ltp->tm_mday;
618         stm.wHour = ltp->tm_hour;
619         stm.wMinute = ltp->tm_min;
620         stm.wSecond = ltp->tm_sec;
621         stm.wMilliseconds = 0;
622
623         SystemTimeToFileTime(&stm, largeTimep);
624 }
625 #else /* DJGPP */
626 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, long unixTime)
627 {
628         /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
629         /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 ??? */
630         LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
631         LARGE_INTEGER ut;
632         int leap_years = 89;   /* leap years betw 1/1/1601 and 1/1/1970 */
633
634         /* set ft to number of 100ns intervals betw 1/1/1601 and 1/1/1970 GMT */
635         *ft = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years)
636                                    * 24 * 60);
637         *ft = LargeIntegerMultiplyByLong(*ft, 60);
638         *ft = LargeIntegerMultiplyByLong(*ft, 10000000);
639
640         /* add unix time */
641         ut = ConvertLongToLargeInteger(unixTime);
642         ut = LargeIntegerMultiplyByLong(ut, 10000000);
643         *ft = LargeIntegerAdd(*ft, ut);
644 }
645 #endif /* !DJGPP */
646
647 #ifndef DJGPP
648 void smb_UnixTimeFromLargeSearchTime(long *unixTimep, FILETIME *largeTimep)
649 {
650         SYSTEMTIME stm;
651         struct tm lt;
652         long save_timezone;
653
654         FileTimeToSystemTime(largeTimep, &stm);
655
656         lt.tm_year = stm.wYear - 1900;
657         lt.tm_mon = stm.wMonth - 1;
658         lt.tm_wday = stm.wDayOfWeek;
659         lt.tm_mday = stm.wDay;
660         lt.tm_hour = stm.wHour;
661         lt.tm_min = stm.wMinute;
662         lt.tm_sec = stm.wSecond;
663         lt.tm_isdst = -1;
664
665         save_timezone = _timezone;
666         _timezone += smb_NowTZ;
667         *unixTimep = mktime(&lt);
668         _timezone = save_timezone;
669 }
670 #else /* DJGPP */
671 void smb_UnixTimeFromLargeSearchTime(long *unixTimep, FILETIME *largeTimep)
672 {
673         /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
674         /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 GMT? */
675         LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
676         LARGE_INTEGER a;
677         int leap_years = 89;
678
679         /* set to number of 100ns intervals betw 1/1/1601 and 1/1/1970 */
680         a = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years) * 24 * 60);
681         a = LargeIntegerMultiplyByLong(a, 60);
682         a = LargeIntegerMultiplyByLong(a, 10000000);
683
684         /* subtract it from ft */
685         a = LargeIntegerSubtract(*ft, a);
686
687         /* divide down to seconds */
688         *unixTimep = LargeIntegerDivideByLong(a, 10000000);
689 }
690 #endif /* !DJGPP */
691
692 void smb_SearchTimeFromUnixTime(long *dosTimep, long unixTime)
693 {
694         struct tm *ltp;
695         int dosDate;
696         int dosTime;
697         struct tm localJunk;
698
699         ltp = localtime((time_t*) &unixTime);
700
701         /* if we fail, make up something */
702         if (!ltp) {
703                 ltp = &localJunk;
704                 localJunk.tm_year = 89 - 20;
705                 localJunk.tm_mon = 4;
706                 localJunk.tm_mday = 12;
707                 localJunk.tm_hour = 0;
708                 localJunk.tm_min = 0;
709                 localJunk.tm_sec = 0;
710         }       
711
712         dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
713         dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
714         *dosTimep = (dosDate<<16) | dosTime;
715 }       
716
717 void smb_UnixTimeFromSearchTime(long *unixTimep, long searchTime)
718 {
719         unsigned short dosDate;
720         unsigned short dosTime;
721         struct tm localTm;
722         
723         dosDate = searchTime & 0xffff;
724         dosTime = (searchTime >> 16) & 0xffff;
725         
726         localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
727         localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1;    /* January is 0 in localTm */
728         localTm.tm_mday = (dosDate) & 0x1f;
729         localTm.tm_hour = (dosTime>>11) & 0x1f;
730         localTm.tm_min = (dosTime >> 5) & 0x3f;
731         localTm.tm_sec = (dosTime & 0x1f) * 2;
732         localTm.tm_isdst = -1;                          /* compute whether DST in effect */
733
734         *unixTimep = mktime(&localTm);
735 }
736
737 void smb_DosUTimeFromUnixTime(long *dosUTimep, long unixTime)
738 {
739         *dosUTimep = unixTime - smb_localZero;
740 }
741
742 void smb_UnixTimeFromDosUTime(long *unixTimep, long dosTime)
743 {
744 #ifndef DJGPP
745         *unixTimep = dosTime + smb_localZero;
746 #else /* DJGPP */
747         /* dosTime seems to be already adjusted for GMT */
748         *unixTimep = dosTime;
749 #endif /* !DJGPP */
750 }
751
752 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
753 {
754         smb_vc_t *vcp;
755
756         lock_ObtainWrite(&smb_rctLock);
757         for(vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
758                 if (lsn == vcp->lsn && lana == vcp->lana) {
759                         vcp->refCount++;
760                         break;
761                 }
762         }
763         if (!vcp && (flags & SMB_FLAG_CREATE)) {
764                 vcp = malloc(sizeof(*vcp));
765                 memset(vcp, 0, sizeof(*vcp));
766         vcp->vcID = numVCs++;
767                 vcp->refCount = 1;
768                 vcp->tidCounter = 1;
769                 vcp->fidCounter = 1;
770                 vcp->uidCounter = 1;  /* UID 0 is reserved for blank user */
771                 vcp->nextp = smb_allVCsp;
772                 smb_allVCsp = vcp;
773                 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
774                 vcp->lsn = lsn;
775                 vcp->lana = lana;
776         vcp->secCtx = NULL;
777
778                 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
779             /* We must obtain a challenge for extended auth 
780              * in case the client negotiates smb v3 
781              */
782             NTSTATUS nts,ntsEx;
783                         MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
784                         PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp;
785                         ULONG lsaRespSize;
786
787                         lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
788
789                         nts = LsaCallAuthenticationPackage( smb_lsaHandle,
790                                                 smb_lsaSecPackage,
791                                                 &lsaReq,
792                                                 sizeof(lsaReq),
793                                                 &lsaResp,
794                                                 &lsaRespSize,
795                                                 &ntsEx);
796                         osi_assert(nts == STATUS_SUCCESS); /* this had better work! */
797
798                         memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
799             LsaFreeReturnBuffer(lsaResp);
800                 }
801                 else
802                         memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
803         }
804         lock_ReleaseWrite(&smb_rctLock);
805         return vcp;
806 }
807
808 int smb_IsStarMask(char *maskp)
809 {
810         int i;
811         char tc;
812         
813         for(i=0; i<11; i++) {
814                 tc = *maskp++;
815                 if (tc == '?' || tc == '*' || tc == '>') return 1;        
816         }       
817         return 0;
818 }
819
820 void smb_ReleaseVC(smb_vc_t *vcp)
821 {
822         lock_ObtainWrite(&smb_rctLock);
823         osi_assert(vcp->refCount-- > 0);
824         lock_ReleaseWrite(&smb_rctLock);
825 }
826
827 void smb_HoldVC(smb_vc_t *vcp)
828 {
829         lock_ObtainWrite(&smb_rctLock);
830         vcp->refCount++;
831         lock_ReleaseWrite(&smb_rctLock);
832 }
833
834 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
835 {
836         smb_tid_t *tidp;
837
838         lock_ObtainWrite(&smb_rctLock);
839         for(tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
840                 if (tid == tidp->tid) {
841                         tidp->refCount++;
842                         break;
843                 }       
844         }
845         if (!tidp && (flags & SMB_FLAG_CREATE)) {
846                 tidp = malloc(sizeof(*tidp));
847                 memset(tidp, 0, sizeof(*tidp));
848                 tidp->nextp = vcp->tidsp;
849                 tidp->refCount = 1;
850                 tidp->vcp = vcp;
851         vcp->refCount++;
852                 vcp->tidsp = tidp;
853                 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
854                 tidp->tid = tid;
855         }
856         lock_ReleaseWrite(&smb_rctLock);
857         return tidp;
858 }       
859
860 void smb_ReleaseTID(smb_tid_t *tidp)
861 {
862         smb_tid_t *tp;
863         smb_tid_t **ltpp;
864         cm_user_t *userp;
865     smb_vc_t  *vcp;
866
867         userp = NULL;
868     vcp = NULL;
869         lock_ObtainWrite(&smb_rctLock);
870         osi_assert(tidp->refCount-- > 0);
871         if (tidp->refCount == 0 && (tidp->flags & SMB_TIDFLAG_DELETE)) {
872                 ltpp = &tidp->vcp->tidsp;
873                 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
874                         if (tp == tidp) break;
875                 }
876                 osi_assert(tp != NULL);
877                 *ltpp = tp->nextp;
878                 lock_FinalizeMutex(&tidp->mx);
879                 userp = tidp->userp;    /* remember to drop ref later */
880         vcp = tidp->vcp;
881         }
882         lock_ReleaseWrite(&smb_rctLock);
883         if (userp) {
884                 cm_ReleaseUser(userp);
885         }       
886     if (vcp) {
887         smb_ReleaseVC(vcp);
888     }
889 }       
890
891 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
892 {
893         smb_user_t *uidp = NULL;
894
895         lock_ObtainWrite(&smb_rctLock);
896         for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
897                 if (uid == uidp->userID) {
898                         uidp->refCount++;
899                         osi_LogEvent("AFS smb_FindUID (Find by UID)",NULL," VCP[%x] found-uid[%d] name[%s]",(int)vcp,uidp->userID,(uidp->unp) ? uidp->unp->name : "");
900                 break;
901                 }
902         }
903         if (!uidp && (flags & SMB_FLAG_CREATE)) {
904                 uidp = malloc(sizeof(*uidp));
905                 memset(uidp, 0, sizeof(*uidp));
906                 uidp->nextp = vcp->usersp;
907                 uidp->refCount = 1;
908                 uidp->vcp = vcp;
909         vcp->refCount++;
910                 vcp->usersp = uidp;
911                 lock_InitializeMutex(&uidp->mx, "user_t mutex");
912                 uidp->userID = uid;
913                 osi_LogEvent("AFS smb_FindUID (Find by UID)",NULL,"VCP[%x] new-uid[%d] name[%s]",(int)vcp,uidp->userID,(uidp->unp ? uidp->unp->name : ""));
914         }
915         lock_ReleaseWrite(&smb_rctLock);
916         return uidp;
917 }       
918
919 smb_username_t *smb_FindUserByName(char *usern, char *machine, int flags)
920 {
921         smb_username_t *unp= NULL;
922
923         lock_ObtainWrite(&smb_rctLock);
924         for(unp = usernamesp; unp; unp = unp->nextp) {
925                 if (stricmp(unp->name, usern) == 0 &&
926                         stricmp(unp->machine, machine) == 0) {
927                         unp->refCount++;
928                         break;
929                 }
930         }
931         if (!unp && (flags & SMB_FLAG_CREATE)) {
932                 unp = malloc(sizeof(*unp));
933                 memset(unp, 0, sizeof(*unp));
934                 unp->refCount = 1;
935                 unp->nextp = usernamesp;
936                 unp->name = strdup(usern);
937                 unp->machine = strdup(machine);
938                 usernamesp = unp;
939                 lock_InitializeMutex(&unp->mx, "username_t mutex");
940         }
941         lock_ReleaseWrite(&smb_rctLock);
942         return unp;
943 }       
944
945 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
946 {
947         smb_user_t *uidp= NULL;
948
949         lock_ObtainWrite(&smb_rctLock);
950         for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
951                 if (!uidp->unp) 
952             continue;
953                 if (stricmp(uidp->unp->name, usern) == 0) {
954             uidp->refCount++;
955                         osi_LogEvent("AFS smb_FindUserByNameThisSession",NULL,"VCP[%x] uid[%d] match-name[%s]",(int)vcp,uidp->userID,usern);
956             break;
957                 } else
958             continue;
959         }       
960         lock_ReleaseWrite(&smb_rctLock);
961         return uidp;
962 }
963 void smb_ReleaseUID(smb_user_t *uidp)
964 {
965         smb_user_t *up;
966         smb_user_t **lupp;
967         cm_user_t *userp;
968     smb_vc_t  *vcp;
969
970         userp = NULL;
971     vcp = NULL;
972         lock_ObtainWrite(&smb_rctLock);
973         osi_assert(uidp->refCount-- > 0);
974         if (uidp->refCount == 0 && (uidp->flags & SMB_USERFLAG_DELETE)) {
975                 lupp = &uidp->vcp->usersp;
976                 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
977                         if (up == uidp) break;
978                 }
979                 osi_assert(up != NULL);
980                 *lupp = up->nextp;
981                 lock_FinalizeMutex(&uidp->mx);
982                 if (uidp->unp) {
983                         userp = uidp->unp->userp;       /* remember to drop ref later */
984             uidp->unp->userp = NULL;
985         }
986         vcp = uidp->vcp;
987         uidp->vcp = NULL;
988         }               
989         lock_ReleaseWrite(&smb_rctLock);
990         if (userp) {
991                 cm_ReleaseUserVCRef(userp);
992                 cm_ReleaseUser(userp);
993         }       
994     if (vcp) {
995         smb_ReleaseVC(vcp);
996     }
997 }       
998
999 /* retrieve a held reference to a user structure corresponding to an incoming
1000  * request.
1001  * corresponding release function is cm_ReleaseUser.
1002  */
1003 cm_user_t *smb_GetUser(smb_vc_t *vcp, smb_packet_t *inp)
1004 {
1005         smb_user_t *uidp;
1006         cm_user_t *up;
1007         smb_t *smbp;
1008
1009         smbp = (smb_t *) inp;
1010         uidp = smb_FindUID(vcp, smbp->uid, 0);
1011         if ((!uidp) ||  (!uidp->unp))
1012                 return NULL;
1013         
1014         lock_ObtainMutex(&uidp->mx);
1015         up = uidp->unp->userp;
1016         cm_HoldUser(up);
1017         lock_ReleaseMutex(&uidp->mx);
1018
1019         smb_ReleaseUID(uidp);
1020         
1021         return up;
1022 }
1023
1024 /*
1025  * Return a pointer to a pathname extracted from a TID structure.  The
1026  * TID structure is not held; assume it won't go away.
1027  */
1028 char *smb_GetTIDPath(smb_vc_t *vcp, unsigned short tid)
1029 {
1030         smb_tid_t *tidp;
1031         char *tpath;
1032
1033         tidp = smb_FindTID(vcp, tid, 0);
1034     if (!tidp) 
1035         return NULL;
1036         tpath = tidp->pathname;
1037         smb_ReleaseTID(tidp);
1038         return tpath;
1039 }
1040
1041 /* check to see if we have a chained fid, that is, a fid that comes from an
1042  * OpenAndX message that ran earlier in this packet.  In this case, the fid
1043  * field in a read, for example, request, isn't set, since the value is
1044  * supposed to be inherited from the openAndX call.
1045  */
1046 int smb_ChainFID(int fid, smb_packet_t *inp)
1047 {
1048         if (inp->fid == 0 || inp->inCount == 0) 
1049                 return fid;
1050         else 
1051                 return inp->fid;
1052 }
1053
1054 /* are we a priv'd user?  What does this mean on NT? */
1055 int smb_SUser(cm_user_t *userp)
1056 {
1057         return 1;
1058 }
1059
1060 /* find a file ID.  If we pass in 0 we select an used File ID.
1061  * If the SMB_FLAG_CREATE flag is set, we allocate a new  
1062  * smb_fid_t data structure if desired File ID cannot be found.
1063  */
1064 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1065 {
1066         smb_fid_t *fidp;
1067         int newFid = 0;
1068         
1069     if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1070         return NULL;
1071
1072         lock_ObtainWrite(&smb_rctLock);
1073         /* figure out if we need to allocate a new file ID */
1074         if (fid == 0) {
1075                 newFid = 1;
1076                 fid = vcp->fidCounter;
1077         }
1078
1079 retry:
1080         for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1081                 if (fid == fidp->fid) {
1082                         if (newFid) {
1083                                 fid++;
1084                 if (fid == 0) 
1085                                         fid = 1;
1086                 goto retry;
1087             }
1088                         fidp->refCount++;
1089             break;
1090                 }
1091     }
1092     if (!fidp && (flags & SMB_FLAG_CREATE)) {
1093         char eventName[MAX_PATH];
1094         EVENT_HANDLE event;
1095         sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1096         event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1097         if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1098             afsi_log("Event Object Already Exists: %s", eventName);
1099             thrd_CloseHandle(event);
1100             fid++;
1101             if (fid == 0)
1102                 fid = 1;
1103             goto retry;
1104         }
1105
1106                 fidp = malloc(sizeof(*fidp));
1107         memset(fidp, 0, sizeof(*fidp));
1108                 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1109         fidp->refCount = 1;
1110         fidp->vcp = vcp;
1111         vcp->refCount++;
1112         lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1113         fidp->fid = fid;
1114                 fidp->curr_chunk = fidp->prev_chunk = -2;
1115                 fidp->raw_write_event = event;
1116         if (newFid) {
1117             vcp->fidCounter = fid+1;
1118             if (vcp->fidCounter == 0) 
1119                 vcp->fidCounter = 1;
1120         }
1121     }
1122     lock_ReleaseWrite(&smb_rctLock);
1123     return fidp;
1124 }
1125
1126 void smb_ReleaseFID(smb_fid_t *fidp)
1127 {
1128         cm_scache_t *scp;
1129     smb_vc_t *vcp = NULL;
1130     smb_ioctl_t *ioctlp;
1131
1132     if (!fidp)
1133         return;
1134
1135         scp = NULL;
1136         lock_ObtainWrite(&smb_rctLock);
1137         osi_assert(fidp->refCount-- > 0);
1138     if (fidp->refCount == 0 && (fidp->flags & SMB_FID_DELETE)) {
1139                 vcp = fidp->vcp;
1140                 if (!(fidp->flags & SMB_FID_IOCTL))
1141                         scp = fidp->scp;
1142                 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1143                 thrd_CloseHandle(fidp->raw_write_event);
1144
1145                 /* and see if there is ioctl stuff to free */
1146         ioctlp = fidp->ioctlp;
1147         if (ioctlp) {
1148                         if (ioctlp->prefix) cm_FreeSpace(ioctlp->prefix);
1149                         if (ioctlp->inAllocp) free(ioctlp->inAllocp);
1150                         if (ioctlp->outAllocp) free(ioctlp->outAllocp);
1151                         free(ioctlp);
1152         }
1153
1154         free(fidp);
1155
1156         /* do not call smb_ReleaseVC() because we already have the lock */
1157         vcp->refCount--;
1158     }
1159         lock_ReleaseWrite(&smb_rctLock);
1160
1161         /* now release the scache structure */
1162         if (scp) 
1163                 cm_ReleaseSCache(scp);
1164 }
1165
1166 /*
1167  * Case-insensitive search for one string in another;
1168  * used to find variable names in submount pathnames.
1169  */
1170 static char *smb_stristr(char *str1, char *str2)
1171 {
1172         char *cursor;
1173
1174         for (cursor = str1; *cursor; cursor++)
1175                 if (stricmp(cursor, str2) == 0)
1176                         return cursor;
1177
1178         return NULL;
1179 }
1180
1181 /*
1182  * Substitute a variable value for its name in a submount pathname.  Variable
1183  * name has been identified by smb_stristr() and is in substr.  Variable name
1184  * length (plus one) is in substr_size.  Variable value is in newstr.
1185  */
1186 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1187         char *newstr)
1188 {
1189         char temp[1024];
1190
1191         strcpy(temp, substr + substr_size - 1);
1192         strcpy(substr, newstr);
1193         strcat(str1, temp);
1194 }
1195
1196 char VNUserName[] = "%USERNAME%";
1197 char VNLCUserName[] = "%LCUSERNAME%";
1198 char VNComputerName[] = "%COMPUTERNAME%";
1199 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1200
1201 #ifdef DJGPP
1202 /* List available shares */
1203 int smb_ListShares()
1204 {
1205         char sbmtpath[256];
1206         char pathName[256];
1207         char shareBuf[4096];
1208         int num_shares=0;
1209         char *this_share;
1210         int len;
1211         char *p;
1212         int print_afs = 0;
1213         int code;
1214
1215         /*strcpy(shareNameList[num_shares], "all");
1216          strcpy(pathNameList[num_shares++], "/afs");*/
1217         fprintf(stderr, "The following shares are available:\n");
1218         fprintf(stderr, "Share Name (AFS Path)\n");
1219         fprintf(stderr, "---------------------\n");
1220         fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
1221
1222 #ifndef DJGPP
1223         code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1224         if (code == 0 || code > sizeof(sbmtpath)) return -1;
1225 #else
1226         strcpy(sbmtpath, cm_confDir);
1227 #endif /* !DJGPP */
1228         strcat(sbmtpath, "/afsdsbmt.ini");
1229         len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1230                                                                    shareBuf, sizeof(shareBuf),
1231                                                                    sbmtpath);
1232         if (len == 0) {
1233                 return num_shares;
1234         }
1235
1236         this_share = shareBuf;
1237         do
1238         {
1239                 print_afs = 0;
1240                 /*strcpy(shareNameList[num_shares], this_share);*/
1241                 len = GetPrivateProfileString("AFS Submounts", this_share,
1242                                                                            NULL,
1243                                                                            pathName, 256,
1244                                                                            sbmtpath);
1245                 if (!len) 
1246                         return num_shares;
1247                 p = pathName;
1248                 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) != 0)
1249             print_afs = 1;
1250                 while (*p) {
1251             if (*p == '\\') *p = '/';    /* change to / */
1252             p++;
1253                 }
1254
1255                 fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1256                                  smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
1257                                  pathName);
1258                 num_shares++;
1259                 while (*this_share != 0) this_share++;  /* find next NUL */
1260                 this_share++;   /* skip past the NUL */
1261         } while (*this_share != 0);  /* stop at final NUL */
1262
1263         return num_shares;
1264 }
1265 #endif /* DJGPP */
1266 /* find a shareName in the table of submounts */
1267 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1268         char **pathNamep)
1269 {
1270         DWORD len;
1271         char pathName[1024];
1272         char *var;
1273         char temp[1024];
1274         DWORD sizeTemp;
1275     char sbmtpath[MAX_PATH];
1276     char *p, *q;
1277         HKEY parmKey;
1278         DWORD code;
1279     DWORD allSubmount = 1;
1280
1281         if (strcmp(shareName, "IPC$") == 0) {
1282                 *pathNamep = NULL;
1283                 return 0;
1284         }
1285
1286     /* if allSubmounts == 0, only return the //mountRoot/all share 
1287      * if in fact it has been been created in the subMounts table.  
1288      * This is to allow sites that want to restrict access to the 
1289      * world to do so.
1290      */
1291         code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName,
1292                                                 0, KEY_QUERY_VALUE, &parmKey);
1293         if (code == ERROR_SUCCESS) {
1294         len = sizeof(allSubmount);
1295         code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1296                                 (BYTE *) &allSubmount, &len);
1297         if (code != ERROR_SUCCESS) {
1298             allSubmount = 1;
1299         }
1300         RegCloseKey (parmKey);
1301         }
1302
1303         if (allSubmount && _stricmp(shareName, "all") == 0) {
1304                 *pathNamep = NULL;
1305                 return 1;
1306         }
1307
1308     /* In case, the all share is disabled we need to still be able
1309      * to handle ioctl requests 
1310      */
1311         if (_stricmp(shareName, "ioctl$") == 0) {
1312                 *pathNamep = strdup("/.__ioctl__");
1313                 return 1;
1314         }
1315
1316 #ifndef DJGPP
1317         code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts",
1318                                                 0, KEY_QUERY_VALUE, &parmKey);
1319         if (code == ERROR_SUCCESS) {
1320         len = sizeof(pathName);
1321         code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1322                                 (BYTE *) pathName, &len);
1323                 if (code != ERROR_SUCCESS)
1324                         len = 0;
1325         RegCloseKey (parmKey);
1326         } else {
1327         len = 0;
1328     }   
1329 #else /* DJGPP */
1330     strcpy(sbmtpath, cm_confDir);
1331     strcat(sbmtpath, "/afsdsbmt.ini");
1332         len = GetPrivateProfileString("AFS Submounts", shareName, "",
1333                                   pathName, sizeof(pathName), sbmtpath);
1334 #endif /* !DJGPP */
1335         if (len != 0 && len != sizeof(pathName) - 1) {
1336         /* We can accept either unix or PC style AFS pathnames.  Convert
1337          * Unix-style to PC style here for internal use. 
1338          */
1339         p = pathName;
1340         if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1341             p += strlen(cm_mountRoot);  /* skip mount path */
1342         q = p;
1343         while (*q) {
1344             if (*q == '/') *q = '\\';    /* change to \ */
1345             q++;
1346         }
1347
1348         while (1)
1349         {
1350             if (var = smb_stristr(p, VNUserName)) {
1351                 if (uidp && uidp->unp)
1352                     smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1353                 else
1354                     smb_subst(p, var, sizeof(VNUserName)," ");
1355             }
1356             else if (var = smb_stristr(p, VNLCUserName)) 
1357             {
1358                 if (uidp && uidp->unp)
1359                     strcpy(temp, uidp->unp->name);
1360                 else 
1361                     strcpy(temp, " ");
1362                 _strlwr(temp);
1363                 smb_subst(p, var, sizeof(VNLCUserName), temp);
1364             }
1365             else if (var = smb_stristr(p, VNComputerName)) 
1366             {
1367                 sizeTemp = sizeof(temp);
1368                 GetComputerName((LPTSTR)temp, &sizeTemp);
1369                 smb_subst(p, var, sizeof(VNComputerName), temp);
1370             }
1371             else if (var = smb_stristr(p, VNLCComputerName)) 
1372             {
1373                 sizeTemp = sizeof(temp);
1374                 GetComputerName((LPTSTR)temp, &sizeTemp);
1375                 _strlwr(temp);
1376                 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1377             }
1378             else     
1379                 break;
1380         }
1381         *pathNamep = strdup(p);
1382         return 1;
1383     } 
1384     else /* create  \\<netbiosName>\<cellname>  */
1385     {
1386         char * p = shareName; 
1387         int rw = 0;
1388
1389         if ( *p == '.' ) {
1390             p++;
1391             rw = 1;
1392         }
1393         /* Get the full name for this cell */
1394         code = cm_SearchCellFile(p, temp, 0, 0);
1395 #ifdef AFS_AFSDB_ENV
1396                 if (code && cm_dnsEnabled) {
1397             int ttl;
1398             code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1399         }
1400 #endif
1401         /* construct the path */
1402         if (code == 0) {     
1403             sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1404             *pathNamep = strdup(strlwr(pathName));
1405             return 1;
1406         }
1407         }
1408     /* failure */
1409     *pathNamep = NULL;
1410     return 0;
1411 }
1412
1413 /* Client-side offline caching policy types */
1414 #define CSC_POLICY_MANUAL 0
1415 #define CSC_POLICY_DOCUMENTS 1
1416 #define CSC_POLICY_PROGRAMS 2
1417 #define CSC_POLICY_DISABLE 3
1418
1419 int smb_FindShareCSCPolicy(char *shareName)
1420 {
1421         DWORD len;
1422         char policy[1024];
1423     DWORD dwType;
1424     HKEY hkCSCPolicy;
1425     int  retval = CSC_POLICY_MANUAL;
1426
1427     RegCreateKeyEx( HKEY_LOCAL_MACHINE, 
1428                     "SOFTWARE\\OpenAFS\\Client\\CSCPolicy",
1429                     0, 
1430                     "AFS", 
1431                     REG_OPTION_NON_VOLATILE,
1432                     KEY_READ,
1433                     NULL, 
1434                     &hkCSCPolicy,
1435                     NULL );
1436
1437     len = sizeof(policy);
1438     if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1439          len == 0) {
1440                 retval = CSC_POLICY_MANUAL;
1441     }
1442         else if (stricmp(policy, "documents") == 0)
1443         {
1444                 retval = CSC_POLICY_DOCUMENTS;
1445         }
1446         else if (stricmp(policy, "programs") == 0)
1447         {
1448                 retval = CSC_POLICY_PROGRAMS;
1449         }
1450         else if (stricmp(policy, "disable") == 0)
1451         {
1452                 retval = CSC_POLICY_DISABLE;
1453         }
1454         
1455     RegCloseKey(hkCSCPolicy);
1456         return retval;
1457 }
1458
1459 /* find a dir search structure by cookie value, and return it held.
1460  * Must be called with smb_globalLock held.
1461  */
1462 smb_dirSearch_t *smb_FindDirSearchNL(long cookie)
1463 {
1464         smb_dirSearch_t *dsp;
1465         
1466         for(dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1467                 if (dsp->cookie == cookie) {
1468                         if (dsp != smb_firstDirSearchp) {
1469                                 /* move to head of LRU queue, too, if we're not already there */
1470                                 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1471                                         smb_lastDirSearchp = (smb_dirSearch_t *)
1472                                                 osi_QPrev(&dsp->q);
1473                                 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1474                                 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1475                                 if (!smb_lastDirSearchp)
1476                                         smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1477                         }
1478                         dsp->refCount++;
1479                         break;
1480                 }
1481         }
1482         return dsp;
1483 }
1484
1485 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1486 {
1487         lock_ObtainWrite(&smb_globalLock);
1488         dsp->flags |= SMB_DIRSEARCH_DELETE;
1489         lock_ReleaseWrite(&smb_globalLock);
1490         lock_ObtainMutex(&dsp->mx);
1491         if(dsp->scp != NULL) {
1492                 lock_ObtainMutex(&dsp->scp->mx);
1493                 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1494                         dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1495                     dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1496                     dsp->scp->bulkStatProgress = hones;
1497                 }       
1498                 lock_ReleaseMutex(&dsp->scp->mx);
1499         }       
1500         lock_ReleaseMutex(&dsp->mx);
1501 }
1502
1503 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1504 {
1505         cm_scache_t *scp;
1506         
1507         scp = NULL;
1508
1509         lock_ObtainWrite(&smb_globalLock);
1510         osi_assert(dsp->refCount-- > 0);
1511         if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1512                 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1513                         smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1514                 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1515                 lock_FinalizeMutex(&dsp->mx);
1516                 scp = dsp->scp;
1517                 free(dsp);
1518         }
1519         lock_ReleaseWrite(&smb_globalLock);
1520
1521         /* do this now to avoid spurious locking hierarchy creation */
1522         if (scp) cm_ReleaseSCache(scp);
1523 }
1524
1525 /* find a dir search structure by cookie value, and return it held */
1526 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1527 {
1528         smb_dirSearch_t *dsp;
1529
1530         lock_ObtainWrite(&smb_globalLock);
1531         dsp = smb_FindDirSearchNL(cookie);
1532         lock_ReleaseWrite(&smb_globalLock);
1533         return dsp;
1534 }
1535
1536 /* GC some dir search entries, in the address space expected by the specific protocol.
1537  * Must be called with smb_globalLock held; release the lock temporarily.
1538  */
1539 #define SMB_DIRSEARCH_GCMAX     10      /* how many at once */
1540 void smb_GCDirSearches(int isV3)
1541 {
1542         smb_dirSearch_t *prevp;
1543         smb_dirSearch_t *tp;
1544         smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1545         int victimCount;
1546         int i;
1547         
1548         victimCount = 0;        /* how many have we got so far */
1549         for(tp = smb_lastDirSearchp; tp; tp=prevp) {
1550                 /* we'll move tp from queue, so
1551                  * do this early.
1552                  */
1553                 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);  
1554                 /* if no one is using this guy, and we're either in the new protocol,
1555                  * or we're in the old one and this is a small enough ID to be useful
1556                  * to the old protocol, GC this guy.
1557                  */
1558                 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1559                         /* hold and delete */
1560                         tp->flags |= SMB_DIRSEARCH_DELETE;
1561                         victimsp[victimCount++] = tp;
1562                         tp->refCount++;
1563                 }
1564
1565                 /* don't do more than this */
1566                 if (victimCount >= SMB_DIRSEARCH_GCMAX) break;
1567         }
1568         
1569         /* now release them */
1570         lock_ReleaseWrite(&smb_globalLock);
1571         for(i = 0; i < victimCount; i++) {
1572                 smb_ReleaseDirSearch(victimsp[i]);
1573         }
1574         lock_ObtainWrite(&smb_globalLock);
1575 }
1576
1577 /* function for allocating a dir search entry.  We need these to remember enough context
1578  * since we don't get passed the path from call to call during a directory search.
1579  *
1580  * Returns a held dir search structure, and bumps the reference count on the vnode,
1581  * since it saves a pointer to the vnode.
1582  */
1583 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1584 {
1585         smb_dirSearch_t *dsp;
1586         int counter;
1587         int maxAllowed;
1588
1589         lock_ObtainWrite(&smb_globalLock);
1590         counter = 0;
1591
1592         /* what's the biggest ID allowed in this version of the protocol */
1593         if (isV3) maxAllowed = 65535;
1594         else maxAllowed = 255;
1595
1596         while(1) {
1597                 /* twice so we have enough tries to find guys we GC after one pass;
1598                  * 10 extra is just in case I mis-counted.
1599                  */
1600                 if (++counter > 2*maxAllowed+10) osi_panic("afsd: dir search cookie leak",
1601                                                                                                         __FILE__, __LINE__);
1602                 if (smb_dirSearchCounter > maxAllowed) {        
1603                         smb_dirSearchCounter = 1;
1604                         smb_GCDirSearches(isV3);        /* GC some (drops global lock) */
1605                 }       
1606                 dsp = smb_FindDirSearchNL(smb_dirSearchCounter);
1607                 if (dsp) {
1608                         /* don't need to watch for refcount zero and deleted, since
1609                          * we haven't dropped the global lock.
1610                          */
1611                         dsp->refCount--;
1612                         ++smb_dirSearchCounter;
1613                         continue;
1614                 }       
1615                 
1616                 dsp = malloc(sizeof(*dsp));
1617                 memset(dsp, 0, sizeof(*dsp));
1618                 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1619                 if (!smb_lastDirSearchp) smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1620                 dsp->cookie = smb_dirSearchCounter;
1621                 ++smb_dirSearchCounter;
1622                 dsp->refCount = 1;
1623                 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
1624                 dsp->lastTime = osi_Time();
1625                 break;
1626         }       
1627         lock_ReleaseWrite(&smb_globalLock);
1628         return dsp;
1629 }
1630
1631 static smb_packet_t *GetPacket(void)
1632 {
1633         smb_packet_t *tbp;
1634 #ifdef DJGPP
1635         unsigned int npar, seg, tb_sel;
1636 #endif
1637
1638         lock_ObtainWrite(&smb_globalLock);
1639         tbp = smb_packetFreeListp;
1640     if (tbp) 
1641         smb_packetFreeListp = tbp->nextp;
1642         lock_ReleaseWrite(&smb_globalLock);
1643     if (!tbp) {
1644 #ifndef DJGPP
1645         tbp = calloc(65540,1);
1646 #else /* DJGPP */
1647         tbp = malloc(sizeof(smb_packet_t));
1648 #endif /* !DJGPP */
1649         tbp->magic = SMB_PACKETMAGIC;
1650                 tbp->ncbp = NULL;
1651                 tbp->vcp = NULL;
1652                 tbp->resumeCode = 0;
1653                 tbp->inCount = 0;
1654                 tbp->fid = 0;
1655                 tbp->wctp = NULL;
1656                 tbp->inCom = 0;
1657                 tbp->oddByte = 0;
1658                 tbp->ncb_length = 0;
1659                 tbp->flags = 0;
1660         tbp->spacep = NULL;
1661         
1662 #ifdef DJGPP
1663         npar = SMB_PACKETSIZE >> 4;  /* number of paragraphs */
1664         {
1665             signed int retval =
1666                 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1667             if (retval == -1) {
1668                 afsi_log("Cannot allocate %d paragraphs of DOS memory",
1669                           npar);
1670                 osi_panic("",__FILE__,__LINE__);
1671             }
1672             else {
1673                 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
1674                           npar, retval);
1675                 seg = retval;
1676             }
1677         }
1678         tbp->dos_pkt = (seg * 16) + 0;  /* DOS physical address */
1679         tbp->dos_pkt_sel = tb_sel;
1680 #endif /* DJGPP */
1681         }
1682     osi_assert(tbp->magic == SMB_PACKETMAGIC);
1683
1684     return tbp;
1685 }
1686
1687 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
1688 {
1689         smb_packet_t *tbp;
1690         tbp = GetPacket();
1691         memcpy(tbp, pkt, sizeof(smb_packet_t));
1692         tbp->wctp = tbp->data + ((unsigned int)pkt->wctp - (unsigned int)pkt->data);
1693         return tbp;
1694 }
1695
1696 static NCB *GetNCB(void)
1697 {
1698         smb_ncb_t *tbp;
1699     NCB *ncbp;
1700 #ifdef DJGPP
1701     unsigned int npar, seg, tb_sel;
1702 #endif /* DJGPP */
1703
1704         lock_ObtainWrite(&smb_globalLock);
1705         tbp = smb_ncbFreeListp;
1706     if (tbp) 
1707         smb_ncbFreeListp = tbp->nextp;
1708         lock_ReleaseWrite(&smb_globalLock);
1709     if (!tbp) {
1710 #ifndef DJGPP
1711         tbp = calloc(sizeof(*tbp),1);
1712 #else /* DJGPP */
1713         tbp = malloc(sizeof(*tbp));
1714         npar = (sizeof(NCB)+15) >> 4;  /* number of paragraphs */
1715         {
1716             signed int retval =
1717                 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1718             if (retval == -1) {
1719                 afsi_log("Cannot allocate %d paragraphs of DOS mem in GetNCB",
1720                           npar);
1721                 osi_panic("",__FILE__,__LINE__);
1722             } else {
1723                 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
1724                           npar, retval);
1725                 seg = retval;
1726             }
1727         }
1728         tbp->dos_ncb = (seg * 16) + 0;  /* DOS physical address */
1729         tbp->dos_ncb_sel = tb_sel;
1730 #endif /* !DJGPP */
1731         tbp->magic = SMB_NCBMAGIC;
1732         }
1733         
1734     osi_assert(tbp->magic == SMB_NCBMAGIC);
1735
1736         memset(&tbp->ncb, 0, sizeof(NCB));
1737     ncbp = &tbp->ncb;
1738 #ifdef DJGPP
1739     dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
1740 #endif /* DJGPP */
1741     return ncbp;
1742 }
1743
1744 void smb_FreePacket(smb_packet_t *tbp)
1745 {
1746     osi_assert(tbp->magic == SMB_PACKETMAGIC);
1747         
1748     lock_ObtainWrite(&smb_globalLock);
1749         tbp->nextp = smb_packetFreeListp;
1750         smb_packetFreeListp = tbp;
1751         tbp->magic = SMB_PACKETMAGIC;
1752         tbp->ncbp = NULL;
1753         tbp->vcp = NULL;
1754         tbp->resumeCode = 0;
1755         tbp->inCount = 0;
1756         tbp->fid = 0;
1757         tbp->wctp = NULL;
1758         tbp->inCom = 0;
1759         tbp->oddByte = 0;
1760         tbp->ncb_length = 0;
1761         tbp->flags = 0;
1762     lock_ReleaseWrite(&smb_globalLock);
1763 }
1764
1765 static void FreeNCB(NCB *bufferp)
1766 {
1767         smb_ncb_t *tbp;
1768         
1769     tbp = (smb_ncb_t *) bufferp;
1770     osi_assert(tbp->magic == SMB_NCBMAGIC);
1771         
1772     lock_ObtainWrite(&smb_globalLock);
1773         tbp->nextp = smb_ncbFreeListp;
1774         smb_ncbFreeListp = tbp;
1775     lock_ReleaseWrite(&smb_globalLock);
1776 }
1777
1778 /* get a ptr to the data part of a packet, and its count */
1779 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
1780 {
1781     int parmBytes;
1782     int dataBytes;
1783     unsigned char *afterParmsp;
1784
1785     parmBytes = *smbp->wctp << 1;
1786         afterParmsp = smbp->wctp + parmBytes + 1;
1787         
1788     dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
1789     if (nbytesp) *nbytesp = dataBytes;
1790         
1791         /* don't forget to skip the data byte count, since it follows
1792      * the parameters; that's where the "2" comes from below.
1793      */
1794     return (unsigned char *) (afterParmsp + 2);
1795 }
1796
1797 /* must set all the returned parameters before playing around with the
1798  * data region, since the data region is located past the end of the
1799  * variable number of parameters.
1800  */
1801 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
1802 {
1803         unsigned char *afterParmsp;
1804
1805         afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
1806         
1807         *afterParmsp++ = dsize & 0xff;
1808         *afterParmsp = (dsize>>8) & 0xff;
1809 }
1810
1811 /* return the parm'th parameter in the smbp packet */
1812 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
1813 {
1814         int parmCount;
1815         unsigned char *parmDatap;
1816
1817         parmCount = *smbp->wctp;
1818
1819         if (parm >= parmCount) {
1820 #ifndef DJGPP
1821         HANDLE h;
1822                 char *ptbuf[1];
1823                 char s[100];
1824                 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1825                 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
1826                                 parm, parmCount, smbp->ncb_length);
1827                 ptbuf[0] = s;
1828                 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1829                                         1, smbp->ncb_length, ptbuf, smbp);
1830                 DeregisterEventSource(h);
1831 #else /* DJGPP */
1832                 char s[100];
1833
1834                 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
1835                                 parm, parmCount, smbp->ncb_length);
1836                 osi_Log0(smb_logp, s);
1837 #endif /* !DJGPP */
1838                 osi_panic(s, __FILE__, __LINE__);
1839         }
1840         parmDatap = smbp->wctp + (2*parm) + 1;
1841         
1842         return parmDatap[0] + (parmDatap[1] << 8);
1843 }
1844
1845 /* return the parm'th parameter in the smbp packet */
1846 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
1847 {
1848         int parmCount;
1849         unsigned char *parmDatap;
1850
1851         parmCount = *smbp->wctp;
1852
1853         if (parm * 2 + offset >= parmCount * 2) {
1854 #ifndef DJGPP
1855                 HANDLE h;
1856                 char *ptbuf[1];
1857                 char s[100];
1858                 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1859                 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
1860                                 parm, offset, parmCount, smbp->ncb_length);
1861                 ptbuf[0] = s;
1862                 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1863                                         1, smbp->ncb_length, ptbuf, smbp);
1864                 DeregisterEventSource(h);
1865 #else /* DJGPP */
1866                 char s[100];
1867                 
1868                 sprintf(s, "Bad SMB param %d offset %d out of %d, "
1869                                 "ncb len %d",
1870                                  parm, offset, parmCount, smbp->ncb_length);
1871                 osi_Log0(smb_logp, s);
1872 #endif /* !DJGPP */
1873
1874                 osi_panic(s, __FILE__, __LINE__);
1875         }
1876         parmDatap = smbp->wctp + (2*parm) + 1 + offset;
1877         
1878         return parmDatap[0] + (parmDatap[1] << 8);
1879 }
1880
1881 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
1882 {
1883         char *parmDatap;
1884
1885         /* make sure we have enough slots */
1886         if (*smbp->wctp <= slot) *smbp->wctp = slot+1;
1887         
1888         parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1889         *parmDatap++ = parmValue & 0xff;
1890         *parmDatap = (parmValue>>8) & 0xff;
1891 }
1892
1893 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
1894 {
1895         char *parmDatap;
1896
1897         /* make sure we have enough slots */
1898         if (*smbp->wctp <= slot) *smbp->wctp = slot+2;
1899
1900         parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1901         *parmDatap++ = parmValue & 0xff;
1902         *parmDatap++ = (parmValue>>8) & 0xff;
1903         *parmDatap++ = (parmValue>>16) & 0xff;
1904         *parmDatap++ = (parmValue>>24) & 0xff;
1905 }
1906
1907 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
1908 {
1909         char *parmDatap;
1910         int i;
1911
1912         /* make sure we have enough slots */
1913         if (*smbp->wctp <= slot) *smbp->wctp = slot+4;
1914
1915         parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1916         for (i=0; i<8; i++)
1917                 *parmDatap++ = *parmValuep++;
1918 }
1919
1920 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
1921 {
1922         char *parmDatap;
1923
1924         /* make sure we have enough slots */
1925         if (*smbp->wctp <= slot) {
1926                 if (smbp->oddByte) {
1927                         smbp->oddByte = 0;
1928                         *smbp->wctp = slot+1;
1929                 } else
1930                         smbp->oddByte = 1;
1931         }
1932
1933         parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
1934         *parmDatap++ = parmValue & 0xff;
1935 }
1936
1937 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
1938 {
1939         char *lastSlashp;
1940         
1941         lastSlashp = strrchr(inPathp, '\\');
1942         if (lastComponentp)
1943                 *lastComponentp = lastSlashp;
1944         if (lastSlashp) {
1945                 while (1) {
1946                         if (inPathp == lastSlashp) 
1947                                 break;
1948                         *outPathp++ = *inPathp++;
1949                 }
1950                 *outPathp++ = 0;
1951         }
1952         else {
1953                 *outPathp++ = 0;
1954         }
1955 }
1956
1957 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
1958 {
1959         if (*inp++ != 0x4) 
1960                 return NULL;
1961         if (chainpp) {
1962                 *chainpp = inp + strlen(inp) + 1;       /* skip over null-terminated string */
1963         }
1964         return inp;
1965 }
1966
1967 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
1968 {
1969         int tlen;
1970
1971         if (*inp++ != 0x5) 
1972                 return NULL;
1973         tlen = inp[0] + (inp[1]<<8);
1974         inp += 2;               /* skip length field */
1975         
1976         if (chainpp) {
1977                 *chainpp = inp + tlen;
1978         }
1979         
1980         if (lengthp) 
1981                 *lengthp = tlen;
1982         
1983         return inp;
1984 }       
1985
1986 /* format a packet as a response */
1987 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
1988 {
1989         smb_t *outp;
1990         smb_t *inSmbp;
1991
1992         outp = (smb_t *) op;
1993         
1994         /* zero the basic structure through the smb_wct field, and zero the data
1995          * size field, assuming that wct stays zero; otherwise, you have to 
1996          * explicitly set the data size field, too.
1997          */
1998         inSmbp = (smb_t *) inp;
1999         memset(outp, 0, sizeof(smb_t)+2);
2000         outp->id[0] = 0xff;
2001         outp->id[1] = 'S';
2002         outp->id[2] = 'M';
2003         outp->id[3] = 'B';
2004         if (inp) {
2005                 outp->com = inSmbp->com;
2006                 outp->tid = inSmbp->tid;
2007                 outp->pid = inSmbp->pid;
2008                 outp->uid = inSmbp->uid;
2009                 outp->mid = inSmbp->mid;
2010                 outp->res[0] = inSmbp->res[0];
2011                 outp->res[1] = inSmbp->res[1];
2012                 op->inCom = inSmbp->com;
2013         }
2014         outp->reb = 0x80;       /* SERVER_RESP */
2015         outp->flg2 = 0x1;       /* KNOWS_LONG_NAMES */
2016
2017         /* copy fields in generic packet area */
2018         op->wctp = &outp->wct;
2019 }
2020
2021 /* send a (probably response) packet; vcp tells us to whom to send it.
2022  * we compute the length by looking at wct and bcc fields.
2023  */
2024 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2025 {
2026         NCB *ncbp;
2027         int extra;
2028         long code = 0;
2029         unsigned char *tp;
2030         int localNCB = 0;
2031 #ifdef DJGPP
2032         dos_ptr dos_ncb;
2033 #endif /* DJGPP */
2034         
2035         ncbp = inp->ncbp;
2036         if (ncbp == NULL) {
2037                 ncbp = GetNCB();
2038                 localNCB = 1;
2039         }
2040 #ifdef DJGPP
2041         dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2042 #endif /* DJGPP */
2043  
2044         memset((char *)ncbp, 0, sizeof(NCB));
2045
2046         extra = 2 * (*inp->wctp);       /* space used by parms, in bytes */
2047         tp = inp->wctp + 1+ extra;      /* points to count of data bytes */
2048         extra += tp[0] + (tp[1]<<8);
2049         extra += ((unsigned int)inp->wctp - (unsigned int)inp->data);   /* distance to last wct field */
2050         extra += 3;                     /* wct and length fields */
2051         
2052         ncbp->ncb_length = extra;       /* bytes to send */
2053         ncbp->ncb_lsn = (unsigned char) vcp->lsn;       /* vc to use */
2054         ncbp->ncb_lana_num = vcp->lana;
2055         ncbp->ncb_command = NCBSEND;    /* op means send data */
2056 #ifndef DJGPP
2057         ncbp->ncb_buffer = (char *) inp;/* packet */
2058         code = Netbios(ncbp);
2059 #else /* DJGPP */
2060         ncbp->ncb_buffer = inp->dos_pkt;/* packet */
2061         ((smb_ncb_t*)ncbp)->orig_pkt = inp;
2062
2063         /* copy header information from virtual to DOS address space */
2064         dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
2065         code = Netbios(ncbp, dos_ncb);
2066 #endif /* !DJGPP */
2067         
2068         if (code != 0)
2069                 osi_Log1(smb_logp, "SendPacket failure code %d", code);
2070
2071         if (localNCB)
2072                 FreeNCB(ncbp);
2073 }
2074
2075 void smb_MapNTError(long code, unsigned long *NTStatusp)
2076 {
2077         unsigned long NTStatus;
2078
2079         /* map CM_ERROR_* errors to NT 32-bit status codes */
2080     /* NT Status codes are listed in ntstatus.h not winerror.h */
2081         if (code == CM_ERROR_NOSUCHCELL) {
2082                 NTStatus = 0xC000000FL; /* No such file */
2083         }
2084         else if (code == CM_ERROR_NOSUCHVOLUME) {
2085                 NTStatus = 0xC000000FL; /* No such file */
2086         }
2087         else if (code == CM_ERROR_TIMEDOUT) {
2088                 NTStatus = 0xC00000CFL; /* Sharing Paused */
2089         }
2090         else if (code == CM_ERROR_RETRY) {
2091                 NTStatus = 0xC000022DL; /* Retry */
2092         }
2093         else if (code == CM_ERROR_NOACCESS) {
2094                 NTStatus = 0xC0000022L; /* Access denied */
2095         }
2096         else if (code == CM_ERROR_READONLY) {
2097                 NTStatus = 0xC00000A2L; /* Write protected */
2098         }       
2099         else if (code == CM_ERROR_NOSUCHFILE) {
2100                 NTStatus = 0xC000000FL; /* No such file */
2101         }
2102         else if (code == CM_ERROR_NOSUCHPATH) {
2103                 NTStatus = 0xC000003AL; /* Object path not found */
2104         }               
2105         else if (code == CM_ERROR_TOOBIG) {
2106                 NTStatus = 0xC000007BL; /* Invalid image format */
2107         }
2108         else if (code == CM_ERROR_INVAL) {
2109                 NTStatus = 0xC000000DL; /* Invalid parameter */
2110         }
2111         else if (code == CM_ERROR_BADFD) {
2112                 NTStatus = 0xC0000008L; /* Invalid handle */
2113         }
2114         else if (code == CM_ERROR_BADFDOP) {
2115                 NTStatus = 0xC0000022L; /* Access denied */
2116         }
2117         else if (code == CM_ERROR_EXISTS) {
2118                 NTStatus = 0xC0000035L; /* Object name collision */
2119         }
2120         else if (code == CM_ERROR_NOTEMPTY) {
2121                 NTStatus = 0xC0000101L; /* Directory not empty */
2122         }       
2123         else if (code == CM_ERROR_CROSSDEVLINK) {
2124                 NTStatus = 0xC00000D4L; /* Not same device */
2125         }
2126         else if (code == CM_ERROR_NOTDIR) {
2127                 NTStatus = 0xC0000103L; /* Not a directory */
2128         }
2129         else if (code == CM_ERROR_ISDIR) {
2130                 NTStatus = 0xC00000BAL; /* File is a directory */
2131         }
2132         else if (code == CM_ERROR_BADOP) {
2133                 NTStatus = 0xC09820FFL; /* SMB no support */
2134         }
2135         else if (code == CM_ERROR_BADSHARENAME) {
2136                 NTStatus = 0xC00000CCL; /* Bad network name */
2137         }
2138         else if (code == CM_ERROR_NOIPC) {
2139 #ifdef COMMENT
2140                 NTStatus = 0xC0000022L; /* Access Denied */
2141 #else
2142         NTStatus = 0xC000013DL; /* Remote Resources */
2143 #endif
2144         }
2145         else if (code == CM_ERROR_CLOCKSKEW) {
2146                 NTStatus = 0xC0000133L; /* Time difference at DC */
2147         }
2148         else if (code == CM_ERROR_BADTID) {
2149                 NTStatus = 0xC0982005L; /* SMB bad TID */
2150         }
2151         else if (code == CM_ERROR_USESTD) {
2152                 NTStatus = 0xC09820FBL; /* SMB use standard */
2153         }
2154         else if (code == CM_ERROR_QUOTA) {
2155                 NTStatus = 0xC0000044L; /* Quota exceeded */
2156         }
2157         else if (code == CM_ERROR_SPACE) {
2158                 NTStatus = 0xC000007FL; /* Disk full */
2159         }
2160         else if (code == CM_ERROR_ATSYS) {
2161                 NTStatus = 0xC0000033L; /* Object name invalid */
2162         }
2163         else if (code == CM_ERROR_BADNTFILENAME) {
2164                 NTStatus = 0xC0000033L; /* Object name invalid */
2165         }
2166         else if (code == CM_ERROR_WOULDBLOCK) {
2167                 NTStatus = 0xC0000055L; /* Lock not granted */
2168         }
2169         else if (code == CM_ERROR_PARTIALWRITE) {
2170                 NTStatus = 0xC000007FL; /* Disk full */
2171         }
2172         else if (code == CM_ERROR_BUFFERTOOSMALL) {
2173                 NTStatus = 0xC0000023L; /* Buffer too small */
2174         }
2175     else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2176                 NTStatus = 0xC0000035L; /* Object name collision */
2177     }
2178         else if (code == CM_ERROR_BADPASSWORD) {
2179                 NTStatus = 0xC000006DL; /* unknown username or bad password */
2180         }
2181         else if (code == CM_ERROR_BADLOGONTYPE) {
2182                 NTStatus = 0xC000015BL; /* logon type not granted */
2183         }
2184         else if (code == CM_ERROR_GSSCONTINUE) {
2185                 NTStatus = 0xC0000016L; /* more processing required */
2186         }
2187         else {
2188                 NTStatus = 0xC0982001L; /* SMB non-specific error */
2189         }
2190
2191         *NTStatusp = NTStatus;
2192         osi_Log2(smb_logp, "SMB SEND code %x as NT %x", code, NTStatus);
2193 }
2194
2195 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2196         unsigned char *classp)
2197 {
2198         unsigned char class;
2199         unsigned short error;
2200
2201         /* map CM_ERROR_* errors to SMB errors */
2202         if (code == CM_ERROR_NOSUCHCELL) {
2203                 class = 1;
2204                 error = 3;      /* bad path */
2205         }
2206         else if (code == CM_ERROR_NOSUCHVOLUME) {
2207                 class = 1;
2208                 error = 3;      /* bad path */
2209         }
2210         else if (code == CM_ERROR_TIMEDOUT) {
2211                 class = 2;
2212                 error = 81;     /* server is paused */
2213         }
2214         else if (code == CM_ERROR_RETRY) {
2215                 class = 2;      /* shouldn't happen */
2216                 error = 1;
2217         }
2218         else if (code == CM_ERROR_NOACCESS) {
2219                 class = 2;
2220                 error = 4;      /* bad access */
2221         }
2222         else if (code == CM_ERROR_READONLY) {
2223                 class = 3;
2224                 error = 19;     /* read only */
2225         }
2226         else if (code == CM_ERROR_NOSUCHFILE) {
2227                 class = 1;
2228                 error = 2;      /* ENOENT! */
2229         }
2230         else if (code == CM_ERROR_NOSUCHPATH) {
2231                 class = 1;
2232                 error = 3;      /* Bad path */
2233         }
2234         else if (code == CM_ERROR_TOOBIG) {
2235                 class = 1;
2236                 error = 11;     /* bad format */
2237         }
2238         else if (code == CM_ERROR_INVAL) {
2239                 class = 2;      /* server non-specific error code */
2240                 error = 1;
2241         }
2242         else if (code == CM_ERROR_BADFD) {
2243                 class = 1;
2244                 error = 6;      /* invalid file handle */
2245         }
2246         else if (code == CM_ERROR_BADFDOP) {
2247                 class = 1;      /* invalid op on FD */
2248                 error = 5;
2249         }
2250         else if (code == CM_ERROR_EXISTS) {
2251                 class = 1;
2252                 error = 80;     /* file already exists */
2253         }
2254         else if (code == CM_ERROR_NOTEMPTY) {
2255                 class = 1;
2256                 error = 5;      /* delete directory not empty */
2257         }
2258         else if (code == CM_ERROR_CROSSDEVLINK) {
2259                 class = 1;
2260                 error = 17;     /* EXDEV */
2261         }
2262         else if (code == CM_ERROR_NOTDIR) {
2263                 class = 1;      /* bad path */
2264                 error = 3;
2265         }
2266         else if (code == CM_ERROR_ISDIR) {
2267                 class = 1;      /* access denied; DOS doesn't have a good match */
2268                 error = 5;
2269         }
2270         else if (code == CM_ERROR_BADOP) {
2271                 class = 2;
2272                 error = 65535;
2273         }
2274         else if (code == CM_ERROR_BADSHARENAME) {
2275                 class = 2;
2276                 error = 6;
2277         }
2278         else if (code == CM_ERROR_NOIPC) {
2279                 class = 2;
2280                 error = 4; /* bad access */
2281         }
2282         else if (code == CM_ERROR_CLOCKSKEW) {
2283                 class = 1;      /* invalid function */
2284                 error = 1;
2285         }
2286         else if (code == CM_ERROR_BADTID) {
2287                 class = 2;
2288                 error = 5;
2289         }
2290         else if (code == CM_ERROR_USESTD) {
2291                 class = 2;
2292                 error = 251;
2293         }
2294         else if (code == CM_ERROR_REMOTECONN) {
2295                 class = 2;
2296                 error = 82;
2297         }
2298         else if (code == CM_ERROR_QUOTA) {
2299                 if (vcp->flags & SMB_VCFLAG_USEV3) {
2300                         class = 3;
2301                         error = 39;     /* disk full */
2302                 }
2303                 else {
2304                         class = 1;
2305                         error = 5;      /* access denied */
2306                 }
2307         }
2308         else if (code == CM_ERROR_SPACE) {
2309                 if (vcp->flags & SMB_VCFLAG_USEV3) {
2310                         class = 3;
2311                         error = 39;     /* disk full */
2312                 }
2313                 else {
2314                         class = 1;
2315                         error = 5;      /* access denied */
2316                 }
2317         }
2318         else if (code == CM_ERROR_PARTIALWRITE) {
2319                 class = 3;
2320                 error = 39;     /* disk full */
2321         }
2322         else if (code == CM_ERROR_ATSYS) {
2323                 class = 1;
2324                 error = 2;      /* ENOENT */
2325         }
2326         else if (code == CM_ERROR_WOULDBLOCK) {
2327                 class = 1;
2328                 error = 33;     /* lock conflict */
2329         }
2330         else if (code == CM_ERROR_NOFILES) {
2331                 class = 1;
2332                 error = 18;     /* no files in search */
2333         }
2334         else if (code == CM_ERROR_RENAME_IDENTICAL) {
2335                 class = 1;
2336                 error = 183;     /* Samba uses this */
2337         }
2338         else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2339                 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2340                 class = 2;
2341                 error = 2; /* bad password */
2342         }
2343         else {
2344                 class = 2;
2345                 error = 1;
2346         }
2347
2348         *scodep = error;
2349         *classp = class;
2350         osi_Log3(smb_logp, "SMB SEND code %x as SMB %d: %d", code, class, error);
2351 }
2352
2353 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2354 {
2355         return CM_ERROR_BADOP;
2356 }
2357
2358 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2359 {
2360         unsigned short EchoCount, i;
2361         char *data, *outdata;
2362         int dataSize;
2363
2364         EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2365
2366         for (i=1; i<=EchoCount; i++) {
2367             data = smb_GetSMBData(inp, &dataSize);
2368             smb_SetSMBParm(outp, 0, i);
2369             smb_SetSMBDataLength(outp, dataSize);
2370             outdata = smb_GetSMBData(outp, NULL);
2371             memcpy(outdata, data, dataSize);
2372             smb_SendPacket(vcp, outp);
2373         }
2374
2375         return 0;
2376 }
2377
2378 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2379 {
2380         osi_hyper_t offset;
2381         long count, minCount, finalCount;
2382         unsigned short fd;
2383         smb_fid_t *fidp;
2384         long code = 0;
2385         cm_user_t *userp = NULL;
2386     NCB *ncbp;
2387     int rc;
2388 #ifndef DJGPP
2389     char *rawBuf = NULL;
2390 #else
2391     dos_ptr rawBuf = NULL;
2392     dos_ptr dos_ncb;
2393 #endif /* DJGPP */
2394
2395         rawBuf = NULL;
2396         finalCount = 0;
2397
2398         fd = smb_GetSMBParm(inp, 0);
2399         count = smb_GetSMBParm(inp, 3);
2400         minCount = smb_GetSMBParm(inp, 4);
2401         offset.HighPart = 0;    /* too bad */
2402         offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2403
2404         osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2405              fd, offset.LowPart, count);
2406
2407         fidp = smb_FindFID(vcp, fd, 0);
2408         if (!fidp)
2409                 goto send1;
2410
2411         lock_ObtainMutex(&smb_RawBufLock);
2412         if (smb_RawBufs) {
2413                 /* Get a raw buf, from head of list */
2414                 rawBuf = smb_RawBufs;
2415 #ifndef DJGPP
2416                 smb_RawBufs = *(char **)smb_RawBufs;
2417 #else /* DJGPP */
2418         smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2419 #endif /* !DJGPP */
2420         }
2421         lock_ReleaseMutex(&smb_RawBufLock);
2422         if (!rawBuf)
2423                 goto send1a;
2424
2425     if (fidp->flags & SMB_FID_IOCTL)
2426     {
2427 #ifndef DJGPP
2428         rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2429 #else
2430         rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2431 #endif
2432         if (rawBuf) {
2433             /* Give back raw buffer */
2434             lock_ObtainMutex(&smb_RawBufLock);
2435 #ifndef DJGPP
2436             *((char **) rawBuf) = smb_RawBufs;
2437 #else /* DJGPP */
2438             _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2439 #endif /* !DJGPP */
2440             
2441             smb_RawBufs = rawBuf;
2442             lock_ReleaseMutex(&smb_RawBufLock);
2443         }
2444
2445         smb_ReleaseFID(fidp);
2446         return rc;
2447     }
2448         
2449     userp = smb_GetUser(vcp, inp);
2450
2451 #ifndef DJGPP
2452         code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2453 #else /* DJGPP */
2454     /* have to give ReadData flag so it will treat buffer as DOS mem. */
2455     code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2456                         userp, &finalCount, TRUE /* rawFlag */);
2457 #endif /* !DJGPP */
2458
2459         if (code != 0)
2460                 goto send;
2461
2462   send:
2463     cm_ReleaseUser(userp);
2464
2465   send1a:
2466         smb_ReleaseFID(fidp);
2467
2468   send1:
2469         ncbp = outp->ncbp;
2470 #ifdef DJGPP
2471     dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2472 #endif /* DJGPP */
2473         memset((char *)ncbp, 0, sizeof(NCB));
2474
2475         ncbp->ncb_length = (unsigned short) finalCount;
2476         ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2477         ncbp->ncb_lana_num = vcp->lana;
2478         ncbp->ncb_command = NCBSEND;
2479         ncbp->ncb_buffer = rawBuf;
2480
2481 #ifndef DJGPP
2482         code = Netbios(ncbp);
2483 #else /* DJGPP */
2484         code = Netbios(ncbp, dos_ncb);
2485 #endif /* !DJGPP */
2486         if (code != 0)
2487                 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2488
2489         if (rawBuf) {
2490                 /* Give back raw buffer */
2491                 lock_ObtainMutex(&smb_RawBufLock);
2492 #ifndef DJGPP
2493                 *((char **) rawBuf) = smb_RawBufs;
2494 #else /* DJGPP */
2495         _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2496 #endif /* !DJGPP */
2497
2498                 smb_RawBufs = rawBuf;
2499                 lock_ReleaseMutex(&smb_RawBufLock);
2500         }
2501
2502         return 0;
2503 }
2504
2505 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2506 {
2507         return 0;
2508 }
2509
2510 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2511 {
2512         return 0;
2513 }
2514
2515 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2516 {
2517         char *namep;
2518     char *datap;
2519         int coreProtoIndex;
2520         int v3ProtoIndex;
2521         int NTProtoIndex;
2522         int protoIndex;                         /* index we're using */
2523         int namex;
2524         int dbytes;
2525         int entryLength;
2526         int tcounter;
2527         char protocol_array[10][1024];  /* protocol signature of the client */
2528     int caps;                       /* capabilities */
2529     time_t unixTime;
2530         long dosTime;
2531         TIME_ZONE_INFORMATION tzi;
2532
2533     osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2534                          ongoingOps - 1);
2535         if (!isGateway) {
2536                 if (active_vcp) {
2537                         DWORD now = GetCurrentTime();
2538                         if (now - last_msg_time >= 30000
2539                                 && now - last_msg_time <= 90000) {
2540                                 osi_Log1(smb_logp,
2541                                                  "Setting dead_vcp %x", active_vcp);
2542                 if (dead_vcp) {
2543                     smb_ReleaseVC(dead_vcp);
2544                     osi_Log1(smb_logp,
2545                               "Previous dead_vcp %x", dead_vcp);
2546                 }
2547                 smb_HoldVC(active_vcp);
2548                                 dead_vcp = active_vcp;
2549                                 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2550                         }
2551                 }
2552         }
2553
2554         inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
2555
2556         namep = smb_GetSMBData(inp, &dbytes);
2557         namex = 0;
2558         tcounter = 0;
2559         coreProtoIndex = -1;            /* not found */
2560         v3ProtoIndex = -1;
2561         NTProtoIndex = -1;
2562         while(namex < dbytes) {
2563                 osi_Log1(smb_logp, "Protocol %s",
2564                                  osi_LogSaveString(smb_logp, namep+1));
2565                 strcpy(protocol_array[tcounter], namep+1);
2566
2567                 /* namep points at the first protocol, or really, a 0x02
2568                  * byte preceding the null-terminated ASCII name.
2569                  */
2570                 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2571                         coreProtoIndex = tcounter;
2572                 }       
2573                 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2574                         v3ProtoIndex = tcounter;
2575                 }
2576                 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
2577                         NTProtoIndex = tcounter;
2578                 }
2579
2580                 /* compute size of protocol entry */
2581                 entryLength = strlen(namep+1);
2582         entryLength += 2;       /* 0x02 bytes and null termination */
2583                 
2584         /* advance over this protocol entry */
2585                 namex += entryLength;
2586         namep += entryLength;
2587         tcounter++;             /* which proto entry we're looking at */
2588         }
2589
2590         if (NTProtoIndex != -1) {
2591                 protoIndex = NTProtoIndex;
2592                 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2593         }
2594         else if (v3ProtoIndex != -1) {
2595                 protoIndex = v3ProtoIndex;
2596                 vcp->flags |= SMB_VCFLAG_USEV3;
2597         }       
2598         else if (coreProtoIndex != -1) {
2599                 protoIndex = coreProtoIndex;
2600                 vcp->flags |= SMB_VCFLAG_USECORE;
2601         }       
2602         else protoIndex = -1;
2603
2604         if (protoIndex == -1)
2605                 return CM_ERROR_INVAL;
2606         else if (NTProtoIndex != -1) {
2607         smb_SetSMBParm(outp, 0, protoIndex);
2608                 if (smb_authType != SMB_AUTH_NONE) {
2609                         smb_SetSMBParmByte(outp, 1,
2610                                 NEGOTIATE_SECURITY_USER_LEVEL |
2611                                 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2612                 } else {
2613             smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
2614                 }
2615         smb_SetSMBParm(outp, 1, smb_maxMpxRequests);    /* max multiplexed requests */
2616         smb_SetSMBParm(outp, 2, smb_maxVCPerServer);    /* max VCs per consumer/server connection */
2617         smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE);    /* xmit buffer size */
2618                 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE);    /* raw buffer size */
2619         /* The session key is not a well documented field however most clients
2620          * will echo back the session key to the server.  Currently we are using
2621          * the same value for all sessions.  We should generate a random value
2622          * and store it into the vcp 
2623          */
2624         smb_SetSMBParm(outp, 7, 1);     /* next 2: session key */
2625         smb_SetSMBParm(outp, 8, 1);
2626                 /* 
2627                  * Tried changing the capabilities to support for W2K - defect 117695
2628                  * Maybe something else needs to be changed here?
2629                  */
2630                 /*
2631                   if (isWindows2000) 
2632                   smb_SetSMBParmLong(outp, 9, 0x43fd);
2633                   else 
2634                   smb_SetSMBParmLong(outp, 9, 0x251);
2635                   */
2636                 /* Capabilities: *
2637                  * 32-bit error codes *
2638                  * and NT Find *
2639                  * and NT SMB's *
2640                  * and raw mode */
2641         caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
2642                            NTNEGOTIATE_CAPABILITY_NTFIND |
2643                NTNEGOTIATE_CAPABILITY_RAWMODE |
2644                            NTNEGOTIATE_CAPABILITY_NTSMB;
2645
2646         if ( smb_authType == SMB_AUTH_EXTENDED )
2647             caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
2648
2649         smb_SetSMBParmLong(outp, 9, caps);
2650                 time(&unixTime);
2651                 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2652                 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
2653                 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
2654
2655                 GetTimeZoneInformation(&tzi);
2656                 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias);    /* server tzone */
2657
2658                 if (smb_authType == SMB_AUTH_NTLM) {
2659                         smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
2660                         smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
2661                         /* paste in encryption key */
2662                         datap = smb_GetSMBData(outp, NULL);
2663                         memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
2664                         /* and the faux domain name */
2665                         strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
2666                 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
2667             void * secBlob;
2668                         int secBlobLength;
2669
2670                         smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2671
2672                         smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
2673
2674                         smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
2675                         
2676                         datap = smb_GetSMBData(outp, NULL);
2677                         memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
2678
2679                         if (secBlob) {
2680                                 datap += sizeof(smb_ServerGUID);
2681                                 memcpy(datap, secBlob, secBlobLength);
2682                                 free(secBlob);
2683                         }
2684         } else {
2685                         smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2686                         smb_SetSMBDataLength(outp, 0);   /* Perhaps we should specify 8 bytes anyway */
2687                 }
2688         }
2689         else if (v3ProtoIndex != -1) {
2690                 smb_SetSMBParm(outp, 0, protoIndex);
2691
2692         /* NOTE: Extended authentication cannot be negotiated with v3
2693          * therefore we fail over to NTLM 
2694          */
2695         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2696                         smb_SetSMBParm(outp, 1,
2697                                 NEGOTIATE_SECURITY_USER_LEVEL |
2698                                 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2699                 } else {
2700                         smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
2701                 }
2702                 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
2703                 smb_SetSMBParm(outp, 3, smb_maxMpxRequests);    /* max multiplexed requests */
2704                 smb_SetSMBParm(outp, 4, smb_maxVCPerServer);    /* max VCs per consumer/server connection */
2705                 smb_SetSMBParm(outp, 5, 0);     /* no support of block mode for read or write */
2706                 smb_SetSMBParm(outp, 6, 1);     /* next 2: session key */
2707                 smb_SetSMBParm(outp, 7, 1);
2708                 time(&unixTime);
2709                 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2710                 smb_SetSMBParm(outp, 8, LOWORD(dosTime));       /* server time */
2711                 smb_SetSMBParm(outp, 9, HIWORD(dosTime));       /* server date */
2712
2713                 GetTimeZoneInformation(&tzi);
2714                 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias);    /* server tzone */
2715
2716         /* NOTE: Extended authentication cannot be negotiated with v3
2717          * therefore we fail over to NTLM 
2718          */
2719                 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2720                         smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH);      /* encryption key length */
2721             smb_SetSMBParm(outp, 12, 0);        /* resvd */
2722                         smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);       /* perhaps should specify 8 bytes anyway */
2723                         datap = smb_GetSMBData(outp, NULL);
2724                         /* paste in a new encryption key */
2725                         memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
2726                         /* and the faux domain name */
2727                         strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
2728                 } else {
2729                         smb_SetSMBParm(outp, 11, 0); /* encryption key length */
2730                         smb_SetSMBParm(outp, 12, 0); /* resvd */
2731                         smb_SetSMBDataLength(outp, 0);
2732                 }
2733         }
2734         else if (coreProtoIndex != -1) {     /* not really supported anymore */
2735                 smb_SetSMBParm(outp, 0, protoIndex);
2736                 smb_SetSMBDataLength(outp, 0);
2737         }
2738         return 0;
2739 }
2740
2741 void smb_Daemon(void *parmp)
2742 {
2743         int count = 0;
2744
2745         while(1) {
2746                 count++;
2747                 thrd_Sleep(10000);
2748                 if ((count % 360) == 0) {       /* every hour */
2749             struct tm myTime;
2750                  
2751             /* Initialize smb_localZero */
2752             myTime.tm_isdst = -1;               /* compute whether on DST or not */
2753             myTime.tm_year = 70;
2754             myTime.tm_mon = 0;
2755             myTime.tm_mday = 1;
2756             myTime.tm_hour = 0;
2757             myTime.tm_min = 0;
2758             myTime.tm_sec = 0;
2759             smb_localZero = mktime(&myTime);
2760
2761             smb_CalculateNowTZ();
2762         }
2763                 /* XXX GC dir search entries */
2764         }
2765 }
2766
2767 void smb_WaitingLocksDaemon()
2768 {
2769         smb_waitingLock_t *wL, *nwL;
2770         int first;
2771         smb_vc_t *vcp;
2772         smb_packet_t *inp, *outp;
2773         NCB *ncbp;
2774         long code = 0;
2775
2776         while(1) {
2777                 lock_ObtainWrite(&smb_globalLock);
2778                 nwL = smb_allWaitingLocks;
2779                 if (nwL == NULL) {
2780                         osi_SleepW((long)&smb_allWaitingLocks, &smb_globalLock);
2781                         thrd_Sleep(1000);
2782                         continue;
2783                 }
2784                 else first = 1;
2785                 do {
2786                         if (first)
2787                                 first = 0;
2788                         else
2789                                 lock_ObtainWrite(&smb_globalLock);
2790                         wL = nwL;
2791                         nwL = (smb_waitingLock_t *) osi_QNext(&wL->q);
2792                         lock_ReleaseWrite(&smb_globalLock);
2793                         code = cm_RetryLock((cm_file_lock_t *) wL->lockp,
2794                                                                 wL->vcp->flags & SMB_VCFLAG_ALREADYDEAD);
2795                         if (code == CM_ERROR_WOULDBLOCK) {
2796                                 /* no progress */
2797                                 if (wL->timeRemaining != 0xffffffff
2798                                     && (wL->timeRemaining -= 1000) < 0)
2799                                         goto endWait;
2800                                 continue;
2801                         }
2802                   endWait:
2803                         vcp = wL->vcp;
2804                         inp = wL->inp;
2805                         outp = wL->outp;
2806                         ncbp = GetNCB();
2807                         ncbp->ncb_length = inp->ncb_length;
2808                         inp->spacep = cm_GetSpace();
2809
2810                         /* Remove waitingLock from list */
2811                         lock_ObtainWrite(&smb_globalLock);
2812                         osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
2813                                     &wL->q);
2814                         lock_ReleaseWrite(&smb_globalLock);
2815
2816                         /* Resume packet processing */
2817                         if (code == 0)
2818                                 smb_SetSMBDataLength(outp, 0);
2819                         outp->flags |= SMB_PACKETFLAG_SUSPENDED;
2820                         outp->resumeCode = code;
2821                         outp->ncbp = ncbp;
2822                         smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
2823
2824                         /* Clean up */
2825                         cm_FreeSpace(inp->spacep);
2826                         smb_FreePacket(inp);
2827                         smb_FreePacket(outp);
2828                         FreeNCB(ncbp);
2829                         free(wL);
2830                 } while (nwL);
2831                 thrd_Sleep(1000);
2832         }
2833 }
2834
2835 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2836 {
2837         osi_Log0(smb_logp, "SMB receive get disk attributes");
2838
2839         smb_SetSMBParm(outp, 0, 32000);
2840         smb_SetSMBParm(outp, 1, 64);
2841         smb_SetSMBParm(outp, 2, 1024);
2842         smb_SetSMBParm(outp, 3, 30000);
2843         smb_SetSMBParm(outp, 4, 0);
2844         smb_SetSMBDataLength(outp, 0);
2845         return 0;
2846 }
2847
2848 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
2849 {
2850         smb_tid_t *tidp;
2851     smb_user_t *uidp;
2852         unsigned short newTid;
2853         char shareName[256];
2854         char *sharePath;
2855         int shareFound;
2856         char *tp;
2857         char *pathp;
2858         char *passwordp;
2859         cm_user_t *userp;
2860
2861         osi_Log0(smb_logp, "SMB receive tree connect");
2862
2863         /* parse input parameters */
2864         tp = smb_GetSMBData(inp, NULL);
2865         pathp = smb_ParseASCIIBlock(tp, &tp);
2866         passwordp = smb_ParseASCIIBlock(tp, &tp);
2867         tp = strrchr(pathp, '\\');
2868         if (!tp)
2869                 return CM_ERROR_BADSMB;
2870         strcpy(shareName, tp+1);
2871
2872         userp = smb_GetUser(vcp, inp);
2873
2874         lock_ObtainMutex(&vcp->mx);
2875         newTid = vcp->tidCounter++;
2876         lock_ReleaseMutex(&vcp->mx);
2877         
2878         tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
2879     uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
2880         shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
2881     if (uidp)
2882         smb_ReleaseUID(uidp);
2883         if (!shareFound) {
2884                 smb_ReleaseTID(tidp);
2885                 return CM_ERROR_BADSHARENAME;
2886         }
2887         lock_ObtainMutex(&tidp->mx);
2888         tidp->userp = userp;
2889         tidp->pathname = sharePath;
2890         lock_ReleaseMutex(&tidp->mx);
2891         smb_ReleaseTID(tidp);
2892
2893         smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
2894         smb_SetSMBParm(rsp, 1, newTid);
2895         smb_SetSMBDataLength(rsp, 0);
2896
2897         osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
2898         return 0;
2899 }
2900
2901 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2902 {
2903         int tlen;
2904
2905         if (*inp++ != 0x1) return NULL;
2906         tlen = inp[0] + (inp[1]<<8);
2907         inp += 2;               /* skip length field */
2908         
2909         if (chainpp) {
2910                 *chainpp = inp + tlen;
2911         }       
2912         
2913         if (lengthp) *lengthp = tlen;
2914         
2915         return inp;
2916 }
2917
2918 /* set maskp to the mask part of the incoming path.
2919  * Mask is 11 bytes long (8.3 with the dot elided).
2920  * Returns true if succeeds with a valid name, otherwise it does
2921  * its best, but returns false.
2922  */
2923 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
2924 {
2925         char *tp;
2926         char *up;
2927         int i;
2928         int tc;
2929         int valid8Dot3;
2930
2931         /* starts off valid */
2932         valid8Dot3 = 1;
2933
2934         /* mask starts out all blanks */
2935         memset(maskp, ' ', 11);
2936
2937         /* find last backslash, or use whole thing if there is none */
2938         tp = strrchr(pathp, '\\');
2939         if (!tp) tp = pathp;
2940         else tp++;      /* skip slash */
2941         
2942         up = maskp;
2943
2944         /* names starting with a dot are illegal */
2945         if (*tp == '.') valid8Dot3 = 0;
2946
2947     for(i=0;; i++) {
2948                 tc = *tp++;
2949         if (tc == 0) return valid8Dot3;
2950         if (tc == '.' || tc == '"') break;
2951         if (i < 8) *up++ = tc;
2952         else valid8Dot3 = 0;
2953     }
2954         
2955     /* if we get here, tp point after the dot */
2956     up = maskp+8;       /* ext goes here */
2957     for(i=0;;i++) {
2958         tc = *tp++;
2959         if (tc == 0) 
2960                         return valid8Dot3;
2961
2962         /* too many dots */
2963         if (tc == '.' || tc == '"') 
2964                         valid8Dot3 = 0;
2965
2966         /* copy extension if not too long */
2967         if (i < 3) 
2968                         *up++ = tc;
2969         else 
2970                         valid8Dot3 = 0;
2971     }   
2972
2973     /* unreachable */
2974 }
2975
2976 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
2977 {
2978         char umask[11];
2979         int valid;
2980         int i;
2981         char tc1;
2982         char tc2;
2983         char *tp1;
2984         char *tp2;
2985
2986         /* XXX redo this, calling smb_V3MatchMask with a converted mask */
2987
2988         valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
2989         if (!valid) 
2990                 return 0;
2991  
2992         /* otherwise, we have a valid 8.3 name; see if we have a match,
2993          * treating '?' as a wildcard in maskp (but not in the file name).
2994          */
2995         tp1 = umask;    /* real name, in mask format */
2996         tp2 = maskp;    /* mask, in mask format */
2997         for(i=0; i<11; i++) {
2998                 tc1 = *tp1++;   /* char from real name */
2999                 tc2 = *tp2++;   /* char from mask */
3000                 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3001                 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3002                 if (tc1 == tc2) 
3003                         continue;
3004                 if (tc2 == '?' && tc1 != ' ') 
3005                         continue;
3006                 if (tc2 == '>') 
3007                         continue;
3008                 return 0;
3009         }
3010
3011         /* we got a match */
3012         return 1;
3013 }
3014
3015 char *smb_FindMask(char *pathp)
3016 {
3017         char *tp;
3018         
3019         tp = strrchr(pathp, '\\');      /* find last slash */
3020
3021         if (tp) 
3022                 return tp+1;    /* skip the slash */
3023         else 
3024                 return pathp;   /* no slash, return the entire path */
3025 }
3026
3027 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3028 {
3029         unsigned char *pathp;
3030         unsigned char *tp;
3031         unsigned char mask[11];
3032         unsigned char *statBlockp;
3033         unsigned char initStatBlock[21];
3034         int statLen;
3035         
3036         osi_Log0(smb_logp, "SMB receive search volume");
3037
3038         /* pull pathname and stat block out of request */
3039         tp = smb_GetSMBData(inp, NULL);
3040         pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3041         osi_assert(pathp != NULL);
3042         statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3043         osi_assert(statBlockp != NULL);
3044         if (statLen == 0) {
3045                 statBlockp = initStatBlock;
3046                 statBlockp[0] = 8;
3047         }
3048         
3049         /* for returning to caller */
3050         smb_Get8Dot3MaskFromPath(mask, pathp);
3051         
3052         smb_SetSMBParm(outp, 0, 1);             /* we're returning one entry */
3053         tp = smb_GetSMBData(outp, NULL);
3054         *tp++ = 5;
3055         *tp++ = 43;     /* bytes in a dir entry */
3056         *tp++ = 0;      /* high byte in counter */
3057
3058         /* now marshall the dir entry, starting with the search status */
3059         *tp++ = statBlockp[0];          /* Reserved */
3060         memcpy(tp, mask, 11); tp += 11; /* FileName */
3061
3062         /* now pass back server use info, with 1st byte non-zero */
3063         *tp++ = 1;
3064         memset(tp, 0, 4); tp += 4;      /* reserved for server use */
3065
3066         memcpy(tp, statBlockp+17, 4); tp += 4;  /* reserved for consumer */
3067
3068         *tp++ = 0x8;            /* attribute: volume */
3069
3070         /* copy out time */
3071         *tp++ = 0;
3072         *tp++ = 0;
3073
3074         /* copy out date */
3075         *tp++ = 18;
3076         *tp++ = 178;
3077
3078         /* 4 byte file size */
3079         *tp++ = 0;
3080         *tp++ = 0;
3081         *tp++ = 0;
3082         *tp++ = 0;
3083
3084         /* finally, null-terminated 8.3 pathname, which we set to AFS */
3085         memset(tp, ' ', 13);
3086         strcpy(tp, "AFS");
3087
3088         /* set the length of the data part of the packet to 43 + 3, for the dir
3089          * entry plus the 5 and the length fields.
3090          */
3091         smb_SetSMBDataLength(outp, 46);
3092         return 0;
3093 }
3094
3095 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3096         cm_user_t *userp, cm_req_t *reqp)
3097 {
3098         long code = 0;
3099         cm_scache_t *scp;
3100         char *dptr;
3101         long dosTime;
3102         u_short shortTemp;
3103         char attr;
3104         smb_dirListPatch_t *patchp;
3105         smb_dirListPatch_t *npatchp;
3106
3107         for(patchp = *dirPatchespp; patchp; patchp =
3108                  (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3109                 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3110                 if (code) continue;
3111                 lock_ObtainMutex(&scp->mx);
3112                 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3113                                                   CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3114                 if (code) {     
3115                         lock_ReleaseMutex(&scp->mx);
3116                         cm_ReleaseSCache(scp);
3117                         continue;
3118                 }
3119                 dptr = patchp->dptr;
3120
3121                 attr = smb_Attributes(scp);
3122         /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3123         if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3124             attr |= SMB_ATTR_HIDDEN;
3125         *dptr++ = attr;
3126
3127                 /* get dos time */
3128                 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3129                 
3130                 /* copy out time */
3131                 shortTemp = dosTime & 0xffff;
3132                 *((u_short *)dptr) = shortTemp;
3133                 dptr += 2;
3134
3135                 /* and copy out date */
3136                 shortTemp = (dosTime>>16) & 0xffff;
3137                 *((u_short *)dptr) = shortTemp;
3138                 dptr += 2;
3139                 
3140                 /* copy out file length */
3141                 *((u_long *)dptr) = scp->length.LowPart;
3142                 dptr += 4;
3143                 lock_ReleaseMutex(&scp->mx);
3144                 cm_ReleaseSCache(scp);
3145         }
3146         
3147         /* now free the patches */
3148         for(patchp = *dirPatchespp; patchp; patchp = npatchp) {
3149                 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3150                 free(patchp);
3151         }       
3152         
3153         /* and mark the list as empty */
3154         *dirPatchespp = NULL;
3155
3156         return code;
3157 }
3158
3159 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3160 {
3161         int attribute;
3162         long nextCookie;
3163         char *tp;
3164         long code = 0;
3165         char *pathp;
3166         cm_dirEntry_t *dep;
3167         int maxCount;
3168         smb_dirListPatch_t *dirListPatchesp;
3169         smb_dirListPatch_t *curPatchp;
3170         int dataLength;
3171         cm_buf_t *bufferp;
3172         long temp;
3173         osi_hyper_t dirLength;
3174         osi_hyper_t bufferOffset;
3175         osi_hyper_t curOffset;
3176         osi_hyper_t thyper;
3177         unsigned char *inCookiep;
3178         smb_dirSearch_t *dsp;
3179         cm_scache_t *scp;
3180         long entryInDir;
3181         long entryInBuffer;
3182         unsigned long clientCookie;
3183         cm_pageHeader_t *pageHeaderp;
3184         cm_user_t *userp = NULL;
3185         int slotInPage;
3186         char shortName[13];
3187         char *actualName;
3188         char *shortNameEnd;
3189         char mask[11];
3190         int returnedNames;
3191         long nextEntryCookie;
3192         int numDirChunks;               /* # of 32 byte dir chunks in this entry */
3193         char resByte;                   /* reserved byte from the cookie */
3194         char *op;                       /* output data ptr */
3195         char *origOp;                   /* original value of op */
3196         cm_space_t *spacep;             /* for pathname buffer */
3197         int starPattern;
3198         int rootPath = 0;
3199         int caseFold;
3200         char *tidPathp;
3201         cm_req_t req;
3202         cm_fid_t fid;
3203         int fileType;
3204
3205         cm_InitReq(&req);
3206
3207         maxCount = smb_GetSMBParm(inp, 0);
3208
3209         dirListPatchesp = NULL;
3210         
3211         caseFold = CM_FLAG_CASEFOLD;
3212
3213         tp = smb_GetSMBData(inp, NULL);
3214         pathp = smb_ParseASCIIBlock(tp, &tp);
3215         inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3216
3217         /* bail out if request looks bad */
3218         if (!tp || !pathp) {
3219                 return CM_ERROR_BADSMB;
3220         }
3221
3222         /* We can handle long names */
3223         if (vcp->flags & SMB_VCFLAG_USENT)
3224                 ((smb_t *)outp)->flg2 |= 0x40;  /* IS_LONG_NAME */
3225
3226         /* make sure we got a whole search status */
3227         if (dataLength < 21) {
3228                 nextCookie = 0;         /* start at the beginning of the dir */
3229                 resByte = 0;
3230                 clientCookie = 0;
3231                 attribute = smb_GetSMBParm(inp, 1);
3232
3233                 /* handle volume info in another function */
3234                 if (attribute & 0x8)
3235                         return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3236
3237                 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3238                                  maxCount, osi_LogSaveString(smb_logp, pathp));
3239
3240                 if (*pathp == 0) {      /* null pathp, treat as root dir */
3241                         if (!(attribute & SMB_ATTR_DIRECTORY))  /* exclude dirs */
3242                                 return CM_ERROR_NOFILES;
3243                         rootPath = 1;
3244                 }
3245
3246                 dsp = smb_NewDirSearch(0);
3247                 dsp->attribute = attribute;
3248                 smb_Get8Dot3MaskFromPath(mask, pathp);
3249                 memcpy(dsp->mask, mask, 11);
3250
3251                 /* track if this is likely to match a lot of entries */
3252                 if (smb_IsStarMask(mask)) starPattern = 1;
3253                 else starPattern = 0;
3254         }       
3255         else {
3256                 /* pull the next cookie value out of the search status block */
3257                 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3258                         + (inCookiep[16]<<24);
3259                 dsp = smb_FindDirSearch(inCookiep[12]);
3260                 if (!dsp) {
3261                         /* can't find dir search status; fatal error */
3262                         return CM_ERROR_BADFD;
3263                 }
3264                 attribute = dsp->attribute;
3265                 resByte = inCookiep[0];
3266
3267                 /* copy out client cookie, in host byte order.  Don't bother
3268                  * interpreting it, since we're just passing it through, anyway.
3269                  */
3270                 memcpy(&clientCookie, &inCookiep[17], 4);
3271
3272                 memcpy(mask, dsp->mask, 11);
3273
3274                 /* assume we're doing a star match if it has continued for more
3275                  * than one call.
3276                  */
3277                 starPattern = 1;
3278         }
3279
3280         osi_Log3(smb_logp, "SMB dir search cookie 0x%x, connection %d, attr 0x%x",
3281                          nextCookie, dsp->cookie, attribute);
3282
3283         userp = smb_GetUser(vcp, inp);
3284
3285         /* try to get the vnode for the path name next */
3286         lock_ObtainMutex(&dsp->mx);
3287         if (dsp->scp) {
3288                 scp = dsp->scp;
3289                 cm_HoldSCache(scp);
3290                 code = 0;
3291         }
3292         else {
3293                 spacep = inp->spacep;
3294                 smb_StripLastComponent(spacep->data, NULL, pathp);
3295                 lock_ReleaseMutex(&dsp->mx);
3296                 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3297                 code = cm_NameI(cm_rootSCachep, spacep->data,
3298                                                 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3299                 lock_ObtainMutex(&dsp->mx);
3300                 if (code == 0) {
3301                         if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
3302                         dsp->scp = scp;
3303                         /* we need one hold for the entry we just stored into,
3304                          * and one for our own processing.  When we're done with this
3305                          * function, we'll drop the one for our own processing.
3306                          * We held it once from the namei call, and so we do another hold
3307                          * now.
3308                          */
3309                         cm_HoldSCache(scp);
3310                         lock_ObtainMutex(&scp->mx);
3311                         if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3312                             && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3313                                 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3314                                 dsp->flags |= SMB_DIRSEARCH_BULKST;
3315                         }
3316                         lock_ReleaseMutex(&scp->mx);
3317                 }
3318         }
3319         lock_ReleaseMutex(&dsp->mx);
3320         if (code) {
3321                 cm_ReleaseUser(userp);
3322                 smb_DeleteDirSearch(dsp);
3323                 smb_ReleaseDirSearch(dsp);
3324                 return code;
3325         }
3326
3327         /* reserves space for parameter; we'll adjust it again later to the
3328          * real count of the # of entries we returned once we've actually
3329          * assembled the directory listing.
3330          */
3331         smb_SetSMBParm(outp, 0, 0);
3332         
3333         /* get the directory size */
3334         lock_ObtainMutex(&scp->mx);
3335         code = cm_SyncOp(scp, NULL, userp, &req, 0,
3336                                          CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3337         if (code) {
3338                 lock_ReleaseMutex(&scp->mx);
3339                 cm_ReleaseSCache(scp);
3340                 cm_ReleaseUser(userp);
3341                 smb_DeleteDirSearch(dsp);
3342                 smb_ReleaseDirSearch(dsp);
3343                 return code;
3344         }
3345         
3346         dirLength = scp->length;
3347         bufferp = NULL;
3348         bufferOffset.LowPart = bufferOffset.HighPart = 0;
3349         curOffset.HighPart = 0;
3350         curOffset.LowPart = nextCookie;
3351         origOp = op = smb_GetSMBData(outp, NULL);
3352         /* and write out the basic header */
3353         *op++ = 5;              /* variable block */
3354         op += 2;                /* skip vbl block length; we'll fill it in later */
3355         code = 0;
3356         returnedNames = 0;
3357         while (1) {
3358                 /* make sure that curOffset.LowPart doesn't point to the first
3359                  * 32 bytes in the 2nd through last dir page, and that it doesn't
3360                  * point at the first 13 32-byte chunks in the first dir page,
3361                  * since those are dir and page headers, and don't contain useful
3362                  * information.
3363                  */
3364                 temp = curOffset.LowPart & (2048-1);
3365                 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3366                         /* we're in the first page */
3367                         if (temp < 13*32) temp = 13*32;
3368                 }
3369                 else {
3370                         /* we're in a later dir page */
3371                         if (temp < 32) temp = 32;
3372                 }
3373                 
3374                 /* make sure the low order 5 bits are zero */
3375                 temp &= ~(32-1);
3376
3377                 /* now put temp bits back ito curOffset.LowPart */
3378                 curOffset.LowPart &= ~(2048-1);
3379                 curOffset.LowPart |= temp;
3380
3381                 /* check if we've returned all the names that will fit in the
3382                  * response packet.
3383                  */
3384                 if (returnedNames >= maxCount) 
3385                         break;
3386                 
3387                 /* check if we've passed the dir's EOF */
3388                 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
3389
3390                 /* see if we can use the bufferp we have now; compute in which page
3391                  * the current offset would be, and check whether that's the offset
3392                  * of the buffer we have.  If not, get the buffer.
3393                  */
3394                 thyper.HighPart = curOffset.HighPart;
3395                 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
3396                 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3397                         /* wrong buffer */
3398                         if (bufferp) {
3399                                 buf_Release(bufferp);
3400                                 bufferp = NULL;
3401                         }       
3402                         lock_ReleaseMutex(&scp->mx);
3403                         lock_ObtainRead(&scp->bufCreateLock);
3404                         code = buf_Get(scp, &thyper, &bufferp);
3405                         lock_ReleaseRead(&scp->bufCreateLock);
3406
3407                         /* now, if we're doing a star match, do bulk fetching of all of 
3408                          * the status info for files in the dir.
3409                          */
3410                         if (starPattern) {
3411                                 smb_ApplyDirListPatches(&dirListPatchesp, userp,
3412                                                                                 &req);
3413                                 if ((dsp->flags & SMB_DIRSEARCH_BULKST)
3414                                     && LargeIntegerGreaterThanOrEqualTo(thyper, 
3415                                                                         scp->bulkStatProgress)) {
3416                                         /* Don't bulk stat if risking timeout */
3417                                         int now = GetCurrentTime();
3418                                         if (now - req.startTime > 5000) {
3419                                                 scp->bulkStatProgress = thyper;
3420                                                 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3421                                                 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3422                                         } else
3423                                                 cm_TryBulkStat(scp, &thyper, userp, &req);
3424                                 }
3425                         }
3426
3427                         lock_ObtainMutex(&scp->mx);
3428                         if (code) 
3429                                 break;
3430                         bufferOffset = thyper;
3431
3432                         /* now get the data in the cache */
3433                         while (1) {
3434                                 code = cm_SyncOp(scp, bufferp, userp, &req,
3435                                                                   PRSFS_LOOKUP,
3436                                                                   CM_SCACHESYNC_NEEDCALLBACK
3437                                                                   | CM_SCACHESYNC_READ);
3438                                 if (code) break;
3439                                 
3440                                 if (cm_HaveBuffer(scp, bufferp, 0)) break;
3441
3442                                 /* otherwise, load the buffer and try again */
3443                                 code = cm_GetBuffer(scp, bufferp, NULL, userp,
3444                                                                         &req);
3445                                 if (code) break;
3446                         }
3447                         if (code) {
3448                                 buf_Release(bufferp);
3449                                 bufferp = NULL;
3450                                 break;
3451