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