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