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