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