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