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