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