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