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