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