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