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