smb-auth-20040711
[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         char sbmtpath[256];
1392
1393 #ifndef DJGPP
1394         strcpy(sbmtpath, "afsdsbmt.ini");
1395 #else /* DJGPP */
1396         strcpy(sbmtpath, cm_confDir);
1397         strcat(sbmtpath, "/afsdsbmt.ini");
1398 #endif /* !DJGPP */
1399         len = GetPrivateProfileString("CSC Policy", shareName, "",
1400                                       policy, sizeof(policy), sbmtpath);
1401         if (len == 0 || len == sizeof(policy) - 1) {
1402                 return CSC_POLICY_MANUAL;
1403         }
1404         
1405         if (stricmp(policy, "documents") == 0)
1406         {
1407                 return CSC_POLICY_DOCUMENTS;
1408         }
1409         
1410         if (stricmp(policy, "programs") == 0)
1411         {
1412                 return CSC_POLICY_PROGRAMS;
1413         }
1414         
1415         if (stricmp(policy, "disable") == 0)
1416         {
1417                 return CSC_POLICY_DISABLE;
1418         }
1419         
1420         return CSC_POLICY_MANUAL;
1421 }
1422
1423 /* find a dir search structure by cookie value, and return it held.
1424  * Must be called with smb_globalLock held.
1425  */
1426 smb_dirSearch_t *smb_FindDirSearchNL(long cookie)
1427 {
1428         smb_dirSearch_t *dsp;
1429         
1430         for(dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1431                 if (dsp->cookie == cookie) {
1432                         if (dsp != smb_firstDirSearchp) {
1433                                 /* move to head of LRU queue, too, if we're not already there */
1434                                 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1435                                         smb_lastDirSearchp = (smb_dirSearch_t *)
1436                                                 osi_QPrev(&dsp->q);
1437                                 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1438                                 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1439                                 if (!smb_lastDirSearchp)
1440                                         smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1441                         }
1442                         dsp->refCount++;
1443                         break;
1444                 }
1445         }
1446         return dsp;
1447 }
1448
1449 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1450 {
1451         lock_ObtainWrite(&smb_globalLock);
1452         dsp->flags |= SMB_DIRSEARCH_DELETE;
1453         lock_ReleaseWrite(&smb_globalLock);
1454         lock_ObtainMutex(&dsp->mx);
1455         if(dsp->scp != NULL) {
1456                 lock_ObtainMutex(&dsp->scp->mx);
1457                 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1458                         dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1459                     dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1460                     dsp->scp->bulkStatProgress = hones;
1461                 }       
1462                 lock_ReleaseMutex(&dsp->scp->mx);
1463         }       
1464         lock_ReleaseMutex(&dsp->mx);
1465 }
1466
1467 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1468 {
1469         cm_scache_t *scp;
1470         
1471         scp = NULL;
1472
1473         lock_ObtainWrite(&smb_globalLock);
1474         osi_assert(dsp->refCount-- > 0);
1475         if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1476                 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1477                         smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1478                 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1479                 lock_FinalizeMutex(&dsp->mx);
1480                 scp = dsp->scp;
1481                 free(dsp);
1482         }
1483         lock_ReleaseWrite(&smb_globalLock);
1484
1485         /* do this now to avoid spurious locking hierarchy creation */
1486         if (scp) cm_ReleaseSCache(scp);
1487 }
1488
1489 /* find a dir search structure by cookie value, and return it held */
1490 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1491 {
1492         smb_dirSearch_t *dsp;
1493
1494         lock_ObtainWrite(&smb_globalLock);
1495         dsp = smb_FindDirSearchNL(cookie);
1496         lock_ReleaseWrite(&smb_globalLock);
1497         return dsp;
1498 }
1499
1500 /* GC some dir search entries, in the address space expected by the specific protocol.
1501  * Must be called with smb_globalLock held; release the lock temporarily.
1502  */
1503 #define SMB_DIRSEARCH_GCMAX     10      /* how many at once */
1504 void smb_GCDirSearches(int isV3)
1505 {
1506         smb_dirSearch_t *prevp;
1507         smb_dirSearch_t *tp;
1508         smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1509         int victimCount;
1510         int i;
1511         
1512         victimCount = 0;        /* how many have we got so far */
1513         for(tp = smb_lastDirSearchp; tp; tp=prevp) {
1514                 /* we'll move tp from queue, so
1515                  * do this early.
1516                  */
1517                 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);  
1518                 /* if no one is using this guy, and we're either in the new protocol,
1519                  * or we're in the old one and this is a small enough ID to be useful
1520                  * to the old protocol, GC this guy.
1521                  */
1522                 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1523                         /* hold and delete */
1524                         tp->flags |= SMB_DIRSEARCH_DELETE;
1525                         victimsp[victimCount++] = tp;
1526                         tp->refCount++;
1527                 }
1528
1529                 /* don't do more than this */
1530                 if (victimCount >= SMB_DIRSEARCH_GCMAX) break;
1531         }
1532         
1533         /* now release them */
1534         lock_ReleaseWrite(&smb_globalLock);
1535         for(i = 0; i < victimCount; i++) {
1536                 smb_ReleaseDirSearch(victimsp[i]);
1537         }
1538         lock_ObtainWrite(&smb_globalLock);
1539 }
1540
1541 /* function for allocating a dir search entry.  We need these to remember enough context
1542  * since we don't get passed the path from call to call during a directory search.
1543  *
1544  * Returns a held dir search structure, and bumps the reference count on the vnode,
1545  * since it saves a pointer to the vnode.
1546  */
1547 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1548 {
1549         smb_dirSearch_t *dsp;
1550         int counter;
1551         int maxAllowed;
1552
1553         lock_ObtainWrite(&smb_globalLock);
1554         counter = 0;
1555
1556         /* what's the biggest ID allowed in this version of the protocol */
1557         if (isV3) maxAllowed = 65535;
1558         else maxAllowed = 255;
1559
1560         while(1) {
1561                 /* twice so we have enough tries to find guys we GC after one pass;
1562                  * 10 extra is just in case I mis-counted.
1563                  */
1564                 if (++counter > 2*maxAllowed+10) osi_panic("afsd: dir search cookie leak",
1565                                                                                                         __FILE__, __LINE__);
1566                 if (smb_dirSearchCounter > maxAllowed) {        
1567                         smb_dirSearchCounter = 1;
1568                         smb_GCDirSearches(isV3);        /* GC some (drops global lock) */
1569                 }       
1570                 dsp = smb_FindDirSearchNL(smb_dirSearchCounter);
1571                 if (dsp) {
1572                         /* don't need to watch for refcount zero and deleted, since
1573                          * we haven't dropped the global lock.
1574                          */
1575                         dsp->refCount--;
1576                         ++smb_dirSearchCounter;
1577                         continue;
1578                 }       
1579                 
1580                 dsp = malloc(sizeof(*dsp));
1581                 memset(dsp, 0, sizeof(*dsp));
1582                 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1583                 if (!smb_lastDirSearchp) smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1584                 dsp->cookie = smb_dirSearchCounter;
1585                 ++smb_dirSearchCounter;
1586                 dsp->refCount = 1;
1587                 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
1588                 dsp->lastTime = osi_Time();
1589                 break;
1590         }       
1591         lock_ReleaseWrite(&smb_globalLock);
1592         return dsp;
1593 }
1594
1595 static smb_packet_t *GetPacket(void)
1596 {
1597         smb_packet_t *tbp;
1598 #ifdef DJGPP
1599         unsigned int npar, seg, tb_sel;
1600 #endif
1601
1602         lock_ObtainWrite(&smb_globalLock);
1603         tbp = smb_packetFreeListp;
1604     if (tbp) 
1605         smb_packetFreeListp = tbp->nextp;
1606         lock_ReleaseWrite(&smb_globalLock);
1607     if (!tbp) {
1608 #ifndef DJGPP
1609         tbp = calloc(65540,1);
1610 #else /* DJGPP */
1611         tbp = malloc(sizeof(smb_packet_t));
1612 #endif /* !DJGPP */
1613         tbp->magic = SMB_PACKETMAGIC;
1614                 tbp->ncbp = NULL;
1615                 tbp->vcp = NULL;
1616                 tbp->resumeCode = 0;
1617                 tbp->inCount = 0;
1618                 tbp->fid = 0;
1619                 tbp->wctp = NULL;
1620                 tbp->inCom = 0;
1621                 tbp->oddByte = 0;
1622                 tbp->ncb_length = 0;
1623                 tbp->flags = 0;
1624         tbp->spacep = NULL;
1625         
1626 #ifdef DJGPP
1627         npar = SMB_PACKETSIZE >> 4;  /* number of paragraphs */
1628         {
1629             signed int retval =
1630                 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1631             if (retval == -1) {
1632                 afsi_log("Cannot allocate %d paragraphs of DOS memory",
1633                           npar);
1634                 osi_panic("",__FILE__,__LINE__);
1635             }
1636             else {
1637                 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
1638                           npar, retval);
1639                 seg = retval;
1640             }
1641         }
1642         tbp->dos_pkt = (seg * 16) + 0;  /* DOS physical address */
1643         tbp->dos_pkt_sel = tb_sel;
1644 #endif /* DJGPP */
1645         }
1646     osi_assert(tbp->magic == SMB_PACKETMAGIC);
1647
1648     return tbp;
1649 }
1650
1651 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
1652 {
1653         smb_packet_t *tbp;
1654         tbp = GetPacket();
1655         memcpy(tbp, pkt, sizeof(smb_packet_t));
1656         tbp->wctp = tbp->data + ((unsigned int)pkt->wctp - (unsigned int)pkt->data);
1657         return tbp;
1658 }
1659
1660 static NCB *GetNCB(void)
1661 {
1662         smb_ncb_t *tbp;
1663     NCB *ncbp;
1664 #ifdef DJGPP
1665     unsigned int npar, seg, tb_sel;
1666 #endif /* DJGPP */
1667
1668         lock_ObtainWrite(&smb_globalLock);
1669         tbp = smb_ncbFreeListp;
1670     if (tbp) 
1671         smb_ncbFreeListp = tbp->nextp;
1672         lock_ReleaseWrite(&smb_globalLock);
1673     if (!tbp) {
1674 #ifndef DJGPP
1675         tbp = calloc(sizeof(*tbp),1);
1676 #else /* DJGPP */
1677         tbp = malloc(sizeof(*tbp));
1678         npar = (sizeof(NCB)+15) >> 4;  /* number of paragraphs */
1679         {
1680             signed int retval =
1681                 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1682             if (retval == -1) {
1683                 afsi_log("Cannot allocate %d paragraphs of DOS mem in GetNCB",
1684                           npar);
1685                 osi_panic("",__FILE__,__LINE__);
1686             } else {
1687                 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
1688                           npar, retval);
1689                 seg = retval;
1690             }
1691         }
1692         tbp->dos_ncb = (seg * 16) + 0;  /* DOS physical address */
1693         tbp->dos_ncb_sel = tb_sel;
1694 #endif /* !DJGPP */
1695         tbp->magic = SMB_NCBMAGIC;
1696         }
1697         
1698     osi_assert(tbp->magic == SMB_NCBMAGIC);
1699
1700         memset(&tbp->ncb, 0, sizeof(NCB));
1701     ncbp = &tbp->ncb;
1702 #ifdef DJGPP
1703     dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
1704 #endif /* DJGPP */
1705     return ncbp;
1706 }
1707
1708 void smb_FreePacket(smb_packet_t *tbp)
1709 {
1710     osi_assert(tbp->magic == SMB_PACKETMAGIC);
1711         
1712     lock_ObtainWrite(&smb_globalLock);
1713         tbp->nextp = smb_packetFreeListp;
1714         smb_packetFreeListp = tbp;
1715         tbp->magic = SMB_PACKETMAGIC;
1716         tbp->ncbp = NULL;
1717         tbp->vcp = NULL;
1718         tbp->resumeCode = 0;
1719         tbp->inCount = 0;
1720         tbp->fid = 0;
1721         tbp->wctp = NULL;
1722         tbp->inCom = 0;
1723         tbp->oddByte = 0;
1724         tbp->ncb_length = 0;
1725         tbp->flags = 0;
1726     lock_ReleaseWrite(&smb_globalLock);
1727 }
1728
1729 static void FreeNCB(NCB *bufferp)
1730 {
1731         smb_ncb_t *tbp;
1732         
1733     tbp = (smb_ncb_t *) bufferp;
1734     osi_assert(tbp->magic == SMB_NCBMAGIC);
1735         
1736     lock_ObtainWrite(&smb_globalLock);
1737         tbp->nextp = smb_ncbFreeListp;
1738         smb_ncbFreeListp = tbp;
1739     lock_ReleaseWrite(&smb_globalLock);
1740 }
1741
1742 /* get a ptr to the data part of a packet, and its count */
1743 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
1744 {
1745     int parmBytes;
1746     int dataBytes;
1747     unsigned char *afterParmsp;
1748
1749     parmBytes = *smbp->wctp << 1;
1750         afterParmsp = smbp->wctp + parmBytes + 1;
1751         
1752     dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
1753     if (nbytesp) *nbytesp = dataBytes;
1754         
1755         /* don't forget to skip the data byte count, since it follows
1756      * the parameters; that's where the "2" comes from below.
1757      */
1758     return (unsigned char *) (afterParmsp + 2);
1759 }
1760
1761 /* must set all the returned parameters before playing around with the
1762  * data region, since the data region is located past the end of the
1763  * variable number of parameters.
1764  */
1765 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
1766 {
1767         unsigned char *afterParmsp;
1768
1769         afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
1770         
1771         *afterParmsp++ = dsize & 0xff;
1772         *afterParmsp = (dsize>>8) & 0xff;
1773 }
1774
1775 /* return the parm'th parameter in the smbp packet */
1776 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
1777 {
1778         int parmCount;
1779         unsigned char *parmDatap;
1780
1781         parmCount = *smbp->wctp;
1782
1783         if (parm >= parmCount) {
1784 #ifndef DJGPP
1785         HANDLE h;
1786                 char *ptbuf[1];
1787                 char s[100];
1788                 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1789                 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
1790                                 parm, parmCount, smbp->ncb_length);
1791                 ptbuf[0] = s;
1792                 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1793                                         1, smbp->ncb_length, ptbuf, smbp);
1794                 DeregisterEventSource(h);
1795 #else /* DJGPP */
1796                 char s[100];
1797
1798                 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
1799                                 parm, parmCount, smbp->ncb_length);
1800                 osi_Log0(smb_logp, s);
1801 #endif /* !DJGPP */
1802                 osi_panic(s, __FILE__, __LINE__);
1803         }
1804         parmDatap = smbp->wctp + (2*parm) + 1;
1805         
1806         return parmDatap[0] + (parmDatap[1] << 8);
1807 }
1808
1809 /* return the parm'th parameter in the smbp packet */
1810 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
1811 {
1812         int parmCount;
1813         unsigned char *parmDatap;
1814
1815         parmCount = *smbp->wctp;
1816
1817         if (parm * 2 + offset >= parmCount * 2) {
1818 #ifndef DJGPP
1819                 HANDLE h;
1820                 char *ptbuf[1];
1821                 char s[100];
1822                 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1823                 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
1824                                 parm, offset, parmCount, smbp->ncb_length);
1825                 ptbuf[0] = s;
1826                 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1827                                         1, smbp->ncb_length, ptbuf, smbp);
1828                 DeregisterEventSource(h);
1829 #else /* DJGPP */
1830                 char s[100];
1831                 
1832                 sprintf(s, "Bad SMB param %d offset %d out of %d, "
1833                                 "ncb len %d",
1834                                  parm, offset, parmCount, smbp->ncb_length);
1835                 osi_Log0(smb_logp, s);
1836 #endif /* !DJGPP */
1837
1838                 osi_panic(s, __FILE__, __LINE__);
1839         }
1840         parmDatap = smbp->wctp + (2*parm) + 1 + offset;
1841         
1842         return parmDatap[0] + (parmDatap[1] << 8);
1843 }
1844
1845 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
1846 {
1847         char *parmDatap;
1848
1849         /* make sure we have enough slots */
1850         if (*smbp->wctp <= slot) *smbp->wctp = slot+1;
1851         
1852         parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1853         *parmDatap++ = parmValue & 0xff;
1854         *parmDatap = (parmValue>>8) & 0xff;
1855 }
1856
1857 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
1858 {
1859         char *parmDatap;
1860
1861         /* make sure we have enough slots */
1862         if (*smbp->wctp <= slot) *smbp->wctp = slot+2;
1863
1864         parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1865         *parmDatap++ = parmValue & 0xff;
1866         *parmDatap++ = (parmValue>>8) & 0xff;
1867         *parmDatap++ = (parmValue>>16) & 0xff;
1868         *parmDatap++ = (parmValue>>24) & 0xff;
1869 }
1870
1871 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
1872 {
1873         char *parmDatap;
1874         int i;
1875
1876         /* make sure we have enough slots */
1877         if (*smbp->wctp <= slot) *smbp->wctp = slot+4;
1878
1879         parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1880         for (i=0; i<8; i++)
1881                 *parmDatap++ = *parmValuep++;
1882 }
1883
1884 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
1885 {
1886         char *parmDatap;
1887
1888         /* make sure we have enough slots */
1889         if (*smbp->wctp <= slot) {
1890                 if (smbp->oddByte) {
1891                         smbp->oddByte = 0;
1892                         *smbp->wctp = slot+1;
1893                 } else
1894                         smbp->oddByte = 1;
1895         }
1896
1897         parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
1898         *parmDatap++ = parmValue & 0xff;
1899 }
1900
1901 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
1902 {
1903         char *lastSlashp;
1904         
1905         lastSlashp = strrchr(inPathp, '\\');
1906         if (lastComponentp)
1907                 *lastComponentp = lastSlashp;
1908         if (lastSlashp) {
1909                 while (1) {
1910                         if (inPathp == lastSlashp) 
1911                                 break;
1912                         *outPathp++ = *inPathp++;
1913                 }
1914                 *outPathp++ = 0;
1915         }
1916         else {
1917                 *outPathp++ = 0;
1918         }
1919 }
1920
1921 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
1922 {
1923         if (*inp++ != 0x4) 
1924                 return NULL;
1925         if (chainpp) {
1926                 *chainpp = inp + strlen(inp) + 1;       /* skip over null-terminated string */
1927         }
1928         return inp;
1929 }
1930
1931 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
1932 {
1933         int tlen;
1934
1935         if (*inp++ != 0x5) 
1936                 return NULL;
1937         tlen = inp[0] + (inp[1]<<8);
1938         inp += 2;               /* skip length field */
1939         
1940         if (chainpp) {
1941                 *chainpp = inp + tlen;
1942         }
1943         
1944         if (lengthp) 
1945                 *lengthp = tlen;
1946         
1947         return inp;
1948 }       
1949
1950 /* format a packet as a response */
1951 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
1952 {
1953         smb_t *outp;
1954         smb_t *inSmbp;
1955
1956         outp = (smb_t *) op;
1957         
1958         /* zero the basic structure through the smb_wct field, and zero the data
1959          * size field, assuming that wct stays zero; otherwise, you have to 
1960          * explicitly set the data size field, too.
1961          */
1962         inSmbp = (smb_t *) inp;
1963         memset(outp, 0, sizeof(smb_t)+2);
1964         outp->id[0] = 0xff;
1965         outp->id[1] = 'S';
1966         outp->id[2] = 'M';
1967         outp->id[3] = 'B';
1968         if (inp) {
1969                 outp->com = inSmbp->com;
1970                 outp->tid = inSmbp->tid;
1971                 outp->pid = inSmbp->pid;
1972                 outp->uid = inSmbp->uid;
1973                 outp->mid = inSmbp->mid;
1974                 outp->res[0] = inSmbp->res[0];
1975                 outp->res[1] = inSmbp->res[1];
1976                 op->inCom = inSmbp->com;
1977         }
1978         outp->reb = 0x80;       /* SERVER_RESP */
1979         outp->flg2 = 0x1;       /* KNOWS_LONG_NAMES */
1980
1981         /* copy fields in generic packet area */
1982         op->wctp = &outp->wct;
1983 }
1984
1985 /* send a (probably response) packet; vcp tells us to whom to send it.
1986  * we compute the length by looking at wct and bcc fields.
1987  */
1988 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
1989 {
1990         NCB *ncbp;
1991         int extra;
1992         long code = 0;
1993         unsigned char *tp;
1994         int localNCB = 0;
1995 #ifdef DJGPP
1996         dos_ptr dos_ncb;
1997 #endif /* DJGPP */
1998         
1999         ncbp = inp->ncbp;
2000         if (ncbp == NULL) {
2001                 ncbp = GetNCB();
2002                 localNCB = 1;
2003         }
2004 #ifdef DJGPP
2005         dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2006 #endif /* DJGPP */
2007  
2008         memset((char *)ncbp, 0, sizeof(NCB));
2009
2010         extra = 2 * (*inp->wctp);       /* space used by parms, in bytes */
2011         tp = inp->wctp + 1+ extra;      /* points to count of data bytes */
2012         extra += tp[0] + (tp[1]<<8);
2013         extra += ((unsigned int)inp->wctp - (unsigned int)inp->data);   /* distance to last wct field */
2014         extra += 3;                     /* wct and length fields */
2015         
2016         ncbp->ncb_length = extra;       /* bytes to send */
2017         ncbp->ncb_lsn = (unsigned char) vcp->lsn;       /* vc to use */
2018         ncbp->ncb_lana_num = vcp->lana;
2019         ncbp->ncb_command = NCBSEND;    /* op means send data */
2020 #ifndef DJGPP
2021         ncbp->ncb_buffer = (char *) inp;/* packet */
2022         code = Netbios(ncbp);
2023 #else /* DJGPP */
2024         ncbp->ncb_buffer = inp->dos_pkt;/* packet */
2025         ((smb_ncb_t*)ncbp)->orig_pkt = inp;
2026
2027         /* copy header information from virtual to DOS address space */
2028         dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
2029         code = Netbios(ncbp, dos_ncb);
2030 #endif /* !DJGPP */
2031         
2032         if (code != 0)
2033                 osi_Log1(smb_logp, "SendPacket failure code %d", code);
2034
2035         if (localNCB)
2036                 FreeNCB(ncbp);
2037 }
2038
2039 void smb_MapNTError(long code, unsigned long *NTStatusp)
2040 {
2041         unsigned long NTStatus;
2042
2043         /* map CM_ERROR_* errors to NT 32-bit status codes */
2044     /* NT Status codes are listed in ntstatus.h not winerror.h */
2045         if (code == CM_ERROR_NOSUCHCELL) {
2046                 NTStatus = 0xC000000FL; /* No such file */
2047         }
2048         else if (code == CM_ERROR_NOSUCHVOLUME) {
2049                 NTStatus = 0xC000000FL; /* No such file */
2050         }
2051         else if (code == CM_ERROR_TIMEDOUT) {
2052                 NTStatus = 0xC00000CFL; /* Sharing Paused */
2053         }
2054         else if (code == CM_ERROR_RETRY) {
2055                 NTStatus = 0xC000022DL; /* Retry */
2056         }
2057         else if (code == CM_ERROR_NOACCESS) {
2058                 NTStatus = 0xC0000022L; /* Access denied */
2059         }
2060         else if (code == CM_ERROR_READONLY) {
2061                 NTStatus = 0xC00000A2L; /* Write protected */
2062         }       
2063         else if (code == CM_ERROR_NOSUCHFILE) {
2064                 NTStatus = 0xC000000FL; /* No such file */
2065         }
2066         else if (code == CM_ERROR_NOSUCHPATH) {
2067                 NTStatus = 0xC000003AL; /* Object path not found */
2068         }               
2069         else if (code == CM_ERROR_TOOBIG) {
2070                 NTStatus = 0xC000007BL; /* Invalid image format */
2071         }
2072         else if (code == CM_ERROR_INVAL) {
2073                 NTStatus = 0xC000000DL; /* Invalid parameter */
2074         }
2075         else if (code == CM_ERROR_BADFD) {
2076                 NTStatus = 0xC0000008L; /* Invalid handle */
2077         }
2078         else if (code == CM_ERROR_BADFDOP) {
2079                 NTStatus = 0xC0000022L; /* Access denied */
2080         }
2081         else if (code == CM_ERROR_EXISTS) {
2082                 NTStatus = 0xC0000035L; /* Object name collision */
2083         }
2084         else if (code == CM_ERROR_NOTEMPTY) {
2085                 NTStatus = 0xC0000101L; /* Directory not empty */
2086         }       
2087         else if (code == CM_ERROR_CROSSDEVLINK) {
2088                 NTStatus = 0xC00000D4L; /* Not same device */
2089         }
2090         else if (code == CM_ERROR_NOTDIR) {
2091                 NTStatus = 0xC0000103L; /* Not a directory */
2092         }
2093         else if (code == CM_ERROR_ISDIR) {
2094                 NTStatus = 0xC00000BAL; /* File is a directory */
2095         }
2096         else if (code == CM_ERROR_BADOP) {
2097                 NTStatus = 0xC09820FFL; /* SMB no support */
2098         }
2099         else if (code == CM_ERROR_BADSHARENAME) {
2100                 NTStatus = 0xC00000CCL; /* Bad network name */
2101         }
2102         else if (code == CM_ERROR_NOIPC) {
2103 #ifdef COMMENT
2104                 NTStatus = 0xC0000022L; /* Access Denied */
2105 #else
2106         NTStatus = 0xC000013DL; /* Remote Resources */
2107 #endif
2108         }
2109         else if (code == CM_ERROR_CLOCKSKEW) {
2110                 NTStatus = 0xC0000133L; /* Time difference at DC */
2111         }
2112         else if (code == CM_ERROR_BADTID) {
2113                 NTStatus = 0xC0982005L; /* SMB bad TID */
2114         }
2115         else if (code == CM_ERROR_USESTD) {
2116                 NTStatus = 0xC09820FBL; /* SMB use standard */
2117         }
2118         else if (code == CM_ERROR_QUOTA) {
2119                 NTStatus = 0xC0000044L; /* Quota exceeded */
2120         }
2121         else if (code == CM_ERROR_SPACE) {
2122                 NTStatus = 0xC000007FL; /* Disk full */
2123         }
2124         else if (code == CM_ERROR_ATSYS) {
2125                 NTStatus = 0xC0000033L; /* Object name invalid */
2126         }
2127         else if (code == CM_ERROR_BADNTFILENAME) {
2128                 NTStatus = 0xC0000033L; /* Object name invalid */
2129         }
2130         else if (code == CM_ERROR_WOULDBLOCK) {
2131                 NTStatus = 0xC0000055L; /* Lock not granted */
2132         }
2133         else if (code == CM_ERROR_PARTIALWRITE) {
2134                 NTStatus = 0xC000007FL; /* Disk full */
2135         }
2136         else if (code == CM_ERROR_BUFFERTOOSMALL) {
2137                 NTStatus = 0xC0000023L; /* Buffer too small */
2138         }
2139     else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2140                 NTStatus = 0xC0000035L; /* Object name collision */
2141     }
2142         else if (code == CM_ERROR_BADPASSWORD) {
2143                 NTStatus = 0xC000006DL; /* unknown username or bad password */
2144         }
2145         else if (code == CM_ERROR_BADLOGONTYPE) {
2146                 NTStatus = 0xC000015BL; /* logon type not granted */
2147         }
2148         else if (code == CM_ERROR_GSSCONTINUE) {
2149                 NTStatus = 0xC0000016L; /* more processing required */
2150         }
2151         else {
2152                 NTStatus = 0xC0982001L; /* SMB non-specific error */
2153         }
2154
2155         *NTStatusp = NTStatus;
2156         osi_Log2(smb_logp, "SMB SEND code %x as NT %x", code, NTStatus);
2157 }
2158
2159 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2160         unsigned char *classp)
2161 {
2162         unsigned char class;
2163         unsigned short error;
2164
2165         /* map CM_ERROR_* errors to SMB errors */
2166         if (code == CM_ERROR_NOSUCHCELL) {
2167                 class = 1;
2168                 error = 3;      /* bad path */
2169         }
2170         else if (code == CM_ERROR_NOSUCHVOLUME) {
2171                 class = 1;
2172                 error = 3;      /* bad path */
2173         }
2174         else if (code == CM_ERROR_TIMEDOUT) {
2175                 class = 2;
2176                 error = 81;     /* server is paused */
2177         }
2178         else if (code == CM_ERROR_RETRY) {
2179                 class = 2;      /* shouldn't happen */
2180                 error = 1;
2181         }
2182         else if (code == CM_ERROR_NOACCESS) {
2183                 class = 2;
2184                 error = 4;      /* bad access */
2185         }
2186         else if (code == CM_ERROR_READONLY) {
2187                 class = 3;
2188                 error = 19;     /* read only */
2189         }
2190         else if (code == CM_ERROR_NOSUCHFILE) {
2191                 class = 1;
2192                 error = 2;      /* ENOENT! */
2193         }
2194         else if (code == CM_ERROR_NOSUCHPATH) {
2195                 class = 1;
2196                 error = 3;      /* Bad path */
2197         }
2198         else if (code == CM_ERROR_TOOBIG) {
2199                 class = 1;
2200                 error = 11;     /* bad format */
2201         }
2202         else if (code == CM_ERROR_INVAL) {
2203                 class = 2;      /* server non-specific error code */
2204                 error = 1;
2205         }
2206         else if (code == CM_ERROR_BADFD) {
2207                 class = 1;
2208                 error = 6;      /* invalid file handle */
2209         }
2210         else if (code == CM_ERROR_BADFDOP) {
2211                 class = 1;      /* invalid op on FD */
2212                 error = 5;
2213         }
2214         else if (code == CM_ERROR_EXISTS) {
2215                 class = 1;
2216                 error = 80;     /* file already exists */
2217         }
2218         else if (code == CM_ERROR_NOTEMPTY) {
2219                 class = 1;
2220                 error = 5;      /* delete directory not empty */
2221         }
2222         else if (code == CM_ERROR_CROSSDEVLINK) {
2223                 class = 1;
2224                 error = 17;     /* EXDEV */
2225         }
2226         else if (code == CM_ERROR_NOTDIR) {
2227                 class = 1;      /* bad path */
2228                 error = 3;
2229         }
2230         else if (code == CM_ERROR_ISDIR) {
2231                 class = 1;      /* access denied; DOS doesn't have a good match */
2232                 error = 5;
2233         }
2234         else if (code == CM_ERROR_BADOP) {
2235                 class = 2;
2236                 error = 65535;
2237         }
2238         else if (code == CM_ERROR_BADSHARENAME) {
2239                 class = 2;
2240                 error = 6;
2241         }
2242         else if (code == CM_ERROR_NOIPC) {
2243                 class = 2;
2244                 error = 4; /* bad access */
2245         }
2246         else if (code == CM_ERROR_CLOCKSKEW) {
2247                 class = 1;      /* invalid function */
2248                 error = 1;
2249         }
2250         else if (code == CM_ERROR_BADTID) {
2251                 class = 2;
2252                 error = 5;
2253         }
2254         else if (code == CM_ERROR_USESTD) {
2255                 class = 2;
2256                 error = 251;
2257         }
2258         else if (code == CM_ERROR_REMOTECONN) {
2259                 class = 2;
2260                 error = 82;
2261         }
2262         else if (code == CM_ERROR_QUOTA) {
2263                 if (vcp->flags & SMB_VCFLAG_USEV3) {
2264                         class = 3;
2265                         error = 39;     /* disk full */
2266                 }
2267                 else {
2268                         class = 1;
2269                         error = 5;      /* access denied */
2270                 }
2271         }
2272         else if (code == CM_ERROR_SPACE) {
2273                 if (vcp->flags & SMB_VCFLAG_USEV3) {
2274                         class = 3;
2275                         error = 39;     /* disk full */
2276                 }
2277                 else {
2278                         class = 1;
2279                         error = 5;      /* access denied */
2280                 }
2281         }
2282         else if (code == CM_ERROR_PARTIALWRITE) {
2283                 class = 3;
2284                 error = 39;     /* disk full */
2285         }
2286         else if (code == CM_ERROR_ATSYS) {
2287                 class = 1;
2288                 error = 2;      /* ENOENT */
2289         }
2290         else if (code == CM_ERROR_WOULDBLOCK) {
2291                 class = 1;
2292                 error = 33;     /* lock conflict */
2293         }
2294         else if (code == CM_ERROR_NOFILES) {
2295                 class = 1;
2296                 error = 18;     /* no files in search */
2297         }
2298         else if (code == CM_ERROR_RENAME_IDENTICAL) {
2299                 class = 1;
2300                 error = 183;     /* Samba uses this */
2301         }
2302         else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2303                 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2304                 class = 2;
2305                 error = 2; /* bad password */
2306         }
2307         else {
2308                 class = 2;
2309                 error = 1;
2310         }
2311
2312         *scodep = error;
2313         *classp = class;
2314         osi_Log3(smb_logp, "SMB SEND code %x as SMB %d: %d", code, class, error);
2315 }
2316
2317 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2318 {
2319         return CM_ERROR_BADOP;
2320 }
2321
2322 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2323 {
2324         unsigned short EchoCount, i;
2325         char *data, *outdata;
2326         int dataSize;
2327
2328         EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2329
2330         for (i=1; i<=EchoCount; i++) {
2331             data = smb_GetSMBData(inp, &dataSize);
2332             smb_SetSMBParm(outp, 0, i);
2333             smb_SetSMBDataLength(outp, dataSize);
2334             outdata = smb_GetSMBData(outp, NULL);
2335             memcpy(outdata, data, dataSize);
2336             smb_SendPacket(vcp, outp);
2337         }
2338
2339         return 0;
2340 }
2341
2342 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2343 {
2344         osi_hyper_t offset;
2345         long count, minCount, finalCount;
2346         unsigned short fd;
2347         smb_fid_t *fidp;
2348         long code = 0;
2349         cm_user_t *userp = NULL;
2350     NCB *ncbp;
2351     int rc;
2352 #ifndef DJGPP
2353     char *rawBuf = NULL;
2354 #else
2355     dos_ptr rawBuf = NULL;
2356     dos_ptr dos_ncb;
2357 #endif /* DJGPP */
2358
2359         rawBuf = NULL;
2360         finalCount = 0;
2361
2362         fd = smb_GetSMBParm(inp, 0);
2363         count = smb_GetSMBParm(inp, 3);
2364         minCount = smb_GetSMBParm(inp, 4);
2365         offset.HighPart = 0;    /* too bad */
2366         offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2367
2368         osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2369              fd, offset.LowPart, count);
2370
2371         fidp = smb_FindFID(vcp, fd, 0);
2372         if (!fidp)
2373                 goto send1;
2374
2375         lock_ObtainMutex(&smb_RawBufLock);
2376         if (smb_RawBufs) {
2377                 /* Get a raw buf, from head of list */
2378                 rawBuf = smb_RawBufs;
2379 #ifndef DJGPP
2380                 smb_RawBufs = *(char **)smb_RawBufs;
2381 #else /* DJGPP */
2382         smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2383 #endif /* !DJGPP */
2384         }
2385         lock_ReleaseMutex(&smb_RawBufLock);
2386         if (!rawBuf)
2387                 goto send1a;
2388
2389     if (fidp->flags & SMB_FID_IOCTL)
2390     {
2391 #ifndef DJGPP
2392         rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2393 #else
2394         rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2395 #endif
2396         if (rawBuf) {
2397             /* Give back raw buffer */
2398             lock_ObtainMutex(&smb_RawBufLock);
2399 #ifndef DJGPP
2400             *((char **) rawBuf) = smb_RawBufs;
2401 #else /* DJGPP */
2402             _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2403 #endif /* !DJGPP */
2404             
2405             smb_RawBufs = rawBuf;
2406             lock_ReleaseMutex(&smb_RawBufLock);
2407         }
2408
2409         smb_ReleaseFID(fidp);
2410         return rc;
2411     }
2412         
2413     userp = smb_GetUser(vcp, inp);
2414
2415 #ifndef DJGPP
2416         code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2417 #else /* DJGPP */
2418     /* have to give ReadData flag so it will treat buffer as DOS mem. */
2419     code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2420                         userp, &finalCount, TRUE /* rawFlag */);
2421 #endif /* !DJGPP */
2422
2423         if (code != 0)
2424                 goto send;
2425
2426   send:
2427     cm_ReleaseUser(userp);
2428
2429   send1a:
2430         smb_ReleaseFID(fidp);
2431
2432   send1:
2433         ncbp = outp->ncbp;
2434 #ifdef DJGPP
2435     dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2436 #endif /* DJGPP */
2437         memset((char *)ncbp, 0, sizeof(NCB));
2438
2439         ncbp->ncb_length = (unsigned short) finalCount;
2440         ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2441         ncbp->ncb_lana_num = vcp->lana;
2442         ncbp->ncb_command = NCBSEND;
2443         ncbp->ncb_buffer = rawBuf;
2444
2445 #ifndef DJGPP
2446         code = Netbios(ncbp);
2447 #else /* DJGPP */
2448         code = Netbios(ncbp, dos_ncb);
2449 #endif /* !DJGPP */
2450         if (code != 0)
2451                 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2452
2453         if (rawBuf) {
2454                 /* Give back raw buffer */
2455                 lock_ObtainMutex(&smb_RawBufLock);
2456 #ifndef DJGPP
2457                 *((char **) rawBuf) = smb_RawBufs;
2458 #else /* DJGPP */
2459         _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2460 #endif /* !DJGPP */
2461
2462                 smb_RawBufs = rawBuf;
2463                 lock_ReleaseMutex(&smb_RawBufLock);
2464         }
2465
2466         return 0;
2467 }
2468
2469 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2470 {
2471         return 0;
2472 }
2473
2474 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2475 {
2476         return 0;
2477 }
2478
2479 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2480 {
2481         char *namep;
2482     char *datap;
2483         int coreProtoIndex;
2484         int v3ProtoIndex;
2485         int NTProtoIndex;
2486         int protoIndex;                         /* index we're using */
2487         int namex;
2488         int dbytes;
2489         int entryLength;
2490         int tcounter;
2491         char protocol_array[10][1024];  /* protocol signature of the client */
2492     int caps;                       /* capabilities */
2493     time_t unixTime;
2494         long dosTime;
2495         TIME_ZONE_INFORMATION tzi;
2496
2497     osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2498                          ongoingOps - 1);
2499         if (!isGateway) {
2500                 if (active_vcp) {
2501                         DWORD now = GetCurrentTime();
2502                         if (now - last_msg_time >= 30000
2503                                 && now - last_msg_time <= 90000) {
2504                                 osi_Log1(smb_logp,
2505                                                  "Setting dead_vcp %x", active_vcp);
2506                 if (dead_vcp) {
2507                     smb_ReleaseVC(dead_vcp);
2508                     osi_Log1(smb_logp,
2509                               "Previous dead_vcp %x", dead_vcp);
2510                 }
2511                 smb_HoldVC(active_vcp);
2512                                 dead_vcp = active_vcp;
2513                                 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2514                         }
2515                 }
2516         }
2517
2518         inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
2519
2520         namep = smb_GetSMBData(inp, &dbytes);
2521         namex = 0;
2522         tcounter = 0;
2523         coreProtoIndex = -1;            /* not found */
2524         v3ProtoIndex = -1;
2525         NTProtoIndex = -1;
2526         while(namex < dbytes) {
2527                 osi_Log1(smb_logp, "Protocol %s",
2528                                  osi_LogSaveString(smb_logp, namep+1));
2529                 strcpy(protocol_array[tcounter], namep+1);
2530
2531                 /* namep points at the first protocol, or really, a 0x02
2532                  * byte preceding the null-terminated ASCII name.
2533                  */
2534                 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2535                         coreProtoIndex = tcounter;
2536                 }       
2537                 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2538                         v3ProtoIndex = tcounter;
2539                 }
2540                 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
2541                         NTProtoIndex = tcounter;
2542                 }
2543
2544                 /* compute size of protocol entry */
2545                 entryLength = strlen(namep+1);
2546         entryLength += 2;       /* 0x02 bytes and null termination */
2547                 
2548         /* advance over this protocol entry */
2549                 namex += entryLength;
2550         namep += entryLength;
2551         tcounter++;             /* which proto entry we're looking at */
2552         }
2553 #ifndef NOMOREFILESFIX
2554         /* 
2555          * NOTE: We can determine what OS (NT4.0, W2K, W9X, etc)
2556          * the client is running by reading the protocol signature.
2557          * ie. the order in which it sends us the protocol list.
2558          *
2559          * Special handling for Windows 2000 clients (defect 11765 )
2560      * <asanka:11Jun03> Proto signature is the same for Win XP. </>
2561          */
2562         if (tcounter == 6) {
2563                 int i = 0;
2564                 smb_t *ip = (smb_t *) inp;
2565                 smb_t *op = (smb_t *) outp;
2566
2567                 if ((strcmp("PC NETWORK PROGRAM 1.0", protocol_array[0]) == 0) &&
2568                          (strcmp("LANMAN1.0", protocol_array[1]) == 0) &&
2569                          (strcmp("Windows for Workgroups 3.1a", protocol_array[2]) == 0) &&
2570                          (strcmp("LM1.2X002", protocol_array[3]) == 0) &&
2571                          (strcmp("LANMAN2.1", protocol_array[4]) == 0) &&
2572                          (strcmp("NT LM 0.12", protocol_array[5]) == 0)) {
2573                         isWindows2000 = TRUE;
2574                         osi_Log0(smb_logp, "Looks like a Windows 2000 client");
2575                         /* 
2576                          * HACK: for now - just negotiate a lower protocol till we 
2577                          * figure out which flag/flag2 or some other field 
2578                          * (capabilities maybe?) to set in order for this to work
2579                          * correctly with Windows 2000 clients (defect 11765)
2580                          */
2581                         NTProtoIndex = -1;
2582                         /* Things to try (after looking at tcpdump output could be
2583                          * setting flags and flags2 to 0x98 and 0xc853 like this
2584                          * op->reb = 0x98; op->flg2 = 0xc853;
2585                          * osi_Log2(smb_logp, "Flags:0x%x Flags2:0x%x", ip->reb, ip->flg2);
2586                          */
2587                 }       
2588         }       
2589 #endif /* NOMOREFILESFIX */
2590
2591         if (NTProtoIndex != -1) {
2592                 protoIndex = NTProtoIndex;
2593                 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2594         }
2595         else if (v3ProtoIndex != -1) {
2596                 protoIndex = v3ProtoIndex;
2597                 vcp->flags |= SMB_VCFLAG_USEV3;
2598         }       
2599         else if (coreProtoIndex != -1) {
2600                 protoIndex = coreProtoIndex;
2601                 vcp->flags |= SMB_VCFLAG_USECORE;
2602         }       
2603         else protoIndex = -1;
2604
2605         if (protoIndex == -1)
2606                 return CM_ERROR_INVAL;
2607         else if (NTProtoIndex != -1) {
2608         smb_SetSMBParm(outp, 0, protoIndex);
2609                 if (smb_authType != SMB_AUTH_NONE) {
2610                         smb_SetSMBParmByte(outp, 1,
2611                                 NEGOTIATE_SECURITY_USER_LEVEL |
2612                                 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2613                 } else {
2614             smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
2615                 }
2616         smb_SetSMBParm(outp, 1, smb_maxMpxRequests);    /* max multiplexed requests */
2617         smb_SetSMBParm(outp, 2, smb_maxVCPerServer);    /* max VCs per consumer/server connection */
2618         smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE);    /* xmit buffer size */
2619                 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE);    /* raw buffer size */
2620         /* The session key is not a well documented field however most clients
2621          * will echo back the session key to the server.  Currently we are using
2622          * the same value for all sessions.  We should generate a random value
2623          * and store it into the vcp 
2624          */
2625         smb_SetSMBParm(outp, 7, 1);     /* next 2: session key */
2626         smb_SetSMBParm(outp, 8, 1);
2627                 /* 
2628                  * Tried changing the capabilities to support for W2K - defect 117695
2629                  * Maybe something else needs to be changed here?
2630                  */
2631                 /*
2632                   if (isWindows2000) 
2633                   smb_SetSMBParmLong(outp, 9, 0x43fd);
2634                   else 
2635                   smb_SetSMBParmLong(outp, 9, 0x251);
2636                   */
2637                 /* Capabilities: *
2638                  * 32-bit error codes *
2639                  * and NT Find *
2640                  * and NT SMB's *
2641                  * and raw mode */
2642         caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
2643                            NTNEGOTIATE_CAPABILITY_NTFIND |
2644                NTNEGOTIATE_CAPABILITY_RAWMODE |
2645                            NTNEGOTIATE_CAPABILITY_NTSMB;
2646
2647         if ( smb_authType == SMB_AUTH_EXTENDED )
2648             caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
2649
2650         smb_SetSMBParmLong(outp, 9, caps);
2651                 time(&unixTime);
2652                 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2653                 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
2654                 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
2655
2656                 GetTimeZoneInformation(&tzi);
2657                 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias);    /* server tzone */
2658
2659                 if (smb_authType == SMB_AUTH_NTLM) {
2660                         smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
2661                         smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
2662                         /* paste in encryption key */
2663                         datap = smb_GetSMBData(outp, NULL);
2664                         memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
2665                         /* and the faux domain name */
2666                         strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
2667                 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
2668             void * secBlob;
2669                         int secBlobLength;
2670
2671                         smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2672
2673                         smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
2674
2675                         smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
2676                         
2677                         datap = smb_GetSMBData(outp, NULL);
2678                         memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
2679
2680                         if (secBlob) {
2681                                 datap += sizeof(smb_ServerGUID);
2682                                 memcpy(datap, secBlob, secBlobLength);
2683                                 free(secBlob);
2684                         }
2685         } else {
2686                         smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2687                         smb_SetSMBDataLength(outp, 0);   /* Perhaps we should specify 8 bytes anyway */
2688                 }
2689         }
2690         else if (v3ProtoIndex != -1) {
2691                 smb_SetSMBParm(outp, 0, protoIndex);
2692
2693         /* NOTE: Extended authentication cannot be negotiated with v3
2694          * therefore we fail over to NTLM 
2695          */
2696         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2697                         smb_SetSMBParm(outp, 1,
2698                                 NEGOTIATE_SECURITY_USER_LEVEL |
2699                                 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2700                 } else {
2701                         smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
2702                 }
2703                 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
2704                 smb_SetSMBParm(outp, 3, smb_maxMpxRequests);    /* max multiplexed requests */
2705                 smb_SetSMBParm(outp, 4, smb_maxVCPerServer);    /* max VCs per consumer/server connection */
2706                 smb_SetSMBParm(outp, 5, 0);     /* no support of block mode for read or write */
2707                 smb_SetSMBParm(outp, 6, 1);     /* next 2: session key */
2708                 smb_SetSMBParm(outp, 7, 1);
2709                 time(&unixTime);
2710                 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2711                 smb_SetSMBParm(outp, 8, LOWORD(dosTime));       /* server time */
2712                 smb_SetSMBParm(outp, 9, HIWORD(dosTime));       /* server date */
2713
2714                 GetTimeZoneInformation(&tzi);
2715                 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias);    /* server tzone */
2716
2717         /* NOTE: Extended authentication cannot be negotiated with v3
2718          * therefore we fail over to NTLM 
2719          */
2720                 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2721                         smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH);      /* encryption key length */
2722             smb_SetSMBParm(outp, 12, 0);        /* resvd */
2723                         smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);       /* perhaps should specify 8 bytes anyway */
2724                         datap = smb_GetSMBData(outp, NULL);
2725                         /* paste in a new encryption key */
2726                         memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
2727                         /* and the faux domain name */
2728                         strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
2729                 } else {
2730                         smb_SetSMBParm(outp, 11, 0); /* encryption key length */
2731                         smb_SetSMBParm(outp, 12, 0); /* resvd */
2732                         smb_SetSMBDataLength(outp, 0);
2733                 }
2734         }
2735         else if (coreProtoIndex != -1) {     /* not really supported anymore */
2736                 smb_SetSMBParm(outp, 0, protoIndex);
2737                 smb_SetSMBDataLength(outp, 0);
2738         }
2739         return 0;
2740 }
2741
2742 void smb_Daemon(void *parmp)
2743 {
2744         int count = 0;
2745
2746         while(1) {
2747                 count++;
2748                 thrd_Sleep(10000);
2749                 if ((count % 360) == 0) {       /* every hour */
2750             struct tm myTime;
2751                  
2752             /* Initialize smb_localZero */
2753             myTime.tm_isdst = -1;               /* compute whether on DST or not */
2754             myTime.tm_year = 70;
2755             myTime.tm_mon = 0;
2756             myTime.tm_mday = 1;
2757             myTime.tm_hour = 0;
2758             myTime.tm_min = 0;
2759             myTime.tm_sec = 0;
2760             smb_localZero = mktime(&myTime);
2761
2762             smb_CalculateNowTZ();
2763         }
2764                 /* XXX GC dir search entries */
2765         }
2766 }
2767
2768 void smb_WaitingLocksDaemon()
2769 {
2770         smb_waitingLock_t *wL, *nwL;
2771         int first;
2772         smb_vc_t *vcp;
2773         smb_packet_t *inp, *outp;
2774         NCB *ncbp;
2775         long code = 0;
2776
2777         while(1) {
2778                 lock_ObtainWrite(&smb_globalLock);
2779                 nwL = smb_allWaitingLocks;
2780                 if (nwL == NULL) {
2781                         osi_SleepW((long)&smb_allWaitingLocks, &smb_globalLock);
2782                         thrd_Sleep(1000);
2783                         continue;
2784                 }
2785                 else first = 1;
2786                 do {
2787                         if (first)
2788                                 first = 0;
2789                         else
2790                                 lock_ObtainWrite(&smb_globalLock);
2791                         wL = nwL;
2792                         nwL = (smb_waitingLock_t *) osi_QNext(&wL->q);
2793                         lock_ReleaseWrite(&smb_globalLock);
2794                         code = cm_RetryLock((cm_file_lock_t *) wL->lockp,
2795                                                                 wL->vcp->flags & SMB_VCFLAG_ALREADYDEAD);
2796                         if (code == CM_ERROR_WOULDBLOCK) {
2797                                 /* no progress */
2798                                 if (wL->timeRemaining != 0xffffffff
2799                                     && (wL->timeRemaining -= 1000) < 0)
2800                                         goto endWait;
2801                                 continue;
2802                         }
2803                   endWait:
2804                         vcp = wL->vcp;
2805                         inp = wL->inp;
2806                         outp = wL->outp;
2807                         ncbp = GetNCB();
2808                         ncbp->ncb_length = inp->ncb_length;
2809                         inp->spacep = cm_GetSpace();
2810
2811                         /* Remove waitingLock from list */
2812                         lock_ObtainWrite(&smb_globalLock);
2813                         osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
2814                                     &wL->q);
2815                         lock_ReleaseWrite(&smb_globalLock);
2816
2817                         /* Resume packet processing */
2818                         if (code == 0)
2819                                 smb_SetSMBDataLength(outp, 0);
2820                         outp->flags |= SMB_PACKETFLAG_SUSPENDED;
2821                         outp->resumeCode = code;
2822                         outp->ncbp = ncbp;
2823                         smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
2824
2825                         /* Clean up */
2826                         cm_FreeSpace(inp->spacep);
2827                         smb_FreePacket(inp);
2828                         smb_FreePacket(outp);
2829                         FreeNCB(ncbp);
2830                         free(wL);
2831                 } while (nwL);
2832                 thrd_Sleep(1000);
2833         }
2834 }
2835
2836 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2837 {
2838         osi_Log0(smb_logp, "SMB receive get disk attributes");
2839
2840         smb_SetSMBParm(outp, 0, 32000);
2841         smb_SetSMBParm(outp, 1, 64);
2842         smb_SetSMBParm(outp, 2, 1024);
2843         smb_SetSMBParm(outp, 3, 30000);
2844         smb_SetSMBParm(outp, 4, 0);
2845         smb_SetSMBDataLength(outp, 0);
2846         return 0;
2847 }
2848
2849 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
2850 {
2851         smb_tid_t *tidp;
2852     smb_user_t *uidp;
2853         unsigned short newTid;
2854         char shareName[256];
2855         char *sharePath;
2856         int shareFound;
2857         char *tp;
2858         char *pathp;
2859         char *passwordp;
2860         cm_user_t *userp;
2861
2862         osi_Log0(smb_logp, "SMB receive tree connect");
2863
2864         /* parse input parameters */
2865         tp = smb_GetSMBData(inp, NULL);
2866         pathp = smb_ParseASCIIBlock(tp, &tp);
2867         passwordp = smb_ParseASCIIBlock(tp, &tp);
2868         tp = strrchr(pathp, '\\');
2869         if (!tp)
2870                 return CM_ERROR_BADSMB;
2871         strcpy(shareName, tp+1);
2872
2873         userp = smb_GetUser(vcp, inp);
2874
2875         lock_ObtainMutex(&vcp->mx);
2876         newTid = vcp->tidCounter++;
2877         lock_ReleaseMutex(&vcp->mx);
2878         
2879         tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
2880     uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
2881         shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
2882     if (uidp)
2883         smb_ReleaseUID(uidp);
2884         if (!shareFound) {
2885                 smb_ReleaseTID(tidp);
2886                 return CM_ERROR_BADSHARENAME;
2887         }
2888         lock_ObtainMutex(&tidp->mx);
2889         tidp->userp = userp;
2890         tidp->pathname = sharePath;
2891         lock_ReleaseMutex(&tidp->mx);
2892         smb_ReleaseTID(tidp);
2893
2894         smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
2895         smb_SetSMBParm(rsp, 1, newTid);
2896         smb_SetSMBDataLength(rsp, 0);
2897
2898         osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
2899         return 0;
2900 }
2901
2902 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2903 {
2904         int tlen;
2905
2906         if (*inp++ != 0x1) return NULL;
2907         tlen = inp[0] + (inp[1]<<8);
2908         inp += 2;               /* skip length field */
2909         
2910         if (chainpp) {
2911                 *chainpp = inp + tlen;
2912         }       
2913         
2914         if (lengthp) *lengthp = tlen;
2915         
2916         return inp;
2917 }
2918
2919 /* set maskp to the mask part of the incoming path.
2920  * Mask is 11 bytes long (8.3 with the dot elided).
2921  * Returns true if succeeds with a valid name, otherwise it does
2922  * its best, but returns false.
2923  */
2924 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
2925 {
2926         char *tp;
2927         char *up;
2928         int i;
2929         int tc;
2930         int valid8Dot3;
2931
2932         /* starts off valid */
2933         valid8Dot3 = 1;
2934
2935         /* mask starts out all blanks */
2936         memset(maskp, ' ', 11);
2937
2938         /* find last backslash, or use whole thing if there is none */
2939         tp = strrchr(pathp, '\\');
2940         if (!tp) tp = pathp;
2941         else tp++;      /* skip slash */
2942         
2943         up = maskp;
2944
2945         /* names starting with a dot are illegal */
2946         if (*tp == '.') valid8Dot3 = 0;
2947
2948     for(i=0;; i++) {
2949                 tc = *tp++;
2950         if (tc == 0) return valid8Dot3;
2951         if (tc == '.' || tc == '"') break;
2952         if (i < 8) *up++ = tc;
2953         else valid8Dot3 = 0;
2954     }
2955         
2956     /* if we get here, tp point after the dot */
2957     up = maskp+8;       /* ext goes here */
2958     for(i=0;;i++) {
2959         tc = *tp++;
2960         if (tc == 0) 
2961                         return valid8Dot3;
2962
2963         /* too many dots */
2964         if (tc == '.' || tc == '"') 
2965                         valid8Dot3 = 0;
2966
2967         /* copy extension if not too long */
2968         if (i < 3) 
2969                         *up++ = tc;
2970         else 
2971                         valid8Dot3 = 0;
2972     }   
2973
2974     /* unreachable */
2975 }
2976
2977 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
2978 {
2979         char umask[11];
2980         int valid;
2981         int i;
2982         char tc1;
2983         char tc2;
2984         char *tp1;
2985         char *tp2;
2986
2987         /* XXX redo this, calling smb_V3MatchMask with a converted mask */
2988
2989         valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
2990         if (!valid) 
2991                 return 0;
2992  
2993         /* otherwise, we have a valid 8.3 name; see if we have a match,
2994          * treating '?' as a wildcard in maskp (but not in the file name).
2995          */
2996         tp1 = umask;    /* real name, in mask format */
2997         tp2 = maskp;    /* mask, in mask format */
2998         for(i=0; i<11; i++) {
2999                 tc1 = *tp1++;   /* char from real name */
3000                 tc2 = *tp2++;   /* char from mask */
3001                 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3002                 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3003                 if (tc1 == tc2) 
3004                         continue;
3005                 if (tc2 == '?' && tc1 != ' ') 
3006                         continue;
3007                 if (tc2 == '>') 
3008                         continue;
3009                 return 0;
3010         }
3011
3012         /* we got a match */
3013         return 1;
3014 }
3015
3016 char *smb_FindMask(char *pathp)
3017 {
3018         char *tp;
3019         
3020         tp = strrchr(pathp, '\\');      /* find last slash */
3021
3022         if (tp) 
3023                 return tp+1;    /* skip the slash */
3024         else 
3025                 return pathp;   /* no slash, return the entire path */
3026 }
3027
3028 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3029 {
3030         unsigned char *pathp;
3031         unsigned char *tp;
3032         unsigned char mask[11];
3033         unsigned char *statBlockp;
3034         unsigned char initStatBlock[21];
3035         int statLen;
3036         
3037         osi_Log0(smb_logp, "SMB receive search volume");
3038
3039         /* pull pathname and stat block out of request */
3040         tp = smb_GetSMBData(inp, NULL);
3041         pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3042         osi_assert(pathp != NULL);
3043         statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3044         osi_assert(statBlockp != NULL);
3045         if (statLen == 0) {
3046                 statBlockp = initStatBlock;
3047                 statBlockp[0] = 8;
3048         }
3049         
3050         /* for returning to caller */
3051         smb_Get8Dot3MaskFromPath(mask, pathp);
3052         
3053         smb_SetSMBParm(outp, 0, 1);             /* we're returning one entry */
3054         tp = smb_GetSMBData(outp, NULL);
3055         *tp++ = 5;
3056         *tp++ = 43;     /* bytes in a dir entry */
3057         *tp++ = 0;      /* high byte in counter */
3058
3059         /* now marshall the dir entry, starting with the search status */
3060         *tp++ = statBlockp[0];          /* Reserved */
3061         memcpy(tp, mask, 11); tp += 11; /* FileName */
3062
3063         /* now pass back server use info, with 1st byte non-zero */
3064         *tp++ = 1;
3065         memset(tp, 0, 4); tp += 4;      /* reserved for server use */
3066
3067         memcpy(tp, statBlockp+17, 4); tp += 4;  /* reserved for consumer */
3068
3069         *tp++ = 0x8;            /* attribute: volume */
3070
3071         /* copy out time */
3072         *tp++ = 0;
3073         *tp++ = 0;
3074
3075         /* copy out date */
3076         *tp++ = 18;
3077         *tp++ = 178;
3078
3079         /* 4 byte file size */
3080         *tp++ = 0;
3081         *tp++ = 0;
3082         *tp++ = 0;
3083         *tp++ = 0;
3084
3085         /* finally, null-terminated 8.3 pathname, which we set to AFS */
3086         memset(tp, ' ', 13);
3087         strcpy(tp, "AFS");
3088
3089         /* set the length of the data part of the packet to 43 + 3, for the dir
3090          * entry plus the 5 and the length fields.
3091          */
3092         smb_SetSMBDataLength(outp, 46);
3093         return 0;
3094 }
3095
3096 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3097         cm_user_t *userp, cm_req_t *reqp)
3098 {
3099         long code = 0;
3100         cm_scache_t *scp;
3101         char *dptr;
3102         long dosTime;
3103         u_short shortTemp;
3104         char attr;
3105         smb_dirListPatch_t *patchp;
3106         smb_dirListPatch_t *npatchp;
3107
3108         for(patchp = *dirPatchespp; patchp; patchp =
3109                  (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3110                 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3111                 if (code) continue;
3112                 lock_ObtainMutex(&scp->mx);
3113                 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3114                                                   CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3115                 if (code) {     
3116                         lock_ReleaseMutex(&scp->mx);
3117                         cm_ReleaseSCache(scp);
3118                         continue;
3119                 }
3120                 dptr = patchp->dptr;
3121
3122                 attr = smb_Attributes(scp);
3123         /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3124         if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3125             attr |= SMB_ATTR_HIDDEN;
3126         *dptr++ = attr;
3127
3128                 /* get dos time */
3129                 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3130                 
3131                 /* copy out time */
3132                 shortTemp = dosTime & 0xffff;
3133                 *((u_short *)dptr) = shortTemp;
3134                 dptr += 2;
3135
3136                 /* and copy out date */
3137                 shortTemp = (dosTime>>16) & 0xffff;
3138                 *((u_short *)dptr) = shortTemp;
3139                 dptr += 2;
3140                 
3141                 /* copy out file length */
3142                 *((u_long *)dptr) = scp->length.LowPart;
3143                 dptr += 4;
3144                 lock_ReleaseMutex(&scp->mx);
3145                 cm_ReleaseSCache(scp);
3146         }
3147         
3148         /* now free the patches */
3149         for(patchp = *dirPatchespp; patchp; patchp = npatchp) {
3150                 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3151                 free(patchp);
3152         }       
3153         
3154         /* and mark the list as empty */
3155         *dirPatchespp = NULL;
3156
3157         return code;
3158 }
3159
3160 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3161 {
3162         int attribute;
3163         long nextCookie;
3164         char *tp;
3165         long code = 0;
3166         char *pathp;
3167         cm_dirEntry_t *dep;
3168         int maxCount;
3169         smb_dirListPatch_t *dirListPatchesp;
3170         smb_dirListPatch_t *curPatchp;
3171         int dataLength;
3172         cm_buf_t *bufferp;
3173         long temp;
3174         osi_hyper_t dirLength;
3175         osi_hyper_t bufferOffset;
3176         osi_hyper_t curOffset;
3177         osi_hyper_t thyper;
3178         unsigned char *inCookiep;
3179         smb_dirSearch_t *dsp;
3180         cm_scache_t *scp;
3181         long entryInDir;
3182         long entryInBuffer;
3183         unsigned long clientCookie;
3184         cm_pageHeader_t *pageHeaderp;
3185         cm_user_t *userp = NULL;
3186         int slotInPage;
3187         char shortName[13];
3188         char *actualName;
3189         char *shortNameEnd;
3190         char mask[11];
3191         int returnedNames;
3192         long nextEntryCookie;
3193         int numDirChunks;               /* # of 32 byte dir chunks in this entry */
3194         char resByte;                   /* reserved byte from the cookie */
3195         char *op;                       /* output data ptr */
3196         char *origOp;                   /* original value of op */
3197         cm_space_t *spacep;             /* for pathname buffer */
3198         int starPattern;
3199         int rootPath = 0;
3200         int caseFold;
3201         char *tidPathp;
3202         cm_req_t req;
3203         cm_fid_t fid;
3204         int fileType;
3205
3206         cm_InitReq(&req);
3207
3208         maxCount = smb_GetSMBParm(inp, 0);
3209
3210         dirListPatchesp = NULL;
3211         
3212         caseFold = CM_FLAG_CASEFOLD;
3213
3214         tp = smb_GetSMBData(inp, NULL);
3215         pathp = smb_ParseASCIIBlock(tp, &tp);
3216         inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3217
3218         /* bail out if request looks bad */
3219         if (!tp || !pathp) {
3220                 return CM_ERROR_BADSMB;
3221         }
3222
3223         /* We can handle long names */
3224         if (vcp->flags & SMB_VCFLAG_USENT)
3225                 ((smb_t *)outp)->flg2 |= 0x40;  /* IS_LONG_NAME */
3226
3227         /* make sure we got a whole search status */
3228         if (dataLength < 21) {
3229                 nextCookie = 0;         /* start at the beginning of the dir */
3230                 resByte = 0;
3231                 clientCookie = 0;
3232                 attribute = smb_GetSMBParm(inp, 1);
3233
3234                 /* handle volume info in another function */
3235                 if (attribute & 0x8)
3236                         return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3237
3238                 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3239                                  maxCount, osi_LogSaveString(smb_logp, pathp));
3240
3241                 if (*pathp == 0) {      /* null pathp, treat as root dir */
3242                         if (!(attribute & SMB_ATTR_DIRECTORY))  /* exclude dirs */
3243                                 return CM_ERROR_NOFILES;
3244                         rootPath = 1;
3245                 }
3246
3247                 dsp = smb_NewDirSearch(0);
3248                 dsp->attribute = attribute;
3249                 smb_Get8Dot3MaskFromPath(mask, pathp);
3250                 memcpy(dsp->mask, mask, 11);
3251
3252                 /* track if this is likely to match a lot of entries */
3253                 if (smb_IsStarMask(mask)) starPattern = 1;
3254                 else starPattern = 0;
3255         }       
3256         else {
3257                 /* pull the next cookie value out of the search status block */
3258                 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3259                         + (inCookiep[16]<<24);
3260                 dsp = smb_FindDirSearch(inCookiep[12]);
3261                 if (!dsp) {
3262                         /* can't find dir search status; fatal error */
3263                         return CM_ERROR_BADFD;
3264                 }
3265                 attribute = dsp->attribute;
3266                 resByte = inCookiep[0];
3267
3268                 /* copy out client cookie, in host byte order.  Don't bother
3269                  * interpreting it, since we're just passing it through, anyway.
3270                  */
3271                 memcpy(&clientCookie, &inCookiep[17], 4);
3272
3273                 memcpy(mask, dsp->mask, 11);
3274
3275                 /* assume we're doing a star match if it has continued for more
3276                  * than one call.
3277                  */
3278                 starPattern = 1;
3279         }
3280
3281         osi_Log3(smb_logp, "SMB dir search cookie 0x%x, connection %d, attr 0x%x",
3282                          nextCookie, dsp->cookie, attribute);
3283
3284         userp = smb_GetUser(vcp, inp);
3285
3286         /* try to get the vnode for the path name next */
3287         lock_ObtainMutex(&dsp->mx);
3288         if (dsp->scp) {
3289                 scp = dsp->scp;
3290                 cm_HoldSCache(scp);
3291                 code = 0;
3292         }
3293         else {
3294                 spacep = inp->spacep;
3295                 smb_StripLastComponent(spacep->data, NULL, pathp);
3296                 lock_ReleaseMutex(&dsp->mx);
3297                 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3298                 code = cm_NameI(cm_rootSCachep, spacep->data,
3299                                                 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3300                 lock_ObtainMutex(&dsp->mx);
3301                 if (code == 0) {
3302                         if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
3303                         dsp->scp = scp;
3304                         /* we need one hold for the entry we just stored into,
3305                          * and one for our own processing.  When we're done with this
3306                          * function, we'll drop the one for our own processing.
3307                          * We held it once from the namei call, and so we do another hold
3308                          * now.
3309                          */
3310                         cm_HoldSCache(scp);
3311                         lock_ObtainMutex(&scp->mx);
3312                         if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3313                             && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3314                                 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3315                                 dsp->flags |= SMB_DIRSEARCH_BULKST;
3316                         }
3317                         lock_ReleaseMutex(&scp->mx);
3318                 }
3319         }
3320         lock_ReleaseMutex(&dsp->mx);
3321         if (code) {
3322                 cm_ReleaseUser(userp);
3323                 smb_DeleteDirSearch(dsp);
3324                 smb_ReleaseDirSearch(dsp);
3325                 return code;
3326         }
3327
3328         /* reserves space for parameter; we'll adjust it again later to the
3329          * real count of the # of entries we returned once we've actually
3330          * assembled the directory listing.
3331          */
3332         smb_SetSMBParm(outp, 0, 0);
3333         
3334         /* get the directory size */
3335         lock_ObtainMutex(&scp->mx);
3336         code = cm_SyncOp(scp, NULL, userp, &req, 0,
3337                                          CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3338         if (code) {
3339                 lock_ReleaseMutex(&scp->mx);
3340                 cm_ReleaseSCache(scp);
3341                 cm_ReleaseUser(userp);
3342                 smb_DeleteDirSearch(dsp);
3343                 smb_ReleaseDirSearch(dsp);
3344                 return code;
3345         }
3346         
3347         dirLength = scp->length;
3348         bufferp = NULL;
3349         bufferOffset.LowPart = bufferOffset.HighPart = 0;
3350         curOffset.HighPart = 0;
3351         curOffset.LowPart = nextCookie;
3352         origOp = op = smb_GetSMBData(outp, NULL);
3353         /* and write out the basic header */
3354         *op++ = 5;              /* variable block */
3355         op += 2;                /* skip vbl block length; we'll fill it in later */
3356         code = 0;
3357         returnedNames = 0;
3358         while (1) {
3359                 /* make sure that curOffset.LowPart doesn't point to the first
3360                  * 32 bytes in the 2nd through last dir page, and that it doesn't
3361                  * point at the first 13 32-byte chunks in the first dir page,
3362                  * since those are dir and page headers, and don't contain useful
3363                  * information.
3364                  */
3365                 temp = curOffset.LowPart & (2048-1);
3366                 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3367                         /* we're in the first page */
3368                         if (temp < 13*32) temp = 13*32;
3369                 }
3370                 else {
3371                         /* we're in a later dir page */
3372                         if (temp < 32) temp = 32;
3373                 }
3374                 
3375                 /* make sure the low order 5 bits are zero */
3376                 temp &= ~(32-1);
3377
3378                 /* now put temp bits back ito curOffset.LowPart */
3379                 curOffset.LowPart &= ~(2048-1);
3380                 curOffset.LowPart |= temp;
3381
3382                 /* check if we've returned all the names that will fit in the
3383                  * response packet.
3384                  */
3385                 if (returnedNames >= maxCount) 
3386                         break;
3387                 
3388                 /* check if we've passed the dir's EOF */
3389                 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
3390
3391                 /* see if we can use the bufferp we have now; compute in which page
3392                  * the current offset would be, and check whether that's the offset
3393                  * of the buffer we have.  If not, get the buffer.
3394                  */
3395                 thyper.HighPart = curOffset.HighPart;
3396                 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
3397                 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3398                         /* wrong buffer */
3399                         if (bufferp) {
3400                                 buf_Release(bufferp);
3401                                 bufferp = NULL;
3402                         }       
3403                         lock_ReleaseMutex(&scp->mx);
3404                         lock_ObtainRead(&scp->bufCreateLock);
3405                         code = buf_Get(scp, &thyper, &bufferp);
3406                         lock_ReleaseRead(&scp->bufCreateLock);
3407
3408                         /* now, if we're doing a star match, do bulk fetching of all of 
3409                          * the status info for files in the dir.
3410                          */
3411                         if (starPattern) {
3412                                 smb_ApplyDirListPatches(&dirListPatchesp, userp,
3413                                                                                 &req);
3414                                 if ((dsp->flags & SMB_DIRSEARCH_BULKST)
3415                                     && LargeIntegerGreaterThanOrEqualTo(thyper, 
3416                                                                         scp->bulkStatProgress)) {
3417                                         /* Don't bulk stat if risking timeout */
3418                                         int now = GetCurrentTime();
3419                                         if (now - req.startTime > 5000) {
3420                                                 scp->bulkStatProgress = thyper;
3421                                                 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3422                                                 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3423                                         } else
3424                                                 cm_TryBulkStat(scp, &thyper, userp, &req);
3425                                 }
3426                         }
3427
3428                         lock_ObtainMutex(&scp->mx);
3429                         if (code) 
3430                                 break;
3431                         bufferOffset = thyper;
3432
3433                         /* now get the data in the cache */
3434                         while (1) {
3435                                 code = cm_SyncOp(scp, bufferp, userp, &req,
3436                                                                   PRSFS_LOOKUP,
3437                                                                   CM_SCACHESYNC_NEEDCALLBACK
3438                                                                   | CM_SCACHESYNC_READ);
3439                                 if (code) break;
3440                                 
3441                                 if (cm_HaveBuffer(scp, bufferp, 0)) break;
3442
3443                                 /* otherwise, load the buffer and try again */
3444                                 code = cm_GetBuffer(scp, bufferp, NULL, userp,
3445                                                                         &req);