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