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