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