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