windows-byte-range-locking-20060108
[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_waitingLockRequest_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     time_t diff_t = unixTime - smb_localZero;
797 #if defined(DEBUG) && !defined(_USE_32BIT_TIME_T)
798     osi_assert(diff_t < _UI32_MAX);
799 #endif
800     *dosUTimep = (afs_uint32)diff_t;
801 }
802
803 void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
804 {
805 #ifndef DJGPP
806     *unixTimep = dosTime + smb_localZero;
807 #else /* DJGPP */
808     /* dosTime seems to be already adjusted for GMT */
809     *unixTimep = dosTime;
810 #endif /* !DJGPP */
811 }
812
813 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
814 {
815     smb_vc_t *vcp;
816
817     lock_ObtainWrite(&smb_rctLock);
818     for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
819         if (lsn == vcp->lsn && lana == vcp->lana) {
820             smb_HoldVCNoLock(vcp);
821             break;
822         }
823     }
824     if (!vcp && (flags & SMB_FLAG_CREATE)) {
825         vcp = malloc(sizeof(*vcp));
826         memset(vcp, 0, sizeof(*vcp));
827         vcp->vcID = numVCs++;
828         vcp->refCount = 1;
829         vcp->tidCounter = 1;
830         vcp->fidCounter = 1;
831         vcp->uidCounter = 1;  /* UID 0 is reserved for blank user */
832         vcp->nextp = smb_allVCsp;
833         smb_allVCsp = vcp;
834         lock_InitializeMutex(&vcp->mx, "vc_t mutex");
835         vcp->lsn = lsn;
836         vcp->lana = lana;
837         vcp->secCtx = NULL;
838
839         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
840             /* We must obtain a challenge for extended auth 
841              * in case the client negotiates smb v3 
842              */
843             NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
844             MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
845             PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp;
846             ULONG lsaRespSize = 0;
847
848             lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
849
850             nts = LsaCallAuthenticationPackage( smb_lsaHandle,
851                                                 smb_lsaSecPackage,
852                                                 &lsaReq,
853                                                 sizeof(lsaReq),
854                                                 &lsaResp,
855                                                 &lsaRespSize,
856                                                 &ntsEx);
857             if (nts != STATUS_SUCCESS)
858                 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
859                          nts, ntsEx, sizeof(lsaReq), lsaRespSize);
860             osi_assert(nts == STATUS_SUCCESS); /* this had better work! */
861
862             memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
863             LsaFreeReturnBuffer(lsaResp);
864         }
865         else
866             memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
867
868         if (numVCs >= CM_SESSION_RESERVED) {
869             numVCs = 0;
870             osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
871         }
872     }
873     lock_ReleaseWrite(&smb_rctLock);
874     return vcp;
875 }
876
877 int smb_IsStarMask(char *maskp)
878 {
879     int i;
880     char tc;
881         
882     for(i=0; i<11; i++) {
883         tc = *maskp++;
884         if (tc == '?' || tc == '*' || tc == '>') return 1;        
885     }   
886     return 0;
887 }
888
889 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
890 {
891     osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
892 #ifdef DEBUG
893     osi_assert(vcp->refCount-- != 0);
894 #else
895     vcp->refCount--;
896 #endif
897 }       
898
899 void smb_ReleaseVC(smb_vc_t *vcp)
900 {
901     lock_ObtainWrite(&smb_rctLock);
902     osi_Log2(smb_logp,"smb_ReleaseVC       vcp %x ref %d",vcp, vcp->refCount);
903 #ifdef DEBUG
904     osi_assert(vcp->refCount-- != 0);
905 #else
906     vcp->refCount--;
907 #endif
908     lock_ReleaseWrite(&smb_rctLock);
909 }       
910
911 void smb_HoldVCNoLock(smb_vc_t *vcp)
912 {
913     vcp->refCount++;
914     osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
915 }       
916
917 void smb_HoldVC(smb_vc_t *vcp)
918 {
919     lock_ObtainWrite(&smb_rctLock);
920     vcp->refCount++;
921     osi_Log2(smb_logp,"smb_HoldVC       vcp %x ref %d",vcp, vcp->refCount);
922     lock_ReleaseWrite(&smb_rctLock);
923 }       
924
925 void smb_CleanupDeadVC(smb_vc_t *vcp)
926 {
927     smb_fid_t *fidpIter;
928     smb_fid_t *fidpNext;
929     smb_fid_t *fidp;
930     unsigned short fid;
931     smb_tid_t *tidpIter;
932     smb_tid_t *tidpNext;
933     smb_tid_t *tidp;
934     unsigned short tid;
935     smb_user_t *userpIter;
936     smb_user_t *userpNext;
937     smb_user_t *userp;
938     unsigned short uid;
939
940     osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
941
942     lock_ObtainRead(&smb_rctLock);
943     for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
944         fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
945
946         if (fidpIter->flags & SMB_FID_DELETE)
947             continue;
948
949         fid = fidpIter->fid;
950         osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
951         lock_ReleaseRead(&smb_rctLock);
952
953         fidp = smb_FindFID(vcp, fid, 0);
954         osi_assert(fidp);
955         smb_CloseFID(vcp, fidp, NULL, 0);
956         smb_ReleaseFID(fidp);
957
958         lock_ObtainRead(&smb_rctLock);
959     }
960
961     for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
962         tidpNext = tidpIter->nextp;
963         if (tidpIter->flags & SMB_TIDFLAG_DELETE)
964             continue;
965
966         tid = tidpIter->tid;
967         osi_Log2(smb_logp, "  Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
968         lock_ReleaseRead(&smb_rctLock);
969
970         tidp = smb_FindTID(vcp, tid, 0);
971         osi_assert(tidp);
972
973         lock_ObtainMutex(&tidp->mx);
974         tidp->flags |= SMB_TIDFLAG_DELETE;
975         lock_ReleaseMutex(&tidp->mx);
976
977         smb_ReleaseTID(tidp);
978
979         lock_ObtainRead(&smb_rctLock);
980     }
981
982     for (userpIter = vcp->usersp; userpIter; userpIter = userpNext) {
983         userpNext = userpIter->nextp;
984
985         if (userpIter->flags & SMB_USERFLAG_DELETE)
986             continue;
987
988         uid = userpIter->userID;
989         osi_Log2(smb_logp, "  Cleanup UID %d (userp=0x%x)", uid, userpIter);
990         lock_ReleaseRead(&smb_rctLock);
991
992         userp = smb_FindUID(vcp, uid, 0);
993         osi_assert(userp);
994
995         lock_ObtainMutex(&userp->mx);
996         userp->flags |= SMB_USERFLAG_DELETE;
997         lock_ReleaseMutex(&userp->mx);
998
999         smb_ReleaseUID(userp);
1000
1001         lock_ObtainRead(&smb_rctLock);
1002     }
1003
1004     lock_ReleaseRead(&smb_rctLock);
1005
1006     osi_Log0(smb_logp, "Done cleaning up dead vcp");
1007 }
1008
1009 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1010 {
1011     smb_tid_t *tidp;
1012
1013     lock_ObtainWrite(&smb_rctLock);
1014     for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1015         if (tid == tidp->tid) {
1016             tidp->refCount++;
1017             break;
1018         }       
1019     }
1020     if (!tidp && (flags & SMB_FLAG_CREATE)) {
1021         tidp = malloc(sizeof(*tidp));
1022         memset(tidp, 0, sizeof(*tidp));
1023         tidp->nextp = vcp->tidsp;
1024         tidp->refCount = 1;
1025         tidp->vcp = vcp;
1026         smb_HoldVCNoLock(vcp);
1027         vcp->tidsp = tidp;
1028         lock_InitializeMutex(&tidp->mx, "tid_t mutex");
1029         tidp->tid = tid;
1030     }
1031     lock_ReleaseWrite(&smb_rctLock);
1032     return tidp;
1033 }               
1034
1035 void smb_ReleaseTID(smb_tid_t *tidp)
1036 {
1037     smb_tid_t *tp;
1038     smb_tid_t **ltpp;
1039     cm_user_t *userp;
1040
1041     userp = NULL;
1042     lock_ObtainWrite(&smb_rctLock);
1043     osi_assert(tidp->refCount-- > 0);
1044     if (tidp->refCount == 0 && (tidp->flags & SMB_TIDFLAG_DELETE)) {
1045         ltpp = &tidp->vcp->tidsp;
1046         for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1047             if (tp == tidp) 
1048                 break;
1049         }
1050         osi_assert(tp != NULL);
1051         *ltpp = tp->nextp;
1052         lock_FinalizeMutex(&tidp->mx);
1053         userp = tidp->userp;    /* remember to drop ref later */
1054         tidp->userp = NULL;
1055         smb_ReleaseVCNoLock(tidp->vcp);
1056         tidp->vcp = 0;
1057     }
1058     lock_ReleaseWrite(&smb_rctLock);
1059     if (userp)
1060         cm_ReleaseUser(userp);
1061 }               
1062
1063 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1064 {
1065     smb_user_t *uidp = NULL;
1066
1067     lock_ObtainWrite(&smb_rctLock);
1068     for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1069         if (uid == uidp->userID) {
1070             uidp->refCount++;
1071             osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%s]",
1072                      vcp, uidp->userID, 
1073                      osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
1074             break;
1075         }
1076     }
1077     if (!uidp && (flags & SMB_FLAG_CREATE)) {
1078         uidp = malloc(sizeof(*uidp));
1079         memset(uidp, 0, sizeof(*uidp));
1080         uidp->nextp = vcp->usersp;
1081         uidp->refCount = 1;
1082         uidp->vcp = vcp;
1083         smb_HoldVCNoLock(vcp);
1084         vcp->usersp = uidp;
1085         lock_InitializeMutex(&uidp->mx, "user_t mutex");
1086         uidp->userID = uid;
1087         osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%s]",
1088                  vcp, uidp->userID, 
1089                  osi_LogSaveString(smb_logp,uidp->unp ? uidp->unp->name : ""));
1090     }
1091     lock_ReleaseWrite(&smb_rctLock);
1092     return uidp;
1093 }               
1094
1095 smb_username_t *smb_FindUserByName(char *usern, char *machine, int flags)
1096 {
1097     smb_username_t *unp= NULL;
1098
1099     lock_ObtainWrite(&smb_rctLock);
1100     for(unp = usernamesp; unp; unp = unp->nextp) {
1101         if (stricmp(unp->name, usern) == 0 &&
1102              stricmp(unp->machine, machine) == 0) {
1103             unp->refCount++;
1104             break;
1105         }
1106     }
1107     if (!unp && (flags & SMB_FLAG_CREATE)) {
1108         unp = malloc(sizeof(*unp));
1109         memset(unp, 0, sizeof(*unp));
1110         unp->refCount = 1;
1111         unp->nextp = usernamesp;
1112         unp->name = strdup(usern);
1113         unp->machine = strdup(machine);
1114         usernamesp = unp;
1115         lock_InitializeMutex(&unp->mx, "username_t mutex");
1116     }
1117     lock_ReleaseWrite(&smb_rctLock);
1118     return unp;
1119 }       
1120
1121 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
1122 {
1123     smb_user_t *uidp= NULL;
1124
1125     lock_ObtainWrite(&smb_rctLock);
1126     for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1127         if (!uidp->unp) 
1128             continue;
1129         if (stricmp(uidp->unp->name, usern) == 0) {
1130             uidp->refCount++;
1131             osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%s]",
1132                      vcp,uidp->userID,osi_LogSaveString(smb_logp,usern));
1133             break;
1134         } else
1135             continue;
1136     }           
1137     lock_ReleaseWrite(&smb_rctLock);
1138     return uidp;
1139 }       
1140 void smb_ReleaseUID(smb_user_t *uidp)
1141 {
1142     smb_user_t *up;
1143     smb_user_t **lupp;
1144     cm_user_t *userp;
1145
1146     userp = NULL;
1147     lock_ObtainWrite(&smb_rctLock);
1148     osi_assert(uidp->refCount-- > 0);
1149     if (uidp->refCount == 0 && (uidp->flags & SMB_USERFLAG_DELETE)) {
1150         lupp = &uidp->vcp->usersp;
1151         for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1152             if (up == uidp) 
1153                 break;
1154         }
1155         osi_assert(up != NULL);
1156         *lupp = up->nextp;
1157         lock_FinalizeMutex(&uidp->mx);
1158         if (uidp->unp) {
1159             userp = uidp->unp->userp;   /* avoid deadlock by releasing */
1160             uidp->unp->userp = NULL;    /* after releasing the lock */
1161         }       
1162         smb_ReleaseVCNoLock(uidp->vcp);
1163         uidp->vcp = NULL;
1164     }           
1165     lock_ReleaseWrite(&smb_rctLock);
1166     if (userp) {
1167         cm_ReleaseUserVCRef(userp);
1168         cm_ReleaseUser(userp);
1169     }   
1170 }       
1171
1172
1173 /* retrieve a held reference to a user structure corresponding to an incoming
1174  * request.
1175  * corresponding release function is cm_ReleaseUser.
1176  */
1177 cm_user_t *smb_GetUser(smb_vc_t *vcp, smb_packet_t *inp)
1178 {
1179     smb_user_t *uidp;
1180     cm_user_t *up;
1181     smb_t *smbp;
1182
1183     smbp = (smb_t *) inp;
1184     uidp = smb_FindUID(vcp, smbp->uid, 0);
1185     if ((!uidp) ||  (!uidp->unp))
1186         return NULL;
1187
1188     lock_ObtainMutex(&uidp->mx);
1189     up = uidp->unp->userp;
1190     cm_HoldUser(up);
1191     lock_ReleaseMutex(&uidp->mx);
1192
1193     smb_ReleaseUID(uidp);
1194
1195     return up;
1196 }
1197
1198 /*
1199  * Return a pointer to a pathname extracted from a TID structure.  The
1200  * TID structure is not held; assume it won't go away.
1201  */
1202 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1203 {
1204     smb_tid_t *tidp;
1205     long code = 0;
1206
1207     tidp = smb_FindTID(vcp, tid, 0);
1208     if (!tidp) {
1209         *treepath = NULL;
1210     } else {
1211         if (tidp->flags & SMB_TIDFLAG_IPC) {
1212             code = CM_ERROR_TIDIPC;
1213             /* tidp->pathname would be NULL, but that's fine */
1214         }
1215         *treepath = tidp->pathname;
1216         smb_ReleaseTID(tidp);
1217     }
1218     return code;
1219 }
1220
1221 /* check to see if we have a chained fid, that is, a fid that comes from an
1222  * OpenAndX message that ran earlier in this packet.  In this case, the fid
1223  * field in a read, for example, request, isn't set, since the value is
1224  * supposed to be inherited from the openAndX call.
1225  */
1226 int smb_ChainFID(int fid, smb_packet_t *inp)
1227 {
1228     if (inp->fid == 0 || inp->inCount == 0) 
1229         return fid;
1230     else 
1231         return inp->fid;
1232 }
1233
1234 /* are we a priv'd user?  What does this mean on NT? */
1235 int smb_SUser(cm_user_t *userp)
1236 {
1237     return 1;
1238 }
1239
1240 /* find a file ID.  If we pass in 0 we select an unused File ID.
1241  * If the SMB_FLAG_CREATE flag is set, we allocate a new  
1242  * smb_fid_t data structure if desired File ID cannot be found.
1243  */
1244 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1245 {
1246     smb_fid_t *fidp;
1247     int newFid = 0;
1248         
1249     if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1250         return NULL;
1251
1252     lock_ObtainWrite(&smb_rctLock);
1253     /* figure out if we need to allocate a new file ID */
1254     if (fid == 0) {
1255         newFid = 1;
1256         fid = vcp->fidCounter;
1257     }
1258
1259   retry:
1260     for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1261         if (fid == fidp->fid) {
1262             if (newFid) {
1263                 fid++;
1264                 if (fid == 0) {
1265                     osi_Log1(smb_logp,
1266                              "New FID number wraps on vcp 0x%x", vcp);
1267                     fid = 1;
1268                 }
1269                 goto retry;
1270             }
1271             fidp->refCount++;
1272             break;
1273         }
1274     }
1275
1276     if (!fidp && (flags & SMB_FLAG_CREATE)) {
1277         char eventName[MAX_PATH];
1278         EVENT_HANDLE event;
1279         sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1280         event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1281         if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1282             osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1283             thrd_CloseHandle(event);
1284             fid++;
1285             if (fid == 0) {
1286                 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1287                 fid = 1;
1288             }
1289             goto retry;
1290         }
1291
1292         fidp = malloc(sizeof(*fidp));
1293         memset(fidp, 0, sizeof(*fidp));
1294         osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1295         fidp->refCount = 1;
1296         fidp->vcp = vcp;
1297         smb_HoldVCNoLock(vcp);
1298         lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1299         fidp->fid = fid;
1300         fidp->curr_chunk = fidp->prev_chunk = -2;
1301         fidp->raw_write_event = event;
1302         if (newFid) {
1303             vcp->fidCounter = fid+1;
1304             if (vcp->fidCounter == 0) {
1305                 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1306                          vcp);
1307                 vcp->fidCounter = 1;
1308         }
1309     }
1310     }
1311
1312     lock_ReleaseWrite(&smb_rctLock);
1313     return fidp;
1314 }
1315
1316 void smb_ReleaseFID(smb_fid_t *fidp)
1317 {
1318     cm_scache_t *scp;
1319     cm_user_t *userp;
1320     smb_vc_t *vcp = NULL;
1321     smb_ioctl_t *ioctlp;
1322
1323     if (!fidp)
1324         return;
1325
1326     scp = NULL;
1327     userp = NULL;
1328     lock_ObtainWrite(&smb_rctLock);
1329     osi_assert(fidp->refCount-- > 0);
1330     if (fidp->refCount == 0 && (fidp->flags & SMB_FID_DELETE)) {
1331         vcp = fidp->vcp;
1332         fidp->vcp = NULL;
1333         scp = fidp->scp;    /* release after lock is released */
1334         fidp->scp = NULL;
1335         userp = fidp->userp;
1336         fidp->userp = NULL;
1337
1338         osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1339         thrd_CloseHandle(fidp->raw_write_event);
1340
1341         /* and see if there is ioctl stuff to free */
1342         ioctlp = fidp->ioctlp;
1343         if (ioctlp) {
1344             if (ioctlp->prefix)
1345                 cm_FreeSpace(ioctlp->prefix);
1346             if (ioctlp->inAllocp)
1347                 free(ioctlp->inAllocp);
1348             if (ioctlp->outAllocp)
1349                 free(ioctlp->outAllocp);
1350             free(ioctlp);
1351         }       
1352
1353         free(fidp);
1354
1355         smb_ReleaseVCNoLock(vcp);
1356     }
1357     lock_ReleaseWrite(&smb_rctLock);
1358
1359     /* now release the scache structure */
1360     if (scp) 
1361         cm_ReleaseSCache(scp);
1362
1363     if (userp)
1364         cm_ReleaseUser(userp);
1365 }       
1366
1367 /*
1368  * Case-insensitive search for one string in another;
1369  * used to find variable names in submount pathnames.
1370  */
1371 static char *smb_stristr(char *str1, char *str2)
1372 {
1373     char *cursor;
1374
1375     for (cursor = str1; *cursor; cursor++)
1376         if (stricmp(cursor, str2) == 0)
1377             return cursor;
1378
1379     return NULL;
1380 }
1381
1382 /*
1383  * Substitute a variable value for its name in a submount pathname.  Variable
1384  * name has been identified by smb_stristr() and is in substr.  Variable name
1385  * length (plus one) is in substr_size.  Variable value is in newstr.
1386  */
1387 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1388                       char *newstr)
1389 {
1390     char temp[1024];
1391
1392     strcpy(temp, substr + substr_size - 1);
1393     strcpy(substr, newstr);
1394     strcat(str1, temp);
1395 }       
1396
1397 char VNUserName[] = "%USERNAME%";
1398 char VNLCUserName[] = "%LCUSERNAME%";
1399 char VNComputerName[] = "%COMPUTERNAME%";
1400 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1401
1402 #ifdef DJGPP
1403 /* List available shares */
1404 int smb_ListShares()
1405 {
1406     char sbmtpath[256];
1407     char pathName[256];
1408     char shareBuf[4096];
1409     int num_shares=0;
1410     char *this_share;
1411     int len;
1412     char *p;
1413     int print_afs = 0;
1414     int code;
1415
1416     /*strcpy(shareNameList[num_shares], "all");
1417       strcpy(pathNameList[num_shares++], "/afs");*/
1418     fprintf(stderr, "The following shares are available:\n");
1419     fprintf(stderr, "Share Name (AFS Path)\n");
1420     fprintf(stderr, "---------------------\n");
1421     fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
1422
1423 #ifndef DJGPP
1424     code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1425     if (code == 0 || code > sizeof(sbmtpath)) return -1;
1426 #else
1427     strcpy(sbmtpath, cm_confDir);
1428 #endif /* !DJGPP */
1429     strcat(sbmtpath, "/afsdsbmt.ini");
1430     len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1431                                    shareBuf, sizeof(shareBuf),
1432                                    sbmtpath);
1433     if (len == 0) {
1434         return num_shares;
1435     }
1436
1437     this_share = shareBuf;
1438     do
1439     {
1440         print_afs = 0;
1441         /*strcpy(shareNameList[num_shares], this_share);*/
1442         len = GetPrivateProfileString("AFS Submounts", this_share,
1443                                        NULL,
1444                                        pathName, 256,
1445                                        sbmtpath);
1446         if (!len) 
1447             return num_shares;
1448         p = pathName;
1449         if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) != 0)
1450             print_afs = 1;
1451         while (*p) {
1452             if (*p == '\\') *p = '/';    /* change to / */
1453             p++;
1454         }
1455
1456         fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1457                  smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
1458                  pathName);
1459         num_shares++;
1460         while (*this_share != 0) this_share++;  /* find next NUL */
1461         this_share++;   /* skip past the NUL */
1462     } while (*this_share != 0);  /* stop at final NUL */
1463
1464     return num_shares;
1465 }
1466 #endif /* DJGPP */
1467
1468 typedef struct smb_findShare_rock {
1469     char * shareName;
1470     char * match;
1471     int matchType;
1472 } smb_findShare_rock_t;
1473
1474 #define SMB_FINDSHARE_EXACT_MATCH 1
1475 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1476
1477 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1478                        osi_hyper_t *offp)
1479 {
1480     int matchType = 0;
1481     smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1482     if (!strnicmp(dep->name, vrock->shareName, 12)) {
1483         if(!stricmp(dep->name, vrock->shareName))
1484             matchType = SMB_FINDSHARE_EXACT_MATCH;
1485         else
1486             matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1487         if(vrock->match) free(vrock->match);
1488         vrock->match = strdup(dep->name);
1489         vrock->matchType = matchType;
1490
1491         if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1492             return CM_ERROR_STOPNOW;
1493     }
1494     return 0;
1495 }
1496
1497
1498 /* find a shareName in the table of submounts */
1499 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1500         char **pathNamep)
1501 {
1502     DWORD len;
1503     char pathName[1024];
1504     char *var;
1505     char temp[1024];
1506     DWORD sizeTemp;
1507 #ifdef DJGPP
1508     char sbmtpath[MAX_PATH];
1509 #endif
1510     char *p, *q;
1511     HKEY parmKey;
1512     DWORD code;
1513     DWORD allSubmount = 1;
1514
1515     /* if allSubmounts == 0, only return the //mountRoot/all share 
1516      * if in fact it has been been created in the subMounts table.  
1517      * This is to allow sites that want to restrict access to the 
1518      * world to do so.
1519      */
1520     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1521                          0, KEY_QUERY_VALUE, &parmKey);
1522     if (code == ERROR_SUCCESS) {
1523         len = sizeof(allSubmount);
1524         code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1525                                 (BYTE *) &allSubmount, &len);
1526         if (code != ERROR_SUCCESS) {
1527             allSubmount = 1;
1528         }
1529         RegCloseKey (parmKey);
1530     }
1531
1532     if (allSubmount && _stricmp(shareName, "all") == 0) {
1533         *pathNamep = NULL;
1534         return 1;
1535     }
1536
1537     /* In case, the all share is disabled we need to still be able
1538      * to handle ioctl requests 
1539      */
1540     if (_stricmp(shareName, "ioctl$") == 0) {
1541         *pathNamep = strdup("/.__ioctl__");
1542         return 1;
1543     }
1544
1545     if (_stricmp(shareName, "IPC$") == 0 ||
1546         _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1547         _stricmp(shareName, "DESKTOP.INI") == 0
1548          ) {
1549         *pathNamep = NULL;
1550         return 0;
1551     }
1552
1553 #ifndef DJGPP
1554     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1555                          0, KEY_QUERY_VALUE, &parmKey);
1556     if (code == ERROR_SUCCESS) {
1557         len = sizeof(pathName);
1558         code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1559                                 (BYTE *) pathName, &len);
1560         if (code != ERROR_SUCCESS)
1561             len = 0;
1562         RegCloseKey (parmKey);
1563     } else {
1564         len = 0;
1565     }   
1566 #else /* DJGPP */
1567     strcpy(sbmtpath, cm_confDir);
1568     strcat(sbmtpath, "/afsdsbmt.ini");
1569     len = GetPrivateProfileString("AFS Submounts", shareName, "",
1570                                    pathName, sizeof(pathName), sbmtpath);
1571 #endif /* !DJGPP */
1572     if (len != 0 && len != sizeof(pathName) - 1) {
1573         /* We can accept either unix or PC style AFS pathnames.  Convert
1574          * Unix-style to PC style here for internal use. 
1575          */
1576         p = pathName;
1577         if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1578             p += strlen(cm_mountRoot);  /* skip mount path */
1579         q = p;
1580         while (*q) {
1581             if (*q == '/') *q = '\\';    /* change to \ */
1582             q++;
1583         }
1584
1585         while (1)
1586         {
1587             if (var = smb_stristr(p, VNUserName)) {
1588                 if (uidp && uidp->unp)
1589                     smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1590                 else
1591                     smb_subst(p, var, sizeof(VNUserName)," ");
1592             }
1593             else if (var = smb_stristr(p, VNLCUserName)) 
1594             {
1595                 if (uidp && uidp->unp)
1596                     strcpy(temp, uidp->unp->name);
1597                 else 
1598                     strcpy(temp, " ");
1599                 _strlwr(temp);
1600                 smb_subst(p, var, sizeof(VNLCUserName), temp);
1601             }
1602             else if (var = smb_stristr(p, VNComputerName)) 
1603             {
1604                 sizeTemp = sizeof(temp);
1605                 GetComputerName((LPTSTR)temp, &sizeTemp);
1606                 smb_subst(p, var, sizeof(VNComputerName), temp);
1607             }
1608             else if (var = smb_stristr(p, VNLCComputerName)) 
1609             {
1610                 sizeTemp = sizeof(temp);
1611                 GetComputerName((LPTSTR)temp, &sizeTemp);
1612                 _strlwr(temp);
1613                 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1614             }
1615             else     
1616                 break;
1617         }
1618         *pathNamep = strdup(p);
1619         return 1;
1620     } 
1621     else
1622     {
1623         /* First lookup shareName in root.afs */
1624         cm_req_t req;
1625         smb_findShare_rock_t vrock;
1626         osi_hyper_t thyper;
1627         char * p = shareName; 
1628         int rw = 0;
1629
1630         /*  attempt to locate a partial match in root.afs.  This is because
1631             when using the ANSI RAP calls, the share name is limited to 13 chars
1632             and hence is truncated. Of course we prefer exact matches. */
1633         cm_InitReq(&req);
1634         thyper.HighPart = 0;
1635         thyper.LowPart = 0;
1636
1637         vrock.shareName = shareName;
1638         vrock.match = NULL;
1639         vrock.matchType = 0;
1640
1641         cm_HoldSCache(cm_data.rootSCachep);
1642         code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1643             (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1644         cm_ReleaseSCache(cm_data.rootSCachep);
1645
1646         if (vrock.matchType) {
1647             sprintf(pathName,"/%s/",vrock.match);
1648             *pathNamep = strdup(strlwr(pathName));
1649             free(vrock.match);
1650             return 1;
1651         }
1652
1653         /* if we get here, there was no match for the share in root.afs */
1654         /* so try to create  \\<netbiosName>\<cellname>  */
1655         if ( *p == '.' ) {
1656             p++;
1657             rw = 1;
1658         }
1659         /* Get the full name for this cell */
1660         code = cm_SearchCellFile(p, temp, 0, 0);
1661 #ifdef AFS_AFSDB_ENV
1662         if (code && cm_dnsEnabled) {
1663             int ttl;
1664             code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1665         }
1666 #endif
1667         /* construct the path */
1668         if (code == 0) {     
1669             sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1670             *pathNamep = strdup(strlwr(pathName));
1671             return 1;
1672         }
1673     }
1674     /* failure */
1675     *pathNamep = NULL;
1676     return 0;
1677 }
1678
1679 /* Client-side offline caching policy types */
1680 #define CSC_POLICY_MANUAL 0
1681 #define CSC_POLICY_DOCUMENTS 1
1682 #define CSC_POLICY_PROGRAMS 2
1683 #define CSC_POLICY_DISABLE 3
1684
1685 int smb_FindShareCSCPolicy(char *shareName)
1686 {
1687     DWORD len;
1688     char policy[1024];
1689     DWORD dwType;
1690     HKEY hkCSCPolicy;
1691     int  retval = CSC_POLICY_MANUAL;
1692
1693     RegCreateKeyEx( HKEY_LOCAL_MACHINE, 
1694                     AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1695                     0, 
1696                     "AFS", 
1697                     REG_OPTION_NON_VOLATILE,
1698                     KEY_READ,
1699                     NULL, 
1700                     &hkCSCPolicy,
1701                     NULL );
1702
1703     len = sizeof(policy);
1704     if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1705          len == 0) {
1706         retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1707     }
1708     else if (stricmp(policy, "documents") == 0)
1709     {
1710         retval = CSC_POLICY_DOCUMENTS;
1711     }
1712     else if (stricmp(policy, "programs") == 0)
1713     {
1714         retval = CSC_POLICY_PROGRAMS;
1715     }
1716     else if (stricmp(policy, "disable") == 0)
1717     {
1718         retval = CSC_POLICY_DISABLE;
1719     }
1720         
1721     RegCloseKey(hkCSCPolicy);
1722     return retval;
1723 }
1724
1725 /* find a dir search structure by cookie value, and return it held.
1726  * Must be called with smb_globalLock held.
1727  */
1728 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
1729 {
1730     smb_dirSearch_t *dsp;
1731         
1732     for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1733         if (dsp->cookie == cookie) {
1734             if (dsp != smb_firstDirSearchp) {
1735                 /* move to head of LRU queue, too, if we're not already there */
1736                 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1737                     smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
1738                 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1739                 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1740                 if (!smb_lastDirSearchp)
1741                     smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1742             }
1743             lock_ObtainMutex(&dsp->mx);
1744             dsp->refCount++;
1745             lock_ReleaseMutex(&dsp->mx);
1746             break;
1747         }
1748     }
1749
1750     if (dsp == NULL) {
1751         osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
1752         for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1753             osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
1754         }
1755     }
1756     return dsp;
1757 }       
1758
1759 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1760 {
1761     lock_ObtainWrite(&smb_globalLock);
1762     lock_ObtainMutex(&dsp->mx);
1763     dsp->flags |= SMB_DIRSEARCH_DELETE;
1764     if (dsp->scp != NULL) {
1765         lock_ObtainMutex(&dsp->scp->mx);
1766         if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1767             dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1768             dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1769             dsp->scp->bulkStatProgress = hones;
1770         }       
1771         lock_ReleaseMutex(&dsp->scp->mx);
1772     }   
1773     lock_ReleaseMutex(&dsp->mx);
1774     lock_ReleaseWrite(&smb_globalLock);
1775 }               
1776
1777 /* Must be called with the smb_globalLock held */
1778 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
1779 {
1780     cm_scache_t *scp = NULL;
1781
1782     lock_ObtainMutex(&dsp->mx);
1783     osi_assert(dsp->refCount-- > 0);
1784     if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1785         if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1786             smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1787         osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1788         lock_ReleaseMutex(&dsp->mx);
1789         lock_FinalizeMutex(&dsp->mx);
1790         scp = dsp->scp;
1791         free(dsp);
1792     } else {
1793         lock_ReleaseMutex(&dsp->mx);
1794     }
1795     /* do this now to avoid spurious locking hierarchy creation */
1796     if (scp) 
1797         cm_ReleaseSCache(scp);
1798 }       
1799
1800 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1801 {
1802     lock_ObtainWrite(&smb_globalLock);
1803     smb_ReleaseDirSearchNoLock(dsp);
1804     lock_ReleaseWrite(&smb_globalLock);
1805 }       
1806
1807 /* find a dir search structure by cookie value, and return it held */
1808 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1809 {
1810     smb_dirSearch_t *dsp;
1811
1812     lock_ObtainWrite(&smb_globalLock);
1813     dsp = smb_FindDirSearchNoLock(cookie);
1814     lock_ReleaseWrite(&smb_globalLock);
1815     return dsp;
1816 }
1817
1818 /* GC some dir search entries, in the address space expected by the specific protocol.
1819  * Must be called with smb_globalLock held; release the lock temporarily.
1820  */
1821 #define SMB_DIRSEARCH_GCMAX     10      /* how many at once */
1822 void smb_GCDirSearches(int isV3)
1823 {
1824     smb_dirSearch_t *prevp;
1825     smb_dirSearch_t *tp;
1826     smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1827     int victimCount;
1828     int i;
1829         
1830     victimCount = 0;    /* how many have we got so far */
1831     for (tp = smb_lastDirSearchp; tp; tp=prevp) {
1832         /* we'll move tp from queue, so
1833          * do this early.
1834          */
1835         prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);  
1836         /* if no one is using this guy, and we're either in the new protocol,
1837          * or we're in the old one and this is a small enough ID to be useful
1838          * to the old protocol, GC this guy.
1839          */
1840         if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1841             /* hold and delete */
1842             tp->flags |= SMB_DIRSEARCH_DELETE;
1843             victimsp[victimCount++] = tp;
1844             tp->refCount++;
1845         }
1846
1847         /* don't do more than this */
1848         if (victimCount >= SMB_DIRSEARCH_GCMAX) 
1849             break;
1850     }
1851         
1852     /* now release them */
1853     for (i = 0; i < victimCount; i++) {
1854         smb_ReleaseDirSearchNoLock(victimsp[i]);
1855     }
1856 }
1857
1858 /* function for allocating a dir search entry.  We need these to remember enough context
1859  * since we don't get passed the path from call to call during a directory search.
1860  *
1861  * Returns a held dir search structure, and bumps the reference count on the vnode,
1862  * since it saves a pointer to the vnode.
1863  */
1864 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1865 {
1866     smb_dirSearch_t *dsp;
1867     int counter;
1868     int maxAllowed;
1869     int start;
1870     int wrapped = 0;
1871
1872     lock_ObtainWrite(&smb_globalLock);
1873     counter = 0;
1874
1875     /* what's the biggest ID allowed in this version of the protocol */
1876     maxAllowed = isV3 ? 65535 : 255;
1877     if (smb_dirSearchCounter > maxAllowed)
1878         smb_dirSearchCounter = 1;
1879
1880     start = smb_dirSearchCounter;
1881
1882     while (1) {
1883         /* twice so we have enough tries to find guys we GC after one pass;
1884          * 10 extra is just in case I mis-counted.
1885          */
1886         if (++counter > 2*maxAllowed+10) 
1887             osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
1888
1889         if (smb_dirSearchCounter > maxAllowed) {        
1890             smb_dirSearchCounter = 1;
1891         }
1892         if (smb_dirSearchCounter == start) {
1893             if (wrapped)
1894                 smb_GCDirSearches(isV3);
1895             wrapped++;
1896         }
1897         dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
1898         if (dsp) {
1899             /* don't need to watch for refcount zero and deleted, since
1900             * we haven't dropped the global lock.
1901             */
1902             lock_ObtainMutex(&dsp->mx);
1903             dsp->refCount--;
1904             lock_ReleaseMutex(&dsp->mx);
1905             ++smb_dirSearchCounter;
1906             continue;
1907         }       
1908
1909         dsp = malloc(sizeof(*dsp));
1910         memset(dsp, 0, sizeof(*dsp));
1911         dsp->cookie = smb_dirSearchCounter;
1912         ++smb_dirSearchCounter;
1913         dsp->refCount = 1;
1914         lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
1915         dsp->lastTime = osi_Time();
1916         osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1917         if (!smb_lastDirSearchp) 
1918             smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1919         break;
1920     }   
1921     lock_ReleaseWrite(&smb_globalLock);
1922     return dsp;
1923 }
1924
1925 static smb_packet_t *GetPacket(void)
1926 {
1927     smb_packet_t *tbp;
1928 #ifdef DJGPP
1929     unsigned int npar, seg, tb_sel;
1930 #endif
1931
1932     lock_ObtainWrite(&smb_globalLock);
1933     tbp = smb_packetFreeListp;
1934     if (tbp) 
1935         smb_packetFreeListp = tbp->nextp;
1936     lock_ReleaseWrite(&smb_globalLock);
1937     if (!tbp) {
1938 #ifndef DJGPP
1939         tbp = calloc(65540,1);
1940 #else /* DJGPP */
1941         tbp = malloc(sizeof(smb_packet_t));
1942 #endif /* !DJGPP */
1943         tbp->magic = SMB_PACKETMAGIC;
1944         tbp->ncbp = NULL;
1945         tbp->vcp = NULL;
1946         tbp->resumeCode = 0;
1947         tbp->inCount = 0;
1948         tbp->fid = 0;
1949         tbp->wctp = NULL;
1950         tbp->inCom = 0;
1951         tbp->oddByte = 0;
1952         tbp->ncb_length = 0;
1953         tbp->flags = 0;
1954         tbp->spacep = NULL;
1955         
1956 #ifdef DJGPP
1957         npar = SMB_PACKETSIZE >> 4;  /* number of paragraphs */
1958         {
1959             signed int retval =
1960                 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1961             if (retval == -1) {
1962                 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS memory",
1963                           npar);
1964                 osi_panic("",__FILE__,__LINE__);
1965             }
1966             else {
1967                 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X",
1968                           npar, retval);
1969                 seg = retval;
1970             }
1971         }
1972         tbp->dos_pkt = (seg * 16) + 0;  /* DOS physical address */
1973         tbp->dos_pkt_sel = tb_sel;
1974 #endif /* DJGPP */
1975     }
1976     osi_assert(tbp->magic == SMB_PACKETMAGIC);
1977
1978     return tbp;
1979 }
1980
1981 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
1982 {
1983     smb_packet_t *tbp;
1984     tbp = GetPacket();
1985     memcpy(tbp, pkt, sizeof(smb_packet_t));
1986     tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
1987     if (tbp->vcp)
1988         smb_HoldVC(tbp->vcp);
1989     return tbp;
1990 }
1991
1992 static NCB *GetNCB(void)
1993 {
1994     smb_ncb_t *tbp;
1995     NCB *ncbp;
1996 #ifdef DJGPP
1997     unsigned int npar, seg, tb_sel;
1998 #endif /* DJGPP */
1999
2000     lock_ObtainWrite(&smb_globalLock);
2001     tbp = smb_ncbFreeListp;
2002     if (tbp) 
2003         smb_ncbFreeListp = tbp->nextp;
2004     lock_ReleaseWrite(&smb_globalLock);
2005     if (!tbp) {
2006 #ifndef DJGPP
2007         tbp = calloc(sizeof(*tbp),1);
2008 #else /* DJGPP */
2009         tbp = malloc(sizeof(*tbp));
2010         npar = (sizeof(NCB)+15) >> 4;  /* number of paragraphs */
2011         {
2012             signed int retval =
2013                 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
2014             if (retval == -1) {
2015                 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS mem in GetNCB",
2016                           npar);
2017                 osi_panic("",__FILE__,__LINE__);
2018             } else {
2019                 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
2020                           npar, retval);
2021                 seg = retval;
2022             }
2023         }
2024         tbp->dos_ncb = (seg * 16) + 0;  /* DOS physical address */
2025         tbp->dos_ncb_sel = tb_sel;
2026 #endif /* !DJGPP */
2027         tbp->magic = SMB_NCBMAGIC;
2028     }
2029         
2030     osi_assert(tbp->magic == SMB_NCBMAGIC);
2031
2032     memset(&tbp->ncb, 0, sizeof(NCB));
2033     ncbp = &tbp->ncb;
2034 #ifdef DJGPP
2035     dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
2036 #endif /* DJGPP */
2037     return ncbp;
2038 }
2039
2040 void smb_FreePacket(smb_packet_t *tbp)
2041 {
2042     smb_vc_t * vcp = NULL;
2043     osi_assert(tbp->magic == SMB_PACKETMAGIC);
2044         
2045     lock_ObtainWrite(&smb_globalLock);
2046     tbp->nextp = smb_packetFreeListp;
2047     smb_packetFreeListp = tbp;
2048     tbp->magic = SMB_PACKETMAGIC;
2049     tbp->ncbp = NULL;
2050     vcp = tbp->vcp;
2051     tbp->vcp = NULL;
2052     tbp->resumeCode = 0;
2053     tbp->inCount = 0;
2054     tbp->fid = 0;
2055     tbp->wctp = NULL;
2056     tbp->inCom = 0;
2057     tbp->oddByte = 0;
2058     tbp->ncb_length = 0;
2059     tbp->flags = 0;
2060     lock_ReleaseWrite(&smb_globalLock);
2061
2062     if (vcp)
2063         smb_ReleaseVC(vcp);
2064 }
2065
2066 static void FreeNCB(NCB *bufferp)
2067 {
2068     smb_ncb_t *tbp;
2069         
2070     tbp = (smb_ncb_t *) bufferp;
2071     osi_assert(tbp->magic == SMB_NCBMAGIC);
2072         
2073     lock_ObtainWrite(&smb_globalLock);
2074     tbp->nextp = smb_ncbFreeListp;
2075     smb_ncbFreeListp = tbp;
2076     lock_ReleaseWrite(&smb_globalLock);
2077 }
2078
2079 /* get a ptr to the data part of a packet, and its count */
2080 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2081 {
2082     int parmBytes;
2083     int dataBytes;
2084     unsigned char *afterParmsp;
2085
2086     parmBytes = *smbp->wctp << 1;
2087     afterParmsp = smbp->wctp + parmBytes + 1;
2088         
2089     dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2090     if (nbytesp) *nbytesp = dataBytes;
2091         
2092     /* don't forget to skip the data byte count, since it follows
2093      * the parameters; that's where the "2" comes from below.
2094      */
2095     return (unsigned char *) (afterParmsp + 2);
2096 }
2097
2098 /* must set all the returned parameters before playing around with the
2099  * data region, since the data region is located past the end of the
2100  * variable number of parameters.
2101  */
2102 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2103 {
2104     unsigned char *afterParmsp;
2105
2106     afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2107         
2108     *afterParmsp++ = dsize & 0xff;
2109     *afterParmsp = (dsize>>8) & 0xff;
2110 }       
2111
2112 /* return the parm'th parameter in the smbp packet */
2113 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
2114 {
2115     int parmCount;
2116     unsigned char *parmDatap;
2117
2118     parmCount = *smbp->wctp;
2119
2120     if (parm >= parmCount) {
2121         char s[100];
2122
2123         sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2124                 parm, parmCount, smbp->ncb_length);
2125         osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2126                  parm, parmCount, smbp->ncb_length);
2127 #ifndef DJGPP
2128         LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM, 
2129                  __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2130 #endif /* !DJGPP */
2131         osi_panic(s, __FILE__, __LINE__);
2132     }
2133     parmDatap = smbp->wctp + (2*parm) + 1;
2134         
2135     return parmDatap[0] + (parmDatap[1] << 8);
2136 }
2137
2138 /* return the parm'th parameter in the smbp packet */
2139 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2140 {
2141     int parmCount;
2142     unsigned char *parmDatap;
2143
2144     parmCount = *smbp->wctp;
2145
2146     if (parm * 2 + offset >= parmCount * 2) {
2147         char s[100];
2148
2149         sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2150                 parm, offset, parmCount, smbp->ncb_length);
2151 #ifndef DJGPP
2152         LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET, 
2153                  __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2154 #endif /* !DJGPP */
2155         osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2156                 parm, offset, parmCount, smbp->ncb_length);
2157         osi_panic(s, __FILE__, __LINE__);
2158     }
2159     parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2160         
2161     return parmDatap[0] + (parmDatap[1] << 8);
2162 }
2163
2164 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2165 {
2166     char *parmDatap;
2167
2168     /* make sure we have enough slots */
2169     if (*smbp->wctp <= slot) 
2170         *smbp->wctp = slot+1;
2171         
2172     parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2173     *parmDatap++ = parmValue & 0xff;
2174     *parmDatap = (parmValue>>8) & 0xff;
2175 }       
2176
2177 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2178 {
2179     char *parmDatap;
2180
2181     /* make sure we have enough slots */
2182     if (*smbp->wctp <= slot) 
2183         *smbp->wctp = slot+2;
2184
2185     parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2186     *parmDatap++ = parmValue & 0xff;
2187     *parmDatap++ = (parmValue>>8) & 0xff;
2188     *parmDatap++ = (parmValue>>16) & 0xff;
2189     *parmDatap++ = (parmValue>>24) & 0xff;
2190 }
2191
2192 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2193 {
2194     char *parmDatap;
2195     int i;
2196
2197     /* make sure we have enough slots */
2198     if (*smbp->wctp <= slot) 
2199         *smbp->wctp = slot+4;
2200
2201     parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2202     for (i=0; i<8; i++)
2203         *parmDatap++ = *parmValuep++;
2204 }       
2205
2206 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2207 {
2208     char *parmDatap;
2209
2210     /* make sure we have enough slots */
2211     if (*smbp->wctp <= slot) {
2212         if (smbp->oddByte) {
2213             smbp->oddByte = 0;
2214             *smbp->wctp = slot+1;
2215         } else
2216             smbp->oddByte = 1;
2217     }
2218
2219     parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2220     *parmDatap++ = parmValue & 0xff;
2221 }
2222
2223 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2224 {
2225     char *lastSlashp;
2226         
2227     lastSlashp = strrchr(inPathp, '\\');
2228     if (lastComponentp)
2229         *lastComponentp = lastSlashp;
2230     if (lastSlashp) {
2231         while (1) {
2232             if (inPathp == lastSlashp) 
2233                 break;
2234             *outPathp++ = *inPathp++;
2235         }
2236         *outPathp++ = 0;
2237     }
2238     else {
2239         *outPathp++ = 0;
2240     }
2241 }
2242
2243 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2244 {
2245     if (*inp++ != 0x4) 
2246         return NULL;
2247     if (chainpp) {
2248         *chainpp = inp + strlen(inp) + 1;       /* skip over null-terminated string */
2249     }
2250     return inp;
2251 }
2252
2253 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2254 {
2255     int tlen;
2256
2257     if (*inp++ != 0x5) 
2258         return NULL;
2259     tlen = inp[0] + (inp[1]<<8);
2260     inp += 2;           /* skip length field */
2261
2262     if (chainpp) {
2263         *chainpp = inp + tlen;
2264     }
2265         
2266     if (lengthp) 
2267         *lengthp = tlen;
2268         
2269     return inp;
2270 }       
2271
2272 /* format a packet as a response */
2273 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2274 {
2275     smb_t *outp;
2276     smb_t *inSmbp;
2277
2278     outp = (smb_t *) op;
2279         
2280     /* zero the basic structure through the smb_wct field, and zero the data
2281      * size field, assuming that wct stays zero; otherwise, you have to 
2282      * explicitly set the data size field, too.
2283      */
2284     inSmbp = (smb_t *) inp;
2285     memset(outp, 0, sizeof(smb_t)+2);
2286     outp->id[0] = 0xff;
2287     outp->id[1] = 'S';
2288     outp->id[2] = 'M';
2289     outp->id[3] = 'B';
2290     if (inp) {
2291         outp->com = inSmbp->com;
2292         outp->tid = inSmbp->tid;
2293         outp->pid = inSmbp->pid;
2294         outp->uid = inSmbp->uid;
2295         outp->mid = inSmbp->mid;
2296         outp->res[0] = inSmbp->res[0];
2297         outp->res[1] = inSmbp->res[1];
2298         op->inCom = inSmbp->com;
2299     }
2300     outp->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
2301     outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2302
2303     /* copy fields in generic packet area */
2304     op->wctp = &outp->wct;
2305 }       
2306
2307 /* send a (probably response) packet; vcp tells us to whom to send it.
2308  * we compute the length by looking at wct and bcc fields.
2309  */
2310 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2311 {
2312     NCB *ncbp;
2313     int extra;
2314     long code = 0;
2315     unsigned char *tp;
2316     int localNCB = 0;
2317 #ifdef DJGPP
2318     dos_ptr dos_ncb;
2319 #endif /* DJGPP */
2320         
2321     ncbp = inp->ncbp;
2322     if (ncbp == NULL) {
2323         ncbp = GetNCB();
2324         localNCB = 1;
2325     }
2326 #ifdef DJGPP
2327     dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2328 #endif /* DJGPP */
2329  
2330     memset((char *)ncbp, 0, sizeof(NCB));
2331
2332     extra = 2 * (*inp->wctp);   /* space used by parms, in bytes */
2333     tp = inp->wctp + 1+ extra;  /* points to count of data bytes */
2334     extra += tp[0] + (tp[1]<<8);
2335     extra += (unsigned int)(inp->wctp - inp->data);     /* distance to last wct field */
2336     extra += 3;                 /* wct and length fields */
2337         
2338     ncbp->ncb_length = extra;   /* bytes to send */
2339     ncbp->ncb_lsn = (unsigned char) vcp->lsn;   /* vc to use */
2340     ncbp->ncb_lana_num = vcp->lana;
2341     ncbp->ncb_command = NCBSEND;        /* op means send data */
2342 #ifndef DJGPP
2343     ncbp->ncb_buffer = (char *) inp;/* packet */
2344     code = Netbios(ncbp);
2345 #else /* DJGPP */
2346     ncbp->ncb_buffer = inp->dos_pkt;/* packet */
2347     ((smb_ncb_t*)ncbp)->orig_pkt = inp;
2348
2349     /* copy header information from virtual to DOS address space */
2350     dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
2351     code = Netbios(ncbp, dos_ncb);
2352 #endif /* !DJGPP */
2353         
2354     if (code != 0) {
2355         char * s;
2356         switch ( code ) {
2357         case 0x01: s = "llegal buffer length                     "; break; 
2358         case 0x03: s = "illegal command                          "; break; 
2359         case 0x05: s = "command timed out                        "; break; 
2360         case 0x06: s = "message incomplete, issue another command"; break; 
2361         case 0x07: s = "illegal buffer address                   "; break; 
2362         case 0x08: s = "session number out of range              "; break; 
2363         case 0x09: s = "no resource available                    "; break; 
2364         case 0x0a: s = "session closed                           "; break; 
2365         case 0x0b: s = "command cancelled                        "; break; 
2366         case 0x0d: s = "duplicate name                           "; break; 
2367         case 0x0e: s = "name table full                          "; break; 
2368         case 0x0f: s = "no deletions, name has active sessions   "; break; 
2369         case 0x11: s = "local session table full                 "; break; 
2370         case 0x12: s = "remote session table full                "; break; 
2371         case 0x13: s = "illegal name number                      "; break; 
2372         case 0x14: s = "no callname                              "; break; 
2373         case 0x15: s = "cannot put * in NCB_NAME                 "; break; 
2374         case 0x16: s = "name in use on remote adapter            "; break; 
2375         case 0x17: s = "name deleted                             "; break; 
2376         case 0x18: s = "session ended abnormally                 "; break; 
2377         case 0x19: s = "name conflict detected                   "; break; 
2378         case 0x21: s = "interface busy, IRET before retrying     "; break; 
2379         case 0x22: s = "too many commands outstanding, retry later"; break;
2380         case 0x23: s = "ncb_lana_num field invalid               "; break; 
2381         case 0x24: s = "command completed while cancel occurring "; break; 
2382         case 0x26: s = "command not valid to cancel              "; break; 
2383         case 0x30: s = "name defined by anther local process     "; break; 
2384         case 0x34: s = "environment undefined. RESET required    "; break; 
2385         case 0x35: s = "required OS resources exhausted          "; break; 
2386         case 0x36: s = "max number of applications exceeded      "; break; 
2387         case 0x37: s = "no saps available for netbios            "; break; 
2388         case 0x38: s = "requested resources are not available    "; break; 
2389         case 0x39: s = "invalid ncb address or length > segment  "; break; 
2390         case 0x3B: s = "invalid NCB DDID                         "; break; 
2391         case 0x3C: s = "lock of user area failed                 "; break; 
2392         case 0x3f: s = "NETBIOS not loaded                       "; break; 
2393         case 0x40: s = "system error                             "; break;                 
2394         default:
2395             s = "unknown error";
2396         }
2397         osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2398     }
2399
2400     if (localNCB)
2401         FreeNCB(ncbp);
2402 }
2403
2404 void smb_MapNTError(long code, unsigned long *NTStatusp)
2405 {
2406     unsigned long NTStatus;
2407
2408     /* map CM_ERROR_* errors to NT 32-bit status codes */
2409     /* NT Status codes are listed in ntstatus.h not winerror.h */
2410     if (code == CM_ERROR_NOSUCHCELL) {
2411         NTStatus = 0xC000000FL; /* No such file */
2412     }
2413     else if (code == CM_ERROR_NOSUCHVOLUME) {
2414         NTStatus = 0xC000000FL; /* No such file */
2415     }
2416     else if (code == CM_ERROR_TIMEDOUT) {
2417 #ifdef COMMENT
2418         NTStatus = 0xC00000CFL; /* Sharing Paused */
2419 #else
2420         NTStatus = 0x00000102L; /* Timeout */
2421 #endif
2422     }
2423     else if (code == CM_ERROR_RETRY) {
2424         NTStatus = 0xC000022DL; /* Retry */
2425     }
2426     else if (code == CM_ERROR_NOACCESS) {
2427         NTStatus = 0xC0000022L; /* Access denied */
2428     }
2429     else if (code == CM_ERROR_READONLY) {
2430         NTStatus = 0xC00000A2L; /* Write protected */
2431     }
2432     else if (code == CM_ERROR_NOSUCHFILE) {
2433         NTStatus = 0xC000000FL; /* No such file */
2434     }
2435     else if (code == CM_ERROR_NOSUCHPATH) {
2436         NTStatus = 0xC000003AL; /* Object path not found */
2437     }           
2438     else if (code == CM_ERROR_TOOBIG) {
2439         NTStatus = 0xC000007BL; /* Invalid image format */
2440     }
2441     else if (code == CM_ERROR_INVAL) {
2442         NTStatus = 0xC000000DL; /* Invalid parameter */
2443     }
2444     else if (code == CM_ERROR_BADFD) {
2445         NTStatus = 0xC0000008L; /* Invalid handle */
2446     }
2447     else if (code == CM_ERROR_BADFDOP) {
2448         NTStatus = 0xC0000022L; /* Access denied */
2449     }
2450     else if (code == CM_ERROR_EXISTS) {
2451         NTStatus = 0xC0000035L; /* Object name collision */
2452     }
2453     else if (code == CM_ERROR_NOTEMPTY) {
2454         NTStatus = 0xC0000101L; /* Directory not empty */
2455     }   
2456     else if (code == CM_ERROR_CROSSDEVLINK) {
2457         NTStatus = 0xC00000D4L; /* Not same device */
2458     }
2459     else if (code == CM_ERROR_NOTDIR) {
2460         NTStatus = 0xC0000103L; /* Not a directory */
2461     }
2462     else if (code == CM_ERROR_ISDIR) {
2463         NTStatus = 0xC00000BAL; /* File is a directory */
2464     }
2465     else if (code == CM_ERROR_BADOP) {
2466 #ifdef COMMENT
2467         /* I have no idea where this comes from */
2468         NTStatus = 0xC09820FFL; /* SMB no support */
2469 #else
2470         NTStatus = 0xC00000BBL;     /* Not supported */
2471 #endif /* COMMENT */
2472     }
2473     else if (code == CM_ERROR_BADSHARENAME) {
2474         NTStatus = 0xC00000CCL; /* Bad network name */
2475     }
2476     else if (code == CM_ERROR_NOIPC) {
2477 #ifdef COMMENT
2478         NTStatus = 0xC0000022L; /* Access Denied */
2479 #else   
2480         NTStatus = 0xC000013DL; /* Remote Resources */
2481 #endif
2482     }
2483     else if (code == CM_ERROR_CLOCKSKEW) {
2484         NTStatus = 0xC0000133L; /* Time difference at DC */
2485     }
2486     else if (code == CM_ERROR_BADTID) {
2487         NTStatus = 0xC0982005L; /* SMB bad TID */
2488     }
2489     else if (code == CM_ERROR_USESTD) {
2490         NTStatus = 0xC09820FBL; /* SMB use standard */
2491     }
2492     else if (code == CM_ERROR_QUOTA) {
2493 #ifdef COMMENT
2494         NTStatus = 0xC0000044L; /* Quota exceeded */
2495 #else
2496         NTStatus = 0xC000007FL; /* Disk full */
2497 #endif
2498     }
2499     else if (code == CM_ERROR_SPACE) {
2500         NTStatus = 0xC000007FL; /* Disk full */
2501     }
2502     else if (code == CM_ERROR_ATSYS) {
2503         NTStatus = 0xC0000033L; /* Object name invalid */
2504     }
2505     else if (code == CM_ERROR_BADNTFILENAME) {
2506         NTStatus = 0xC0000033L; /* Object name invalid */
2507     }
2508     else if (code == CM_ERROR_WOULDBLOCK) {
2509         NTStatus = 0xC0000055L; /* Lock not granted */
2510     }
2511     else if (code == CM_ERROR_SHARING_VIOLATION) {
2512         NTStatus = 0xC0000043L; /* Sharing violation */
2513     }
2514     else if (code == CM_ERROR_LOCK_CONFLICT) {
2515         NTStatus = 0xC0000054L; /* Lock conflict */
2516     }
2517     else if (code == CM_ERROR_PARTIALWRITE) {
2518         NTStatus = 0xC000007FL; /* Disk full */
2519     }
2520     else if (code == CM_ERROR_BUFFERTOOSMALL) {
2521         NTStatus = 0xC0000023L; /* Buffer too small */
2522     }
2523     else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2524         NTStatus = 0xC0000035L; /* Object name collision */
2525     }   
2526     else if (code == CM_ERROR_BADPASSWORD) {
2527         NTStatus = 0xC000006DL; /* unknown username or bad password */
2528     }
2529     else if (code == CM_ERROR_BADLOGONTYPE) {
2530         NTStatus = 0xC000015BL; /* logon type not granted */
2531     }
2532     else if (code == CM_ERROR_GSSCONTINUE) {
2533         NTStatus = 0xC0000016L; /* more processing required */
2534     }
2535     else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2536 #ifdef COMMENT
2537         NTStatus = 0xC0000280L; /* reparse point not resolved */
2538 #else
2539         NTStatus = 0xC0000022L; /* Access Denied */
2540 #endif
2541     }
2542     else if (code == CM_ERROR_PATH_NOT_COVERED) {
2543         NTStatus = 0xC0000257L; /* Path Not Covered */
2544     } 
2545 #ifdef COMMENT
2546     else if (code == CM_ERROR_ALLBUSY) {
2547         NTStatus = 0xC00000BFL; /* Network Busy */
2548     } 
2549     else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
2550         NTStatus = 0xC0000350L; /* Remote Host Down */
2551     } 
2552 #else
2553     /* we do not want to be telling the SMB/CIFS client that
2554      * the AFS Client Service is busy or down.  
2555      */
2556     else if (code == CM_ERROR_ALLBUSY || 
2557              code == CM_ERROR_ALLOFFLINE ||
2558              code == CM_ERROR_ALLDOWN) {
2559         NTStatus = 0xC00000BEL; /* Bad Network Path */
2560     }
2561 #endif
2562     else if (code == RXKADUNKNOWNKEY) {
2563         NTStatus = 0xC0000322L; /* Bad Kerberos key */
2564     } else {
2565         NTStatus = 0xC0982001L; /* SMB non-specific error */
2566     }
2567
2568     *NTStatusp = NTStatus;
2569     osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2570 }       
2571
2572 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2573                       unsigned char *classp)
2574 {
2575     unsigned char class;
2576     unsigned short error;
2577
2578     /* map CM_ERROR_* errors to SMB errors */
2579     if (code == CM_ERROR_NOSUCHCELL) {
2580         class = 1;
2581         error = 3;      /* bad path */
2582     }
2583     else if (code == CM_ERROR_NOSUCHVOLUME) {
2584         class = 1;
2585         error = 3;      /* bad path */
2586     }
2587     else if (code == CM_ERROR_TIMEDOUT) {
2588         class = 2;
2589         error = 81;     /* server is paused */
2590     }
2591     else if (code == CM_ERROR_RETRY) {
2592         class = 2;      /* shouldn't happen */
2593         error = 1;
2594     }
2595     else if (code == CM_ERROR_NOACCESS) {
2596         class = 2;
2597         error = 4;      /* bad access */
2598     }
2599     else if (code == CM_ERROR_READONLY) {
2600         class = 3;
2601         error = 19;     /* read only */
2602     }
2603     else if (code == CM_ERROR_NOSUCHFILE) {
2604         class = 1;
2605         error = 2;      /* ENOENT! */
2606     }
2607     else if (code == CM_ERROR_NOSUCHPATH) {
2608         class = 1;
2609         error = 3;      /* Bad path */
2610     }
2611     else if (code == CM_ERROR_TOOBIG) {
2612         class = 1;
2613         error = 11;     /* bad format */
2614     }
2615     else if (code == CM_ERROR_INVAL) {
2616         class = 2;      /* server non-specific error code */
2617         error = 1;
2618     }
2619     else if (code == CM_ERROR_BADFD) {
2620         class = 1;
2621         error = 6;      /* invalid file handle */
2622     }
2623     else if (code == CM_ERROR_BADFDOP) {
2624         class = 1;      /* invalid op on FD */
2625         error = 5;
2626     }
2627     else if (code == CM_ERROR_EXISTS) {
2628         class = 1;
2629         error = 80;     /* file already exists */
2630     }
2631     else if (code == CM_ERROR_NOTEMPTY) {
2632         class = 1;
2633         error = 5;      /* delete directory not empty */
2634     }
2635     else if (code == CM_ERROR_CROSSDEVLINK) {
2636         class = 1;
2637         error = 17;     /* EXDEV */
2638     }
2639     else if (code == CM_ERROR_NOTDIR) {
2640         class = 1;      /* bad path */
2641         error = 3;
2642     }
2643     else if (code == CM_ERROR_ISDIR) {
2644         class = 1;      /* access denied; DOS doesn't have a good match */
2645         error = 5;
2646     }       
2647     else if (code == CM_ERROR_BADOP) {
2648         class = 2;
2649         error = 65535;
2650     }
2651     else if (code == CM_ERROR_BADSHARENAME) {
2652         class = 2;
2653         error = 6;
2654     }
2655     else if (code == CM_ERROR_NOIPC) {
2656         class = 2;
2657         error = 4; /* bad access */
2658     }
2659     else if (code == CM_ERROR_CLOCKSKEW) {
2660         class = 1;      /* invalid function */
2661         error = 1;
2662     }
2663     else if (code == CM_ERROR_BADTID) {
2664         class = 2;
2665         error = 5;
2666     }
2667     else if (code == CM_ERROR_USESTD) {
2668         class = 2;
2669         error = 251;
2670     }
2671     else if (code == CM_ERROR_REMOTECONN) {
2672         class = 2;
2673         error = 82;
2674     }
2675     else if (code == CM_ERROR_QUOTA) {
2676         if (vcp->flags & SMB_VCFLAG_USEV3) {
2677             class = 3;
2678             error = 39; /* disk full */
2679         }
2680         else {
2681             class = 1;
2682             error = 5;  /* access denied */
2683         }
2684     }
2685     else if (code == CM_ERROR_SPACE) {
2686         if (vcp->flags & SMB_VCFLAG_USEV3) {
2687             class = 3;
2688             error = 39; /* disk full */
2689         }
2690         else {
2691             class = 1;
2692             error = 5;  /* access denied */
2693         }
2694     }
2695     else if (code == CM_ERROR_PARTIALWRITE) {
2696         class = 3;
2697         error = 39;     /* disk full */
2698     }
2699     else if (code == CM_ERROR_ATSYS) {
2700         class = 1;
2701         error = 2;      /* ENOENT */
2702     }
2703     else if (code == CM_ERROR_WOULDBLOCK) {
2704         class = 1;
2705         error = 33;     /* lock conflict */
2706     }
2707     else if (code == CM_ERROR_LOCK_CONFLICT) {
2708         class = 1;
2709         error = 33;     /* lock conflict */
2710     }
2711     else if (code == CM_ERROR_SHARING_VIOLATION) {
2712         class = 1;
2713         error = 33;     /* lock conflict */
2714     }
2715     else if (code == CM_ERROR_NOFILES) {
2716         class = 1;
2717         error = 18;     /* no files in search */
2718     }
2719     else if (code == CM_ERROR_RENAME_IDENTICAL) {
2720         class = 1;
2721         error = 183;     /* Samba uses this */
2722     }
2723     else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2724         /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2725         class = 2;
2726         error = 2; /* bad password */
2727     }
2728     else if (code == CM_ERROR_PATH_NOT_COVERED) {
2729         class = 2;
2730         error = 3;     /* bad path */
2731     }
2732     else {
2733         class = 2;
2734         error = 1;
2735     }
2736
2737     *scodep = error;
2738     *classp = class;
2739     osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2740 }       
2741
2742 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2743 {
2744     osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2745     return CM_ERROR_BADOP;
2746 }
2747
2748 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2749 {
2750     unsigned short EchoCount, i;
2751     char *data, *outdata;
2752     int dataSize;
2753
2754     EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2755
2756     for (i=1; i<=EchoCount; i++) {
2757         data = smb_GetSMBData(inp, &dataSize);
2758         smb_SetSMBParm(outp, 0, i);
2759         smb_SetSMBDataLength(outp, dataSize);
2760         outdata = smb_GetSMBData(outp, NULL);
2761         memcpy(outdata, data, dataSize);
2762         smb_SendPacket(vcp, outp);
2763     }
2764
2765     return 0;
2766 }
2767
2768 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2769 {
2770     osi_hyper_t offset;
2771     long count, minCount, finalCount;
2772     unsigned short fd;
2773     unsigned pid;
2774     smb_fid_t *fidp;
2775     long code = 0;
2776     cm_user_t *userp = NULL;
2777     NCB *ncbp;
2778     int rc;
2779 #ifndef DJGPP
2780     char *rawBuf = NULL;
2781 #else
2782     dos_ptr rawBuf = NULL;
2783     dos_ptr dos_ncb;
2784 #endif /* DJGPP */
2785
2786     rawBuf = NULL;
2787     finalCount = 0;
2788
2789     fd = smb_GetSMBParm(inp, 0);
2790     count = smb_GetSMBParm(inp, 3);
2791     minCount = smb_GetSMBParm(inp, 4);
2792     offset.HighPart = 0;        /* too bad */
2793     offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2794
2795     osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2796              fd, offset.LowPart, count);
2797
2798     fidp = smb_FindFID(vcp, fd, 0);
2799     if (!fidp)
2800         goto send1;
2801
2802     pid = ((smb_t *) inp)->pid;
2803     {
2804         LARGE_INTEGER LOffset, LLength;
2805         cm_key_t key;
2806
2807         key = cm_GenerateKey(vcp->vcID, pid, fd);
2808
2809         LOffset.HighPart = 0;
2810         LOffset.LowPart = offset.LowPart;
2811         LLength.HighPart = 0;
2812         LLength.LowPart = count;
2813
2814         lock_ObtainMutex(&fidp->scp->mx);
2815         code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
2816         lock_ReleaseMutex(&fidp->scp->mx);
2817     }    
2818     if (code) {
2819         goto send1a;
2820     }
2821
2822     lock_ObtainMutex(&smb_RawBufLock);
2823     if (smb_RawBufs) {
2824         /* Get a raw buf, from head of list */
2825         rawBuf = smb_RawBufs;
2826 #ifndef DJGPP
2827         smb_RawBufs = *(char **)smb_RawBufs;
2828 #else /* DJGPP */
2829         smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2830 #endif /* !DJGPP */
2831     }
2832     lock_ReleaseMutex(&smb_RawBufLock);
2833     if (!rawBuf)
2834         goto send1a;
2835
2836     if (fidp->flags & SMB_FID_IOCTL)
2837     {
2838 #ifndef DJGPP
2839         rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2840 #else
2841         rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2842 #endif
2843         if (rawBuf) {
2844             /* Give back raw buffer */
2845             lock_ObtainMutex(&smb_RawBufLock);
2846 #ifndef DJGPP
2847             *((char **) rawBuf) = smb_RawBufs;
2848 #else /* DJGPP */
2849             _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2850 #endif /* !DJGPP */
2851             
2852             smb_RawBufs = rawBuf;
2853             lock_ReleaseMutex(&smb_RawBufLock);
2854         }
2855
2856         smb_ReleaseFID(fidp);
2857         return rc;
2858     }
2859         
2860     userp = smb_GetUser(vcp, inp);
2861
2862 #ifndef DJGPP
2863     code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2864 #else /* DJGPP */
2865     /* have to give ReadData flag so it will treat buffer as DOS mem. */
2866     code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2867                         userp, &finalCount, TRUE /* rawFlag */);
2868 #endif /* !DJGPP */
2869
2870     if (code != 0)
2871         goto send;
2872
2873   send:
2874     cm_ReleaseUser(userp);
2875
2876   send1a:
2877     smb_ReleaseFID(fidp);
2878
2879   send1:
2880     ncbp = outp->ncbp;
2881 #ifdef DJGPP
2882     dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2883 #endif /* DJGPP */
2884     memset((char *)ncbp, 0, sizeof(NCB));
2885
2886     ncbp->ncb_length = (unsigned short) finalCount;
2887     ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2888     ncbp->ncb_lana_num = vcp->lana;
2889     ncbp->ncb_command = NCBSEND;
2890     ncbp->ncb_buffer = rawBuf;
2891
2892 #ifndef DJGPP
2893     code = Netbios(ncbp);
2894 #else /* DJGPP */
2895     code = Netbios(ncbp, dos_ncb);
2896 #endif /* !DJGPP */
2897     if (code != 0)
2898         osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2899
2900     if (rawBuf) {
2901         /* Give back raw buffer */
2902         lock_ObtainMutex(&smb_RawBufLock);
2903 #ifndef DJGPP
2904         *((char **) rawBuf) = smb_RawBufs;
2905 #else /* DJGPP */
2906         _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2907 #endif /* !DJGPP */
2908
2909         smb_RawBufs = rawBuf;
2910         lock_ReleaseMutex(&smb_RawBufLock);
2911     }
2912
2913     return 0;
2914 }
2915
2916 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2917 {
2918     osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
2919                          ongoingOps - 1);
2920     return 0;
2921 }
2922
2923 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2924 {
2925     osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
2926                          ongoingOps - 1);
2927     return 0;
2928 }
2929
2930 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2931 {
2932     char *namep;
2933     char *datap;
2934     int coreProtoIndex;
2935     int v3ProtoIndex;
2936     int NTProtoIndex;
2937     int protoIndex;                             /* index we're using */
2938     int namex;
2939     int dbytes;
2940     int entryLength;
2941     int tcounter;
2942     char protocol_array[10][1024];  /* protocol signature of the client */
2943     int caps;                       /* capabilities */
2944     time_t unixTime;
2945     afs_uint32 dosTime;
2946     TIME_ZONE_INFORMATION tzi;
2947
2948     osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2949                          ongoingOps - 1);
2950     if (!isGateway) {
2951         if (active_vcp) {
2952             DWORD now = GetCurrentTime();
2953             if (now - last_msg_time >= 30000
2954                  && now - last_msg_time <= 90000) {
2955                 osi_Log1(smb_logp,
2956                           "Setting dead_vcp %x", active_vcp);
2957                 if (dead_vcp) {
2958                     smb_ReleaseVC(dead_vcp);
2959                     osi_Log1(smb_logp,
2960                              "Previous dead_vcp %x", dead_vcp);
2961                 }
2962                 smb_HoldVC(active_vcp);
2963                 dead_vcp = active_vcp;
2964                 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2965             }
2966         }
2967     }
2968
2969     inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
2970
2971     namep = smb_GetSMBData(inp, &dbytes);
2972     namex = 0;
2973     tcounter = 0;
2974     coreProtoIndex = -1;                /* not found */
2975     v3ProtoIndex = -1;
2976     NTProtoIndex = -1;
2977     while(namex < dbytes) {
2978         osi_Log1(smb_logp, "Protocol %s",
2979                   osi_LogSaveString(smb_logp, namep+1));
2980         strcpy(protocol_array[tcounter], namep+1);
2981
2982         /* namep points at the first protocol, or really, a 0x02
2983          * byte preceding the null-terminated ASCII name.
2984          */
2985         if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2986             coreProtoIndex = tcounter;
2987         }       
2988         else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2989             v3ProtoIndex = tcounter;
2990         }
2991         else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
2992             NTProtoIndex = tcounter;
2993         }
2994
2995         /* compute size of protocol entry */
2996         entryLength = (int)strlen(namep+1);
2997         entryLength += 2;       /* 0x02 bytes and null termination */
2998
2999         /* advance over this protocol entry */
3000         namex += entryLength;
3001         namep += entryLength;
3002         tcounter++;             /* which proto entry we're looking at */
3003     }
3004
3005     if (NTProtoIndex != -1) {
3006         protoIndex = NTProtoIndex;
3007         vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3008     }
3009     else if (v3ProtoIndex != -1) {
3010         protoIndex = v3ProtoIndex;
3011         vcp->flags |= SMB_VCFLAG_USEV3;
3012     }   
3013     else if (coreProtoIndex != -1) {
3014         protoIndex = coreProtoIndex;
3015         vcp->flags |= SMB_VCFLAG_USECORE;
3016     }   
3017     else protoIndex = -1;
3018
3019     if (protoIndex == -1)
3020         return CM_ERROR_INVAL;
3021     else if (NTProtoIndex != -1) {
3022         smb_SetSMBParm(outp, 0, protoIndex);
3023         if (smb_authType != SMB_AUTH_NONE) {
3024             smb_SetSMBParmByte(outp, 1,
3025                                NEGOTIATE_SECURITY_USER_LEVEL |
3026                                NEGOTIATE_SECURITY_CHALLENGE_RESPONSE);  /* user level security, challenge response */
3027         } else {
3028             smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3029         }
3030         smb_SetSMBParm(outp, 1, smb_maxMpxRequests);    /* max multiplexed requests */
3031         smb_SetSMBParm(outp, 2, smb_maxVCPerServer);    /* max VCs per consumer/server connection */
3032         smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE);    /* xmit buffer size */
3033         smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE);    /* raw buffer size */
3034         /* The session key is not a well documented field however most clients
3035          * will echo back the session key to the server.  Currently we are using
3036          * the same value for all sessions.  We should generate a random value
3037          * and store it into the vcp 
3038          */
3039         smb_SetSMBParm(outp, 7, 1);     /* next 2: session key */
3040         smb_SetSMBParm(outp, 8, 1);
3041         /* 
3042          * Tried changing the capabilities to support for W2K - defect 117695
3043          * Maybe something else needs to be changed here?
3044          */
3045         /*
3046         if (isWindows2000) 
3047         smb_SetSMBParmLong(outp, 9, 0x43fd);
3048         else 
3049         smb_SetSMBParmLong(outp, 9, 0x251);
3050         */
3051         /* Capabilities: *
3052          * 32-bit error codes *
3053          * and NT Find *
3054          * and NT SMB's *
3055          * and raw mode 
3056          * and DFS */
3057         caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3058 #ifdef DFS_SUPPORT
3059                NTNEGOTIATE_CAPABILITY_DFS |
3060 #endif
3061                NTNEGOTIATE_CAPABILITY_NTFIND |
3062                NTNEGOTIATE_CAPABILITY_RAWMODE |
3063                NTNEGOTIATE_CAPABILITY_NTSMB;
3064
3065         if ( smb_authType == SMB_AUTH_EXTENDED )
3066             caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3067
3068         smb_SetSMBParmLong(outp, 9, caps);
3069         time(&unixTime);
3070         smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3071         smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3072         smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3073
3074         GetTimeZoneInformation(&tzi);
3075         smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias);    /* server tzone */
3076
3077         if (smb_authType == SMB_AUTH_NTLM) {
3078             smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3079             smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3080             /* paste in encryption key */
3081             datap = smb_GetSMBData(outp, NULL);
3082             memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3083             /* and the faux domain name */
3084             strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
3085         } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3086             void * secBlob;
3087             int secBlobLength;
3088
3089             smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3090
3091             smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3092
3093             smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3094                         
3095             datap = smb_GetSMBData(outp, NULL);
3096             memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3097
3098             if (secBlob) {
3099                 datap += sizeof(smb_ServerGUID);
3100                 memcpy(datap, secBlob, secBlobLength);
3101                 free(secBlob);
3102             }
3103         } else {
3104             smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3105             smb_SetSMBDataLength(outp, 0);   /* Perhaps we should specify 8 bytes anyway */
3106         }
3107     }
3108     else if (v3ProtoIndex != -1) {
3109         smb_SetSMBParm(outp, 0, protoIndex);
3110
3111         /* NOTE: Extended authentication cannot be negotiated with v3
3112          * therefore we fail over to NTLM 
3113          */
3114         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3115             smb_SetSMBParm(outp, 1,
3116                            NEGOTIATE_SECURITY_USER_LEVEL |
3117                            NEGOTIATE_SECURITY_CHALLENGE_RESPONSE);      /* user level security, challenge response */
3118         } else {
3119             smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3120         }
3121         smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3122         smb_SetSMBParm(outp, 3, smb_maxMpxRequests);    /* max multiplexed requests */
3123         smb_SetSMBParm(outp, 4, smb_maxVCPerServer);    /* max VCs per consumer/server connection */
3124         smb_SetSMBParm(outp, 5, 0);     /* no support of block mode for read or write */
3125         smb_SetSMBParm(outp, 6, 1);     /* next 2: session key */
3126         smb_SetSMBParm(outp, 7, 1);
3127         time(&unixTime);
3128         smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3129         smb_SetSMBParm(outp, 8, LOWORD(dosTime));       /* server time */
3130         smb_SetSMBParm(outp, 9, HIWORD(dosTime));       /* server date */
3131
3132         GetTimeZoneInformation(&tzi);
3133         smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias);    /* server tzone */
3134
3135         /* NOTE: Extended authentication cannot be negotiated with v3
3136          * therefore we fail over to NTLM 
3137          */
3138         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3139             smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH);  /* encryption key length */
3140             smb_SetSMBParm(outp, 12, 0);        /* resvd */
3141             smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);   /* perhaps should specify 8 bytes anyway */
3142             datap = smb_GetSMBData(outp, NULL);
3143             /* paste in a new encryption key */
3144             memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3145             /* and the faux domain name */
3146             strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
3147         } else {
3148             smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3149             smb_SetSMBParm(outp, 12, 0); /* resvd */
3150             smb_SetSMBDataLength(outp, 0);
3151         }
3152     }
3153     else if (coreProtoIndex != -1) {     /* not really supported anymore */
3154         smb_SetSMBParm(outp, 0, protoIndex);
3155         smb_SetSMBDataLength(outp, 0);
3156     }
3157     return 0;
3158 }
3159
3160 void smb_Daemon(void *parmp)
3161 {
3162     afs_uint32 count = 0;
3163
3164     while(smbShutdownFlag == 0) {
3165         count++;
3166         thrd_Sleep(10000);
3167
3168         if (smbShutdownFlag == 1)
3169             break;
3170         
3171         if ((count % 72) == 0)  {       /* every five minutes */
3172             struct tm myTime;
3173             time_t old_localZero = smb_localZero;
3174                  
3175             /* Initialize smb_localZero */
3176             myTime.tm_isdst = -1;               /* compute whether on DST or not */
3177             myTime.tm_year = 70;
3178             myTime.tm_mon = 0;
3179             myTime.tm_mday = 1;
3180             myTime.tm_hour = 0;
3181             myTime.tm_min = 0;
3182             myTime.tm_sec = 0;
3183             smb_localZero = mktime(&myTime);
3184
3185 #ifndef USE_NUMERIC_TIME_CONV
3186             smb_CalculateNowTZ();
3187 #endif /* USE_NUMERIC_TIME_CONV */
3188 #ifdef AFS_FREELANCE
3189             if ( smb_localZero != old_localZero )
3190                 cm_noteLocalMountPointChange();
3191 #endif
3192         }
3193         /* XXX GC dir search entries */
3194     }
3195 }
3196
3197 void smb_WaitingLocksDaemon()
3198 {
3199     smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3200     smb_waitingLock_t *wl, *wlNext;
3201     int first;
3202     smb_vc_t *vcp;
3203     smb_packet_t *inp, *outp;
3204     NCB *ncbp;
3205     long code = 0;
3206
3207     while (smbShutdownFlag == 0) {
3208         lock_ObtainWrite(&smb_globalLock);
3209         nwlRequest = smb_allWaitingLocks;
3210         if (nwlRequest == NULL) {
3211             osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
3212             thrd_Sleep(1000);
3213             continue;
3214         } else {
3215             first = 1;
3216             osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
3217         }
3218
3219         do {
3220             if (first)
3221                 first = 0;
3222             else
3223                 lock_ObtainWrite(&smb_globalLock);
3224
3225             osi_Log1(smb_logp, "    Checking waiting lock request %p", nwlRequest);
3226
3227             wlRequest = nwlRequest;
3228             nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3229             lock_ReleaseWrite(&smb_globalLock);
3230
3231             code = 0;
3232
3233             for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3234                 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3235                     continue;
3236
3237                 osi_assert(wl->state != SMB_WAITINGLOCKSTATE_ERROR);
3238                 
3239                 /* wl->state is either _DONE or _WAITING.  _ERROR
3240                    would no longer be on the queue. */
3241                 code = cm_RetryLock( wl->lockp,
3242                                      !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3243
3244                 if (code == 0) {
3245                     wl->state = SMB_WAITINGLOCKSTATE_DONE;
3246                 } else if (code != CM_ERROR_WOULDBLOCK) {
3247                     wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3248                     break;
3249                 }
3250             }
3251
3252             if (code == CM_ERROR_WOULDBLOCK) {
3253
3254                 /* no progress */
3255                 if (wlRequest->timeRemaining != 0xffffffff
3256                      && (wlRequest->timeRemaining -= 1000) < 0)
3257                     goto endWait;
3258
3259                 continue;
3260             }
3261
3262           endWait:
3263
3264             if (code != 0) {
3265                 cm_scache_t * scp;
3266                 cm_req_t req;
3267
3268                 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
3269                          wlRequest);
3270
3271                 scp = wlRequest->scp;
3272
3273                 cm_InitReq(&req);
3274
3275                 lock_ObtainMutex(&scp->mx);
3276
3277                 for (wl = wlRequest->locks; wl; wl = wlNext) {
3278                     wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3279                     
3280                     cm_Unlock(scp, wlRequest->lockType, wl->LOffset, 
3281                               wl->LLength, wl->key, NULL, &req);
3282
3283                     osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3284
3285                     free(wl);
3286                 }
3287                 
3288                 lock_ReleaseMutex(&scp->mx);
3289
3290             } else {
3291
3292                 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
3293                          wlRequest);
3294
3295                 for (wl = wlRequest->locks; wl; wl = wlNext) {
3296                     wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3297                     osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3298                     free(wl);
3299                 }
3300             }
3301
3302             vcp = wlRequest->vcp;
3303             inp = wlRequest->inp;
3304             outp = wlRequest->outp;
3305             ncbp = GetNCB();
3306             ncbp->ncb_length = inp->ncb_length;
3307             inp->spacep = cm_GetSpace();
3308
3309             /* Remove waitingLock from list */
3310             lock_ObtainWrite(&smb_globalLock);
3311             osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3312                          &wlRequest->q);
3313             lock_ReleaseWrite(&smb_globalLock);
3314
3315             /* Resume packet processing */
3316             if (code == 0)
3317                 smb_SetSMBDataLength(outp, 0);
3318             outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3319             outp->resumeCode = code;
3320             outp->ncbp = ncbp;
3321             smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3322
3323             /* Clean up */
3324             cm_FreeSpace(inp->spacep);
3325             smb_FreePacket(inp);
3326             smb_FreePacket(outp);
3327             smb_ReleaseVC(vcp);
3328             cm_ReleaseSCache(wlRequest->scp);
3329             FreeNCB(ncbp);
3330             free(wlRequest);
3331         } while (nwlRequest && smbShutdownFlag == 0);
3332         thrd_Sleep(1000);
3333     }
3334 }
3335
3336 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3337 {
3338     osi_Log0(smb_logp, "SMB receive get disk attributes");
3339
3340     smb_SetSMBParm(outp, 0, 32000);
3341     smb_SetSMBParm(outp, 1, 64);
3342     smb_SetSMBParm(outp, 2, 1024);
3343     smb_SetSMBParm(outp, 3, 30000);
3344     smb_SetSMBParm(outp, 4, 0);
3345     smb_SetSMBDataLength(outp, 0);
3346     return 0;
3347 }
3348
3349 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3350 {
3351     smb_tid_t *tidp;
3352     smb_user_t *uidp;
3353     unsigned short newTid;
3354     char shareName[256];
3355     char *sharePath;
3356     int shareFound;
3357     char *tp;
3358     char *pathp;
3359     char *passwordp;
3360     cm_user_t *userp;
3361
3362     osi_Log0(smb_logp, "SMB receive tree connect");
3363
3364     /* parse input parameters */
3365     tp = smb_GetSMBData(inp, NULL);
3366     pathp = smb_ParseASCIIBlock(tp, &tp);
3367     if (smb_StoreAnsiFilenames)
3368         OemToChar(pathp,pathp);
3369     passwordp = smb_ParseASCIIBlock(tp, &tp);
3370     tp = strrchr(pathp, '\\');
3371     if (!tp)
3372         return CM_ERROR_BADSMB;
3373     strcpy(shareName, tp+1);
3374
3375     userp = smb_GetUser(vcp, inp);
3376
3377     lock_ObtainMutex(&vcp->mx);
3378     newTid = vcp->tidCounter++;
3379     lock_ReleaseMutex(&vcp->mx);
3380
3381     tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3382     uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3383     shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3384     if (uidp)
3385         smb_ReleaseUID(uidp);
3386     if (!shareFound) {
3387         smb_ReleaseTID(tidp);
3388         return CM_ERROR_BADSHARENAME;
3389     }
3390     lock_ObtainMutex(&tidp->mx);
3391     tidp->userp = userp;
3392     tidp->pathname = sharePath;
3393     lock_ReleaseMutex(&tidp->mx);
3394     smb_ReleaseTID(tidp);
3395
3396     smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3397     smb_SetSMBParm(rsp, 1, newTid);
3398     smb_SetSMBDataLength(rsp, 0);
3399
3400     osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3401     return 0;
3402 }
3403
3404 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3405 {
3406     int tlen;
3407
3408     if (*inp++ != 0x1) return NULL;
3409     tlen = inp[0] + (inp[1]<<8);
3410     inp += 2;           /* skip length field */
3411         
3412     if (chainpp) {
3413         *chainpp = inp + tlen;
3414     }   
3415
3416     if (lengthp) *lengthp = tlen;
3417         
3418     return inp;
3419 }
3420
3421 /* set maskp to the mask part of the incoming path.
3422  * Mask is 11 bytes long (8.3 with the dot elided).
3423  * Returns true if succeeds with a valid name, otherwise it does
3424  * its best, but returns false.
3425  */
3426 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3427 {
3428     char *tp;
3429     char *up;
3430     int i;
3431     int tc;
3432     int valid8Dot3;
3433
3434     /* starts off valid */
3435     valid8Dot3 = 1;
3436
3437     /* mask starts out all blanks */
3438     memset(maskp, ' ', 11);
3439
3440     /* find last backslash, or use whole thing if there is none */
3441     tp = strrchr(pathp, '\\');
3442     if (!tp) tp = pathp;
3443     else tp++;  /* skip slash */
3444         
3445     up = maskp;
3446
3447     /* names starting with a dot are illegal */
3448     if (*tp == '.') valid8Dot3 = 0;
3449
3450     for(i=0;; i++) {
3451         tc = *tp++;
3452         if (tc == 0) return valid8Dot3;
3453         if (tc == '.' || tc == '"') break;
3454         if (i < 8) *up++ = tc;
3455         else valid8Dot3 = 0;
3456     }
3457         
3458     /* if we get here, tp point after the dot */
3459     up = maskp+8;       /* ext goes here */
3460     for(i=0;;i++) {
3461         tc = *tp++;
3462         if (tc == 0) 
3463             return valid8Dot3;
3464
3465         /* too many dots */
3466         if (tc == '.' || tc == '"') 
3467             valid8Dot3 = 0;
3468
3469         /* copy extension if not too long */
3470         if (i < 3) 
3471             *up++ = tc;
3472         else 
3473             valid8Dot3 = 0;
3474     }   
3475
3476     /* unreachable */
3477 }
3478
3479 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3480 {
3481     char umask[11];
3482     int valid;
3483     int i;
3484     char tc1;
3485     char tc2;
3486     char *tp1;
3487     char *tp2;
3488
3489     /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3490
3491     valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3492     if (!valid) 
3493         return 0;
3494  
3495     /* otherwise, we have a valid 8.3 name; see if we have a match,
3496      * treating '?' as a wildcard in maskp (but not in the file name).
3497      */
3498     tp1 = umask;        /* real name, in mask format */
3499     tp2 = maskp;        /* mask, in mask format */
3500     for(i=0; i<11; i++) {
3501         tc1 = *tp1++;   /* char from real name */
3502         tc2 = *tp2++;   /* char from mask */
3503         tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3504         tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3505         if (tc1 == tc2) 
3506             continue;
3507         if (tc2 == '?' && tc1 != ' ') 
3508             continue;
3509         if (tc2 == '>') 
3510             continue;
3511         return 0;
3512     }
3513
3514     /* we got a match */
3515     return 1;
3516 }
3517
3518 char *smb_FindMask(char *pathp)
3519 {
3520     char *tp;
3521         
3522     tp = strrchr(pathp, '\\');  /* find last slash */
3523
3524     if (tp) 
3525         return tp+1;    /* skip the slash */
3526     else 
3527         return pathp;   /* no slash, return the entire path */
3528 }       
3529
3530 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3531 {
3532     unsigned char *pathp;
3533     unsigned char *tp;
3534     unsigned char mask[11];
3535     unsigned char *statBlockp;
3536     unsigned char initStatBlock[21];
3537     int statLen;
3538         
3539     osi_Log0(smb_logp, "SMB receive search volume");
3540
3541     /* pull pathname and stat block out of request */
3542     tp = smb_GetSMBData(inp, NULL);
3543     pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3544     osi_assert(pathp != NULL);
3545     if (smb_StoreAnsiFilenames)
3546         OemToChar(pathp,pathp);
3547     statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3548     osi_assert(statBlockp != NULL);
3549     if (statLen == 0) {
3550         statBlockp = initStatBlock;
3551         statBlockp[0] = 8;
3552     }
3553         
3554     /* for returning to caller */
3555     smb_Get8Dot3MaskFromPath(mask, pathp);
3556
3557     smb_SetSMBParm(outp, 0, 1);         /* we're returning one entry */
3558     tp = smb_GetSMBData(outp, NULL);
3559     *tp++ = 5;
3560     *tp++ = 43; /* bytes in a dir entry */
3561     *tp++ = 0;  /* high byte in counter */
3562
3563     /* now marshall the dir entry, starting with the search status */
3564     *tp++ = statBlockp[0];              /* Reserved */
3565     memcpy(tp, mask, 11); tp += 11;     /* FileName */
3566
3567     /* now pass back server use info, with 1st byte non-zero */
3568     *tp++ = 1;
3569     memset(tp, 0, 4); tp += 4;  /* reserved for server use */
3570
3571     memcpy(tp, statBlockp+17, 4); tp += 4;      /* reserved for consumer */
3572
3573     *tp++ = 0x8;                /* attribute: volume */
3574
3575     /* copy out time */
3576     *tp++ = 0;
3577     *tp++ = 0;
3578
3579     /* copy out date */
3580     *tp++ = 18;
3581     *tp++ = 178;
3582
3583     /* 4 byte file size */
3584     *tp++ = 0;
3585     *tp++ = 0;
3586     *tp++ = 0;
3587     *tp++ = 0;
3588
3589     /* finally, null-terminated 8.3 pathname, which we set to AFS */
3590     memset(tp, ' ', 13);
3591     strcpy(tp, "AFS");
3592
3593     /* set the length of the data part of the packet to 43 + 3, for the dir
3594      * entry plus the 5 and the length fields.
3595      */
3596     smb_SetSMBDataLength(outp, 46);
3597     return 0;
3598 }       
3599
3600 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3601                              cm_user_t *userp, cm_req_t *reqp)
3602 {
3603     long code = 0;
3604     cm_scache_t *scp;
3605     char *dptr;
3606     afs_uint32 dosTime;
3607     u_short shortTemp;
3608     char attr;
3609     smb_dirListPatch_t *patchp;
3610     smb_dirListPatch_t *npatchp;
3611
3612     for (patchp = *dirPatchespp; patchp; patchp =
3613          (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3614
3615         dptr = patchp->dptr;
3616
3617         code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3618         if (code) {
3619             if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3620                 *dptr++ = SMB_ATTR_HIDDEN;
3621             continue;
3622         }
3623         lock_ObtainMutex(&scp->mx);
3624         code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3625                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3626         if (code) {     
3627             lock_ReleaseMutex(&scp->mx);
3628             cm_ReleaseSCache(scp);
3629             if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3630                 *dptr++ = SMB_ATTR_HIDDEN;
3631             continue;
3632         }
3633
3634         attr = smb_Attributes(scp);
3635         /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3636         if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3637             attr |= SMB_ATTR_HIDDEN;
3638         *dptr++ = attr;
3639
3640         /* get dos time */
3641         smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3642                 
3643         /* copy out time */
3644         shortTemp = (unsigned short) (dosTime & 0xffff);
3645         *((u_short *)dptr) = shortTemp;
3646         dptr += 2;
3647
3648         /* and copy out date */
3649         shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3650         *((u_short *)dptr) = shortTemp;
3651         dptr += 2;
3652                 
3653         /* copy out file length */
3654         *((u_long *)dptr) = scp->length.LowPart;
3655         dptr += 4;
3656         lock_ReleaseMutex(&scp->mx);
3657         cm_ReleaseSCache(scp);
3658     }
3659         
3660     /* now free the patches */
3661     for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3662         npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3663         free(patchp);
3664     }   
3665         
3666     /* and mark the list as empty */
3667     *dirPatchespp = NULL;
3668
3669     return code;
3670 }
3671
3672 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3673 {
3674     int attribute;
3675     long nextCookie;
3676     char *tp;
3677     long code = 0;
3678     char *pathp;
3679     cm_dirEntry_t *dep;
3680     int maxCount;
3681     smb_dirListPatch_t *dirListPatchesp;
3682     smb_dirListPatch_t *curPatchp;
3683     int dataLength;
3684     cm_buf_t *bufferp;
3685     long temp;
3686     osi_hyper_t dirLength;
3687     osi_hyper_t bufferOffset;
3688     osi_hyper_t curOffset;
3689     osi_hyper_t thyper;
3690     unsigned char *inCookiep;
3691     smb_dirSearch_t *dsp;
3692     cm_scache_t *scp;
3693     long entryInDir;
3694     long entryInBuffer;
3695     unsigned long clientCookie;
3696     cm_pageHeader_t *pageHeaderp;
3697     cm_user_t *userp = NULL;
3698     int slotInPage;
3699     char shortName[13];
3700     char *actualName;
3701     char *shortNameEnd;
3702     char mask[11];
3703     int returnedNames;
3704     long nextEntryCookie;
3705     int numDirChunks;           /* # of 32 byte dir chunks in this entry */
3706     char resByte;               /* reserved byte from the cookie */
3707     char *op;                   /* output data ptr */
3708     char *origOp;               /* original value of op */
3709     cm_space_t *spacep;         /* for pathname buffer */
3710     int starPattern;
3711     int rootPath = 0;
3712     int caseFold;
3713     char *tidPathp;
3714     cm_req_t req;
3715     cm_fid_t fid;
3716     int fileType;
3717
3718     cm_InitReq(&req);
3719
3720     maxCount = smb_GetSMBParm(inp, 0);
3721
3722     dirListPatchesp = NULL;
3723         
3724     caseFold = CM_FLAG_CASEFOLD;
3725
3726     tp = smb_GetSMBData(inp, NULL);
3727     pathp = smb_ParseASCIIBlock(tp, &tp);
3728     if (smb_StoreAnsiFilenames)
3729         OemToChar(pathp,pathp);
3730     inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3731
3732     /* bail out if request looks bad */
3733     if (!tp || !pathp) {
3734         return CM_ERROR_BADSMB;
3735     }
3736
3737     /* We can handle long names */
3738     if (vcp->flags & SMB_VCFLAG_USENT)
3739         ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
3740
3741     /* make sure we got a whole search status */
3742     if (dataLength < 21) {
3743         nextCookie