windows-hooks-20050418
[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) cm_ReleaseSCache(scp);
1684 }       
1685
1686 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1687 {
1688     lock_ObtainWrite(&smb_globalLock);
1689     smb_ReleaseDirSearchNoLock(dsp);
1690     lock_ReleaseWrite(&smb_globalLock);
1691 }       
1692
1693 /* find a dir search structure by cookie value, and return it held */
1694 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1695 {
1696     smb_dirSearch_t *dsp;
1697
1698     lock_ObtainWrite(&smb_globalLock);
1699     dsp = smb_FindDirSearchNoLock(cookie);
1700     lock_ReleaseWrite(&smb_globalLock);
1701     return dsp;
1702 }
1703
1704 /* GC some dir search entries, in the address space expected by the specific protocol.
1705  * Must be called with smb_globalLock held; release the lock temporarily.
1706  */
1707 #define SMB_DIRSEARCH_GCMAX     10      /* how many at once */
1708 void smb_GCDirSearches(int isV3)
1709 {
1710     smb_dirSearch_t *prevp;
1711     smb_dirSearch_t *tp;
1712     smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1713     int victimCount;
1714     int i;
1715         
1716     victimCount = 0;    /* how many have we got so far */
1717     for (tp = smb_lastDirSearchp; tp; tp=prevp) {
1718         /* we'll move tp from queue, so
1719          * do this early.
1720          */
1721         prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);  
1722         /* if no one is using this guy, and we're either in the new protocol,
1723          * or we're in the old one and this is a small enough ID to be useful
1724          * to the old protocol, GC this guy.
1725          */
1726         if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1727             /* hold and delete */
1728             tp->flags |= SMB_DIRSEARCH_DELETE;
1729             victimsp[victimCount++] = tp;
1730             tp->refCount++;
1731         }
1732
1733         /* don't do more than this */
1734         if (victimCount >= SMB_DIRSEARCH_GCMAX) 
1735             break;
1736     }
1737         
1738     /* now release them */
1739     for (i = 0; i < victimCount; i++) {
1740         smb_ReleaseDirSearchNoLock(victimsp[i]);
1741     }
1742 }
1743
1744 /* function for allocating a dir search entry.  We need these to remember enough context
1745  * since we don't get passed the path from call to call during a directory search.
1746  *
1747  * Returns a held dir search structure, and bumps the reference count on the vnode,
1748  * since it saves a pointer to the vnode.
1749  */
1750 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1751 {
1752     smb_dirSearch_t *dsp;
1753     int counter;
1754     int maxAllowed;
1755     int start;
1756     int wrapped = 0;
1757
1758     lock_ObtainWrite(&smb_globalLock);
1759     counter = 0;
1760
1761     /* what's the biggest ID allowed in this version of the protocol */
1762     maxAllowed = isV3 ? 65535 : 255;
1763     if (smb_dirSearchCounter > maxAllowed)
1764         smb_dirSearchCounter = 1;
1765
1766     start = smb_dirSearchCounter;
1767
1768     while (1) {
1769         /* twice so we have enough tries to find guys we GC after one pass;
1770          * 10 extra is just in case I mis-counted.
1771          */
1772         if (++counter > 2*maxAllowed+10) 
1773             osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
1774
1775         if (smb_dirSearchCounter > maxAllowed) {        
1776             smb_dirSearchCounter = 1;
1777         }
1778         if (smb_dirSearchCounter == start) {
1779             if (wrapped)
1780                 smb_GCDirSearches(isV3);
1781             wrapped++;
1782         }
1783         dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
1784         if (dsp) {
1785             /* don't need to watch for refcount zero and deleted, since
1786             * we haven't dropped the global lock.
1787             */
1788             lock_ObtainMutex(&dsp->mx);
1789             dsp->refCount--;
1790             lock_ReleaseMutex(&dsp->mx);
1791             ++smb_dirSearchCounter;
1792             continue;
1793         }       
1794
1795         dsp = malloc(sizeof(*dsp));
1796         memset(dsp, 0, sizeof(*dsp));
1797         dsp->cookie = smb_dirSearchCounter;
1798         ++smb_dirSearchCounter;
1799         dsp->refCount = 1;
1800         lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
1801         dsp->lastTime = osi_Time();
1802         osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1803         if (!smb_lastDirSearchp) 
1804             smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1805         break;
1806     }   
1807     lock_ReleaseWrite(&smb_globalLock);
1808     return dsp;
1809 }
1810
1811 static smb_packet_t *GetPacket(void)
1812 {
1813     smb_packet_t *tbp;
1814 #ifdef DJGPP
1815     unsigned int npar, seg, tb_sel;
1816 #endif
1817
1818     lock_ObtainWrite(&smb_globalLock);
1819     tbp = smb_packetFreeListp;
1820     if (tbp) 
1821         smb_packetFreeListp = tbp->nextp;
1822     lock_ReleaseWrite(&smb_globalLock);
1823     if (!tbp) {
1824 #ifndef DJGPP
1825         tbp = calloc(65540,1);
1826 #else /* DJGPP */
1827         tbp = malloc(sizeof(smb_packet_t));
1828 #endif /* !DJGPP */
1829         tbp->magic = SMB_PACKETMAGIC;
1830         tbp->ncbp = NULL;
1831         tbp->vcp = NULL;
1832         tbp->resumeCode = 0;
1833         tbp->inCount = 0;
1834         tbp->fid = 0;
1835         tbp->wctp = NULL;
1836         tbp->inCom = 0;
1837         tbp->oddByte = 0;
1838         tbp->ncb_length = 0;
1839         tbp->flags = 0;
1840         tbp->spacep = NULL;
1841         
1842 #ifdef DJGPP
1843         npar = SMB_PACKETSIZE >> 4;  /* number of paragraphs */
1844         {
1845             signed int retval =
1846                 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1847             if (retval == -1) {
1848                 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS memory",
1849                           npar);
1850                 osi_panic("",__FILE__,__LINE__);
1851             }
1852             else {
1853                 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X",
1854                           npar, retval);
1855                 seg = retval;
1856             }
1857         }
1858         tbp->dos_pkt = (seg * 16) + 0;  /* DOS physical address */
1859         tbp->dos_pkt_sel = tb_sel;
1860 #endif /* DJGPP */
1861     }
1862     osi_assert(tbp->magic == SMB_PACKETMAGIC);
1863
1864     return tbp;
1865 }
1866
1867 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
1868 {
1869     smb_packet_t *tbp;
1870     tbp = GetPacket();
1871     memcpy(tbp, pkt, sizeof(smb_packet_t));
1872     tbp->wctp = tbp->data + ((unsigned int)pkt->wctp - (unsigned int)pkt->data);
1873         if (tbp->vcp)
1874                 smb_HoldVC(tbp->vcp);
1875     return tbp;
1876 }
1877
1878 static NCB *GetNCB(void)
1879 {
1880     smb_ncb_t *tbp;
1881     NCB *ncbp;
1882 #ifdef DJGPP
1883     unsigned int npar, seg, tb_sel;
1884 #endif /* DJGPP */
1885
1886     lock_ObtainWrite(&smb_globalLock);
1887     tbp = smb_ncbFreeListp;
1888     if (tbp) 
1889         smb_ncbFreeListp = tbp->nextp;
1890     lock_ReleaseWrite(&smb_globalLock);
1891     if (!tbp) {
1892 #ifndef DJGPP
1893         tbp = calloc(sizeof(*tbp),1);
1894 #else /* DJGPP */
1895         tbp = malloc(sizeof(*tbp));
1896         npar = (sizeof(NCB)+15) >> 4;  /* number of paragraphs */
1897         {
1898             signed int retval =
1899                 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1900             if (retval == -1) {
1901                 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS mem in GetNCB",
1902                           npar);
1903                 osi_panic("",__FILE__,__LINE__);
1904             } else {
1905                 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
1906                           npar, retval);
1907                 seg = retval;
1908             }
1909         }
1910         tbp->dos_ncb = (seg * 16) + 0;  /* DOS physical address */
1911         tbp->dos_ncb_sel = tb_sel;
1912 #endif /* !DJGPP */
1913         tbp->magic = SMB_NCBMAGIC;
1914     }
1915         
1916     osi_assert(tbp->magic == SMB_NCBMAGIC);
1917
1918     memset(&tbp->ncb, 0, sizeof(NCB));
1919     ncbp = &tbp->ncb;
1920 #ifdef DJGPP
1921     dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
1922 #endif /* DJGPP */
1923     return ncbp;
1924 }
1925
1926 void smb_FreePacket(smb_packet_t *tbp)
1927 {
1928     smb_vc_t * vcp = NULL;
1929     osi_assert(tbp->magic == SMB_PACKETMAGIC);
1930         
1931     lock_ObtainWrite(&smb_globalLock);
1932     tbp->nextp = smb_packetFreeListp;
1933     smb_packetFreeListp = tbp;
1934     tbp->magic = SMB_PACKETMAGIC;
1935     tbp->ncbp = NULL;
1936     vcp = tbp->vcp;
1937     tbp->vcp = NULL;
1938     tbp->resumeCode = 0;
1939     tbp->inCount = 0;
1940     tbp->fid = 0;
1941     tbp->wctp = NULL;
1942     tbp->inCom = 0;
1943     tbp->oddByte = 0;
1944     tbp->ncb_length = 0;
1945     tbp->flags = 0;
1946     lock_ReleaseWrite(&smb_globalLock);
1947
1948     if (vcp)
1949         smb_ReleaseVC(vcp);
1950 }
1951
1952 static void FreeNCB(NCB *bufferp)
1953 {
1954     smb_ncb_t *tbp;
1955         
1956     tbp = (smb_ncb_t *) bufferp;
1957     osi_assert(tbp->magic == SMB_NCBMAGIC);
1958         
1959     lock_ObtainWrite(&smb_globalLock);
1960     tbp->nextp = smb_ncbFreeListp;
1961     smb_ncbFreeListp = tbp;
1962     lock_ReleaseWrite(&smb_globalLock);
1963 }
1964
1965 /* get a ptr to the data part of a packet, and its count */
1966 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
1967 {
1968     int parmBytes;
1969     int dataBytes;
1970     unsigned char *afterParmsp;
1971
1972     parmBytes = *smbp->wctp << 1;
1973     afterParmsp = smbp->wctp + parmBytes + 1;
1974         
1975     dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
1976     if (nbytesp) *nbytesp = dataBytes;
1977         
1978     /* don't forget to skip the data byte count, since it follows
1979      * the parameters; that's where the "2" comes from below.
1980      */
1981     return (unsigned char *) (afterParmsp + 2);
1982 }
1983
1984 /* must set all the returned parameters before playing around with the
1985  * data region, since the data region is located past the end of the
1986  * variable number of parameters.
1987  */
1988 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
1989 {
1990     unsigned char *afterParmsp;
1991
1992     afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
1993         
1994     *afterParmsp++ = dsize & 0xff;
1995     *afterParmsp = (dsize>>8) & 0xff;
1996 }       
1997
1998 /* return the parm'th parameter in the smbp packet */
1999 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
2000 {
2001     int parmCount;
2002     unsigned char *parmDatap;
2003
2004     parmCount = *smbp->wctp;
2005
2006     if (parm >= parmCount) {
2007         char s[100];
2008 #ifndef DJGPP
2009         HANDLE h;
2010         char *ptbuf[1];
2011         h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
2012 #endif  
2013         sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2014                  parm, parmCount, smbp->ncb_length);
2015 #ifndef DJGPP   
2016         ptbuf[0] = s;
2017         ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
2018                      1, smbp->ncb_length, ptbuf, smbp);
2019         DeregisterEventSource(h);
2020 #endif
2021         osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2022                  parm, parmCount, smbp->ncb_length);
2023         osi_panic(s, __FILE__, __LINE__);
2024     }
2025     parmDatap = smbp->wctp + (2*parm) + 1;
2026         
2027     return parmDatap[0] + (parmDatap[1] << 8);
2028 }
2029
2030 /* return the parm'th parameter in the smbp packet */
2031 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2032 {
2033     int parmCount;
2034     unsigned char *parmDatap;
2035
2036     parmCount = *smbp->wctp;
2037
2038     if (parm * 2 + offset >= parmCount * 2) {
2039         char s[100];
2040 #ifndef DJGPP
2041         HANDLE h;
2042         char *ptbuf[1];
2043         h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
2044 #endif
2045         sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2046                 parm, offset, parmCount, smbp->ncb_length);
2047 #ifndef DJGPP
2048         ptbuf[0] = s;
2049         ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
2050                     1, smbp->ncb_length, ptbuf, smbp);
2051         DeregisterEventSource(h);
2052 #endif
2053         osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2054                 parm, offset, parmCount, smbp->ncb_length);
2055         osi_panic(s, __FILE__, __LINE__);
2056     }
2057     parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2058         
2059     return parmDatap[0] + (parmDatap[1] << 8);
2060 }
2061
2062 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2063 {
2064     char *parmDatap;
2065
2066     /* make sure we have enough slots */
2067     if (*smbp->wctp <= slot) 
2068         *smbp->wctp = slot+1;
2069         
2070     parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2071     *parmDatap++ = parmValue & 0xff;
2072     *parmDatap = (parmValue>>8) & 0xff;
2073 }       
2074
2075 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2076 {
2077     char *parmDatap;
2078
2079     /* make sure we have enough slots */
2080     if (*smbp->wctp <= slot) 
2081         *smbp->wctp = slot+2;
2082
2083     parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2084     *parmDatap++ = parmValue & 0xff;
2085     *parmDatap++ = (parmValue>>8) & 0xff;
2086     *parmDatap++ = (parmValue>>16) & 0xff;
2087     *parmDatap++ = (parmValue>>24) & 0xff;
2088 }
2089
2090 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2091 {
2092     char *parmDatap;
2093     int i;
2094
2095     /* make sure we have enough slots */
2096     if (*smbp->wctp <= slot) 
2097         *smbp->wctp = slot+4;
2098
2099     parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2100     for (i=0; i<8; i++)
2101         *parmDatap++ = *parmValuep++;
2102 }       
2103
2104 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2105 {
2106     char *parmDatap;
2107
2108     /* make sure we have enough slots */
2109     if (*smbp->wctp <= slot) {
2110         if (smbp->oddByte) {
2111             smbp->oddByte = 0;
2112             *smbp->wctp = slot+1;
2113         } else
2114             smbp->oddByte = 1;
2115     }
2116
2117     parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2118     *parmDatap++ = parmValue & 0xff;
2119 }
2120
2121 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2122 {
2123     char *lastSlashp;
2124         
2125     lastSlashp = strrchr(inPathp, '\\');
2126     if (lastComponentp)
2127         *lastComponentp = lastSlashp;
2128     if (lastSlashp) {
2129         while (1) {
2130             if (inPathp == lastSlashp) 
2131                 break;
2132             *outPathp++ = *inPathp++;
2133         }
2134         *outPathp++ = 0;
2135     }
2136     else {
2137         *outPathp++ = 0;
2138     }
2139 }
2140
2141 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2142 {
2143     if (*inp++ != 0x4) 
2144         return NULL;
2145     if (chainpp) {
2146         *chainpp = inp + strlen(inp) + 1;       /* skip over null-terminated string */
2147     }
2148     return inp;
2149 }
2150
2151 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2152 {
2153     int tlen;
2154
2155     if (*inp++ != 0x5) 
2156         return NULL;
2157     tlen = inp[0] + (inp[1]<<8);
2158     inp += 2;           /* skip length field */
2159
2160     if (chainpp) {
2161         *chainpp = inp + tlen;
2162     }
2163         
2164     if (lengthp) 
2165         *lengthp = tlen;
2166         
2167     return inp;
2168 }       
2169
2170 /* format a packet as a response */
2171 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2172 {
2173     smb_t *outp;
2174     smb_t *inSmbp;
2175
2176     outp = (smb_t *) op;
2177         
2178     /* zero the basic structure through the smb_wct field, and zero the data
2179      * size field, assuming that wct stays zero; otherwise, you have to 
2180      * explicitly set the data size field, too.
2181      */
2182     inSmbp = (smb_t *) inp;
2183     memset(outp, 0, sizeof(smb_t)+2);
2184     outp->id[0] = 0xff;
2185     outp->id[1] = 'S';
2186     outp->id[2] = 'M';
2187     outp->id[3] = 'B';
2188     if (inp) {
2189         outp->com = inSmbp->com;
2190         outp->tid = inSmbp->tid;
2191         outp->pid = inSmbp->pid;
2192         outp->uid = inSmbp->uid;
2193         outp->mid = inSmbp->mid;
2194         outp->res[0] = inSmbp->res[0];
2195         outp->res[1] = inSmbp->res[1];
2196         op->inCom = inSmbp->com;
2197     }
2198     outp->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
2199     outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2200
2201     /* copy fields in generic packet area */
2202     op->wctp = &outp->wct;
2203 }       
2204
2205 /* send a (probably response) packet; vcp tells us to whom to send it.
2206  * we compute the length by looking at wct and bcc fields.
2207  */
2208 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2209 {
2210     NCB *ncbp;
2211     int extra;
2212     long code = 0;
2213     unsigned char *tp;
2214     int localNCB = 0;
2215 #ifdef DJGPP
2216     dos_ptr dos_ncb;
2217 #endif /* DJGPP */
2218         
2219     ncbp = inp->ncbp;
2220     if (ncbp == NULL) {
2221         ncbp = GetNCB();
2222         localNCB = 1;
2223     }
2224 #ifdef DJGPP
2225     dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2226 #endif /* DJGPP */
2227  
2228     memset((char *)ncbp, 0, sizeof(NCB));
2229
2230     extra = 2 * (*inp->wctp);   /* space used by parms, in bytes */
2231     tp = inp->wctp + 1+ extra;  /* points to count of data bytes */
2232     extra += tp[0] + (tp[1]<<8);
2233     extra += ((unsigned int)inp->wctp - (unsigned int)inp->data);       /* distance to last wct field */
2234     extra += 3;                 /* wct and length fields */
2235         
2236     ncbp->ncb_length = extra;   /* bytes to send */
2237     ncbp->ncb_lsn = (unsigned char) vcp->lsn;   /* vc to use */
2238     ncbp->ncb_lana_num = vcp->lana;
2239     ncbp->ncb_command = NCBSEND;        /* op means send data */
2240 #ifndef DJGPP
2241     ncbp->ncb_buffer = (char *) inp;/* packet */
2242     code = Netbios(ncbp);
2243 #else /* DJGPP */
2244     ncbp->ncb_buffer = inp->dos_pkt;/* packet */
2245     ((smb_ncb_t*)ncbp)->orig_pkt = inp;
2246
2247     /* copy header information from virtual to DOS address space */
2248     dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
2249     code = Netbios(ncbp, dos_ncb);
2250 #endif /* !DJGPP */
2251         
2252     if (code != 0)
2253         osi_Log1(smb_logp, "SendPacket failure code %d", code);
2254
2255     if (localNCB)
2256         FreeNCB(ncbp);
2257 }
2258
2259 void smb_MapNTError(long code, unsigned long *NTStatusp)
2260 {
2261     unsigned long NTStatus;
2262
2263     /* map CM_ERROR_* errors to NT 32-bit status codes */
2264     /* NT Status codes are listed in ntstatus.h not winerror.h */
2265     if (code == CM_ERROR_NOSUCHCELL) {
2266         NTStatus = 0xC000000FL; /* No such file */
2267     }
2268     else if (code == CM_ERROR_NOSUCHVOLUME) {
2269         NTStatus = 0xC000000FL; /* No such file */
2270     }
2271     else if (code == CM_ERROR_TIMEDOUT) {
2272         NTStatus = 0xC00000CFL; /* Sharing Paused */
2273     }
2274     else if (code == CM_ERROR_RETRY) {
2275         NTStatus = 0xC000022DL; /* Retry */
2276     }
2277     else if (code == CM_ERROR_NOACCESS) {
2278         NTStatus = 0xC0000022L; /* Access denied */
2279     }
2280     else if (code == CM_ERROR_READONLY) {
2281         NTStatus = 0xC00000A2L; /* Write protected */
2282     }   
2283     else if (code == CM_ERROR_NOSUCHFILE) {
2284         NTStatus = 0xC000000FL; /* No such file */
2285     }
2286     else if (code == CM_ERROR_NOSUCHPATH) {
2287         NTStatus = 0xC000003AL; /* Object path not found */
2288     }           
2289     else if (code == CM_ERROR_TOOBIG) {
2290         NTStatus = 0xC000007BL; /* Invalid image format */
2291     }
2292     else if (code == CM_ERROR_INVAL) {
2293         NTStatus = 0xC000000DL; /* Invalid parameter */
2294     }
2295     else if (code == CM_ERROR_BADFD) {
2296         NTStatus = 0xC0000008L; /* Invalid handle */
2297     }
2298     else if (code == CM_ERROR_BADFDOP) {
2299         NTStatus = 0xC0000022L; /* Access denied */
2300     }
2301     else if (code == CM_ERROR_EXISTS) {
2302         NTStatus = 0xC0000035L; /* Object name collision */
2303     }
2304     else if (code == CM_ERROR_NOTEMPTY) {
2305         NTStatus = 0xC0000101L; /* Directory not empty */
2306     }   
2307     else if (code == CM_ERROR_CROSSDEVLINK) {
2308         NTStatus = 0xC00000D4L; /* Not same device */
2309     }
2310     else if (code == CM_ERROR_NOTDIR) {
2311         NTStatus = 0xC0000103L; /* Not a directory */
2312     }
2313     else if (code == CM_ERROR_ISDIR) {
2314         NTStatus = 0xC00000BAL; /* File is a directory */
2315     }
2316     else if (code == CM_ERROR_BADOP) {
2317 #ifdef COMMENT
2318         /* I have no idea where this comes from */
2319         NTStatus = 0xC09820FFL; /* SMB no support */
2320 #else
2321         NTStatus = 0xC00000BBL;     /* Not supported */
2322 #endif /* COMMENT */
2323     }
2324     else if (code == CM_ERROR_BADSHARENAME) {
2325         NTStatus = 0xC00000CCL; /* Bad network name */
2326     }
2327     else if (code == CM_ERROR_NOIPC) {
2328 #ifdef COMMENT
2329         NTStatus = 0xC0000022L; /* Access Denied */
2330 #else   
2331         NTStatus = 0xC000013DL; /* Remote Resources */
2332 #endif
2333     }
2334     else if (code == CM_ERROR_CLOCKSKEW) {
2335         NTStatus = 0xC0000133L; /* Time difference at DC */
2336     }
2337     else if (code == CM_ERROR_BADTID) {
2338         NTStatus = 0xC0982005L; /* SMB bad TID */
2339     }
2340     else if (code == CM_ERROR_USESTD) {
2341         NTStatus = 0xC09820FBL; /* SMB use standard */
2342     }
2343     else if (code == CM_ERROR_QUOTA) {
2344 #ifdef COMMENT
2345         NTStatus = 0xC0000044L; /* Quota exceeded */
2346 #else
2347         NTStatus = 0xC000007FL; /* Disk full */
2348 #endif
2349     }
2350     else if (code == CM_ERROR_SPACE) {
2351         NTStatus = 0xC000007FL; /* Disk full */
2352     }
2353     else if (code == CM_ERROR_ATSYS) {
2354         NTStatus = 0xC0000033L; /* Object name invalid */
2355     }
2356     else if (code == CM_ERROR_BADNTFILENAME) {
2357         NTStatus = 0xC0000033L; /* Object name invalid */
2358     }
2359     else if (code == CM_ERROR_WOULDBLOCK) {
2360         NTStatus = 0xC0000055L; /* Lock not granted */
2361     }
2362     else if (code == CM_ERROR_PARTIALWRITE) {
2363         NTStatus = 0xC000007FL; /* Disk full */
2364     }
2365     else if (code == CM_ERROR_BUFFERTOOSMALL) {
2366         NTStatus = 0xC0000023L; /* Buffer too small */
2367     }
2368     else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2369         NTStatus = 0xC0000035L; /* Object name collision */
2370     }   
2371     else if (code == CM_ERROR_BADPASSWORD) {
2372         NTStatus = 0xC000006DL; /* unknown username or bad password */
2373     }
2374     else if (code == CM_ERROR_BADLOGONTYPE) {
2375         NTStatus = 0xC000015BL; /* logon type not granted */
2376     }
2377     else if (code == CM_ERROR_GSSCONTINUE) {
2378         NTStatus = 0xC0000016L; /* more processing required */
2379     }
2380     else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2381 #ifdef COMMENT
2382         NTStatus = 0xC0000280L; /* reparse point not resolved */
2383 #else
2384         NTStatus = 0xC0000022L; /* Access Denied */
2385 #endif
2386     }
2387     else if (code == CM_ERROR_PATH_NOT_COVERED) {
2388         NTStatus = 0xC0000257L; /* Path Not Covered */
2389     } 
2390     else if (code == CM_ERROR_ALLBUSY) {
2391         NTStatus = 0xC00000BFL; /* Network Busy */
2392     } else {
2393         NTStatus = 0xC0982001L; /* SMB non-specific error */
2394     }
2395
2396     *NTStatusp = NTStatus;
2397     osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2398 }       
2399
2400 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2401                       unsigned char *classp)
2402 {
2403     unsigned char class;
2404     unsigned short error;
2405
2406     /* map CM_ERROR_* errors to SMB errors */
2407     if (code == CM_ERROR_NOSUCHCELL) {
2408         class = 1;
2409         error = 3;      /* bad path */
2410     }
2411     else if (code == CM_ERROR_NOSUCHVOLUME) {
2412         class = 1;
2413         error = 3;      /* bad path */
2414     }
2415     else if (code == CM_ERROR_TIMEDOUT) {
2416         class = 2;
2417         error = 81;     /* server is paused */
2418     }
2419     else if (code == CM_ERROR_RETRY) {
2420         class = 2;      /* shouldn't happen */
2421         error = 1;
2422     }
2423     else if (code == CM_ERROR_NOACCESS) {
2424         class = 2;
2425         error = 4;      /* bad access */
2426     }
2427     else if (code == CM_ERROR_READONLY) {
2428         class = 3;
2429         error = 19;     /* read only */
2430     }
2431     else if (code == CM_ERROR_NOSUCHFILE) {
2432         class = 1;
2433         error = 2;      /* ENOENT! */
2434     }
2435     else if (code == CM_ERROR_NOSUCHPATH) {
2436         class = 1;
2437         error = 3;      /* Bad path */
2438     }
2439     else if (code == CM_ERROR_TOOBIG) {
2440         class = 1;
2441         error = 11;     /* bad format */
2442     }
2443     else if (code == CM_ERROR_INVAL) {
2444         class = 2;      /* server non-specific error code */
2445         error = 1;
2446     }
2447     else if (code == CM_ERROR_BADFD) {
2448         class = 1;
2449         error = 6;      /* invalid file handle */
2450     }
2451     else if (code == CM_ERROR_BADFDOP) {
2452         class = 1;      /* invalid op on FD */
2453         error = 5;
2454     }
2455     else if (code == CM_ERROR_EXISTS) {
2456         class = 1;
2457         error = 80;     /* file already exists */
2458     }
2459     else if (code == CM_ERROR_NOTEMPTY) {
2460         class = 1;
2461         error = 5;      /* delete directory not empty */
2462     }
2463     else if (code == CM_ERROR_CROSSDEVLINK) {
2464         class = 1;
2465         error = 17;     /* EXDEV */
2466     }
2467     else if (code == CM_ERROR_NOTDIR) {
2468         class = 1;      /* bad path */
2469         error = 3;
2470     }
2471     else if (code == CM_ERROR_ISDIR) {
2472         class = 1;      /* access denied; DOS doesn't have a good match */
2473         error = 5;
2474     }       
2475     else if (code == CM_ERROR_BADOP) {
2476         class = 2;
2477         error = 65535;
2478     }
2479     else if (code == CM_ERROR_BADSHARENAME) {
2480         class = 2;
2481         error = 6;
2482     }
2483     else if (code == CM_ERROR_NOIPC) {
2484         class = 2;
2485         error = 4; /* bad access */
2486     }
2487     else if (code == CM_ERROR_CLOCKSKEW) {
2488         class = 1;      /* invalid function */
2489         error = 1;
2490     }
2491     else if (code == CM_ERROR_BADTID) {
2492         class = 2;
2493         error = 5;
2494     }
2495     else if (code == CM_ERROR_USESTD) {
2496         class = 2;
2497         error = 251;
2498     }
2499     else if (code == CM_ERROR_REMOTECONN) {
2500         class = 2;
2501         error = 82;
2502     }
2503     else if (code == CM_ERROR_QUOTA) {
2504         if (vcp->flags & SMB_VCFLAG_USEV3) {
2505             class = 3;
2506             error = 39; /* disk full */
2507         }
2508         else {
2509             class = 1;
2510             error = 5;  /* access denied */
2511         }
2512     }
2513     else if (code == CM_ERROR_SPACE) {
2514         if (vcp->flags & SMB_VCFLAG_USEV3) {
2515             class = 3;
2516             error = 39; /* disk full */
2517         }
2518         else {
2519             class = 1;
2520             error = 5;  /* access denied */
2521         }
2522     }
2523     else if (code == CM_ERROR_PARTIALWRITE) {
2524         class = 3;
2525         error = 39;     /* disk full */
2526     }
2527     else if (code == CM_ERROR_ATSYS) {
2528         class = 1;
2529         error = 2;      /* ENOENT */
2530     }
2531     else if (code == CM_ERROR_WOULDBLOCK) {
2532         class = 1;
2533         error = 33;     /* lock conflict */
2534     }
2535     else if (code == CM_ERROR_NOFILES) {
2536         class = 1;
2537         error = 18;     /* no files in search */
2538     }
2539     else if (code == CM_ERROR_RENAME_IDENTICAL) {
2540         class = 1;
2541         error = 183;     /* Samba uses this */
2542     }
2543     else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2544         /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2545         class = 2;
2546         error = 2; /* bad password */
2547     }
2548     else if (code == CM_ERROR_PATH_NOT_COVERED) {
2549         class = 2;
2550         error = 3;     /* bad path */
2551     }
2552     else {
2553         class = 2;
2554         error = 1;
2555     }
2556
2557     *scodep = error;
2558     *classp = class;
2559     osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2560 }       
2561
2562 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2563 {
2564     osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2565     return CM_ERROR_BADOP;
2566 }
2567
2568 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2569 {
2570     unsigned short EchoCount, i;
2571     char *data, *outdata;
2572     int dataSize;
2573
2574     EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2575
2576     for (i=1; i<=EchoCount; i++) {
2577         data = smb_GetSMBData(inp, &dataSize);
2578         smb_SetSMBParm(outp, 0, i);
2579         smb_SetSMBDataLength(outp, dataSize);
2580         outdata = smb_GetSMBData(outp, NULL);
2581         memcpy(outdata, data, dataSize);
2582         smb_SendPacket(vcp, outp);
2583     }
2584
2585     return 0;
2586 }
2587
2588 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2589 {
2590     osi_hyper_t offset;
2591     long count, minCount, finalCount;
2592     unsigned short fd;
2593     smb_fid_t *fidp;
2594     long code = 0;
2595     cm_user_t *userp = NULL;
2596     NCB *ncbp;
2597     int rc;
2598 #ifndef DJGPP
2599     char *rawBuf = NULL;
2600 #else
2601     dos_ptr rawBuf = NULL;
2602     dos_ptr dos_ncb;
2603 #endif /* DJGPP */
2604
2605     rawBuf = NULL;
2606     finalCount = 0;
2607
2608     fd = smb_GetSMBParm(inp, 0);
2609     count = smb_GetSMBParm(inp, 3);
2610     minCount = smb_GetSMBParm(inp, 4);
2611     offset.HighPart = 0;        /* too bad */
2612     offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2613
2614     osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2615              fd, offset.LowPart, count);
2616
2617     fidp = smb_FindFID(vcp, fd, 0);
2618     if (!fidp)
2619         goto send1;
2620
2621     lock_ObtainMutex(&smb_RawBufLock);
2622     if (smb_RawBufs) {
2623         /* Get a raw buf, from head of list */
2624         rawBuf = smb_RawBufs;
2625 #ifndef DJGPP
2626         smb_RawBufs = *(char **)smb_RawBufs;
2627 #else /* DJGPP */
2628         smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2629 #endif /* !DJGPP */
2630     }
2631     lock_ReleaseMutex(&smb_RawBufLock);
2632     if (!rawBuf)
2633         goto send1a;
2634
2635     if (fidp->flags & SMB_FID_IOCTL)
2636     {
2637 #ifndef DJGPP
2638         rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2639 #else
2640         rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2641 #endif
2642         if (rawBuf) {
2643             /* Give back raw buffer */
2644             lock_ObtainMutex(&smb_RawBufLock);
2645 #ifndef DJGPP
2646             *((char **) rawBuf) = smb_RawBufs;
2647 #else /* DJGPP */
2648             _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2649 #endif /* !DJGPP */
2650             
2651             smb_RawBufs = rawBuf;
2652             lock_ReleaseMutex(&smb_RawBufLock);
2653         }
2654
2655         smb_ReleaseFID(fidp);
2656         return rc;
2657     }
2658         
2659     userp = smb_GetUser(vcp, inp);
2660
2661 #ifndef DJGPP
2662     code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2663 #else /* DJGPP */
2664     /* have to give ReadData flag so it will treat buffer as DOS mem. */
2665     code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2666                         userp, &finalCount, TRUE /* rawFlag */);
2667 #endif /* !DJGPP */
2668
2669     if (code != 0)
2670         goto send;
2671
2672   send:
2673     cm_ReleaseUser(userp);
2674
2675   send1a:
2676     smb_ReleaseFID(fidp);
2677
2678   send1:
2679     ncbp = outp->ncbp;
2680 #ifdef DJGPP
2681     dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2682 #endif /* DJGPP */
2683     memset((char *)ncbp, 0, sizeof(NCB));
2684
2685     ncbp->ncb_length = (unsigned short) finalCount;
2686     ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2687     ncbp->ncb_lana_num = vcp->lana;
2688     ncbp->ncb_command = NCBSEND;
2689     ncbp->ncb_buffer = rawBuf;
2690
2691 #ifndef DJGPP
2692     code = Netbios(ncbp);
2693 #else /* DJGPP */
2694     code = Netbios(ncbp, dos_ncb);
2695 #endif /* !DJGPP */
2696     if (code != 0)
2697         osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2698
2699     if (rawBuf) {
2700         /* Give back raw buffer */
2701         lock_ObtainMutex(&smb_RawBufLock);
2702 #ifndef DJGPP
2703         *((char **) rawBuf) = smb_RawBufs;
2704 #else /* DJGPP */
2705         _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2706 #endif /* !DJGPP */
2707
2708         smb_RawBufs = rawBuf;
2709         lock_ReleaseMutex(&smb_RawBufLock);
2710     }
2711
2712     return 0;
2713 }
2714
2715 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2716 {
2717     osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
2718                          ongoingOps - 1);
2719     return 0;
2720 }
2721
2722 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2723 {
2724     osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
2725                          ongoingOps - 1);
2726     return 0;
2727 }
2728
2729 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2730 {
2731     char *namep;
2732     char *datap;
2733     int coreProtoIndex;
2734     int v3ProtoIndex;
2735     int NTProtoIndex;
2736     int protoIndex;                             /* index we're using */
2737     int namex;
2738     int dbytes;
2739     int entryLength;
2740     int tcounter;
2741     char protocol_array[10][1024];  /* protocol signature of the client */
2742     int caps;                       /* capabilities */
2743     time_t unixTime;
2744     afs_uint32 dosTime;
2745     TIME_ZONE_INFORMATION tzi;
2746
2747     osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2748                          ongoingOps - 1);
2749     if (!isGateway) {
2750         if (active_vcp) {
2751             DWORD now = GetCurrentTime();
2752             if (now - last_msg_time >= 30000
2753                  && now - last_msg_time <= 90000) {
2754                 osi_Log1(smb_logp,
2755                           "Setting dead_vcp %x", active_vcp);
2756                 if (dead_vcp) {
2757                     smb_ReleaseVC(dead_vcp);
2758                     osi_Log1(smb_logp,
2759                              "Previous dead_vcp %x", dead_vcp);
2760                 }
2761                 smb_HoldVC(active_vcp);
2762                 dead_vcp = active_vcp;
2763                 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2764             }
2765         }
2766     }
2767
2768     inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
2769
2770     namep = smb_GetSMBData(inp, &dbytes);
2771     namex = 0;
2772     tcounter = 0;
2773     coreProtoIndex = -1;                /* not found */
2774     v3ProtoIndex = -1;
2775     NTProtoIndex = -1;
2776     while(namex < dbytes) {
2777         osi_Log1(smb_logp, "Protocol %s",
2778                   osi_LogSaveString(smb_logp, namep+1));
2779         strcpy(protocol_array[tcounter], namep+1);
2780
2781         /* namep points at the first protocol, or really, a 0x02
2782          * byte preceding the null-terminated ASCII name.
2783          */
2784         if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2785             coreProtoIndex = tcounter;
2786         }       
2787         else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2788             v3ProtoIndex = tcounter;
2789         }
2790         else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
2791             NTProtoIndex = tcounter;
2792         }
2793
2794         /* compute size of protocol entry */
2795         entryLength = strlen(namep+1);
2796         entryLength += 2;       /* 0x02 bytes and null termination */
2797
2798         /* advance over this protocol entry */
2799         namex += entryLength;
2800         namep += entryLength;
2801         tcounter++;             /* which proto entry we're looking at */
2802     }
2803
2804     if (NTProtoIndex != -1) {
2805         protoIndex = NTProtoIndex;
2806         vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2807     }
2808     else if (v3ProtoIndex != -1) {
2809         protoIndex = v3ProtoIndex;
2810         vcp->flags |= SMB_VCFLAG_USEV3;
2811     }   
2812     else if (coreProtoIndex != -1) {
2813         protoIndex = coreProtoIndex;
2814         vcp->flags |= SMB_VCFLAG_USECORE;
2815     }   
2816     else protoIndex = -1;
2817
2818     if (protoIndex == -1)
2819         return CM_ERROR_INVAL;
2820     else if (NTProtoIndex != -1) {
2821         smb_SetSMBParm(outp, 0, protoIndex);
2822         if (smb_authType != SMB_AUTH_NONE) {
2823             smb_SetSMBParmByte(outp, 1,
2824                                NEGOTIATE_SECURITY_USER_LEVEL |
2825                                NEGOTIATE_SECURITY_CHALLENGE_RESPONSE);  /* user level security, challenge response */
2826         } else {
2827             smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
2828         }
2829         smb_SetSMBParm(outp, 1, smb_maxMpxRequests);    /* max multiplexed requests */
2830         smb_SetSMBParm(outp, 2, smb_maxVCPerServer);    /* max VCs per consumer/server connection */
2831         smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE);    /* xmit buffer size */
2832         smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE);    /* raw buffer size */
2833         /* The session key is not a well documented field however most clients
2834          * will echo back the session key to the server.  Currently we are using
2835          * the same value for all sessions.  We should generate a random value
2836          * and store it into the vcp 
2837          */
2838         smb_SetSMBParm(outp, 7, 1);     /* next 2: session key */
2839         smb_SetSMBParm(outp, 8, 1);
2840         /* 
2841          * Tried changing the capabilities to support for W2K - defect 117695
2842          * Maybe something else needs to be changed here?
2843          */
2844         /*
2845         if (isWindows2000) 
2846         smb_SetSMBParmLong(outp, 9, 0x43fd);
2847         else 
2848         smb_SetSMBParmLong(outp, 9, 0x251);
2849         */
2850         /* Capabilities: *
2851          * 32-bit error codes *
2852          * and NT Find *
2853          * and NT SMB's *
2854          * and raw mode 
2855          * and DFS */
2856         caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
2857 #ifdef DFS_SUPPORT
2858                NTNEGOTIATE_CAPABILITY_DFS |
2859 #endif
2860                NTNEGOTIATE_CAPABILITY_NTFIND |
2861                NTNEGOTIATE_CAPABILITY_RAWMODE |
2862                NTNEGOTIATE_CAPABILITY_NTSMB;
2863
2864         if ( smb_authType == SMB_AUTH_EXTENDED )
2865             caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
2866
2867         smb_SetSMBParmLong(outp, 9, caps);
2868         time(&unixTime);
2869         smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2870         smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
2871         smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
2872
2873         GetTimeZoneInformation(&tzi);
2874         smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias);    /* server tzone */
2875
2876         if (smb_authType == SMB_AUTH_NTLM) {
2877             smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
2878             smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
2879             /* paste in encryption key */
2880             datap = smb_GetSMBData(outp, NULL);
2881             memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
2882             /* and the faux domain name */
2883             strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
2884         } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
2885             void * secBlob;
2886             int secBlobLength;
2887
2888             smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2889
2890             smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
2891
2892             smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
2893                         
2894             datap = smb_GetSMBData(outp, NULL);
2895             memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
2896
2897             if (secBlob) {
2898                 datap += sizeof(smb_ServerGUID);
2899                 memcpy(datap, secBlob, secBlobLength);
2900                 free(secBlob);
2901             }
2902         } else {
2903             smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2904             smb_SetSMBDataLength(outp, 0);   /* Perhaps we should specify 8 bytes anyway */
2905         }
2906     }
2907     else if (v3ProtoIndex != -1) {
2908         smb_SetSMBParm(outp, 0, protoIndex);
2909
2910         /* NOTE: Extended authentication cannot be negotiated with v3
2911          * therefore we fail over to NTLM 
2912          */
2913         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2914             smb_SetSMBParm(outp, 1,
2915                            NEGOTIATE_SECURITY_USER_LEVEL |
2916                            NEGOTIATE_SECURITY_CHALLENGE_RESPONSE);      /* user level security, challenge response */
2917         } else {
2918             smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
2919         }
2920         smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
2921         smb_SetSMBParm(outp, 3, smb_maxMpxRequests);    /* max multiplexed requests */
2922         smb_SetSMBParm(outp, 4, smb_maxVCPerServer);    /* max VCs per consumer/server connection */
2923         smb_SetSMBParm(outp, 5, 0);     /* no support of block mode for read or write */
2924         smb_SetSMBParm(outp, 6, 1);     /* next 2: session key */
2925         smb_SetSMBParm(outp, 7, 1);
2926         time(&unixTime);
2927         smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2928         smb_SetSMBParm(outp, 8, LOWORD(dosTime));       /* server time */
2929         smb_SetSMBParm(outp, 9, HIWORD(dosTime));       /* server date */
2930
2931         GetTimeZoneInformation(&tzi);
2932         smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias);    /* server tzone */
2933
2934         /* NOTE: Extended authentication cannot be negotiated with v3
2935          * therefore we fail over to NTLM 
2936          */
2937         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2938             smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH);  /* encryption key length */
2939             smb_SetSMBParm(outp, 12, 0);        /* resvd */
2940             smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);   /* perhaps should specify 8 bytes anyway */
2941             datap = smb_GetSMBData(outp, NULL);
2942             /* paste in a new encryption key */
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 {
2947             smb_SetSMBParm(outp, 11, 0); /* encryption key length */
2948             smb_SetSMBParm(outp, 12, 0); /* resvd */
2949             smb_SetSMBDataLength(outp, 0);
2950         }
2951     }
2952     else if (coreProtoIndex != -1) {     /* not really supported anymore */
2953         smb_SetSMBParm(outp, 0, protoIndex);
2954         smb_SetSMBDataLength(outp, 0);
2955     }
2956     return 0;
2957 }
2958
2959 void smb_Daemon(void *parmp)
2960 {
2961     afs_uint32 count = 0;
2962
2963     while(smbShutdownFlag == 0) {
2964         count++;
2965         thrd_Sleep(10000);
2966
2967         if (smbShutdownFlag == 1)
2968             break;
2969         
2970         if ((count % 72) == 0)  {       /* every five minutes */
2971             struct tm myTime;
2972             time_t old_localZero = smb_localZero;
2973                  
2974             /* Initialize smb_localZero */
2975             myTime.tm_isdst = -1;               /* compute whether on DST or not */
2976             myTime.tm_year = 70;
2977             myTime.tm_mon = 0;
2978             myTime.tm_mday = 1;
2979             myTime.tm_hour = 0;
2980             myTime.tm_min = 0;
2981             myTime.tm_sec = 0;
2982             smb_localZero = mktime(&myTime);
2983
2984 #ifndef USE_NUMERIC_TIME_CONV
2985             smb_CalculateNowTZ();
2986 #endif /* USE_NUMERIC_TIME_CONV */
2987 #ifdef AFS_FREELANCE
2988             if ( smb_localZero != old_localZero )
2989                 cm_noteLocalMountPointChange();
2990 #endif
2991         }
2992         /* XXX GC dir search entries */
2993     }
2994 }
2995
2996 void smb_WaitingLocksDaemon()
2997 {
2998     smb_waitingLock_t *wL, *nwL;
2999     int first;
3000     smb_vc_t *vcp;
3001     smb_packet_t *inp, *outp;
3002     NCB *ncbp;
3003     long code = 0;
3004
3005     while (smbShutdownFlag == 0) {
3006         lock_ObtainWrite(&smb_globalLock);
3007         nwL = smb_allWaitingLocks;
3008         if (nwL == NULL) {
3009             osi_SleepW((long)&smb_allWaitingLocks, &smb_globalLock);
3010             thrd_Sleep(1000);
3011             continue;
3012         } else 
3013             first = 1;
3014
3015         do {
3016             if (first)
3017                 first = 0;
3018             else
3019                 lock_ObtainWrite(&smb_globalLock);
3020             wL = nwL;
3021             nwL = (smb_waitingLock_t *) osi_QNext(&wL->q);
3022             lock_ReleaseWrite(&smb_globalLock);
3023             code = cm_RetryLock((cm_file_lock_t *) wL->lockp,
3024                                  wL->vcp->flags & SMB_VCFLAG_ALREADYDEAD);
3025             if (code == CM_ERROR_WOULDBLOCK) {
3026                 /* no progress */
3027                 if (wL->timeRemaining != 0xffffffff
3028                      && (wL->timeRemaining -= 1000) < 0)
3029                     goto endWait;
3030                 continue;
3031             }
3032
3033           endWait:
3034             vcp = wL->vcp;
3035             inp = wL->inp;
3036             outp = wL->outp;
3037             ncbp = GetNCB();
3038             ncbp->ncb_length = inp->ncb_length;
3039             inp->spacep = cm_GetSpace();
3040
3041             /* Remove waitingLock from list */
3042             lock_ObtainWrite(&smb_globalLock);
3043             osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3044                          &wL->q);
3045             lock_ReleaseWrite(&smb_globalLock);
3046
3047             /* Resume packet processing */
3048             if (code == 0)
3049                 smb_SetSMBDataLength(outp, 0);
3050             outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3051             outp->resumeCode = code;
3052             outp->ncbp = ncbp;
3053             smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3054
3055             /* Clean up */
3056             cm_FreeSpace(inp->spacep);
3057             smb_FreePacket(inp);
3058             smb_FreePacket(outp);
3059             smb_ReleaseVC(vcp);
3060             FreeNCB(ncbp);
3061             free(wL);
3062         } while (nwL && smbShutdownFlag == 0);
3063         thrd_Sleep(1000);
3064     }
3065 }
3066
3067 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3068 {
3069     osi_Log0(smb_logp, "SMB receive get disk attributes");
3070
3071     smb_SetSMBParm(outp, 0, 32000);
3072     smb_SetSMBParm(outp, 1, 64);
3073     smb_SetSMBParm(outp, 2, 1024);
3074     smb_SetSMBParm(outp, 3, 30000);
3075     smb_SetSMBParm(outp, 4, 0);
3076     smb_SetSMBDataLength(outp, 0);
3077     return 0;
3078 }
3079
3080 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3081 {
3082     smb_tid_t *tidp;
3083     smb_user_t *uidp;
3084     unsigned short newTid;
3085     char shareName[256];
3086     char *sharePath;
3087     int shareFound;
3088     char *tp;
3089     char *pathp;
3090     char *passwordp;
3091     cm_user_t *userp;
3092
3093     osi_Log0(smb_logp, "SMB receive tree connect");
3094
3095     /* parse input parameters */
3096     tp = smb_GetSMBData(inp, NULL);
3097     pathp = smb_ParseASCIIBlock(tp, &tp);
3098     if (smb_StoreAnsiFilenames)
3099         OemToChar(pathp,pathp);
3100     passwordp = smb_ParseASCIIBlock(tp, &tp);
3101     tp = strrchr(pathp, '\\');
3102     if (!tp)
3103         return CM_ERROR_BADSMB;
3104     strcpy(shareName, tp+1);
3105
3106     userp = smb_GetUser(vcp, inp);
3107
3108     lock_ObtainMutex(&vcp->mx);
3109     newTid = vcp->tidCounter++;
3110     lock_ReleaseMutex(&vcp->mx);
3111
3112     tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3113     uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3114     shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3115     if (uidp)
3116         smb_ReleaseUID(uidp);
3117     if (!shareFound) {
3118         smb_ReleaseTID(tidp);
3119         return CM_ERROR_BADSHARENAME;
3120     }
3121     lock_ObtainMutex(&tidp->mx);
3122     tidp->userp = userp;
3123     tidp->pathname = sharePath;
3124     lock_ReleaseMutex(&tidp->mx);
3125     smb_ReleaseTID(tidp);
3126
3127     smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3128     smb_SetSMBParm(rsp, 1, newTid);
3129     smb_SetSMBDataLength(rsp, 0);
3130
3131     osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3132     return 0;
3133 }
3134
3135 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3136 {
3137     int tlen;
3138
3139     if (*inp++ != 0x1) return NULL;
3140     tlen = inp[0] + (inp[1]<<8);
3141     inp += 2;           /* skip length field */
3142         
3143     if (chainpp) {
3144         *chainpp = inp + tlen;
3145     }   
3146
3147     if (lengthp) *lengthp = tlen;
3148         
3149     return inp;
3150 }
3151
3152 /* set maskp to the mask part of the incoming path.
3153  * Mask is 11 bytes long (8.3 with the dot elided).
3154  * Returns true if succeeds with a valid name, otherwise it does
3155  * its best, but returns false.
3156  */
3157 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3158 {
3159     char *tp;
3160     char *up;
3161     int i;
3162     int tc;
3163     int valid8Dot3;
3164
3165     /* starts off valid */
3166     valid8Dot3 = 1;
3167
3168     /* mask starts out all blanks */
3169     memset(maskp, ' ', 11);
3170
3171     /* find last backslash, or use whole thing if there is none */
3172     tp = strrchr(pathp, '\\');
3173     if (!tp) tp = pathp;
3174     else tp++;  /* skip slash */
3175         
3176     up = maskp;
3177
3178     /* names starting with a dot are illegal */
3179     if (*tp == '.') valid8Dot3 = 0;
3180
3181     for(i=0;; i++) {
3182         tc = *tp++;
3183         if (tc == 0) return valid8Dot3;
3184         if (tc == '.' || tc == '"') break;
3185         if (i < 8) *up++ = tc;
3186         else valid8Dot3 = 0;
3187     }
3188         
3189     /* if we get here, tp point after the dot */
3190     up = maskp+8;       /* ext goes here */
3191     for(i=0;;i++) {
3192         tc = *tp++;
3193         if (tc == 0) 
3194             return valid8Dot3;
3195
3196         /* too many dots */
3197         if (tc == '.' || tc == '"') 
3198             valid8Dot3 = 0;
3199
3200         /* copy extension if not too long */
3201         if (i < 3) 
3202             *up++ = tc;
3203         else 
3204             valid8Dot3 = 0;
3205     }   
3206
3207     /* unreachable */
3208 }
3209
3210 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3211 {
3212     char umask[11];
3213     int valid;
3214     int i;
3215     char tc1;
3216     char tc2;
3217     char *tp1;
3218     char *tp2;
3219
3220     /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3221
3222     valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3223     if (!valid) 
3224         return 0;
3225  
3226     /* otherwise, we have a valid 8.3 name; see if we have a match,
3227      * treating '?' as a wildcard in maskp (but not in the file name).
3228      */
3229     tp1 = umask;        /* real name, in mask format */
3230     tp2 = maskp;        /* mask, in mask format */
3231     for(i=0; i<11; i++) {
3232         tc1 = *tp1++;   /* char from real name */
3233         tc2 = *tp2++;   /* char from mask */
3234         tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3235         tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3236         if (tc1 == tc2) 
3237             continue;
3238         if (tc2 == '?' && tc1 != ' ') 
3239             continue;
3240         if (tc2 == '>') 
3241             continue;
3242         return 0;
3243     }
3244
3245     /* we got a match */
3246     return 1;
3247 }
3248
3249 char *smb_FindMask(char *pathp)
3250 {
3251     char *tp;
3252         
3253     tp = strrchr(pathp, '\\');  /* find last slash */
3254
3255     if (tp) 
3256         return tp+1;    /* skip the slash */
3257     else 
3258         return pathp;   /* no slash, return the entire path */
3259 }       
3260
3261 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3262 {
3263     unsigned char *pathp;
3264     unsigned char *tp;
3265     unsigned char mask[11];
3266     unsigned char *statBlockp;
3267     unsigned char initStatBlock[21];
3268     int statLen;
3269         
3270     osi_Log0(smb_logp, "SMB receive search volume");
3271
3272     /* pull pathname and stat block out of request */
3273     tp = smb_GetSMBData(inp, NULL);
3274     pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3275     osi_assert(pathp != NULL);
3276     if (smb_StoreAnsiFilenames)
3277         OemToChar(pathp,pathp);
3278     statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3279     osi_assert(statBlockp != NULL);
3280     if (statLen == 0) {
3281         statBlockp = initStatBlock;
3282         statBlockp[0] = 8;
3283     }
3284         
3285     /* for returning to caller */
3286     smb_Get8Dot3MaskFromPath(mask, pathp);
3287
3288     smb_SetSMBParm(outp, 0, 1);         /* we're returning one entry */
3289     tp = smb_GetSMBData(outp, NULL);
3290     *tp++ = 5;
3291     *tp++ = 43; /* bytes in a dir entry */
3292     *tp++ = 0;  /* high byte in counter */
3293
3294     /* now marshall the dir entry, starting with the search status */
3295     *tp++ = statBlockp[0];              /* Reserved */
3296     memcpy(tp, mask, 11); tp += 11;     /* FileName */
3297
3298     /* now pass back server use info, with 1st byte non-zero */
3299     *tp++ = 1;
3300     memset(tp, 0, 4); tp += 4;  /* reserved for server use */
3301
3302     memcpy(tp, statBlockp+17, 4); tp += 4;      /* reserved for consumer */
3303
3304     *tp++ = 0x8;                /* attribute: volume */
3305
3306     /* copy out time */
3307     *tp++ = 0;
3308     *tp++ = 0;
3309
3310     /* copy out date */
3311     *tp++ = 18;
3312     *tp++ = 178;
3313
3314     /* 4 byte file size */
3315     *tp++ = 0;
3316     *tp++ = 0;
3317     *tp++ = 0;
3318     *tp++ = 0;
3319
3320     /* finally, null-terminated 8.3 pathname, which we set to AFS */
3321     memset(tp, ' ', 13);
3322     strcpy(tp, "AFS");
3323
3324     /* set the length of the data part of the packet to 43 + 3, for the dir
3325      * entry plus the 5 and the length fields.
3326      */
3327     smb_SetSMBDataLength(outp, 46);
3328     return 0;
3329 }       
3330
3331 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3332                              cm_user_t *userp, cm_req_t *reqp)
3333 {
3334     long code = 0;
3335     cm_scache_t *scp;
3336     char *dptr;
3337     afs_uint32 dosTime;
3338     u_short shortTemp;
3339     char attr;
3340     smb_dirListPatch_t *patchp;
3341     smb_dirListPatch_t *npatchp;
3342
3343     for (patchp = *dirPatchespp; patchp; patchp =
3344          (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3345
3346         dptr = patchp->dptr;
3347
3348         code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3349         if (code) {
3350             if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3351                 *dptr++ = SMB_ATTR_HIDDEN;
3352             continue;
3353         }
3354         lock_ObtainMutex(&scp->mx);
3355         code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3356                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3357         if (code) {     
3358             lock_ReleaseMutex(&scp->mx);
3359             cm_ReleaseSCache(scp);
3360             if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3361                 *dptr++ = SMB_ATTR_HIDDEN;
3362             continue;
3363         }
3364
3365         attr = smb_Attributes(scp);
3366         /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3367         if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3368             attr |= SMB_ATTR_HIDDEN;
3369         *dptr++ = attr;
3370
3371         /* get dos time */
3372         smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3373                 
3374         /* copy out time */
3375         shortTemp = (unsigned short) (dosTime & 0xffff);
3376         *((u_short *)dptr) = shortTemp;
3377         dptr += 2;
3378
3379         /* and copy out date */
3380         shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3381         *((u_short *)dptr) = shortTemp;
3382         dptr += 2;
3383                 
3384         /* copy out file length */
3385         *((u_long *)dptr) = scp->length.LowPart;
3386         dptr += 4;
3387         lock_ReleaseMutex(&scp->mx);
3388         cm_ReleaseSCache(scp);
3389     }
3390         
3391     /* now free the patches */
3392     for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3393         npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3394         free(patchp);
3395     }   
3396         
3397     /* and mark the list as empty */
3398     *dirPatchespp = NULL;
3399
3400     return code;
3401 }
3402
3403 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3404 {
3405     int attribute;
3406     long nextCookie;
3407     char *tp;
3408     long code = 0;
3409     char *pathp;
3410     cm_dirEntry_t *dep;
3411     int maxCount;
3412     smb_dirListPatch_t *dirListPatchesp;
3413     smb_dirListPatch_t *curPatchp;
3414     int dataLength;
3415     cm_buf_t *bufferp;
3416     long temp;
3417     osi_hyper_t dirLength;
3418     osi_hyper_t bufferOffset;
3419     osi_hyper_t curOffset;
3420     osi_hyper_t thyper;
3421     unsigned char *inCookiep;
3422     smb_dirSearch_t *dsp;
3423     cm_scache_t *scp;
3424     long entryInDir;
3425     long entryInBuffer;
3426     unsigned long clientCookie;
3427     cm_pageHeader_t *pageHeaderp;
3428     cm_user_t *userp = NULL;
3429     int slotInPage;
3430     char shortName[13];
3431     char *actualName;
3432     char *shortNameEnd;
3433     char mask[11];
3434     int returnedNames;
3435     long nextEntryCookie;
3436     int numDirChunks;           /* # of 32 byte dir chunks in this entry */
3437     char resByte;               /* reserved byte from the cookie */
3438     char *op;                   /* output data ptr */
3439     char *origOp;               /* original value of op */
3440     cm_space_t *spacep;         /* for pathname buffer */
3441     int starPattern;
3442     int rootPath = 0;
3443     int caseFold;
3444     char *tidPathp;
3445     cm_req_t req;
3446     cm_fid_t fid;
3447     int fileType;
3448
3449     cm_InitReq(&req);
3450
3451     maxCount = smb_GetSMBParm(inp, 0);
3452
3453     dirListPatchesp = NULL;
3454         
3455     caseFold = CM_FLAG_CASEFOLD;
3456
3457     tp = smb_GetSMBData(inp, NULL);
3458     pathp = smb_ParseASCIIBlock(tp, &tp);
3459     if (smb_StoreAnsiFilenames)
3460         OemToChar(pathp,pathp);
3461     inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3462
3463     /* bail out if request looks bad */
3464     if (!tp || !pathp) {
3465         return CM_ERROR_BADSMB;
3466     }
3467
3468     /* We can handle long names */
3469     if (vcp->flags & SMB_VCFLAG_USENT)
3470         ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
3471
3472     /* make sure we got a whole search status */
3473     if (dataLength < 21) {
3474         nextCookie = 0;         /* start at the beginning of the dir */
3475         resByte = 0;
3476         clientCookie = 0;
3477         attribute = smb_GetSMBParm(inp, 1);
3478
3479         /* handle volume info in another function */
3480         if (attribute & 0x8)
3481             return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3482
3483         osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3484                   maxCount, osi_LogSaveString(smb_logp, pathp));
3485
3486         if (*pathp == 0) {      /* null pathp, treat as root dir */
3487             if (!(attribute & SMB_ATTR_DIRECTORY))      /* exclude dirs */
3488                 return CM_ERROR_NOFILES;
3489             rootPath = 1;
3490         }
3491
3492         dsp = smb_NewDirSearch(0);
3493         dsp->attribute = attribute;
3494         smb_Get8Dot3MaskFromPath(mask, pathp);
3495         memcpy(dsp->mask, mask, 11);
3496
3497         /* track if this is likely to match a lot of entries */
3498         if (smb_IsStarMask(mask)) 
3499             starPattern = 1;
3500         else 
3501             starPattern = 0;
3502     } else {
3503         /* pull the next cookie value out of the search status block */
3504         nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3505             + (inCookiep[16]<<24);
3506         dsp = smb_FindDirSearch(inCookiep[12]);
3507         if (!dsp) {
3508             /* can't find dir search status; fatal error */
3509             osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%s]",
3510                      inCookiep[12], nextCookie, osi_LogSaveString(smb_logp, pathp));
3511             return CM_ERROR_BADFD;
3512         }
3513         attribute = dsp->attribute;
3514         resByte = inCookiep[0];
3515
3516         /* copy out client cookie, in host byte order.  Don't bother
3517          * interpreting it, since we're just passing it through, anyway.
3518          */
3519         memcpy(&clientCookie, &inCookiep[17], 4);
3520
3521         memcpy(mask, dsp->mask, 11);
3522
3523         /* assume we're doing a star match if it has continued for more
3524          * than one call.
3525          */
3526         starPattern = 1;
3527     }
3528
3529     osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
3530              nextCookie, dsp->cookie, attribute);
3531
3532     userp = smb_GetUser(vcp, inp);
3533
3534     /* try to get the vnode for the path name next */
3535     lock_ObtainMutex(&dsp->mx);
3536     if (dsp->scp) {
3537         scp = dsp->scp;
3538         cm_HoldSCache(scp);
3539         code = 0;
3540     } else {
3541         spacep = inp->spacep;
3542         smb_StripLastComponent(spacep->data, NULL, pathp);
3543         code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3544         if (code) {
3545             lock_ReleaseMutex(&dsp->mx);
3546             cm_ReleaseUser(userp);
3547             smb_DeleteDirSearch(dsp);
3548             smb_ReleaseDirSearch(dsp);
3549             return CM_ERROR_NOFILES;
3550         }
3551         code = cm_NameI(cm_data.rootSCachep, spacep->data,
3552                         caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3553         if (code == 0) {
3554 #ifdef DFS_SUPPORT
3555             if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3556                 cm_ReleaseSCache(scp);
3557                 lock_ReleaseMutex(&dsp->mx);
3558                 cm_ReleaseUser(userp);
3559                 smb_DeleteDirSearch(dsp);
3560                 smb_ReleaseDirSearch(dsp);
3561                 if ( WANTS_DFS_PATHNAMES(inp) )
3562                     return CM_ERROR_PATH_NOT_COVERED;
3563                 else
3564                     return CM_ERROR_BADSHARENAME;
3565             }
3566 #endif /* DFS_SUPPORT */
3567
3568             dsp->scp = scp;
3569             /* we need one hold for the entry we just stored into,
3570              * and one for our own processing.  When we're done with this
3571              * function, we'll drop the one for our own processing.
3572              * We held it once from the namei call, and so we do another hold
3573              * now.
3574              */
3575             cm_HoldSCache(scp);
3576             lock_ObtainMutex(&scp->mx);
3577             if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3578                  && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3579                 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3580                 dsp->flags |= SMB_DIRSEARCH_BULKST;
3581             }
3582             lock_ReleaseMutex(&scp->mx);
3583         }
3584     }
3585     lock_ReleaseMutex(&dsp->mx);
3586     if (code) {
3587         cm_ReleaseUser(userp);
3588         smb_DeleteDirSearch(dsp);
3589         smb_ReleaseDirSearch(dsp);
3590         return code;
3591     }
3592
3593     /* reserves space for parameter; we'll adjust it again later to the
3594      * real count of the # of entries we returned once we've actually
3595      * assembled the directory listing.
3596      */
3597     smb_SetSMBParm(outp, 0, 0);
3598
3599     /* get the directory size */
3600     lock_ObtainMutex(&scp->mx);
3601     code = cm_SyncOp(scp, NULL, userp, &req, 0,
3602                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3603     if (code) {
3604         lock_ReleaseMutex(&scp->mx);
3605         cm_ReleaseSCache(scp);
3606         cm_ReleaseUser(userp);
3607         smb_DeleteDirSearch(dsp);
3608         smb_ReleaseDirSearch(dsp);
3609         return code;
3610     }
3611         
3612     dirLength = scp->length;
3613     bufferp = NULL;
3614     bufferOffset.LowPart = bufferOffset.HighPart = 0;
3615     curOffset.HighPart = 0;
3616     curOffset.LowPart = nextCookie;
3617     origOp = op = smb_GetSMBData(outp, NULL);
3618     /* and write out the basic header */
3619     *op++ = 5;          /* variable block */
3620     op += 2;            /* skip vbl block length; we'll fill it in later */
3621     code = 0;
3622     returnedNames = 0;
3623     while (1) {
3624         /* make sure that curOffset.LowPart doesn't point to the first
3625          * 32 bytes in the 2nd through last dir page, and that it doesn't
3626          * point at the first 13 32-byte chunks in the first dir page,
3627          * since those are dir and page headers, and don't contain useful
3628          * information.
3629          */
3630         temp = curOffset.LowPart & (2048-1);
3631         if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3632             /* we're in the first page */
3633             if (temp < 13*32) temp = 13*32;
3634         }
3635         else {
3636             /* we're in a later dir page */
3637             if (temp < 32) temp = 32;
3638         }
3639
3640         /* make sure the low order 5 bits are zero */
3641         temp &= ~(32-1);
3642
3643         /* now put temp bits back ito curOffset.LowPart */
3644         curOffset.LowPart &= ~(2048-1);
3645         curOffset.LowPart |= temp;
3646
3647         /* check if we've returned all the names that will fit in the
3648          * response packet.
3649          */
3650         if (returnedNames >= maxCount) {
3651             osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
3652                       returnedNames, maxCount);
3653             break;
3654         }
3655                 
3656         /* check if we've passed the dir's EOF */
3657         if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
3658
3659         /* see if we can use the bufferp we have now; compute in which page
3660          * the current offset would be, and check whether that's the offset
3661          * of the buffer we have.  If not, get the buffer.
3662          */
3663         thyper.HighPart = curOffset.HighPart;
3664         thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
3665         if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3666             /* wrong buffer */
3667             if (bufferp) {
3668                 buf_Release(bufferp);
3669                 bufferp = NULL;
3670             }   
3671             lock_ReleaseMutex(&scp->mx);
3672             lock_ObtainRead(&scp->bufCreateLock);
3673             code = buf_Get(scp, &thyper, &bufferp);
3674             lock_ReleaseRead(&scp->bufCreateLock);
3675             lock_ObtainMutex(&dsp->mx);
3676
3677             /* now, if we're doing a star match, do bulk fetching of all of 
3678              * the status info for files in the dir.
3679              */
3680             if (starPattern) {
3681                 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3682                 lock_ObtainMutex(&scp->mx);
3683                 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
3684                      LargeIntegerGreaterThanOrEqualTo(thyper, 
3685                                                       scp->bulkStatProgress)) {
3686                     /* Don't bulk stat if risking timeout */
3687                     int now = GetCurrentTime();
3688                     if (now - req.startTime > 5000) {
3689                         scp->bulkStatProgress = thyper;
3690                         scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3691                         dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3692                     } else
3693                         cm_TryBulkStat(scp, &thyper, userp, &req);
3694                 }
3695             } else {
3696                 lock_ObtainMutex(&scp->mx);
3697             }
3698             lock_ReleaseMutex(&dsp->mx);
3699             if (code) {
3700                 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
3701                 break;
3702             }
3703
3704             bufferOffset = thyper;
3705
3706             /* now get the data in the cache */
3707             while (1) {
3708                 code = cm_SyncOp(scp, bufferp, userp, &req,
3709                                  PRSFS_LOOKUP,
3710                                  CM_SCACHESYNC_NEEDCALLBACK |
3711                                  CM_SCACHESYNC_READ);
3712                 if (code) {
3713                     osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
3714                     break;
3715                 }
3716                                 
3717                 if (cm_HaveBuffer(scp, bufferp, 0)) {
3718                     osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
3719                     break;
3720                 }
3721
3722                 /* otherwise, load the buffer and try again */
3723                 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
3724                 if (code) {
3725                     osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d", 
3726                               scp, bufferp, code);
3727                     break;
3728                 }
3729             }
3730             if (code) {
3731                 buf_Release(bufferp);
3732                 bufferp = NULL;
3733                 break;
3734             }
3735         }       /* if (wrong buffer) ... */
3736
3737         /* now we have the buffer containing the entry we're interested in; copy