windows-smb-and-symlinks-20041213
[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 = SMB_FLAGS2_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          * and DFS */
2769         caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
2770 #ifdef DFS_SUPPORT
2771                NTNEGOTIATE_CAPABILITY_DFS |
2772 #endif
2773                NTNEGOTIATE_CAPABILITY_NTFIND |
2774                NTNEGOTIATE_CAPABILITY_RAWMODE |
2775                NTNEGOTIATE_CAPABILITY_NTSMB;
2776
2777         if ( smb_authType == SMB_AUTH_EXTENDED )
2778             caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
2779
2780         smb_SetSMBParmLong(outp, 9, caps);
2781         time(&unixTime);
2782         smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2783         smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
2784         smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
2785
2786         GetTimeZoneInformation(&tzi);
2787         smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias);    /* server tzone */
2788
2789         if (smb_authType == SMB_AUTH_NTLM) {
2790             smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
2791             smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
2792             /* paste in encryption key */
2793             datap = smb_GetSMBData(outp, NULL);
2794             memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
2795             /* and the faux domain name */
2796             strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
2797         } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
2798             void * secBlob;
2799             int secBlobLength;
2800
2801             smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2802
2803             smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
2804
2805             smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
2806                         
2807             datap = smb_GetSMBData(outp, NULL);
2808             memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
2809
2810             if (secBlob) {
2811                 datap += sizeof(smb_ServerGUID);
2812                 memcpy(datap, secBlob, secBlobLength);
2813                 free(secBlob);
2814             }
2815         } else {
2816             smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2817             smb_SetSMBDataLength(outp, 0);   /* Perhaps we should specify 8 bytes anyway */
2818         }
2819     }
2820     else if (v3ProtoIndex != -1) {
2821         smb_SetSMBParm(outp, 0, protoIndex);
2822
2823         /* NOTE: Extended authentication cannot be negotiated with v3
2824          * therefore we fail over to NTLM 
2825          */
2826         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2827             smb_SetSMBParm(outp, 1,
2828                            NEGOTIATE_SECURITY_USER_LEVEL |
2829                            NEGOTIATE_SECURITY_CHALLENGE_RESPONSE);      /* user level security, challenge response */
2830         } else {
2831             smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
2832         }
2833         smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
2834         smb_SetSMBParm(outp, 3, smb_maxMpxRequests);    /* max multiplexed requests */
2835         smb_SetSMBParm(outp, 4, smb_maxVCPerServer);    /* max VCs per consumer/server connection */
2836         smb_SetSMBParm(outp, 5, 0);     /* no support of block mode for read or write */
2837         smb_SetSMBParm(outp, 6, 1);     /* next 2: session key */
2838         smb_SetSMBParm(outp, 7, 1);
2839         time(&unixTime);
2840         smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2841         smb_SetSMBParm(outp, 8, LOWORD(dosTime));       /* server time */
2842         smb_SetSMBParm(outp, 9, HIWORD(dosTime));       /* server date */
2843
2844         GetTimeZoneInformation(&tzi);
2845         smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias);    /* server tzone */
2846
2847         /* NOTE: Extended authentication cannot be negotiated with v3
2848          * therefore we fail over to NTLM 
2849          */
2850         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2851             smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH);  /* encryption key length */
2852             smb_SetSMBParm(outp, 12, 0);        /* resvd */
2853             smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);   /* perhaps should specify 8 bytes anyway */
2854             datap = smb_GetSMBData(outp, NULL);
2855             /* paste in a new encryption key */
2856             memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
2857             /* and the faux domain name */
2858             strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
2859         } else {
2860             smb_SetSMBParm(outp, 11, 0); /* encryption key length */
2861             smb_SetSMBParm(outp, 12, 0); /* resvd */
2862             smb_SetSMBDataLength(outp, 0);
2863         }
2864     }
2865     else if (coreProtoIndex != -1) {     /* not really supported anymore */
2866         smb_SetSMBParm(outp, 0, protoIndex);
2867         smb_SetSMBDataLength(outp, 0);
2868     }
2869     return 0;
2870 }
2871
2872 void smb_Daemon(void *parmp)
2873 {
2874     afs_uint32 count = 0;
2875
2876     while(smbShutdownFlag == 0) {
2877         count++;
2878         thrd_Sleep(10000);
2879
2880         if (smbShutdownFlag == 1)
2881             break;
2882         
2883         if ((count % 72) == 0)  {       /* every five minutes */
2884             struct tm myTime;
2885             time_t old_localZero = smb_localZero;
2886                  
2887             /* Initialize smb_localZero */
2888             myTime.tm_isdst = -1;               /* compute whether on DST or not */
2889             myTime.tm_year = 70;
2890             myTime.tm_mon = 0;
2891             myTime.tm_mday = 1;
2892             myTime.tm_hour = 0;
2893             myTime.tm_min = 0;
2894             myTime.tm_sec = 0;
2895             smb_localZero = mktime(&myTime);
2896
2897             smb_CalculateNowTZ();
2898
2899 #ifdef AFS_FREELANCE
2900             if ( smb_localZero != old_localZero )
2901                 cm_noteLocalMountPointChange();
2902 #endif
2903         }
2904         /* XXX GC dir search entries */
2905     }
2906 }
2907
2908 void smb_WaitingLocksDaemon()
2909 {
2910     smb_waitingLock_t *wL, *nwL;
2911     int first;
2912     smb_vc_t *vcp;
2913     smb_packet_t *inp, *outp;
2914     NCB *ncbp;
2915     long code = 0;
2916
2917     while (1) {
2918         lock_ObtainWrite(&smb_globalLock);
2919         nwL = smb_allWaitingLocks;
2920         if (nwL == NULL) {
2921             osi_SleepW((long)&smb_allWaitingLocks, &smb_globalLock);
2922             thrd_Sleep(1000);
2923             continue;
2924         }
2925         else first = 1;
2926         do {
2927             if (first)
2928                 first = 0;
2929             else
2930                 lock_ObtainWrite(&smb_globalLock);
2931             wL = nwL;
2932             nwL = (smb_waitingLock_t *) osi_QNext(&wL->q);
2933             lock_ReleaseWrite(&smb_globalLock);
2934             code = cm_RetryLock((cm_file_lock_t *) wL->lockp,
2935                                  wL->vcp->flags & SMB_VCFLAG_ALREADYDEAD);
2936             if (code == CM_ERROR_WOULDBLOCK) {
2937                 /* no progress */
2938                 if (wL->timeRemaining != 0xffffffff
2939                      && (wL->timeRemaining -= 1000) < 0)
2940                     goto endWait;
2941                 continue;
2942             }
2943           endWait:
2944             vcp = wL->vcp;
2945             inp = wL->inp;
2946             outp = wL->outp;
2947             ncbp = GetNCB();
2948             ncbp->ncb_length = inp->ncb_length;
2949             inp->spacep = cm_GetSpace();
2950
2951             /* Remove waitingLock from list */
2952             lock_ObtainWrite(&smb_globalLock);
2953             osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
2954                          &wL->q);
2955             lock_ReleaseWrite(&smb_globalLock);
2956
2957             /* Resume packet processing */
2958             if (code == 0)
2959                 smb_SetSMBDataLength(outp, 0);
2960             outp->flags |= SMB_PACKETFLAG_SUSPENDED;
2961             outp->resumeCode = code;
2962             outp->ncbp = ncbp;
2963             smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
2964
2965             /* Clean up */
2966             cm_FreeSpace(inp->spacep);
2967             smb_FreePacket(inp);
2968             smb_FreePacket(outp);
2969             FreeNCB(ncbp);
2970             free(wL);
2971         } while (nwL);
2972         thrd_Sleep(1000);
2973     }
2974 }
2975
2976 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2977 {
2978     osi_Log0(smb_logp, "SMB receive get disk attributes");
2979
2980     smb_SetSMBParm(outp, 0, 32000);
2981     smb_SetSMBParm(outp, 1, 64);
2982     smb_SetSMBParm(outp, 2, 1024);
2983     smb_SetSMBParm(outp, 3, 30000);
2984     smb_SetSMBParm(outp, 4, 0);
2985     smb_SetSMBDataLength(outp, 0);
2986     return 0;
2987 }
2988
2989 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
2990 {
2991     smb_tid_t *tidp;
2992     smb_user_t *uidp;
2993     unsigned short newTid;
2994     char shareName[256];
2995     char *sharePath;
2996     int shareFound;
2997     char *tp;
2998     char *pathp;
2999     char *passwordp;
3000     cm_user_t *userp;
3001
3002     osi_Log0(smb_logp, "SMB receive tree connect");
3003
3004     /* parse input parameters */
3005     tp = smb_GetSMBData(inp, NULL);
3006     pathp = smb_ParseASCIIBlock(tp, &tp);
3007     if (smb_StoreAnsiFilenames)
3008         OemToChar(pathp,pathp);
3009     passwordp = smb_ParseASCIIBlock(tp, &tp);
3010     tp = strrchr(pathp, '\\');
3011     if (!tp)
3012         return CM_ERROR_BADSMB;
3013     strcpy(shareName, tp+1);
3014
3015     userp = smb_GetUser(vcp, inp);
3016
3017     lock_ObtainMutex(&vcp->mx);
3018     newTid = vcp->tidCounter++;
3019     lock_ReleaseMutex(&vcp->mx);
3020
3021     tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3022     uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3023     shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3024     if (uidp)
3025         smb_ReleaseUID(uidp);
3026     if (!shareFound) {
3027         smb_ReleaseTID(tidp);
3028         return CM_ERROR_BADSHARENAME;
3029     }
3030     lock_ObtainMutex(&tidp->mx);
3031     tidp->userp = userp;
3032     tidp->pathname = sharePath;
3033     lock_ReleaseMutex(&tidp->mx);
3034     smb_ReleaseTID(tidp);
3035
3036     smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3037     smb_SetSMBParm(rsp, 1, newTid);
3038     smb_SetSMBDataLength(rsp, 0);
3039
3040     osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3041     return 0;
3042 }
3043
3044 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3045 {
3046     int tlen;
3047
3048     if (*inp++ != 0x1) return NULL;
3049     tlen = inp[0] + (inp[1]<<8);
3050     inp += 2;           /* skip length field */
3051         
3052     if (chainpp) {
3053         *chainpp = inp + tlen;
3054     }   
3055
3056     if (lengthp) *lengthp = tlen;
3057         
3058     return inp;
3059 }
3060
3061 /* set maskp to the mask part of the incoming path.
3062  * Mask is 11 bytes long (8.3 with the dot elided).
3063  * Returns true if succeeds with a valid name, otherwise it does
3064  * its best, but returns false.
3065  */
3066 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3067 {
3068     char *tp;
3069     char *up;
3070     int i;
3071     int tc;
3072     int valid8Dot3;
3073
3074     /* starts off valid */
3075     valid8Dot3 = 1;
3076
3077     /* mask starts out all blanks */
3078     memset(maskp, ' ', 11);
3079
3080     /* find last backslash, or use whole thing if there is none */
3081     tp = strrchr(pathp, '\\');
3082     if (!tp) tp = pathp;
3083     else tp++;  /* skip slash */
3084         
3085     up = maskp;
3086
3087     /* names starting with a dot are illegal */
3088     if (*tp == '.') valid8Dot3 = 0;
3089
3090     for(i=0;; i++) {
3091         tc = *tp++;
3092         if (tc == 0) return valid8Dot3;
3093         if (tc == '.' || tc == '"') break;
3094         if (i < 8) *up++ = tc;
3095         else valid8Dot3 = 0;
3096     }
3097         
3098     /* if we get here, tp point after the dot */
3099     up = maskp+8;       /* ext goes here */
3100     for(i=0;;i++) {
3101         tc = *tp++;
3102         if (tc == 0) 
3103             return valid8Dot3;
3104
3105         /* too many dots */
3106         if (tc == '.' || tc == '"') 
3107             valid8Dot3 = 0;
3108
3109         /* copy extension if not too long */
3110         if (i < 3) 
3111             *up++ = tc;
3112         else 
3113             valid8Dot3 = 0;
3114     }   
3115
3116     /* unreachable */
3117 }
3118
3119 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3120 {
3121     char umask[11];
3122     int valid;
3123     int i;
3124     char tc1;
3125     char tc2;
3126     char *tp1;
3127     char *tp2;
3128
3129     /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3130
3131     valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3132     if (!valid) 
3133         return 0;
3134  
3135     /* otherwise, we have a valid 8.3 name; see if we have a match,
3136      * treating '?' as a wildcard in maskp (but not in the file name).
3137      */
3138     tp1 = umask;        /* real name, in mask format */
3139     tp2 = maskp;        /* mask, in mask format */
3140     for(i=0; i<11; i++) {
3141         tc1 = *tp1++;   /* char from real name */
3142         tc2 = *tp2++;   /* char from mask */
3143         tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3144         tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3145         if (tc1 == tc2) 
3146             continue;
3147         if (tc2 == '?' && tc1 != ' ') 
3148             continue;
3149         if (tc2 == '>') 
3150             continue;
3151         return 0;
3152     }
3153
3154     /* we got a match */
3155     return 1;
3156 }
3157
3158 char *smb_FindMask(char *pathp)
3159 {
3160     char *tp;
3161         
3162     tp = strrchr(pathp, '\\');  /* find last slash */
3163
3164     if (tp) 
3165         return tp+1;    /* skip the slash */
3166     else 
3167         return pathp;   /* no slash, return the entire path */
3168 }       
3169
3170 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3171 {
3172     unsigned char *pathp;
3173     unsigned char *tp;
3174     unsigned char mask[11];
3175     unsigned char *statBlockp;
3176     unsigned char initStatBlock[21];
3177     int statLen;
3178         
3179     osi_Log0(smb_logp, "SMB receive search volume");
3180
3181     /* pull pathname and stat block out of request */
3182     tp = smb_GetSMBData(inp, NULL);
3183     pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3184     osi_assert(pathp != NULL);
3185     if (smb_StoreAnsiFilenames)
3186         OemToChar(pathp,pathp);
3187     statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3188     osi_assert(statBlockp != NULL);
3189     if (statLen == 0) {
3190         statBlockp = initStatBlock;
3191         statBlockp[0] = 8;
3192     }
3193         
3194     /* for returning to caller */
3195     smb_Get8Dot3MaskFromPath(mask, pathp);
3196
3197     smb_SetSMBParm(outp, 0, 1);         /* we're returning one entry */
3198     tp = smb_GetSMBData(outp, NULL);
3199     *tp++ = 5;
3200     *tp++ = 43; /* bytes in a dir entry */
3201     *tp++ = 0;  /* high byte in counter */
3202
3203     /* now marshall the dir entry, starting with the search status */
3204     *tp++ = statBlockp[0];              /* Reserved */
3205     memcpy(tp, mask, 11); tp += 11;     /* FileName */
3206
3207     /* now pass back server use info, with 1st byte non-zero */
3208     *tp++ = 1;
3209     memset(tp, 0, 4); tp += 4;  /* reserved for server use */
3210
3211     memcpy(tp, statBlockp+17, 4); tp += 4;      /* reserved for consumer */
3212
3213     *tp++ = 0x8;                /* attribute: volume */
3214
3215     /* copy out time */
3216     *tp++ = 0;
3217     *tp++ = 0;
3218
3219     /* copy out date */
3220     *tp++ = 18;
3221     *tp++ = 178;
3222
3223     /* 4 byte file size */
3224     *tp++ = 0;
3225     *tp++ = 0;
3226     *tp++ = 0;
3227     *tp++ = 0;
3228
3229     /* finally, null-terminated 8.3 pathname, which we set to AFS */
3230     memset(tp, ' ', 13);
3231     strcpy(tp, "AFS");
3232
3233     /* set the length of the data part of the packet to 43 + 3, for the dir
3234      * entry plus the 5 and the length fields.
3235      */
3236     smb_SetSMBDataLength(outp, 46);
3237     return 0;
3238 }       
3239
3240 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3241                              cm_user_t *userp, cm_req_t *reqp)
3242 {
3243     long code = 0;
3244     cm_scache_t *scp;
3245     char *dptr;
3246     time_t dosTime;
3247     u_short shortTemp;
3248     char attr;
3249     smb_dirListPatch_t *patchp;
3250     smb_dirListPatch_t *npatchp;
3251
3252     for (patchp = *dirPatchespp; patchp; patchp =
3253          (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3254
3255         dptr = patchp->dptr;
3256
3257         code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3258         if (code) {
3259             if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3260                 *dptr++ = SMB_ATTR_HIDDEN;
3261             continue;
3262         }
3263         lock_ObtainMutex(&scp->mx);
3264         code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3265                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3266         if (code) {     
3267             lock_ReleaseMutex(&scp->mx);
3268             cm_ReleaseSCache(scp);
3269             if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3270                 *dptr++ = SMB_ATTR_HIDDEN;
3271             continue;
3272         }
3273
3274         attr = smb_Attributes(scp);
3275         /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3276         if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3277             attr |= SMB_ATTR_HIDDEN;
3278         *dptr++ = attr;
3279
3280         /* get dos time */
3281         smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3282                 
3283         /* copy out time */
3284         shortTemp = (unsigned short) (dosTime & 0xffff);
3285         *((u_short *)dptr) = shortTemp;
3286         dptr += 2;
3287
3288         /* and copy out date */
3289         shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3290         *((u_short *)dptr) = shortTemp;
3291         dptr += 2;
3292                 
3293         /* copy out file length */
3294         *((u_long *)dptr) = scp->length.LowPart;
3295         dptr += 4;
3296         lock_ReleaseMutex(&scp->mx);
3297         cm_ReleaseSCache(scp);
3298     }
3299         
3300     /* now free the patches */
3301     for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3302         npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3303         free(patchp);
3304     }   
3305         
3306     /* and mark the list as empty */
3307     *dirPatchespp = NULL;
3308
3309     return code;
3310 }
3311
3312 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3313 {
3314     int attribute;
3315     long nextCookie;
3316     char *tp;
3317     long code = 0;
3318     char *pathp;
3319     cm_dirEntry_t *dep;
3320     int maxCount;
3321     smb_dirListPatch_t *dirListPatchesp;
3322     smb_dirListPatch_t *curPatchp;
3323     int dataLength;
3324     cm_buf_t *bufferp;
3325     long temp;
3326     osi_hyper_t dirLength;
3327     osi_hyper_t bufferOffset;
3328     osi_hyper_t curOffset;
3329     osi_hyper_t thyper;
3330     unsigned char *inCookiep;
3331     smb_dirSearch_t *dsp;
3332     cm_scache_t *scp;
3333     long entryInDir;
3334     long entryInBuffer;
3335     unsigned long clientCookie;
3336     cm_pageHeader_t *pageHeaderp;
3337     cm_user_t *userp = NULL;
3338     int slotInPage;
3339     char shortName[13];
3340     char *actualName;
3341     char *shortNameEnd;
3342     char mask[11];
3343     int returnedNames;
3344     long nextEntryCookie;
3345     int numDirChunks;           /* # of 32 byte dir chunks in this entry */
3346     char resByte;                       /* reserved byte from the cookie */
3347     char *op;                   /* output data ptr */
3348     char *origOp;                       /* original value of op */
3349     cm_space_t *spacep;         /* for pathname buffer */
3350     int starPattern;
3351     int rootPath = 0;
3352     int caseFold;
3353     char *tidPathp;
3354     cm_req_t req;
3355     cm_fid_t fid;
3356     int fileType;
3357
3358     cm_InitReq(&req);
3359
3360     maxCount = smb_GetSMBParm(inp, 0);
3361
3362     dirListPatchesp = NULL;
3363         
3364     caseFold = CM_FLAG_CASEFOLD;
3365
3366     tp = smb_GetSMBData(inp, NULL);
3367     pathp = smb_ParseASCIIBlock(tp, &tp);
3368     if (smb_StoreAnsiFilenames)
3369         OemToChar(pathp,pathp);
3370     inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3371
3372     /* bail out if request looks bad */
3373     if (!tp || !pathp) {
3374         return CM_ERROR_BADSMB;
3375     }
3376
3377     /* We can handle long names */
3378     if (vcp->flags & SMB_VCFLAG_USENT)
3379         ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
3380
3381     /* make sure we got a whole search status */
3382     if (dataLength < 21) {
3383         nextCookie = 0;         /* start at the beginning of the dir */
3384         resByte = 0;
3385         clientCookie = 0;
3386         attribute = smb_GetSMBParm(inp, 1);
3387
3388         /* handle volume info in another function */
3389         if (attribute & 0x8)
3390             return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3391
3392         osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3393                   maxCount, osi_LogSaveString(smb_logp, pathp));
3394
3395         if (*pathp == 0) {      /* null pathp, treat as root dir */
3396             if (!(attribute & SMB_ATTR_DIRECTORY))      /* exclude dirs */
3397                 return CM_ERROR_NOFILES;
3398             rootPath = 1;
3399         }
3400
3401         dsp = smb_NewDirSearch(0);
3402         dsp->attribute = attribute;
3403         smb_Get8Dot3MaskFromPath(mask, pathp);
3404         memcpy(dsp->mask, mask, 11);
3405
3406         /* track if this is likely to match a lot of entries */
3407         if (smb_IsStarMask(mask)) starPattern = 1;
3408         else starPattern = 0;
3409     }   
3410     else {
3411         /* pull the next cookie value out of the search status block */
3412         nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3413             + (inCookiep[16]<<24);
3414         dsp = smb_FindDirSearch(inCookiep[12]);
3415         if (!dsp) {
3416             /* can't find dir search status; fatal error */
3417             return CM_ERROR_BADFD;
3418         }
3419         attribute = dsp->attribute;
3420         resByte = inCookiep[0];
3421
3422         /* copy out client cookie, in host byte order.  Don't bother
3423          * interpreting it, since we're just passing it through, anyway.
3424          */
3425         memcpy(&clientCookie, &inCookiep[17], 4);
3426
3427         memcpy(mask, dsp->mask, 11);
3428
3429         /* assume we're doing a star match if it has continued for more
3430          * than one call.
3431          */
3432         starPattern = 1;
3433     }
3434
3435     osi_Log3(smb_logp, "SMB dir search cookie 0x%x, connection %d, attr 0x%x",
3436              nextCookie, dsp->cookie, attribute);
3437
3438     userp = smb_GetUser(vcp, inp);
3439
3440     /* try to get the vnode for the path name next */
3441     lock_ObtainMutex(&dsp->mx);
3442     if (dsp->scp) {
3443         scp = dsp->scp;
3444         cm_HoldSCache(scp);
3445         code = 0;
3446     }
3447     else {
3448         spacep = inp->spacep;
3449         smb_StripLastComponent(spacep->data, NULL, pathp);
3450         code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3451         if (code) {
3452             lock_ReleaseMutex(&dsp->mx);
3453             cm_ReleaseUser(userp);
3454             smb_DeleteDirSearch(dsp);
3455             smb_ReleaseDirSearch(dsp);
3456             return CM_ERROR_NOFILES;
3457         }
3458         code = cm_NameI(cm_rootSCachep, spacep->data,
3459                         caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3460         if (code == 0) {
3461             if (dsp->scp != 0) 
3462                 cm_ReleaseSCache(dsp->scp);
3463             dsp->scp = scp;
3464             /* we need one hold for the entry we just stored into,
3465              * and one for our own processing.  When we're done with this
3466              * function, we'll drop the one for our own processing.
3467              * We held it once from the namei call, and so we do another hold
3468              * now.
3469              */
3470             cm_HoldSCache(scp);
3471             lock_ObtainMutex(&scp->mx);
3472             if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3473                  && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3474                 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3475                 dsp->flags |= SMB_DIRSEARCH_BULKST;
3476             }
3477             lock_ReleaseMutex(&scp->mx);
3478         }
3479     }
3480     lock_ReleaseMutex(&dsp->mx);
3481     if (code) {
3482         cm_ReleaseUser(userp);
3483         smb_DeleteDirSearch(dsp);
3484         smb_ReleaseDirSearch(dsp);
3485         return code;
3486     }
3487
3488     /* reserves space for parameter; we'll adjust it again later to the
3489      * real count of the # of entries we returned once we've actually
3490      * assembled the directory listing.
3491      */
3492     smb_SetSMBParm(outp, 0, 0);
3493
3494     /* get the directory size */
3495     lock_ObtainMutex(&scp->mx);
3496     code = cm_SyncOp(scp, NULL, userp, &req, 0,
3497                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3498     if (code) {
3499         lock_ReleaseMutex(&scp->mx);
3500         cm_ReleaseSCache(scp);
3501         cm_ReleaseUser(userp);
3502         smb_DeleteDirSearch(dsp);
3503         smb_ReleaseDirSearch(dsp);
3504         return code;
3505     }
3506         
3507     dirLength = scp->length;
3508     bufferp = NULL;
3509     bufferOffset.LowPart = bufferOffset.HighPart = 0;
3510     curOffset.HighPart = 0;
3511     curOffset.LowPart = nextCookie;
3512     origOp = op = smb_GetSMBData(outp, NULL);
3513     /* and write out the basic header */
3514     *op++ = 5;          /* variable block */
3515     op += 2;            /* skip vbl block length; we'll fill it in later */
3516     code = 0;
3517     returnedNames = 0;
3518     while (1) {
3519         /* make sure that curOffset.LowPart doesn't point to the first
3520          * 32 bytes in the 2nd through last dir page, and that it doesn't
3521          * point at the first 13 32-byte chunks in the first dir page,
3522          * since those are dir and page headers, and don't contain useful
3523          * information.
3524          */
3525         temp = curOffset.LowPart & (2048-1);
3526         if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3527             /* we're in the first page */
3528             if (temp < 13*32) temp = 13*32;
3529         }
3530         else {
3531             /* we're in a later dir page */
3532             if (temp < 32) temp = 32;
3533         }
3534
3535         /* make sure the low order 5 bits are zero */
3536         temp &= ~(32-1);
3537
3538         /* now put temp bits back ito curOffset.LowPart */
3539         curOffset.LowPart &= ~(2048-1);
3540         curOffset.LowPart |= temp;
3541
3542         /* check if we've returned all the names that will fit in the
3543          * response packet.
3544          */
3545         if (returnedNames >= maxCount) 
3546             break;
3547                 
3548         /* check if we've passed the dir's EOF */
3549         if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
3550
3551         /* see if we can use the bufferp we have now; compute in which page
3552          * the current offset would be, and check whether that's the offset
3553          * of the buffer we have.  If not, get the buffer.
3554          */
3555         thyper.HighPart = curOffset.HighPart;
3556         thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
3557         if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3558             /* wrong buffer */
3559             if (bufferp) {
3560                 buf_Release(bufferp);
3561                 bufferp = NULL;
3562             }   
3563             lock_ReleaseMutex(&scp->mx);
3564             lock_ObtainRead(&scp->bufCreateLock);
3565             code = buf_Get(scp, &thyper, &bufferp);
3566             lock_ReleaseRead(&scp->bufCreateLock);
3567             lock_ObtainMutex(&dsp->mx);
3568
3569             /* now, if we're doing a star match, do bulk fetching of all of 
3570              * the status info for files in the dir.
3571              */
3572             if (starPattern) {
3573                 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3574                 lock_ObtainMutex(&scp->mx);
3575                 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
3576                      LargeIntegerGreaterThanOrEqualTo(thyper, 
3577                                                       scp->bulkStatProgress)) {
3578                     /* Don't bulk stat if risking timeout */
3579                     int now = GetCurrentTime();
3580                     if (now - req.startTime > 5000) {
3581                         scp->bulkStatProgress = thyper;
3582                         scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3583                         dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3584                     } else
3585                         cm_TryBulkStat(scp, &thyper, userp, &req);
3586                 }
3587             } else {
3588                 lock_ObtainMutex(&scp->mx);
3589             }
3590             lock_ReleaseMutex(&dsp->mx);
3591             if (code) 
3592                 break;
3593
3594             bufferOffset = thyper;
3595
3596             /* now get the data in the cache */
3597             while (1) {
3598                 code = cm_SyncOp(scp, bufferp, userp, &req,
3599                                  PRSFS_LOOKUP,
3600                                  CM_SCACHESYNC_NEEDCALLBACK |
3601                                  CM_SCACHESYNC_READ);
3602                 if (code) break;
3603                                 
3604                 if (cm_HaveBuffer(scp, bufferp, 0)) break;
3605
3606                 /* otherwise, load the buffer and try again */
3607                 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
3608                 if (code) break;
3609             }
3610             if (code) {
3611                 buf_Release(bufferp);
3612                 bufferp = NULL;
3613                 break;
3614             }
3615         }       /* if (wrong buffer) ... */
3616
3617         /* now we have the buffer containing the entry we're interested in; copy
3618          * it out if it represents a non-deleted entry.
3619          */
3620         entryInDir = curOffset.LowPart & (2048-1);
3621         entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
3622
3623         /* page header will help tell us which entries are free.  Page header
3624          * can change more often than once per buffer, since AFS 3 dir page size
3625          * may be less than (but not more than a buffer package buffer.
3626          */
3627         temp = curOffset.LowPart & (buf_bufferSize - 1);  /* only look intra-buffer */
3628         temp &= ~(2048 - 1);    /* turn off intra-page bits */
3629         pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3630
3631         /* now determine which entry we're looking at in the page.  If it is
3632          * free (there's a free bitmap at the start of the dir), we should
3633          * skip these 32 bytes.
3634          */
3635         slotInPage = (entryInDir & 0x7e0) >> 5;
3636         if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
3637             /* this entry is free */
3638             numDirChunks = 1;           /* only skip this guy */
3639             goto nextEntry;
3640         }
3641
3642         tp = bufferp->datap + entryInBuffer;
3643         dep = (cm_dirEntry_t *) tp;             /* now points to AFS3 dir entry */
3644
3645         /* while we're here, compute the next entry's location, too,
3646          * since we'll need it when writing out the cookie into the dir
3647          * listing stream.
3648          *
3649          * XXXX Probably should do more sanity checking.
3650          */
3651         numDirChunks = cm_NameEntries(dep->name, NULL);
3652
3653         /* compute the offset of the cookie representing the next entry */
3654         nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3655
3656         /* Compute 8.3 name if necessary */
3657         actualName = dep->name;
3658         if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
3659             cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3660             actualName = shortName;
3661         }
3662
3663         if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
3664             /* this is one of the entries to use: it is not deleted
3665              * and it matches the star pattern we're looking for.
3666              */
3667
3668             /* Eliminate entries that don't match requested
3669              * attributes */
3670
3671             /* no hidden files */
3672             if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName))
3673                 goto nextEntry;
3674
3675             if (!(dsp->attribute & SMB_ATTR_DIRECTORY))  /* no directories */
3676             {
3677                 /* We have already done the cm_TryBulkStat above */
3678                 fid.cell = scp->fid.cell;
3679                 fid.volume = scp->fid.volume;
3680                 fid.vnode = ntohl(dep->fid.vnode);
3681                 fid.unique = ntohl(dep->fid.unique);
3682                 fileType = cm_FindFileType(&fid);
3683                 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
3684                          "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
3685                           fileType);
3686                 if (fileType == CM_SCACHETYPE_DIRECTORY)
3687                     goto nextEntry;
3688             }
3689
3690             *op++ = resByte;
3691             memcpy(op, mask, 11); op += 11;
3692             *op++ = (char) dsp->cookie; /* they say it must be non-zero */
3693             *op++ = nextEntryCookie & 0xff;
3694             *op++ = (nextEntryCookie>>8) & 0xff;
3695             *op++ = (nextEntryCookie>>16) & 0xff;
3696             *op++ = (nextEntryCookie>>24) & 0xff;
3697             memcpy(op, &clientCookie, 4); op += 4;
3698
3699             /* now we emit the attribute.  This is sort of tricky,
3700              * since we need to really stat the file to find out
3701              * what type of entry we've got.  Right now, we're
3702              * copying out data from a buffer, while holding the
3703              * scp locked, so it isn't really convenient to stat
3704              * something now.  We'll put in a place holder now,
3705              * and make a second pass before returning this to get
3706              * the real attributes.  So, we just skip the data for
3707              * now, and adjust it later.  We allocate a patch
3708              * record to make it easy to find this point later.
3709              * The replay will happen at a time when it is safe to
3710              * unlock the directory.
3711              */
3712             curPatchp = malloc(sizeof(*curPatchp));
3713             osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
3714             curPatchp->dptr = op;
3715             curPatchp->fid.cell = scp->fid.cell;
3716             curPatchp->fid.volume = scp->fid.volume;
3717             curPatchp->fid.vnode = ntohl(dep->fid.vnode);
3718             curPatchp->fid.unique = ntohl(dep->fid.unique);
3719
3720             /* do hidden attribute here since name won't be around when applying
3721              * dir list patches
3722              */
3723
3724