windows-eventlog-20051219
[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     time_t diff_t = unixTime - smb_localZero;
797 #if defined(DEBUG) && !defined(_USE_32BIT_TIME_T)
798     osi_assert(diff_t < _UI32_MAX);
799 #endif
800     *dosUTimep = (afs_uint32)diff_t;
801 }
802
803 void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
804 {
805 #ifndef DJGPP
806     *unixTimep = dosTime + smb_localZero;
807 #else /* DJGPP */
808     /* dosTime seems to be already adjusted for GMT */
809     *unixTimep = dosTime;
810 #endif /* !DJGPP */
811 }
812
813 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
814 {
815     smb_vc_t *vcp;
816
817     lock_ObtainWrite(&smb_rctLock);
818     for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
819         if (lsn == vcp->lsn && lana == vcp->lana) {
820             smb_HoldVCNoLock(vcp);
821             break;
822         }
823     }
824     if (!vcp && (flags & SMB_FLAG_CREATE)) {
825         vcp = malloc(sizeof(*vcp));
826         memset(vcp, 0, sizeof(*vcp));
827         vcp->vcID = numVCs++;
828         vcp->refCount = 1;
829         vcp->tidCounter = 1;
830         vcp->fidCounter = 1;
831         vcp->uidCounter = 1;  /* UID 0 is reserved for blank user */
832         vcp->nextp = smb_allVCsp;
833         smb_allVCsp = vcp;
834         lock_InitializeMutex(&vcp->mx, "vc_t mutex");
835         vcp->lsn = lsn;
836         vcp->lana = lana;
837         vcp->secCtx = NULL;
838
839         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
840             /* We must obtain a challenge for extended auth 
841              * in case the client negotiates smb v3 
842              */
843             NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
844             MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
845             PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp;
846             ULONG lsaRespSize = 0;
847
848             lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
849
850             nts = LsaCallAuthenticationPackage( smb_lsaHandle,
851                                                 smb_lsaSecPackage,
852                                                 &lsaReq,
853                                                 sizeof(lsaReq),
854                                                 &lsaResp,
855                                                 &lsaRespSize,
856                                                 &ntsEx);
857             if (nts != STATUS_SUCCESS)
858                 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
859                          nts, ntsEx, sizeof(lsaReq), lsaRespSize);
860             osi_assert(nts == STATUS_SUCCESS); /* this had better work! */
861
862             memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
863             LsaFreeReturnBuffer(lsaResp);
864         }
865         else
866             memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
867
868         if (numVCs >= CM_SESSION_RESERVED) {
869             numVCs = 0;
870             osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
871         }
872     }
873     lock_ReleaseWrite(&smb_rctLock);
874     return vcp;
875 }
876
877 int smb_IsStarMask(char *maskp)
878 {
879     int i;
880     char tc;
881         
882     for(i=0; i<11; i++) {
883         tc = *maskp++;
884         if (tc == '?' || tc == '*' || tc == '>') return 1;        
885     }   
886     return 0;
887 }
888
889 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
890 {
891     osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
892 #ifdef DEBUG
893     osi_assert(vcp->refCount-- != 0);
894 #else
895     vcp->refCount--;
896 #endif
897 }       
898
899 void smb_ReleaseVC(smb_vc_t *vcp)
900 {
901     lock_ObtainWrite(&smb_rctLock);
902     osi_Log2(smb_logp,"smb_ReleaseVC       vcp %x ref %d",vcp, vcp->refCount);
903 #ifdef DEBUG
904     osi_assert(vcp->refCount-- != 0);
905 #else
906     vcp->refCount--;
907 #endif
908     lock_ReleaseWrite(&smb_rctLock);
909 }       
910
911 void smb_HoldVCNoLock(smb_vc_t *vcp)
912 {
913     vcp->refCount++;
914     osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
915 }       
916
917 void smb_HoldVC(smb_vc_t *vcp)
918 {
919     lock_ObtainWrite(&smb_rctLock);
920     vcp->refCount++;
921     osi_Log2(smb_logp,"smb_HoldVC       vcp %x ref %d",vcp, vcp->refCount);
922     lock_ReleaseWrite(&smb_rctLock);
923 }       
924
925 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
926 {
927     smb_tid_t *tidp;
928
929     lock_ObtainWrite(&smb_rctLock);
930     for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
931         if (tid == tidp->tid) {
932             tidp->refCount++;
933             break;
934         }       
935     }
936     if (!tidp && (flags & SMB_FLAG_CREATE)) {
937         tidp = malloc(sizeof(*tidp));
938         memset(tidp, 0, sizeof(*tidp));
939         tidp->nextp = vcp->tidsp;
940         tidp->refCount = 1;
941         tidp->vcp = vcp;
942         smb_HoldVCNoLock(vcp);
943         vcp->tidsp = tidp;
944         lock_InitializeMutex(&tidp->mx, "tid_t mutex");
945         tidp->tid = tid;
946     }
947     lock_ReleaseWrite(&smb_rctLock);
948     return tidp;
949 }               
950
951 void smb_ReleaseTID(smb_tid_t *tidp)
952 {
953     smb_tid_t *tp;
954     smb_tid_t **ltpp;
955     cm_user_t *userp;
956
957     userp = NULL;
958     lock_ObtainWrite(&smb_rctLock);
959     osi_assert(tidp->refCount-- > 0);
960     if (tidp->refCount == 0 && (tidp->flags & SMB_TIDFLAG_DELETE)) {
961         ltpp = &tidp->vcp->tidsp;
962         for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
963             if (tp == tidp) 
964                 break;
965         }
966         osi_assert(tp != NULL);
967         *ltpp = tp->nextp;
968         lock_FinalizeMutex(&tidp->mx);
969         userp = tidp->userp;    /* remember to drop ref later */
970         tidp->userp = NULL;
971         smb_ReleaseVCNoLock(tidp->vcp);
972         tidp->vcp = 0;
973     }
974     lock_ReleaseWrite(&smb_rctLock);
975     if (userp)
976         cm_ReleaseUser(userp);
977 }               
978
979 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
980 {
981     smb_user_t *uidp = NULL;
982
983     lock_ObtainWrite(&smb_rctLock);
984     for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
985         if (uid == uidp->userID) {
986             uidp->refCount++;
987             osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%s]",
988                      vcp, uidp->userID, 
989                      osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
990             break;
991         }
992     }
993     if (!uidp && (flags & SMB_FLAG_CREATE)) {
994         uidp = malloc(sizeof(*uidp));
995         memset(uidp, 0, sizeof(*uidp));
996         uidp->nextp = vcp->usersp;
997         uidp->refCount = 1;
998         uidp->vcp = vcp;
999         smb_HoldVCNoLock(vcp);
1000         vcp->usersp = uidp;
1001         lock_InitializeMutex(&uidp->mx, "user_t mutex");
1002         uidp->userID = uid;
1003         osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%s]",
1004                  vcp, uidp->userID, 
1005                  osi_LogSaveString(smb_logp,uidp->unp ? uidp->unp->name : ""));
1006     }
1007     lock_ReleaseWrite(&smb_rctLock);
1008     return uidp;
1009 }               
1010
1011 smb_username_t *smb_FindUserByName(char *usern, char *machine, int flags)
1012 {
1013     smb_username_t *unp= NULL;
1014
1015     lock_ObtainWrite(&smb_rctLock);
1016     for(unp = usernamesp; unp; unp = unp->nextp) {
1017         if (stricmp(unp->name, usern) == 0 &&
1018              stricmp(unp->machine, machine) == 0) {
1019             unp->refCount++;
1020             break;
1021         }
1022     }
1023     if (!unp && (flags & SMB_FLAG_CREATE)) {
1024         unp = malloc(sizeof(*unp));
1025         memset(unp, 0, sizeof(*unp));
1026         unp->refCount = 1;
1027         unp->nextp = usernamesp;
1028         unp->name = strdup(usern);
1029         unp->machine = strdup(machine);
1030         usernamesp = unp;
1031         lock_InitializeMutex(&unp->mx, "username_t mutex");
1032     }
1033     lock_ReleaseWrite(&smb_rctLock);
1034     return unp;
1035 }       
1036
1037 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
1038 {
1039     smb_user_t *uidp= NULL;
1040
1041     lock_ObtainWrite(&smb_rctLock);
1042     for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1043         if (!uidp->unp) 
1044             continue;
1045         if (stricmp(uidp->unp->name, usern) == 0) {
1046             uidp->refCount++;
1047             osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%s]",
1048                      vcp,uidp->userID,osi_LogSaveString(smb_logp,usern));
1049             break;
1050         } else
1051             continue;
1052     }           
1053     lock_ReleaseWrite(&smb_rctLock);
1054     return uidp;
1055 }       
1056 void smb_ReleaseUID(smb_user_t *uidp)
1057 {
1058     smb_user_t *up;
1059     smb_user_t **lupp;
1060     cm_user_t *userp;
1061
1062     userp = NULL;
1063     lock_ObtainWrite(&smb_rctLock);
1064     osi_assert(uidp->refCount-- > 0);
1065     if (uidp->refCount == 0 && (uidp->flags & SMB_USERFLAG_DELETE)) {
1066         lupp = &uidp->vcp->usersp;
1067         for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1068             if (up == uidp) 
1069                 break;
1070         }
1071         osi_assert(up != NULL);
1072         *lupp = up->nextp;
1073         lock_FinalizeMutex(&uidp->mx);
1074         if (uidp->unp) {
1075             userp = uidp->unp->userp;   /* avoid deadlock by releasing */
1076             uidp->unp->userp = NULL;    /* after releasing the lock */
1077         }       
1078         smb_ReleaseVCNoLock(uidp->vcp);
1079         uidp->vcp = NULL;
1080     }           
1081     lock_ReleaseWrite(&smb_rctLock);
1082     if (userp) {
1083         cm_ReleaseUserVCRef(userp);
1084         cm_ReleaseUser(userp);
1085     }   
1086 }       
1087
1088
1089 /* retrieve a held reference to a user structure corresponding to an incoming
1090  * request.
1091  * corresponding release function is cm_ReleaseUser.
1092  */
1093 cm_user_t *smb_GetUser(smb_vc_t *vcp, smb_packet_t *inp)
1094 {
1095     smb_user_t *uidp;
1096     cm_user_t *up;
1097     smb_t *smbp;
1098
1099     smbp = (smb_t *) inp;
1100     uidp = smb_FindUID(vcp, smbp->uid, 0);
1101     if ((!uidp) ||  (!uidp->unp))
1102         return NULL;
1103
1104     lock_ObtainMutex(&uidp->mx);
1105     up = uidp->unp->userp;
1106     cm_HoldUser(up);
1107     lock_ReleaseMutex(&uidp->mx);
1108
1109     smb_ReleaseUID(uidp);
1110
1111     return up;
1112 }
1113
1114 /*
1115  * Return a pointer to a pathname extracted from a TID structure.  The
1116  * TID structure is not held; assume it won't go away.
1117  */
1118 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1119 {
1120     smb_tid_t *tidp;
1121     long code = 0;
1122
1123     tidp = smb_FindTID(vcp, tid, 0);
1124     if (!tidp) {
1125         *treepath = NULL;
1126     } else {
1127         if (tidp->flags & SMB_TIDFLAG_IPC) {
1128             code = CM_ERROR_TIDIPC;
1129             /* tidp->pathname would be NULL, but that's fine */
1130         }
1131         *treepath = tidp->pathname;
1132         smb_ReleaseTID(tidp);
1133     }
1134     return code;
1135 }
1136
1137 /* check to see if we have a chained fid, that is, a fid that comes from an
1138  * OpenAndX message that ran earlier in this packet.  In this case, the fid
1139  * field in a read, for example, request, isn't set, since the value is
1140  * supposed to be inherited from the openAndX call.
1141  */
1142 int smb_ChainFID(int fid, smb_packet_t *inp)
1143 {
1144     if (inp->fid == 0 || inp->inCount == 0) 
1145         return fid;
1146     else 
1147         return inp->fid;
1148 }
1149
1150 /* are we a priv'd user?  What does this mean on NT? */
1151 int smb_SUser(cm_user_t *userp)
1152 {
1153     return 1;
1154 }
1155
1156 /* find a file ID.  If we pass in 0 we select an unused File ID.
1157  * If the SMB_FLAG_CREATE flag is set, we allocate a new  
1158  * smb_fid_t data structure if desired File ID cannot be found.
1159  */
1160 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1161 {
1162     smb_fid_t *fidp;
1163     int newFid = 0;
1164         
1165     if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1166         return NULL;
1167
1168     lock_ObtainWrite(&smb_rctLock);
1169     /* figure out if we need to allocate a new file ID */
1170     if (fid == 0) {
1171         newFid = 1;
1172         fid = vcp->fidCounter;
1173     }
1174
1175   retry:
1176     for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1177         if (fid == fidp->fid) {
1178             if (newFid) {
1179                 fid++;
1180                 if (fid == 0) 
1181                     fid = 1;
1182                 goto retry;
1183             }
1184             fidp->refCount++;
1185             break;
1186         }
1187     }
1188
1189     if (!fidp && (flags & SMB_FLAG_CREATE)) {
1190         char eventName[MAX_PATH];
1191         EVENT_HANDLE event;
1192         sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1193         event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1194         if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1195             osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1196             thrd_CloseHandle(event);
1197             fid++;
1198             if (fid == 0)
1199                 fid = 1;
1200             goto retry;
1201         }
1202
1203         fidp = malloc(sizeof(*fidp));
1204         memset(fidp, 0, sizeof(*fidp));
1205         osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1206         fidp->refCount = 1;
1207         fidp->vcp = vcp;
1208         smb_HoldVCNoLock(vcp);
1209         lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1210         fidp->fid = fid;
1211         fidp->curr_chunk = fidp->prev_chunk = -2;
1212         fidp->raw_write_event = event;
1213         if (newFid) {
1214             vcp->fidCounter = fid+1;
1215             if (vcp->fidCounter == 0) 
1216                 vcp->fidCounter = 1;
1217         }
1218     }
1219
1220     lock_ReleaseWrite(&smb_rctLock);
1221     return fidp;
1222 }
1223
1224 void smb_ReleaseFID(smb_fid_t *fidp)
1225 {
1226     cm_scache_t *scp;
1227     smb_vc_t *vcp = NULL;
1228     smb_ioctl_t *ioctlp;
1229
1230     if (!fidp)
1231         return;
1232
1233     scp = NULL;
1234     lock_ObtainWrite(&smb_rctLock);
1235     osi_assert(fidp->refCount-- > 0);
1236     if (fidp->refCount == 0 && (fidp->flags & SMB_FID_DELETE)) {
1237         vcp = fidp->vcp;
1238         fidp->vcp = 0;
1239         scp = fidp->scp;    /* release after lock is released */
1240         fidp->scp = 0;
1241
1242         osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1243         thrd_CloseHandle(fidp->raw_write_event);
1244
1245         /* and see if there is ioctl stuff to free */
1246         ioctlp = fidp->ioctlp;
1247         if (ioctlp) {
1248             if (ioctlp->prefix)
1249                 cm_FreeSpace(ioctlp->prefix);
1250             if (ioctlp->inAllocp)
1251                 free(ioctlp->inAllocp);
1252             if (ioctlp->outAllocp)
1253                 free(ioctlp->outAllocp);
1254             free(ioctlp);
1255         }       
1256
1257         free(fidp);
1258
1259         smb_ReleaseVCNoLock(vcp);
1260     }
1261     lock_ReleaseWrite(&smb_rctLock);
1262
1263     /* now release the scache structure */
1264     if (scp) 
1265         cm_ReleaseSCache(scp);
1266 }       
1267
1268 /*
1269  * Case-insensitive search for one string in another;
1270  * used to find variable names in submount pathnames.
1271  */
1272 static char *smb_stristr(char *str1, char *str2)
1273 {
1274     char *cursor;
1275
1276     for (cursor = str1; *cursor; cursor++)
1277         if (stricmp(cursor, str2) == 0)
1278             return cursor;
1279
1280     return NULL;
1281 }
1282
1283 /*
1284  * Substitute a variable value for its name in a submount pathname.  Variable
1285  * name has been identified by smb_stristr() and is in substr.  Variable name
1286  * length (plus one) is in substr_size.  Variable value is in newstr.
1287  */
1288 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1289                       char *newstr)
1290 {
1291     char temp[1024];
1292
1293     strcpy(temp, substr + substr_size - 1);
1294     strcpy(substr, newstr);
1295     strcat(str1, temp);
1296 }       
1297
1298 char VNUserName[] = "%USERNAME%";
1299 char VNLCUserName[] = "%LCUSERNAME%";
1300 char VNComputerName[] = "%COMPUTERNAME%";
1301 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1302
1303 #ifdef DJGPP
1304 /* List available shares */
1305 int smb_ListShares()
1306 {
1307     char sbmtpath[256];
1308     char pathName[256];
1309     char shareBuf[4096];
1310     int num_shares=0;
1311     char *this_share;
1312     int len;
1313     char *p;
1314     int print_afs = 0;
1315     int code;
1316
1317     /*strcpy(shareNameList[num_shares], "all");
1318       strcpy(pathNameList[num_shares++], "/afs");*/
1319     fprintf(stderr, "The following shares are available:\n");
1320     fprintf(stderr, "Share Name (AFS Path)\n");
1321     fprintf(stderr, "---------------------\n");
1322     fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
1323
1324 #ifndef DJGPP
1325     code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1326     if (code == 0 || code > sizeof(sbmtpath)) return -1;
1327 #else
1328     strcpy(sbmtpath, cm_confDir);
1329 #endif /* !DJGPP */
1330     strcat(sbmtpath, "/afsdsbmt.ini");
1331     len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1332                                    shareBuf, sizeof(shareBuf),
1333                                    sbmtpath);
1334     if (len == 0) {
1335         return num_shares;
1336     }
1337
1338     this_share = shareBuf;
1339     do
1340     {
1341         print_afs = 0;
1342         /*strcpy(shareNameList[num_shares], this_share);*/
1343         len = GetPrivateProfileString("AFS Submounts", this_share,
1344                                        NULL,
1345                                        pathName, 256,
1346                                        sbmtpath);
1347         if (!len) 
1348             return num_shares;
1349         p = pathName;
1350         if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) != 0)
1351             print_afs = 1;
1352         while (*p) {
1353             if (*p == '\\') *p = '/';    /* change to / */
1354             p++;
1355         }
1356
1357         fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1358                  smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
1359                  pathName);
1360         num_shares++;
1361         while (*this_share != 0) this_share++;  /* find next NUL */
1362         this_share++;   /* skip past the NUL */
1363     } while (*this_share != 0);  /* stop at final NUL */
1364
1365     return num_shares;
1366 }
1367 #endif /* DJGPP */
1368
1369 typedef struct smb_findShare_rock {
1370     char * shareName;
1371     char * match;
1372     int matchType;
1373 } smb_findShare_rock_t;
1374
1375 #define SMB_FINDSHARE_EXACT_MATCH 1
1376 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1377
1378 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1379                        osi_hyper_t *offp)
1380 {
1381     int matchType = 0;
1382     smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1383     if (!strnicmp(dep->name, vrock->shareName, 12)) {
1384         if(!stricmp(dep->name, vrock->shareName))
1385             matchType = SMB_FINDSHARE_EXACT_MATCH;
1386         else
1387             matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1388         if(vrock->match) free(vrock->match);
1389         vrock->match = strdup(dep->name);
1390         vrock->matchType = matchType;
1391
1392         if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1393             return CM_ERROR_STOPNOW;
1394     }
1395     return 0;
1396 }
1397
1398
1399 /* find a shareName in the table of submounts */
1400 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1401         char **pathNamep)
1402 {
1403     DWORD len;
1404     char pathName[1024];
1405     char *var;
1406     char temp[1024];
1407     DWORD sizeTemp;
1408 #ifdef DJGPP
1409     char sbmtpath[MAX_PATH];
1410 #endif
1411     char *p, *q;
1412     HKEY parmKey;
1413     DWORD code;
1414     DWORD allSubmount = 1;
1415
1416     /* if allSubmounts == 0, only return the //mountRoot/all share 
1417      * if in fact it has been been created in the subMounts table.  
1418      * This is to allow sites that want to restrict access to the 
1419      * world to do so.
1420      */
1421     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1422                          0, KEY_QUERY_VALUE, &parmKey);
1423     if (code == ERROR_SUCCESS) {
1424         len = sizeof(allSubmount);
1425         code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1426                                 (BYTE *) &allSubmount, &len);
1427         if (code != ERROR_SUCCESS) {
1428             allSubmount = 1;
1429         }
1430         RegCloseKey (parmKey);
1431     }
1432
1433     if (allSubmount && _stricmp(shareName, "all") == 0) {
1434         *pathNamep = NULL;
1435         return 1;
1436     }
1437
1438     /* In case, the all share is disabled we need to still be able
1439      * to handle ioctl requests 
1440      */
1441     if (_stricmp(shareName, "ioctl$") == 0) {
1442         *pathNamep = strdup("/.__ioctl__");
1443         return 1;
1444     }
1445
1446     if (_stricmp(shareName, "IPC$") == 0 ||
1447         _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1448         _stricmp(shareName, "DESKTOP.INI") == 0
1449          ) {
1450         *pathNamep = NULL;
1451         return 0;
1452     }
1453
1454 #ifndef DJGPP
1455     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1456                          0, KEY_QUERY_VALUE, &parmKey);
1457     if (code == ERROR_SUCCESS) {
1458         len = sizeof(pathName);
1459         code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1460                                 (BYTE *) pathName, &len);
1461         if (code != ERROR_SUCCESS)
1462             len = 0;
1463         RegCloseKey (parmKey);
1464     } else {
1465         len = 0;
1466     }   
1467 #else /* DJGPP */
1468     strcpy(sbmtpath, cm_confDir);
1469     strcat(sbmtpath, "/afsdsbmt.ini");
1470     len = GetPrivateProfileString("AFS Submounts", shareName, "",
1471                                    pathName, sizeof(pathName), sbmtpath);
1472 #endif /* !DJGPP */
1473     if (len != 0 && len != sizeof(pathName) - 1) {
1474         /* We can accept either unix or PC style AFS pathnames.  Convert
1475          * Unix-style to PC style here for internal use. 
1476          */
1477         p = pathName;
1478         if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1479             p += strlen(cm_mountRoot);  /* skip mount path */
1480         q = p;
1481         while (*q) {
1482             if (*q == '/') *q = '\\';    /* change to \ */
1483             q++;
1484         }
1485
1486         while (1)
1487         {
1488             if (var = smb_stristr(p, VNUserName)) {
1489                 if (uidp && uidp->unp)
1490                     smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1491                 else
1492                     smb_subst(p, var, sizeof(VNUserName)," ");
1493             }
1494             else if (var = smb_stristr(p, VNLCUserName)) 
1495             {
1496                 if (uidp && uidp->unp)
1497                     strcpy(temp, uidp->unp->name);
1498                 else 
1499                     strcpy(temp, " ");
1500                 _strlwr(temp);
1501                 smb_subst(p, var, sizeof(VNLCUserName), temp);
1502             }
1503             else if (var = smb_stristr(p, VNComputerName)) 
1504             {
1505                 sizeTemp = sizeof(temp);
1506                 GetComputerName((LPTSTR)temp, &sizeTemp);
1507                 smb_subst(p, var, sizeof(VNComputerName), temp);
1508             }
1509             else if (var = smb_stristr(p, VNLCComputerName)) 
1510             {
1511                 sizeTemp = sizeof(temp);
1512                 GetComputerName((LPTSTR)temp, &sizeTemp);
1513                 _strlwr(temp);
1514                 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1515             }
1516             else     
1517                 break;
1518         }
1519         *pathNamep = strdup(p);
1520         return 1;
1521     } 
1522     else
1523     {
1524         /* First lookup shareName in root.afs */
1525         cm_req_t req;
1526         smb_findShare_rock_t vrock;
1527         osi_hyper_t thyper;
1528         char * p = shareName; 
1529         int rw = 0;
1530
1531         /*  attempt to locate a partial match in root.afs.  This is because
1532             when using the ANSI RAP calls, the share name is limited to 13 chars
1533             and hence is truncated. Of course we prefer exact matches. */
1534         cm_InitReq(&req);
1535         thyper.HighPart = 0;
1536         thyper.LowPart = 0;
1537
1538         vrock.shareName = shareName;
1539         vrock.match = NULL;
1540         vrock.matchType = 0;
1541
1542         cm_HoldSCache(cm_data.rootSCachep);
1543         code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1544             (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1545         cm_ReleaseSCache(cm_data.rootSCachep);
1546
1547         if (vrock.matchType) {
1548             sprintf(pathName,"/%s/",vrock.match);
1549             *pathNamep = strdup(strlwr(pathName));
1550             free(vrock.match);
1551             return 1;
1552         }
1553
1554         /* if we get here, there was no match for the share in root.afs */
1555         /* so try to create  \\<netbiosName>\<cellname>  */
1556         if ( *p == '.' ) {
1557             p++;
1558             rw = 1;
1559         }
1560         /* Get the full name for this cell */
1561         code = cm_SearchCellFile(p, temp, 0, 0);
1562 #ifdef AFS_AFSDB_ENV
1563         if (code && cm_dnsEnabled) {
1564             int ttl;
1565             code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1566         }
1567 #endif
1568         /* construct the path */
1569         if (code == 0) {     
1570             sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1571             *pathNamep = strdup(strlwr(pathName));
1572             return 1;
1573         }
1574     }
1575     /* failure */
1576     *pathNamep = NULL;
1577     return 0;
1578 }
1579
1580 /* Client-side offline caching policy types */
1581 #define CSC_POLICY_MANUAL 0
1582 #define CSC_POLICY_DOCUMENTS 1
1583 #define CSC_POLICY_PROGRAMS 2
1584 #define CSC_POLICY_DISABLE 3
1585
1586 int smb_FindShareCSCPolicy(char *shareName)
1587 {
1588     DWORD len;
1589     char policy[1024];
1590     DWORD dwType;
1591     HKEY hkCSCPolicy;
1592     int  retval = CSC_POLICY_MANUAL;
1593
1594     RegCreateKeyEx( HKEY_LOCAL_MACHINE, 
1595                     AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1596                     0, 
1597                     "AFS", 
1598                     REG_OPTION_NON_VOLATILE,
1599                     KEY_READ,
1600                     NULL, 
1601                     &hkCSCPolicy,
1602                     NULL );
1603
1604     len = sizeof(policy);
1605     if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1606          len == 0) {
1607         retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1608     }
1609     else if (stricmp(policy, "documents") == 0)
1610     {
1611         retval = CSC_POLICY_DOCUMENTS;
1612     }
1613     else if (stricmp(policy, "programs") == 0)
1614     {
1615         retval = CSC_POLICY_PROGRAMS;
1616     }
1617     else if (stricmp(policy, "disable") == 0)
1618     {
1619         retval = CSC_POLICY_DISABLE;
1620     }
1621         
1622     RegCloseKey(hkCSCPolicy);
1623     return retval;
1624 }
1625
1626 /* find a dir search structure by cookie value, and return it held.
1627  * Must be called with smb_globalLock held.
1628  */
1629 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
1630 {
1631     smb_dirSearch_t *dsp;
1632         
1633     for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1634         if (dsp->cookie == cookie) {
1635             if (dsp != smb_firstDirSearchp) {
1636                 /* move to head of LRU queue, too, if we're not already there */
1637                 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1638                     smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
1639                 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1640                 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1641                 if (!smb_lastDirSearchp)
1642                     smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1643             }
1644             lock_ObtainMutex(&dsp->mx);
1645             dsp->refCount++;
1646             lock_ReleaseMutex(&dsp->mx);
1647             break;
1648         }
1649     }
1650
1651     if (dsp == NULL) {
1652         osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
1653         for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1654             osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
1655         }
1656     }
1657     return dsp;
1658 }       
1659
1660 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1661 {
1662     lock_ObtainWrite(&smb_globalLock);
1663     lock_ObtainMutex(&dsp->mx);
1664     dsp->flags |= SMB_DIRSEARCH_DELETE;
1665     if (dsp->scp != NULL) {
1666         lock_ObtainMutex(&dsp->scp->mx);
1667         if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1668             dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1669             dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1670             dsp->scp->bulkStatProgress = hones;
1671         }       
1672         lock_ReleaseMutex(&dsp->scp->mx);
1673     }   
1674     lock_ReleaseMutex(&dsp->mx);
1675     lock_ReleaseWrite(&smb_globalLock);
1676 }               
1677
1678 /* Must be called with the smb_globalLock held */
1679 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
1680 {
1681     cm_scache_t *scp = NULL;
1682
1683     lock_ObtainMutex(&dsp->mx);
1684     osi_assert(dsp->refCount-- > 0);
1685     if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1686         if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1687             smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1688         osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1689         lock_ReleaseMutex(&dsp->mx);
1690         lock_FinalizeMutex(&dsp->mx);
1691         scp = dsp->scp;
1692         free(dsp);
1693     } else {
1694         lock_ReleaseMutex(&dsp->mx);
1695     }
1696     /* do this now to avoid spurious locking hierarchy creation */
1697     if (scp) 
1698         cm_ReleaseSCache(scp);
1699 }       
1700
1701 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1702 {
1703     lock_ObtainWrite(&smb_globalLock);
1704     smb_ReleaseDirSearchNoLock(dsp);
1705     lock_ReleaseWrite(&smb_globalLock);
1706 }       
1707
1708 /* find a dir search structure by cookie value, and return it held */
1709 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1710 {
1711     smb_dirSearch_t *dsp;
1712
1713     lock_ObtainWrite(&smb_globalLock);
1714     dsp = smb_FindDirSearchNoLock(cookie);
1715     lock_ReleaseWrite(&smb_globalLock);
1716     return dsp;
1717 }
1718
1719 /* GC some dir search entries, in the address space expected by the specific protocol.
1720  * Must be called with smb_globalLock held; release the lock temporarily.
1721  */
1722 #define SMB_DIRSEARCH_GCMAX     10      /* how many at once */
1723 void smb_GCDirSearches(int isV3)
1724 {
1725     smb_dirSearch_t *prevp;
1726     smb_dirSearch_t *tp;
1727     smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1728     int victimCount;
1729     int i;
1730         
1731     victimCount = 0;    /* how many have we got so far */
1732     for (tp = smb_lastDirSearchp; tp; tp=prevp) {
1733         /* we'll move tp from queue, so
1734          * do this early.
1735          */
1736         prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);  
1737         /* if no one is using this guy, and we're either in the new protocol,
1738          * or we're in the old one and this is a small enough ID to be useful
1739          * to the old protocol, GC this guy.
1740          */
1741         if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1742             /* hold and delete */
1743             tp->flags |= SMB_DIRSEARCH_DELETE;
1744             victimsp[victimCount++] = tp;
1745             tp->refCount++;
1746         }
1747
1748         /* don't do more than this */
1749         if (victimCount >= SMB_DIRSEARCH_GCMAX) 
1750             break;
1751     }
1752         
1753     /* now release them */
1754     for (i = 0; i < victimCount; i++) {
1755         smb_ReleaseDirSearchNoLock(victimsp[i]);
1756     }
1757 }
1758
1759 /* function for allocating a dir search entry.  We need these to remember enough context
1760  * since we don't get passed the path from call to call during a directory search.
1761  *
1762  * Returns a held dir search structure, and bumps the reference count on the vnode,
1763  * since it saves a pointer to the vnode.
1764  */
1765 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1766 {
1767     smb_dirSearch_t *dsp;
1768     int counter;
1769     int maxAllowed;
1770     int start;
1771     int wrapped = 0;
1772
1773     lock_ObtainWrite(&smb_globalLock);
1774     counter = 0;
1775
1776     /* what's the biggest ID allowed in this version of the protocol */
1777     maxAllowed = isV3 ? 65535 : 255;
1778     if (smb_dirSearchCounter > maxAllowed)
1779         smb_dirSearchCounter = 1;
1780
1781     start = smb_dirSearchCounter;
1782
1783     while (1) {
1784         /* twice so we have enough tries to find guys we GC after one pass;
1785          * 10 extra is just in case I mis-counted.
1786          */
1787         if (++counter > 2*maxAllowed+10) 
1788             osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
1789
1790         if (smb_dirSearchCounter > maxAllowed) {        
1791             smb_dirSearchCounter = 1;
1792         }
1793         if (smb_dirSearchCounter == start) {
1794             if (wrapped)
1795                 smb_GCDirSearches(isV3);
1796             wrapped++;
1797         }
1798         dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
1799         if (dsp) {
1800             /* don't need to watch for refcount zero and deleted, since
1801             * we haven't dropped the global lock.
1802             */
1803             lock_ObtainMutex(&dsp->mx);
1804             dsp->refCount--;
1805             lock_ReleaseMutex(&dsp->mx);
1806             ++smb_dirSearchCounter;
1807             continue;
1808         }       
1809
1810         dsp = malloc(sizeof(*dsp));
1811         memset(dsp, 0, sizeof(*dsp));
1812         dsp->cookie = smb_dirSearchCounter;
1813         ++smb_dirSearchCounter;
1814         dsp->refCount = 1;
1815         lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
1816         dsp->lastTime = osi_Time();
1817         osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1818         if (!smb_lastDirSearchp) 
1819             smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1820         break;
1821     }   
1822     lock_ReleaseWrite(&smb_globalLock);
1823     return dsp;
1824 }
1825
1826 static smb_packet_t *GetPacket(void)
1827 {
1828     smb_packet_t *tbp;
1829 #ifdef DJGPP
1830     unsigned int npar, seg, tb_sel;
1831 #endif
1832
1833     lock_ObtainWrite(&smb_globalLock);
1834     tbp = smb_packetFreeListp;
1835     if (tbp) 
1836         smb_packetFreeListp = tbp->nextp;
1837     lock_ReleaseWrite(&smb_globalLock);
1838     if (!tbp) {
1839 #ifndef DJGPP
1840         tbp = calloc(65540,1);
1841 #else /* DJGPP */
1842         tbp = malloc(sizeof(smb_packet_t));
1843 #endif /* !DJGPP */
1844         tbp->magic = SMB_PACKETMAGIC;
1845         tbp->ncbp = NULL;
1846         tbp->vcp = NULL;
1847         tbp->resumeCode = 0;
1848         tbp->inCount = 0;
1849         tbp->fid = 0;
1850         tbp->wctp = NULL;
1851         tbp->inCom = 0;
1852         tbp->oddByte = 0;
1853         tbp->ncb_length = 0;
1854         tbp->flags = 0;
1855         tbp->spacep = NULL;
1856         
1857 #ifdef DJGPP
1858         npar = SMB_PACKETSIZE >> 4;  /* number of paragraphs */
1859         {
1860             signed int retval =
1861                 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1862             if (retval == -1) {
1863                 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS memory",
1864                           npar);
1865                 osi_panic("",__FILE__,__LINE__);
1866             }
1867             else {
1868                 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X",
1869                           npar, retval);
1870                 seg = retval;
1871             }
1872         }
1873         tbp->dos_pkt = (seg * 16) + 0;  /* DOS physical address */
1874         tbp->dos_pkt_sel = tb_sel;
1875 #endif /* DJGPP */
1876     }
1877     osi_assert(tbp->magic == SMB_PACKETMAGIC);
1878
1879     return tbp;
1880 }
1881
1882 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
1883 {
1884     smb_packet_t *tbp;
1885     tbp = GetPacket();
1886     memcpy(tbp, pkt, sizeof(smb_packet_t));
1887     tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
1888     if (tbp->vcp)
1889         smb_HoldVC(tbp->vcp);
1890     return tbp;
1891 }
1892
1893 static NCB *GetNCB(void)
1894 {
1895     smb_ncb_t *tbp;
1896     NCB *ncbp;
1897 #ifdef DJGPP
1898     unsigned int npar, seg, tb_sel;
1899 #endif /* DJGPP */
1900
1901     lock_ObtainWrite(&smb_globalLock);
1902     tbp = smb_ncbFreeListp;
1903     if (tbp) 
1904         smb_ncbFreeListp = tbp->nextp;
1905     lock_ReleaseWrite(&smb_globalLock);
1906     if (!tbp) {
1907 #ifndef DJGPP
1908         tbp = calloc(sizeof(*tbp),1);
1909 #else /* DJGPP */
1910         tbp = malloc(sizeof(*tbp));
1911         npar = (sizeof(NCB)+15) >> 4;  /* number of paragraphs */
1912         {
1913             signed int retval =
1914                 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1915             if (retval == -1) {
1916                 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS mem in GetNCB",
1917                           npar);
1918                 osi_panic("",__FILE__,__LINE__);
1919             } else {
1920                 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
1921                           npar, retval);
1922                 seg = retval;
1923             }
1924         }
1925         tbp->dos_ncb = (seg * 16) + 0;  /* DOS physical address */
1926         tbp->dos_ncb_sel = tb_sel;
1927 #endif /* !DJGPP */
1928         tbp->magic = SMB_NCBMAGIC;
1929     }
1930         
1931     osi_assert(tbp->magic == SMB_NCBMAGIC);
1932
1933     memset(&tbp->ncb, 0, sizeof(NCB));
1934     ncbp = &tbp->ncb;
1935 #ifdef DJGPP
1936     dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
1937 #endif /* DJGPP */
1938     return ncbp;
1939 }
1940
1941 void smb_FreePacket(smb_packet_t *tbp)
1942 {
1943     smb_vc_t * vcp = NULL;
1944     osi_assert(tbp->magic == SMB_PACKETMAGIC);
1945         
1946     lock_ObtainWrite(&smb_globalLock);
1947     tbp->nextp = smb_packetFreeListp;
1948     smb_packetFreeListp = tbp;
1949     tbp->magic = SMB_PACKETMAGIC;
1950     tbp->ncbp = NULL;
1951     vcp = tbp->vcp;
1952     tbp->vcp = NULL;
1953     tbp->resumeCode = 0;
1954     tbp->inCount = 0;
1955     tbp->fid = 0;
1956     tbp->wctp = NULL;
1957     tbp->inCom = 0;
1958     tbp->oddByte = 0;
1959     tbp->ncb_length = 0;
1960     tbp->flags = 0;
1961     lock_ReleaseWrite(&smb_globalLock);
1962
1963     if (vcp)
1964         smb_ReleaseVC(vcp);
1965 }
1966
1967 static void FreeNCB(NCB *bufferp)
1968 {
1969     smb_ncb_t *tbp;
1970         
1971     tbp = (smb_ncb_t *) bufferp;
1972     osi_assert(tbp->magic == SMB_NCBMAGIC);
1973         
1974     lock_ObtainWrite(&smb_globalLock);
1975     tbp->nextp = smb_ncbFreeListp;
1976     smb_ncbFreeListp = tbp;
1977     lock_ReleaseWrite(&smb_globalLock);
1978 }
1979
1980 /* get a ptr to the data part of a packet, and its count */
1981 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
1982 {
1983     int parmBytes;
1984     int dataBytes;
1985     unsigned char *afterParmsp;
1986
1987     parmBytes = *smbp->wctp << 1;
1988     afterParmsp = smbp->wctp + parmBytes + 1;
1989         
1990     dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
1991     if (nbytesp) *nbytesp = dataBytes;
1992         
1993     /* don't forget to skip the data byte count, since it follows
1994      * the parameters; that's where the "2" comes from below.
1995      */
1996     return (unsigned char *) (afterParmsp + 2);
1997 }
1998
1999 /* must set all the returned parameters before playing around with the
2000  * data region, since the data region is located past the end of the
2001  * variable number of parameters.
2002  */
2003 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2004 {
2005     unsigned char *afterParmsp;
2006
2007     afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2008         
2009     *afterParmsp++ = dsize & 0xff;
2010     *afterParmsp = (dsize>>8) & 0xff;
2011 }       
2012
2013 /* return the parm'th parameter in the smbp packet */
2014 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
2015 {
2016     int parmCount;
2017     unsigned char *parmDatap;
2018
2019     parmCount = *smbp->wctp;
2020
2021     if (parm >= parmCount) {
2022         char s[100];
2023
2024         sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2025                 parm, parmCount, smbp->ncb_length);
2026         osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2027                  parm, parmCount, smbp->ncb_length);
2028 #ifndef DJGPP
2029         LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM, 
2030                  __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2031 #endif /* !DJGPP */
2032         osi_panic(s, __FILE__, __LINE__);
2033     }
2034     parmDatap = smbp->wctp + (2*parm) + 1;
2035         
2036     return parmDatap[0] + (parmDatap[1] << 8);
2037 }
2038
2039 /* return the parm'th parameter in the smbp packet */
2040 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2041 {
2042     int parmCount;
2043     unsigned char *parmDatap;
2044
2045     parmCount = *smbp->wctp;
2046
2047     if (parm * 2 + offset >= parmCount * 2) {
2048         char s[100];
2049
2050         sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2051                 parm, offset, parmCount, smbp->ncb_length);
2052 #ifndef DJGPP
2053         LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET, 
2054                  __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2055 #endif /* !DJGPP */
2056         osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2057                 parm, offset, parmCount, smbp->ncb_length);
2058         osi_panic(s, __FILE__, __LINE__);
2059     }
2060     parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2061         
2062     return parmDatap[0] + (parmDatap[1] << 8);
2063 }
2064
2065 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2066 {
2067     char *parmDatap;
2068
2069     /* make sure we have enough slots */
2070     if (*smbp->wctp <= slot) 
2071         *smbp->wctp = slot+1;
2072         
2073     parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2074     *parmDatap++ = parmValue & 0xff;
2075     *parmDatap = (parmValue>>8) & 0xff;
2076 }       
2077
2078 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2079 {
2080     char *parmDatap;
2081
2082     /* make sure we have enough slots */
2083     if (*smbp->wctp <= slot) 
2084         *smbp->wctp = slot+2;
2085
2086     parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2087     *parmDatap++ = parmValue & 0xff;
2088     *parmDatap++ = (parmValue>>8) & 0xff;
2089     *parmDatap++ = (parmValue>>16) & 0xff;
2090     *parmDatap++ = (parmValue>>24) & 0xff;
2091 }
2092
2093 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2094 {
2095     char *parmDatap;
2096     int i;
2097
2098     /* make sure we have enough slots */
2099     if (*smbp->wctp <= slot) 
2100         *smbp->wctp = slot+4;
2101
2102     parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2103     for (i=0; i<8; i++)
2104         *parmDatap++ = *parmValuep++;
2105 }       
2106
2107 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2108 {
2109     char *parmDatap;
2110
2111     /* make sure we have enough slots */
2112     if (*smbp->wctp <= slot) {
2113         if (smbp->oddByte) {
2114             smbp->oddByte = 0;
2115             *smbp->wctp = slot+1;
2116         } else
2117             smbp->oddByte = 1;
2118     }
2119
2120     parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2121     *parmDatap++ = parmValue & 0xff;
2122 }
2123
2124 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2125 {
2126     char *lastSlashp;
2127         
2128     lastSlashp = strrchr(inPathp, '\\');
2129     if (lastComponentp)
2130         *lastComponentp = lastSlashp;
2131     if (lastSlashp) {
2132         while (1) {
2133             if (inPathp == lastSlashp) 
2134                 break;
2135             *outPathp++ = *inPathp++;
2136         }
2137         *outPathp++ = 0;
2138     }
2139     else {
2140         *outPathp++ = 0;
2141     }
2142 }
2143
2144 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2145 {
2146     if (*inp++ != 0x4) 
2147         return NULL;
2148     if (chainpp) {
2149         *chainpp = inp + strlen(inp) + 1;       /* skip over null-terminated string */
2150     }
2151     return inp;
2152 }
2153
2154 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2155 {
2156     int tlen;
2157
2158     if (*inp++ != 0x5) 
2159         return NULL;
2160     tlen = inp[0] + (inp[1]<<8);
2161     inp += 2;           /* skip length field */
2162
2163     if (chainpp) {
2164         *chainpp = inp + tlen;
2165     }
2166         
2167     if (lengthp) 
2168         *lengthp = tlen;
2169         
2170     return inp;
2171 }       
2172
2173 /* format a packet as a response */
2174 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2175 {
2176     smb_t *outp;
2177     smb_t *inSmbp;
2178
2179     outp = (smb_t *) op;
2180         
2181     /* zero the basic structure through the smb_wct field, and zero the data
2182      * size field, assuming that wct stays zero; otherwise, you have to 
2183      * explicitly set the data size field, too.
2184      */
2185     inSmbp = (smb_t *) inp;
2186     memset(outp, 0, sizeof(smb_t)+2);
2187     outp->id[0] = 0xff;
2188     outp->id[1] = 'S';
2189     outp->id[2] = 'M';
2190     outp->id[3] = 'B';
2191     if (inp) {
2192         outp->com = inSmbp->com;
2193         outp->tid = inSmbp->tid;
2194         outp->pid = inSmbp->pid;
2195         outp->uid = inSmbp->uid;
2196         outp->mid = inSmbp->mid;
2197         outp->res[0] = inSmbp->res[0];
2198         outp->res[1] = inSmbp->res[1];
2199         op->inCom = inSmbp->com;
2200     }
2201     outp->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
2202     outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2203
2204     /* copy fields in generic packet area */
2205     op->wctp = &outp->wct;
2206 }       
2207
2208 /* send a (probably response) packet; vcp tells us to whom to send it.
2209  * we compute the length by looking at wct and bcc fields.
2210  */
2211 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2212 {
2213     NCB *ncbp;
2214     int extra;
2215     long code = 0;
2216     unsigned char *tp;
2217     int localNCB = 0;
2218 #ifdef DJGPP
2219     dos_ptr dos_ncb;
2220 #endif /* DJGPP */
2221         
2222     ncbp = inp->ncbp;
2223     if (ncbp == NULL) {
2224         ncbp = GetNCB();
2225         localNCB = 1;
2226     }
2227 #ifdef DJGPP
2228     dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2229 #endif /* DJGPP */
2230  
2231     memset((char *)ncbp, 0, sizeof(NCB));
2232
2233     extra = 2 * (*inp->wctp);   /* space used by parms, in bytes */
2234     tp = inp->wctp + 1+ extra;  /* points to count of data bytes */
2235     extra += tp[0] + (tp[1]<<8);
2236     extra += (unsigned int)(inp->wctp - inp->data);     /* distance to last wct field */
2237     extra += 3;                 /* wct and length fields */
2238         
2239     ncbp->ncb_length = extra;   /* bytes to send */
2240     ncbp->ncb_lsn = (unsigned char) vcp->lsn;   /* vc to use */
2241     ncbp->ncb_lana_num = vcp->lana;
2242     ncbp->ncb_command = NCBSEND;        /* op means send data */
2243 #ifndef DJGPP
2244     ncbp->ncb_buffer = (char *) inp;/* packet */
2245     code = Netbios(ncbp);
2246 #else /* DJGPP */
2247     ncbp->ncb_buffer = inp->dos_pkt;/* packet */
2248     ((smb_ncb_t*)ncbp)->orig_pkt = inp;
2249
2250     /* copy header information from virtual to DOS address space */
2251     dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
2252     code = Netbios(ncbp, dos_ncb);
2253 #endif /* !DJGPP */
2254         
2255     if (code != 0) {
2256         char * s;
2257         switch ( code ) {
2258         case 0x01: s = "llegal buffer length                     "; break; 
2259         case 0x03: s = "illegal command                          "; break; 
2260         case 0x05: s = "command timed out                        "; break; 
2261         case 0x06: s = "message incomplete, issue another command"; break; 
2262         case 0x07: s = "illegal buffer address                   "; break; 
2263         case 0x08: s = "session number out of range              "; break; 
2264         case 0x09: s = "no resource available                    "; break; 
2265         case 0x0a: s = "session closed                           "; break; 
2266         case 0x0b: s = "command cancelled                        "; break; 
2267         case 0x0d: s = "duplicate name                           "; break; 
2268         case 0x0e: s = "name table full                          "; break; 
2269         case 0x0f: s = "no deletions, name has active sessions   "; break; 
2270         case 0x11: s = "local session table full                 "; break; 
2271         case 0x12: s = "remote session table full                "; break; 
2272         case 0x13: s = "illegal name number                      "; break; 
2273         case 0x14: s = "no callname                              "; break; 
2274         case 0x15: s = "cannot put * in NCB_NAME                 "; break; 
2275         case 0x16: s = "name in use on remote adapter            "; break; 
2276         case 0x17: s = "name deleted                             "; break; 
2277         case 0x18: s = "session ended abnormally                 "; break; 
2278         case 0x19: s = "name conflict detected                   "; break; 
2279         case 0x21: s = "interface busy, IRET before retrying     "; break; 
2280         case 0x22: s = "too many commands outstanding, retry later"; break;
2281         case 0x23: s = "ncb_lana_num field invalid               "; break; 
2282         case 0x24: s = "command completed while cancel occurring "; break; 
2283         case 0x26: s = "command not valid to cancel              "; break; 
2284         case 0x30: s = "name defined by anther local process     "; break; 
2285         case 0x34: s = "environment undefined. RESET required    "; break; 
2286         case 0x35: s = "required OS resources exhausted          "; break; 
2287         case 0x36: s = "max number of applications exceeded      "; break; 
2288         case 0x37: s = "no saps available for netbios            "; break; 
2289         case 0x38: s = "requested resources are not available    "; break; 
2290         case 0x39: s = "invalid ncb address or length > segment  "; break; 
2291         case 0x3B: s = "invalid NCB DDID                         "; break; 
2292         case 0x3C: s = "lock of user area failed                 "; break; 
2293         case 0x3f: s = "NETBIOS not loaded                       "; break; 
2294         case 0x40: s = "system error                             "; break;                 
2295         default:
2296             s = "unknown error";
2297         }
2298         osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2299     }
2300
2301     if (localNCB)
2302         FreeNCB(ncbp);
2303 }
2304
2305 void smb_MapNTError(long code, unsigned long *NTStatusp)
2306 {
2307     unsigned long NTStatus;
2308
2309     /* map CM_ERROR_* errors to NT 32-bit status codes */
2310     /* NT Status codes are listed in ntstatus.h not winerror.h */
2311     if (code == CM_ERROR_NOSUCHCELL) {
2312         NTStatus = 0xC000000FL; /* No such file */
2313     }
2314     else if (code == CM_ERROR_NOSUCHVOLUME) {
2315         NTStatus = 0xC000000FL; /* No such file */
2316     }
2317     else if (code == CM_ERROR_TIMEDOUT) {
2318 #ifdef COMMENT
2319         NTStatus = 0xC00000CFL; /* Sharing Paused */
2320 #else
2321         NTStatus = 0x00000102L; /* Timeout */
2322 #endif
2323     }
2324     else if (code == CM_ERROR_RETRY) {
2325         NTStatus = 0xC000022DL; /* Retry */
2326     }
2327     else if (code == CM_ERROR_NOACCESS) {
2328         NTStatus = 0xC0000022L; /* Access denied */
2329     }
2330     else if (code == CM_ERROR_READONLY) {
2331         NTStatus = 0xC00000A2L; /* Write protected */
2332     }
2333     else if (code == CM_ERROR_NOSUCHFILE) {
2334         NTStatus = 0xC000000FL; /* No such file */
2335     }
2336     else if (code == CM_ERROR_NOSUCHPATH) {
2337         NTStatus = 0xC000003AL; /* Object path not found */
2338     }           
2339     else if (code == CM_ERROR_TOOBIG) {
2340         NTStatus = 0xC000007BL; /* Invalid image format */
2341     }
2342     else if (code == CM_ERROR_INVAL) {
2343         NTStatus = 0xC000000DL; /* Invalid parameter */
2344     }
2345     else if (code == CM_ERROR_BADFD) {
2346         NTStatus = 0xC0000008L; /* Invalid handle */
2347     }
2348     else if (code == CM_ERROR_BADFDOP) {
2349         NTStatus = 0xC0000022L; /* Access denied */
2350     }
2351     else if (code == CM_ERROR_EXISTS) {
2352         NTStatus = 0xC0000035L; /* Object name collision */
2353     }
2354     else if (code == CM_ERROR_NOTEMPTY) {
2355         NTStatus = 0xC0000101L; /* Directory not empty */
2356     }   
2357     else if (code == CM_ERROR_CROSSDEVLINK) {
2358         NTStatus = 0xC00000D4L; /* Not same device */
2359     }
2360     else if (code == CM_ERROR_NOTDIR) {
2361         NTStatus = 0xC0000103L; /* Not a directory */
2362     }
2363     else if (code == CM_ERROR_ISDIR) {
2364         NTStatus = 0xC00000BAL; /* File is a directory */
2365     }
2366     else if (code == CM_ERROR_BADOP) {
2367 #ifdef COMMENT
2368         /* I have no idea where this comes from */
2369         NTStatus = 0xC09820FFL; /* SMB no support */
2370 #else
2371         NTStatus = 0xC00000BBL;     /* Not supported */
2372 #endif /* COMMENT */
2373     }
2374     else if (code == CM_ERROR_BADSHARENAME) {
2375         NTStatus = 0xC00000CCL; /* Bad network name */
2376     }
2377     else if (code == CM_ERROR_NOIPC) {
2378 #ifdef COMMENT
2379         NTStatus = 0xC0000022L; /* Access Denied */
2380 #else   
2381         NTStatus = 0xC000013DL; /* Remote Resources */
2382 #endif
2383     }
2384     else if (code == CM_ERROR_CLOCKSKEW) {
2385         NTStatus = 0xC0000133L; /* Time difference at DC */
2386     }
2387     else if (code == CM_ERROR_BADTID) {
2388         NTStatus = 0xC0982005L; /* SMB bad TID */
2389     }
2390     else if (code == CM_ERROR_USESTD) {
2391         NTStatus = 0xC09820FBL; /* SMB use standard */
2392     }
2393     else if (code == CM_ERROR_QUOTA) {
2394 #ifdef COMMENT
2395         NTStatus = 0xC0000044L; /* Quota exceeded */
2396 #else
2397         NTStatus = 0xC000007FL; /* Disk full */
2398 #endif
2399     }
2400     else if (code == CM_ERROR_SPACE) {
2401         NTStatus = 0xC000007FL; /* Disk full */
2402     }
2403     else if (code == CM_ERROR_ATSYS) {
2404         NTStatus = 0xC0000033L; /* Object name invalid */
2405     }
2406     else if (code == CM_ERROR_BADNTFILENAME) {
2407         NTStatus = 0xC0000033L; /* Object name invalid */
2408     }
2409     else if (code == CM_ERROR_WOULDBLOCK) {
2410         NTStatus = 0xC0000055L; /* Lock not granted */
2411     }
2412     else if (code == CM_ERROR_SHARING_VIOLATION) {
2413         NTStatus = 0xC0000043L; /* Sharing violation */
2414     }
2415     else if (code == CM_ERROR_LOCK_CONFLICT) {
2416         NTStatus = 0xC0000054L; /* Lock conflict */
2417     }
2418     else if (code == CM_ERROR_PARTIALWRITE) {
2419         NTStatus = 0xC000007FL; /* Disk full */
2420     }
2421     else if (code == CM_ERROR_BUFFERTOOSMALL) {
2422         NTStatus = 0xC0000023L; /* Buffer too small */
2423     }
2424     else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2425         NTStatus = 0xC0000035L; /* Object name collision */
2426     }   
2427     else if (code == CM_ERROR_BADPASSWORD) {
2428         NTStatus = 0xC000006DL; /* unknown username or bad password */
2429     }
2430     else if (code == CM_ERROR_BADLOGONTYPE) {
2431         NTStatus = 0xC000015BL; /* logon type not granted */
2432     }
2433     else if (code == CM_ERROR_GSSCONTINUE) {
2434         NTStatus = 0xC0000016L; /* more processing required */
2435     }
2436     else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2437 #ifdef COMMENT
2438         NTStatus = 0xC0000280L; /* reparse point not resolved */
2439 #else
2440         NTStatus = 0xC0000022L; /* Access Denied */
2441 #endif
2442     }
2443     else if (code == CM_ERROR_PATH_NOT_COVERED) {
2444         NTStatus = 0xC0000257L; /* Path Not Covered */
2445     } 
2446 #ifdef COMMENT
2447     else if (code == CM_ERROR_ALLBUSY) {
2448         NTStatus = 0xC00000BFL; /* Network Busy */
2449     } 
2450     else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
2451         NTStatus = 0xC0000350L; /* Remote Host Down */
2452     } 
2453 #else
2454     /* we do not want to be telling the SMB/CIFS client that
2455      * the AFS Client Service is busy or down.  
2456      */
2457     else if (code == CM_ERROR_ALLBUSY || 
2458              code == CM_ERROR_ALLOFFLINE ||
2459              code == CM_ERROR_ALLDOWN) {
2460         NTStatus = 0xC00000BEL; /* Bad Network Path */
2461     }
2462 #endif
2463     else if (code == RXKADUNKNOWNKEY) {
2464         NTStatus = 0xC0000322L; /* Bad Kerberos key */
2465     } else {
2466         NTStatus = 0xC0982001L; /* SMB non-specific error */
2467     }
2468
2469     *NTStatusp = NTStatus;
2470     osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2471 }       
2472
2473 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2474                       unsigned char *classp)
2475 {
2476     unsigned char class;
2477     unsigned short error;
2478
2479     /* map CM_ERROR_* errors to SMB errors */
2480     if (code == CM_ERROR_NOSUCHCELL) {
2481         class = 1;
2482         error = 3;      /* bad path */
2483     }
2484     else if (code == CM_ERROR_NOSUCHVOLUME) {
2485         class = 1;
2486         error = 3;      /* bad path */
2487     }
2488     else if (code == CM_ERROR_TIMEDOUT) {
2489         class = 2;
2490         error = 81;     /* server is paused */
2491     }
2492     else if (code == CM_ERROR_RETRY) {
2493         class = 2;      /* shouldn't happen */
2494         error = 1;
2495     }
2496     else if (code == CM_ERROR_NOACCESS) {
2497         class = 2;
2498         error = 4;      /* bad access */
2499     }
2500     else if (code == CM_ERROR_READONLY) {
2501         class = 3;
2502         error = 19;     /* read only */
2503     }
2504     else if (code == CM_ERROR_NOSUCHFILE) {
2505         class = 1;
2506         error = 2;      /* ENOENT! */
2507     }
2508     else if (code == CM_ERROR_NOSUCHPATH) {
2509         class = 1;
2510         error = 3;      /* Bad path */
2511     }
2512     else if (code == CM_ERROR_TOOBIG) {
2513         class = 1;
2514         error = 11;     /* bad format */
2515     }
2516     else if (code == CM_ERROR_INVAL) {
2517         class = 2;      /* server non-specific error code */
2518         error = 1;
2519     }
2520     else if (code == CM_ERROR_BADFD) {
2521         class = 1;
2522         error = 6;      /* invalid file handle */
2523     }
2524     else if (code == CM_ERROR_BADFDOP) {
2525         class = 1;      /* invalid op on FD */
2526         error = 5;
2527     }
2528     else if (code == CM_ERROR_EXISTS) {
2529         class = 1;
2530         error = 80;     /* file already exists */
2531     }
2532     else if (code == CM_ERROR_NOTEMPTY) {
2533         class = 1;
2534         error = 5;      /* delete directory not empty */
2535     }
2536     else if (code == CM_ERROR_CROSSDEVLINK) {
2537         class = 1;
2538         error = 17;     /* EXDEV */
2539     }
2540     else if (code == CM_ERROR_NOTDIR) {
2541         class = 1;      /* bad path */
2542         error = 3;
2543     }
2544     else if (code == CM_ERROR_ISDIR) {
2545         class = 1;      /* access denied; DOS doesn't have a good match */
2546         error = 5;
2547     }       
2548     else if (code == CM_ERROR_BADOP) {
2549         class = 2;
2550         error = 65535;
2551     }
2552     else if (code == CM_ERROR_BADSHARENAME) {
2553         class = 2;
2554         error = 6;
2555     }
2556     else if (code == CM_ERROR_NOIPC) {
2557         class = 2;
2558         error = 4; /* bad access */
2559     }
2560     else if (code == CM_ERROR_CLOCKSKEW) {
2561         class = 1;      /* invalid function */
2562         error = 1;
2563     }
2564     else if (code == CM_ERROR_BADTID) {
2565         class = 2;
2566         error = 5;
2567     }
2568     else if (code == CM_ERROR_USESTD) {
2569         class = 2;
2570         error = 251;
2571     }
2572     else if (code == CM_ERROR_REMOTECONN) {
2573         class = 2;
2574         error = 82;
2575     }
2576     else if (code == CM_ERROR_QUOTA) {
2577         if (vcp->flags & SMB_VCFLAG_USEV3) {
2578             class = 3;
2579             error = 39; /* disk full */
2580         }
2581         else {
2582             class = 1;
2583             error = 5;  /* access denied */
2584         }
2585     }
2586     else if (code == CM_ERROR_SPACE) {
2587         if (vcp->flags & SMB_VCFLAG_USEV3) {
2588             class = 3;
2589             error = 39; /* disk full */
2590         }
2591         else {
2592             class = 1;
2593             error = 5;  /* access denied */
2594         }
2595     }
2596     else if (code == CM_ERROR_PARTIALWRITE) {
2597         class = 3;
2598         error = 39;     /* disk full */
2599     }
2600     else if (code == CM_ERROR_ATSYS) {
2601         class = 1;
2602         error = 2;      /* ENOENT */
2603     }
2604     else if (code == CM_ERROR_WOULDBLOCK) {
2605         class = 1;
2606         error = 33;     /* lock conflict */
2607     }
2608     else if (code == CM_ERROR_LOCK_CONFLICT) {
2609         class = 1;
2610         error = 33;     /* lock conflict */
2611     }
2612     else if (code == CM_ERROR_SHARING_VIOLATION) {
2613         class = 1;
2614         error = 33;     /* lock conflict */
2615     }
2616     else if (code == CM_ERROR_NOFILES) {
2617         class = 1;
2618         error = 18;     /* no files in search */
2619     }
2620     else if (code == CM_ERROR_RENAME_IDENTICAL) {
2621         class = 1;
2622         error = 183;     /* Samba uses this */
2623     }
2624     else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2625         /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2626         class = 2;
2627         error = 2; /* bad password */
2628     }
2629     else if (code == CM_ERROR_PATH_NOT_COVERED) {
2630         class = 2;
2631         error = 3;     /* bad path */
2632     }
2633     else {
2634         class = 2;
2635         error = 1;
2636     }
2637
2638     *scodep = error;
2639     *classp = class;
2640     osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2641 }       
2642
2643 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2644 {
2645     osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2646     return CM_ERROR_BADOP;
2647 }
2648
2649 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2650 {
2651     unsigned short EchoCount, i;
2652     char *data, *outdata;
2653     int dataSize;
2654
2655     EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2656
2657     for (i=1; i<=EchoCount; i++) {
2658         data = smb_GetSMBData(inp, &dataSize);
2659         smb_SetSMBParm(outp, 0, i);
2660         smb_SetSMBDataLength(outp, dataSize);
2661         outdata = smb_GetSMBData(outp, NULL);
2662         memcpy(outdata, data, dataSize);
2663         smb_SendPacket(vcp, outp);
2664     }
2665
2666     return 0;
2667 }
2668
2669 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2670 {
2671     osi_hyper_t offset;
2672     long count, minCount, finalCount;
2673     unsigned short fd;
2674     unsigned pid;
2675     smb_fid_t *fidp;
2676     long code = 0;
2677     cm_user_t *userp = NULL;
2678     NCB *ncbp;
2679     int rc;
2680 #ifndef DJGPP
2681     char *rawBuf = NULL;
2682 #else
2683     dos_ptr rawBuf = NULL;
2684     dos_ptr dos_ncb;
2685 #endif /* DJGPP */
2686
2687     rawBuf = NULL;
2688     finalCount = 0;
2689
2690     fd = smb_GetSMBParm(inp, 0);
2691     count = smb_GetSMBParm(inp, 3);
2692     minCount = smb_GetSMBParm(inp, 4);
2693     offset.HighPart = 0;        /* too bad */
2694     offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2695
2696     osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2697              fd, offset.LowPart, count);
2698
2699     fidp = smb_FindFID(vcp, fd, 0);
2700     if (!fidp)
2701         goto send1;
2702
2703     pid = ((smb_t *) inp)->pid;
2704     {
2705         LARGE_INTEGER LOffset, LLength;
2706         cm_key_t key;
2707
2708         key = cm_GenerateKey(vcp->vcID, pid, fd);
2709
2710         LOffset.HighPart = 0;
2711         LOffset.LowPart = offset.LowPart;
2712         LLength.HighPart = 0;
2713         LLength.LowPart = count;
2714
2715         lock_ObtainMutex(&fidp->scp->mx);
2716         code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
2717         lock_ReleaseMutex(&fidp->scp->mx);
2718     }    
2719     if (code) {
2720         goto send1a;
2721     }
2722
2723     lock_ObtainMutex(&smb_RawBufLock);
2724     if (smb_RawBufs) {
2725         /* Get a raw buf, from head of list */
2726         rawBuf = smb_RawBufs;
2727 #ifndef DJGPP
2728         smb_RawBufs = *(char **)smb_RawBufs;
2729 #else /* DJGPP */
2730         smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2731 #endif /* !DJGPP */
2732     }
2733     lock_ReleaseMutex(&smb_RawBufLock);
2734     if (!rawBuf)
2735         goto send1a;
2736
2737     if (fidp->flags & SMB_FID_IOCTL)
2738     {
2739 #ifndef DJGPP
2740         rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2741 #else
2742         rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2743 #endif
2744         if (rawBuf) {
2745             /* Give back raw buffer */
2746             lock_ObtainMutex(&smb_RawBufLock);
2747 #ifndef DJGPP
2748             *((char **) rawBuf) = smb_RawBufs;
2749 #else /* DJGPP */
2750             _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2751 #endif /* !DJGPP */
2752             
2753             smb_RawBufs = rawBuf;
2754             lock_ReleaseMutex(&smb_RawBufLock);
2755         }
2756
2757         smb_ReleaseFID(fidp);
2758         return rc;
2759     }
2760         
2761     userp = smb_GetUser(vcp, inp);
2762
2763 #ifndef DJGPP
2764     code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2765 #else /* DJGPP */
2766     /* have to give ReadData flag so it will treat buffer as DOS mem. */
2767     code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2768                         userp, &finalCount, TRUE /* rawFlag */);
2769 #endif /* !DJGPP */
2770
2771     if (code != 0)
2772         goto send;
2773
2774   send:
2775     cm_ReleaseUser(userp);
2776
2777   send1a:
2778     smb_ReleaseFID(fidp);
2779
2780   send1:
2781     ncbp = outp->ncbp;
2782 #ifdef DJGPP
2783     dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2784 #endif /* DJGPP */
2785     memset((char *)ncbp, 0, sizeof(NCB));
2786
2787     ncbp->ncb_length = (unsigned short) finalCount;
2788     ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2789     ncbp->ncb_lana_num = vcp->lana;
2790     ncbp->ncb_command = NCBSEND;
2791     ncbp->ncb_buffer = rawBuf;
2792
2793 #ifndef DJGPP
2794     code = Netbios(ncbp);
2795 #else /* DJGPP */
2796     code = Netbios(ncbp, dos_ncb);
2797 #endif /* !DJGPP */
2798     if (code != 0)
2799         osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2800
2801     if (rawBuf) {
2802         /* Give back raw buffer */
2803         lock_ObtainMutex(&smb_RawBufLock);
2804 #ifndef DJGPP
2805         *((char **) rawBuf) = smb_RawBufs;
2806 #else /* DJGPP */
2807         _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2808 #endif /* !DJGPP */
2809
2810         smb_RawBufs = rawBuf;
2811         lock_ReleaseMutex(&smb_RawBufLock);
2812     }
2813
2814     return 0;
2815 }
2816
2817 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2818 {
2819     osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
2820                          ongoingOps - 1);
2821     return 0;
2822 }
2823
2824 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2825 {
2826     osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
2827                          ongoingOps - 1);
2828     return 0;
2829 }
2830
2831 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2832 {
2833     char *namep;
2834     char *datap;
2835     int coreProtoIndex;
2836     int v3ProtoIndex;
2837     int NTProtoIndex;
2838     int protoIndex;                             /* index we're using */
2839     int namex;
2840     int dbytes;
2841     int entryLength;
2842     int tcounter;
2843     char protocol_array[10][1024];  /* protocol signature of the client */
2844     int caps;                       /* capabilities */
2845     time_t unixTime;
2846     afs_uint32 dosTime;
2847     TIME_ZONE_INFORMATION tzi;
2848
2849     osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2850                          ongoingOps - 1);
2851     if (!isGateway) {
2852         if (active_vcp) {
2853             DWORD now = GetCurrentTime();
2854             if (now - last_msg_time >= 30000
2855                  && now - last_msg_time <= 90000) {
2856                 osi_Log1(smb_logp,
2857                           "Setting dead_vcp %x", active_vcp);
2858                 if (dead_vcp) {
2859                     smb_ReleaseVC(dead_vcp);
2860                     osi_Log1(smb_logp,
2861                              "Previous dead_vcp %x", dead_vcp);
2862                 }
2863                 smb_HoldVC(active_vcp);
2864                 dead_vcp = active_vcp;
2865                 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2866             }
2867         }
2868     }
2869
2870     inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
2871
2872     namep = smb_GetSMBData(inp, &dbytes);
2873     namex = 0;
2874     tcounter = 0;
2875     coreProtoIndex = -1;                /* not found */
2876     v3ProtoIndex = -1;
2877     NTProtoIndex = -1;
2878     while(namex < dbytes) {
2879         osi_Log1(smb_logp, "Protocol %s",
2880                   osi_LogSaveString(smb_logp, namep+1));
2881         strcpy(protocol_array[tcounter], namep+1);
2882
2883         /* namep points at the first protocol, or really, a 0x02
2884          * byte preceding the null-terminated ASCII name.
2885          */
2886         if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2887             coreProtoIndex = tcounter;
2888         }       
2889         else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2890             v3ProtoIndex = tcounter;
2891         }
2892         else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
2893             NTProtoIndex = tcounter;
2894         }
2895
2896         /* compute size of protocol entry */
2897         entryLength = (int)strlen(namep+1);
2898         entryLength += 2;       /* 0x02 bytes and null termination */
2899
2900         /* advance over this protocol entry */
2901         namex += entryLength;
2902         namep += entryLength;
2903         tcounter++;             /* which proto entry we're looking at */
2904     }
2905
2906     if (NTProtoIndex != -1) {
2907         protoIndex = NTProtoIndex;
2908         vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2909     }
2910     else if (v3ProtoIndex != -1) {
2911         protoIndex = v3ProtoIndex;
2912         vcp->flags |= SMB_VCFLAG_USEV3;
2913     }   
2914     else if (coreProtoIndex != -1) {
2915         protoIndex = coreProtoIndex;
2916         vcp->flags |= SMB_VCFLAG_USECORE;
2917     }   
2918     else protoIndex = -1;
2919
2920     if (protoIndex == -1)
2921         return CM_ERROR_INVAL;
2922     else if (NTProtoIndex != -1) {
2923         smb_SetSMBParm(outp, 0, protoIndex);
2924         if (smb_authType != SMB_AUTH_NONE) {
2925             smb_SetSMBParmByte(outp, 1,
2926                                NEGOTIATE_SECURITY_USER_LEVEL |
2927                                NEGOTIATE_SECURITY_CHALLENGE_RESPONSE);  /* user level security, challenge response */
2928         } else {
2929             smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
2930         }
2931         smb_SetSMBParm(outp, 1, smb_maxMpxRequests);    /* max multiplexed requests */
2932         smb_SetSMBParm(outp, 2, smb_maxVCPerServer);    /* max VCs per consumer/server connection */
2933         smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE);    /* xmit buffer size */
2934         smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE);    /* raw buffer size */
2935         /* The session key is not a well documented field however most clients
2936          * will echo back the session key to the server.  Currently we are using
2937          * the same value for all sessions.  We should generate a random value
2938          * and store it into the vcp 
2939          */
2940         smb_SetSMBParm(outp, 7, 1);     /* next 2: session key */
2941         smb_SetSMBParm(outp, 8, 1);
2942         /* 
2943          * Tried changing the capabilities to support for W2K - defect 117695
2944          * Maybe something else needs to be changed here?
2945          */
2946         /*
2947         if (isWindows2000) 
2948         smb_SetSMBParmLong(outp, 9, 0x43fd);
2949         else 
2950         smb_SetSMBParmLong(outp, 9, 0x251);
2951         */
2952         /* Capabilities: *
2953          * 32-bit error codes *
2954          * and NT Find *
2955          * and NT SMB's *
2956          * and raw mode 
2957          * and DFS */
2958         caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
2959 #ifdef DFS_SUPPORT
2960                NTNEGOTIATE_CAPABILITY_DFS |
2961 #endif
2962                NTNEGOTIATE_CAPABILITY_NTFIND |
2963                NTNEGOTIATE_CAPABILITY_RAWMODE |
2964                NTNEGOTIATE_CAPABILITY_NTSMB;
2965
2966         if ( smb_authType == SMB_AUTH_EXTENDED )
2967             caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
2968
2969         smb_SetSMBParmLong(outp, 9, caps);
2970         time(&unixTime);
2971         smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2972         smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
2973         smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
2974
2975         GetTimeZoneInformation(&tzi);
2976         smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias);    /* server tzone */
2977
2978         if (smb_authType == SMB_AUTH_NTLM) {
2979             smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
2980             smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
2981             /* paste in encryption key */
2982             datap = smb_GetSMBData(outp, NULL);
2983             memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
2984             /* and the faux domain name */
2985             strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
2986         } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
2987             void * secBlob;
2988             int secBlobLength;
2989
2990             smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2991
2992             smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
2993
2994             smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
2995                         
2996             datap = smb_GetSMBData(outp, NULL);
2997             memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
2998
2999             if (secBlob) {
3000                 datap += sizeof(smb_ServerGUID);
3001                 memcpy(datap, secBlob, secBlobLength);
3002                 free(secBlob);
3003             }
3004         } else {
3005             smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3006             smb_SetSMBDataLength(outp, 0);   /* Perhaps we should specify 8 bytes anyway */
3007         }
3008     }
3009     else if (v3ProtoIndex != -1) {
3010         smb_SetSMBParm(outp, 0, protoIndex);
3011
3012         /* NOTE: Extended authentication cannot be negotiated with v3
3013          * therefore we fail over to NTLM 
3014          */
3015         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3016             smb_SetSMBParm(outp, 1,
3017                            NEGOTIATE_SECURITY_USER_LEVEL |
3018                            NEGOTIATE_SECURITY_CHALLENGE_RESPONSE);      /* user level security, challenge response */
3019         } else {
3020             smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3021         }
3022         smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3023         smb_SetSMBParm(outp, 3, smb_maxMpxRequests);    /* max multiplexed requests */
3024         smb_SetSMBParm(outp, 4, smb_maxVCPerServer);    /* max VCs per consumer/server connection */
3025         smb_SetSMBParm(outp, 5, 0);     /* no support of block mode for read or write */
3026         smb_SetSMBParm(outp, 6, 1);     /* next 2: session key */
3027         smb_SetSMBParm(outp, 7, 1);
3028         time(&unixTime);
3029         smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3030         smb_SetSMBParm(outp, 8, LOWORD(dosTime));       /* server time */
3031         smb_SetSMBParm(outp, 9, HIWORD(dosTime));       /* server date */
3032
3033         GetTimeZoneInformation(&tzi);
3034         smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias);    /* server tzone */
3035
3036         /* NOTE: Extended authentication cannot be negotiated with v3
3037          * therefore we fail over to NTLM 
3038          */
3039         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3040             smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH);  /* encryption key length */
3041             smb_SetSMBParm(outp, 12, 0);        /* resvd */
3042             smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);   /* perhaps should specify 8 bytes anyway */
3043             datap = smb_GetSMBData(outp, NULL);
3044             /* paste in a new encryption key */
3045             memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3046             /* and the faux domain name */
3047             strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
3048         } else {
3049             smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3050             smb_SetSMBParm(outp, 12, 0); /* resvd */
3051             smb_SetSMBDataLength(outp, 0);
3052         }
3053     }
3054     else if (coreProtoIndex != -1) {     /* not really supported anymore */
3055         smb_SetSMBParm(outp, 0, protoIndex);
3056         smb_SetSMBDataLength(outp, 0);
3057     }
3058     return 0;
3059 }
3060
3061 void smb_Daemon(void *parmp)
3062 {
3063     afs_uint32 count = 0;
3064
3065     while(smbShutdownFlag == 0) {
3066         count++;
3067         thrd_Sleep(10000);
3068
3069         if (smbShutdownFlag == 1)
3070             break;
3071         
3072         if ((count % 72) == 0)  {       /* every five minutes */
3073             struct tm myTime;
3074             time_t old_localZero = smb_localZero;
3075                  
3076             /* Initialize smb_localZero */
3077             myTime.tm_isdst = -1;               /* compute whether on DST or not */
3078             myTime.tm_year = 70;
3079             myTime.tm_mon = 0;
3080             myTime.tm_mday = 1;
3081             myTime.tm_hour = 0;
3082             myTime.tm_min = 0;
3083             myTime.tm_sec = 0;
3084             smb_localZero = mktime(&myTime);
3085
3086 #ifndef USE_NUMERIC_TIME_CONV
3087             smb_CalculateNowTZ();
3088 #endif /* USE_NUMERIC_TIME_CONV */
3089 #ifdef AFS_FREELANCE
3090             if ( smb_localZero != old_localZero )
3091                 cm_noteLocalMountPointChange();
3092 #endif
3093         }
3094         /* XXX GC dir search entries */
3095     }
3096 }
3097
3098 void smb_WaitingLocksDaemon()
3099 {
3100     smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3101     smb_waitingLock_t *wl, *wlNext;
3102     int first;
3103     smb_vc_t *vcp;
3104     smb_packet_t *inp, *outp;
3105     NCB *ncbp;
3106     long code = 0;
3107
3108     while (smbShutdownFlag == 0) {
3109         lock_ObtainWrite(&smb_globalLock);
3110         nwlRequest = smb_allWaitingLocks;
3111         if (nwlRequest == NULL) {
3112             osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
3113             thrd_Sleep(1000);
3114             continue;
3115         } else 
3116             first = 1;
3117
3118         do {
3119             if (first)
3120                 first = 0;
3121             else
3122                 lock_ObtainWrite(&smb_globalLock);
3123
3124             wlRequest = nwlRequest;
3125             nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3126             lock_ReleaseWrite(&smb_globalLock);
3127
3128             code = 0;
3129
3130             for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3131                 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3132                     continue;
3133                 
3134                 /* wl->state is either _DONE or _WAITING.  _ERROR
3135                    would no longer be on the queue. */
3136                 code = cm_RetryLock( wl->lockp,
3137                                      !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3138
3139                 if (code == 0) {
3140                     wl->state = SMB_WAITINGLOCKSTATE_DONE;
3141                 } else if (code != CM_ERROR_WOULDBLOCK) {
3142                     wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3143                     break;
3144                 }
3145             }
3146
3147             if (code == CM_ERROR_WOULDBLOCK) {
3148
3149                 /* no progress */
3150                 if (wlRequest->timeRemaining != 0xffffffff
3151                      && (wlRequest->timeRemaining -= 1000) < 0)
3152                     goto endWait;
3153
3154                 continue;
3155             }
3156
3157           endWait:
3158
3159             if (code != 0) {
3160                 cm_scache_t * scp;
3161                 cm_req_t req;
3162
3163                 scp = wlRequest->scp;
3164
3165                 cm_InitReq(&req);
3166
3167                 lock_ObtainMutex(&scp->mx);
3168
3169                 for (wl = wlRequest->locks; wl; wl = wlNext) {
3170                     wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3171                     
3172                     cm_Unlock(scp, wlRequest->lockType, wl->LOffset, 
3173                               wl->LLength, wl->key, NULL, &req);
3174
3175                     osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3176
3177                     free(wl);
3178                 }
3179                 
3180                 lock_ReleaseMutex(&scp->mx);
3181
3182             } else {
3183                 for (wl = wlRequest->locks; wl; wl = wlNext) {
3184                     wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3185                     osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3186                     free(wl);
3187                 }
3188             }
3189
3190             vcp = wlRequest->vcp;
3191             inp = wlRequest->inp;
3192             outp = wlRequest->outp;
3193             ncbp = GetNCB();
3194             ncbp->ncb_length = inp->ncb_length;
3195             inp->spacep = cm_GetSpace();
3196
3197             /* Remove waitingLock from list */
3198             lock_ObtainWrite(&smb_globalLock);
3199             osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3200                          &wlRequest->q);
3201             lock_ReleaseWrite(&smb_globalLock);
3202
3203             /* Resume packet processing */
3204             if (code == 0)
3205                 smb_SetSMBDataLength(outp, 0);
3206             outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3207             outp->resumeCode = code;
3208             outp->ncbp = ncbp;
3209             smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3210
3211             /* Clean up */
3212             cm_FreeSpace(inp->spacep);
3213             smb_FreePacket(inp);
3214             smb_FreePacket(outp);
3215             smb_ReleaseVC(vcp);
3216             cm_ReleaseSCache(wlRequest->scp);
3217             FreeNCB(ncbp);
3218             free(wlRequest);
3219         } while (nwlRequest && smbShutdownFlag == 0);
3220         thrd_Sleep(1000);
3221     }
3222 }
3223
3224 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3225 {
3226     osi_Log0(smb_logp, "SMB receive get disk attributes");
3227
3228     smb_SetSMBParm(outp, 0, 32000);
3229     smb_SetSMBParm(outp, 1, 64);
3230     smb_SetSMBParm(outp, 2, 1024);
3231     smb_SetSMBParm(outp, 3, 30000);
3232     smb_SetSMBParm(outp, 4, 0);
3233     smb_SetSMBDataLength(outp, 0);
3234     return 0;
3235 }
3236
3237 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3238 {
3239     smb_tid_t *tidp;
3240     smb_user_t *uidp;
3241     unsigned short newTid;
3242     char shareName[256];
3243     char *sharePath;
3244     int shareFound;
3245     char *tp;
3246     char *pathp;
3247     char *passwordp;
3248     cm_user_t *userp;
3249
3250     osi_Log0(smb_logp, "SMB receive tree connect");
3251
3252     /* parse input parameters */
3253     tp = smb_GetSMBData(inp, NULL);
3254     pathp = smb_ParseASCIIBlock(tp, &tp);
3255     if (smb_StoreAnsiFilenames)
3256         OemToChar(pathp,pathp);
3257     passwordp = smb_ParseASCIIBlock(tp, &tp);
3258     tp = strrchr(pathp, '\\');
3259     if (!tp)
3260         return CM_ERROR_BADSMB;
3261     strcpy(shareName, tp+1);
3262
3263     userp = smb_GetUser(vcp, inp);
3264
3265     lock_ObtainMutex(&vcp->mx);
3266     newTid = vcp->tidCounter++;
3267     lock_ReleaseMutex(&vcp->mx);
3268
3269     tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3270     uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3271     shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3272     if (uidp)
3273         smb_ReleaseUID(uidp);
3274     if (!shareFound) {
3275         smb_ReleaseTID(tidp);
3276         return CM_ERROR_BADSHARENAME;
3277     }
3278     lock_ObtainMutex(&tidp->mx);
3279     tidp->userp = userp;
3280     tidp->pathname = sharePath;
3281     lock_ReleaseMutex(&tidp->mx);
3282     smb_ReleaseTID(tidp);
3283
3284     smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3285     smb_SetSMBParm(rsp, 1, newTid);
3286     smb_SetSMBDataLength(rsp, 0);
3287
3288     osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3289     return 0;
3290 }
3291
3292 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3293 {
3294     int tlen;
3295
3296     if (*inp++ != 0x1) return NULL;
3297     tlen = inp[0] + (inp[1]<<8);
3298     inp += 2;           /* skip length field */
3299         
3300     if (chainpp) {
3301         *chainpp = inp + tlen;
3302     }   
3303
3304     if (lengthp) *lengthp = tlen;
3305         
3306     return inp;
3307 }
3308
3309 /* set maskp to the mask part of the incoming path.
3310  * Mask is 11 bytes long (8.3 with the dot elided).
3311  * Returns true if succeeds with a valid name, otherwise it does
3312  * its best, but returns false.
3313  */
3314 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3315 {
3316     char *tp;
3317     char *up;
3318     int i;
3319     int tc;
3320     int valid8Dot3;
3321
3322     /* starts off valid */
3323     valid8Dot3 = 1;
3324
3325     /* mask starts out all blanks */
3326     memset(maskp, ' ', 11);
3327
3328     /* find last backslash, or use whole thing if there is none */
3329     tp = strrchr(pathp, '\\');
3330     if (!tp) tp = pathp;
3331     else tp++;  /* skip slash */
3332         
3333     up = maskp;
3334
3335     /* names starting with a dot are illegal */
3336     if (*tp == '.') valid8Dot3 = 0;
3337
3338     for(i=0;; i++) {
3339         tc = *tp++;
3340         if (tc == 0) return valid8Dot3;
3341         if (tc == '.' || tc == '"') break;
3342         if (i < 8) *up++ = tc;
3343         else valid8Dot3 = 0;
3344     }
3345         
3346     /* if we get here, tp point after the dot */
3347     up = maskp+8;       /* ext goes here */
3348     for(i=0;;i++) {
3349         tc = *tp++;
3350         if (tc == 0) 
3351             return valid8Dot3;
3352
3353         /* too many dots */
3354         if (tc == '.' || tc == '"') 
3355             valid8Dot3 = 0;
3356
3357         /* copy extension if not too long */
3358         if (i < 3) 
3359             *up++ = tc;
3360         else 
3361             valid8Dot3 = 0;
3362     }   
3363
3364     /* unreachable */
3365 }
3366
3367 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3368 {
3369     char umask[11];
3370     int valid;
3371     int i;
3372     char tc1;
3373     char tc2;
3374     char *tp1;
3375     char *tp2;
3376
3377     /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3378
3379     valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3380     if (!valid) 
3381         return 0;
3382  
3383     /* otherwise, we have a valid 8.3 name; see if we have a match,
3384      * treating '?' as a wildcard in maskp (but not in the file name).
3385      */
3386     tp1 = umask;        /* real name, in mask format */
3387     tp2 = maskp;        /* mask, in mask format */
3388     for(i=0; i<11; i++) {
3389         tc1 = *tp1++;   /* char from real name */
3390         tc2 = *tp2++;   /* char from mask */
3391         tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3392         tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3393         if (tc1 == tc2) 
3394             continue;
3395         if (tc2 == '?' && tc1 != ' ') 
3396             continue;
3397         if (tc2 == '>') 
3398             continue;
3399         return 0;
3400     }
3401
3402     /* we got a match */
3403     return 1;
3404 }
3405
3406 char *smb_FindMask(char *pathp)
3407 {
3408     char *tp;
3409         
3410     tp = strrchr(pathp, '\\');  /* find last slash */
3411
3412     if (tp) 
3413         return tp+1;    /* skip the slash */
3414     else 
3415         return pathp;   /* no slash, return the entire path */
3416 }       
3417
3418 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3419 {
3420     unsigned char *pathp;
3421     unsigned char *tp;
3422     unsigned char mask[11];
3423     unsigned char *statBlockp;
3424     unsigned char initStatBlock[21];
3425     int statLen;
3426         
3427     osi_Log0(smb_logp, "SMB receive search volume");
3428
3429     /* pull pathname and stat block out of request */
3430     tp = smb_GetSMBData(inp, NULL);
3431     pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3432     osi_assert(pathp != NULL);
3433     if (smb_StoreAnsiFilenames)
3434         OemToChar(pathp,pathp);
3435     statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3436     osi_assert(statBlockp != NULL);
3437     if (statLen == 0) {
3438         statBlockp = initStatBlock;
3439         statBlockp[0] = 8;
3440     }
3441         
3442     /* for returning to caller */
3443     smb_Get8Dot3MaskFromPath(mask, pathp);
3444
3445     smb_SetSMBParm(outp, 0, 1);         /* we're returning one entry */
3446     tp = smb_GetSMBData(outp, NULL);
3447     *tp++ = 5;
3448     *tp++ = 43; /* bytes in a dir entry */
3449     *tp++ = 0;  /* high byte in counter */
3450
3451     /* now marshall the dir entry, starting with the search status */
3452     *tp++ = statBlockp[0];              /* Reserved */
3453     memcpy(tp, mask, 11); tp += 11;     /* FileName */
3454
3455     /* now pass back server use info, with 1st byte non-zero */
3456     *tp++ = 1;
3457     memset(tp, 0, 4); tp += 4;  /* reserved for server use */
3458
3459     memcpy(tp, statBlockp+17, 4); tp += 4;      /* reserved for consumer */
3460
3461     *tp++ = 0x8;                /* attribute: volume */
3462
3463     /* copy out time */
3464     *tp++ = 0;
3465     *tp++ = 0;
3466
3467     /* copy out date */
3468     *tp++ = 18;
3469     *tp++ = 178;
3470
3471     /* 4 byte file size */
3472     *tp++ = 0;
3473     *tp++ = 0;
3474     *tp++ = 0;
3475     *tp++ = 0;
3476
3477     /* finally, null-terminated 8.3 pathname, which we set to AFS */
3478     memset(tp, ' ', 13);
3479     strcpy(tp, "AFS");
3480
3481     /* set the length of the data part of the packet to 43 + 3, for the dir
3482      * entry plus the 5 and the length fields.
3483      */
3484     smb_SetSMBDataLength(outp, 46);
3485     return 0;
3486 }       
3487
3488 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3489                              cm_user_t *userp, cm_req_t *reqp)
3490 {
3491     long code = 0;
3492     cm_scache_t *scp;
3493     char *dptr;
3494     afs_uint32 dosTime;
3495     u_short shortTemp;
3496     char attr;
3497     smb_dirListPatch_t *patchp;
3498     smb_dirListPatch_t *npatchp;
3499
3500     for (patchp = *dirPatchespp; patchp; patchp =
3501          (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3502
3503         dptr = patchp->dptr;
3504
3505         code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3506         if (code) {
3507             if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3508                 *dptr++ = SMB_ATTR_HIDDEN;
3509             continue;
3510         }
3511         lock_ObtainMutex(&scp->mx);
3512         code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3513                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3514         if (code) {     
3515             lock_ReleaseMutex(&scp->mx);
3516             cm_ReleaseSCache(scp);
3517             if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3518                 *dptr++ = SMB_ATTR_HIDDEN;
3519             continue;
3520         }
3521
3522         attr = smb_Attributes(scp);
3523         /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3524         if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3525             attr |= SMB_ATTR_HIDDEN;
3526         *dptr++ = attr;
3527
3528         /* get dos time */
3529         smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3530                 
3531         /* copy out time */
3532         shortTemp = (unsigned short) (dosTime & 0xffff);
3533         *((u_short *)dptr) = shortTemp;
3534         dptr += 2;
3535
3536         /* and copy out date */
3537         shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3538         *((u_short *)dptr) = shortTemp;
3539         dptr += 2;
3540                 
3541         /* copy out file length */
3542         *((u_long *)dptr) = scp->length.LowPart;
3543         dptr += 4;
3544         lock_ReleaseMutex(&scp->mx);
3545         cm_ReleaseSCache(scp);
3546     }
3547         
3548     /* now free the patches */
3549     for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3550         npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3551         free(patchp);
3552     }   
3553         
3554     /* and mark the list as empty */
3555     *dirPatchespp = NULL;
3556
3557     return code;
3558 }
3559
3560 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3561 {
3562     int attribute;
3563     long nextCookie;
3564     char *tp;
3565     long code = 0;
3566     char *pathp;
3567     cm_dirEntry_t *dep;
3568     int maxCount;
3569     smb_dirListPatch_t *dirListPatchesp;
3570     smb_dirListPatch_t *curPatchp;
3571     int dataLength;
3572     cm_buf_t *bufferp;
3573     long temp;
3574     osi_hyper_t dirLength;
3575     osi_hyper_t bufferOffset;
3576     osi_hyper_t curOffset;
3577     osi_hyper_t thyper;
3578     unsigned char *inCookiep;
3579     smb_dirSearch_t *dsp;
3580     cm_scache_t *scp;
3581     long entryInDir;
3582     long entryInBuffer;
3583     unsigned long clientCookie;
3584     cm_pageHeader_t *pageHeaderp;
3585     cm_user_t *userp = NULL;
3586     int slotInPage;
3587     char shortName[13];
3588     char *actualName;
3589     char *shortNameEnd;
3590     char mask[11];
3591     int returnedNames;
3592     long nextEntryCookie;
3593     int numDirChunks;           /* # of 32 byte dir chunks in this entry */
3594     char resByte;               /* reserved byte from the cookie */
3595     char *op;                   /* output data ptr */
3596     char *origOp;               /* original value of op */
3597     cm_space_t *spacep;         /* for pathname buffer */
3598     int starPattern;
3599     int rootPath = 0;
3600     int caseFold;
3601     char *tidPathp;
3602     cm_req_t req;
3603     cm_fid_t fid;
3604     int fileType;
3605
3606     cm_InitReq(&req);
3607
3608     maxCount = smb_GetSMBParm(inp, 0);
3609
3610     dirListPatchesp = NULL;
3611         
3612     caseFold = CM_FLAG_CASEFOLD;
3613
3614     tp = smb_GetSMBData(inp, NULL);
3615     pathp = smb_ParseASCIIBlock(tp, &tp);
3616     if (smb_StoreAnsiFilenames)
3617         OemToChar(pathp,pathp);
3618     inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3619
3620     /* bail out if request looks bad */
3621     if (!tp || !pathp) {
3622         return CM_ERROR_BADSMB;
3623     }
3624
3625     /* We can handle long names */
3626     if (vcp->flags & SMB_VCFLAG_USENT)
3627         ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
3628
3629     /* make sure we got a whole search status */
3630     if (dataLength < 21) {
3631         nextCookie = 0;         /* start at the beginning of the dir */
3632         resByte = 0;
3633         clientCookie = 0;
3634         attribute = smb_GetSMBParm(inp, 1);
3635
3636         /* handle volume info in another function */
3637         if (attribute & 0x8)
3638             return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3639
3640         osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3641                   maxCount, osi_LogSaveString(smb_logp, pathp));
3642
3643         if (*pathp == 0) {      /* null pathp, treat as root dir */
3644             if (!(attribute & SMB_ATTR_DIRECTORY))      /* exclude dirs */
3645                 return CM_ERROR_NOFILES;
3646             rootPath = 1;
3647         }
3648
3649         dsp = smb_NewDirSearch(0);
3650         dsp->attribute = attribute;
3651         smb_Get8Dot3MaskFromPath(mask, pathp);
3652         memcpy(dsp->mask, mask, 11);
3653
3654         /* track if this is likely to match a lot of entries */
3655         if (smb_IsStarMask(mask)) 
3656             starPattern = 1;
3657         else 
3658             starPattern = 0;
3659     } else {
3660         /* pull the next cookie value out of the search status block */
3661         nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3662             + (inCookiep[16]<<24);
3663         dsp = smb_FindDirSearch(inCookiep[12]);
3664         if (!dsp) {
3665             /* can't find dir search status; fatal error */
3666             osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%s]",
3667                      inCookiep[12], nextCookie, osi_LogSaveString(smb_logp, pathp));
3668             return CM_ERROR_BADFD;
3669         }
3670         attribute = dsp->attribute;
3671         resByte = inCookiep[0];
3672
3673         /* copy out client cookie, in host byte order.  Don't bother
3674          * interpreting it, since we're just passing it through, anyway.
3675          */
3676         memcpy(&clientCookie, &inCookiep[17], 4);
3677
3678         memcpy(mask, dsp->mask, 11);
3679
3680         /* assume we're doing a star match if it has continued for more
3681          * than one call.
3682          */
3683         starPattern = 1;
3684     }
3685
3686     osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
3687              nextCookie, dsp->cookie, attribute);
3688
3689     userp = smb_GetUser(vcp, inp);
3690
3691     /* try to get the vnode for the path name next */
3692     lock_ObtainMutex(&dsp->mx);
3693     if (dsp->scp) {
3694         scp = dsp->scp;
3695         cm_HoldSCache(scp);
3696         code = 0;
3697     } else {
3698         spacep = inp->spacep;
3699         smb_StripLastComponent(spacep->data, NULL, pathp);
3700         code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3701         if (code) {
3702             lock_ReleaseMutex(&dsp->mx);
3703             cm_ReleaseUser(userp);
3704             smb_DeleteDirSearch(dsp);
3705             smb_ReleaseDirSearch(dsp);
3706             return CM_ERROR_NOFILES;
3707         }
3708         code = cm_NameI(cm_data.rootSCachep, spacep->data,
3709                         caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3710         if (code == 0) {
3711 #ifdef DFS_SUPPORT
3712             if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3713                 cm_ReleaseSCache(scp);
3714                 lock_ReleaseMutex(&dsp->mx);
3715                 cm_ReleaseUser(userp);
3716                 smb_DeleteDirSearch(dsp);
3717                 smb_ReleaseDirSearch(dsp);
3718                 if ( WANTS_DFS_PATHNAMES(inp) )
3719                     return CM_ERROR_PATH_NOT_COVERED;
3720                 else
3721                     return CM_ERROR_BADSHARENAME;
3722             }
3723 #endif /* DFS_SUPPORT */
3724
3725             dsp->scp = scp;
3726             /* we need one hold for the entry we just stored into,
3727              * and one for our own processing.  When we're done with this
3728              * function, we'll drop the one for our own processing.
3729              * We held it once from the namei call, and so we do another hold
3730              * now.
3731              */
3732             cm_HoldSCache(scp);