db1a2118090041c23381161c15954eaf424efbfa
[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_LogEvent("AFS smb_FindUID (Find by UID)",NULL," 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_LogEvent("AFS smb_FindUID (Find by UID)",NULL,"VCP[0x%p] new-uid[%d] name[%s]",vcp,uidp->userID,(uidp->unp ? uidp->unp->name : ""));
1004     }
1005     lock_ReleaseWrite(&smb_rctLock);
1006     return uidp;
1007 }               
1008
1009 smb_username_t *smb_FindUserByName(char *usern, char *machine, int flags)
1010 {
1011     smb_username_t *unp= NULL;
1012
1013     lock_ObtainWrite(&smb_rctLock);
1014     for(unp = usernamesp; unp; unp = unp->nextp) {
1015         if (stricmp(unp->name, usern) == 0 &&
1016              stricmp(unp->machine, machine) == 0) {
1017             unp->refCount++;
1018             break;
1019         }
1020     }
1021     if (!unp && (flags & SMB_FLAG_CREATE)) {
1022         unp = malloc(sizeof(*unp));
1023         memset(unp, 0, sizeof(*unp));
1024         unp->refCount = 1;
1025         unp->nextp = usernamesp;
1026         unp->name = strdup(usern);
1027         unp->machine = strdup(machine);
1028         usernamesp = unp;
1029         lock_InitializeMutex(&unp->mx, "username_t mutex");
1030     }
1031     lock_ReleaseWrite(&smb_rctLock);
1032     return unp;
1033 }       
1034
1035 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
1036 {
1037     smb_user_t *uidp= NULL;
1038
1039     lock_ObtainWrite(&smb_rctLock);
1040     for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1041         if (!uidp->unp) 
1042             continue;
1043         if (stricmp(uidp->unp->name, usern) == 0) {
1044             uidp->refCount++;
1045             osi_LogEvent("AFS smb_FindUserByNameThisSession",NULL,"VCP[0x%x] uid[%d] match-name[%s]",vcp,uidp->userID,usern);
1046             break;
1047         } else
1048             continue;
1049     }           
1050     lock_ReleaseWrite(&smb_rctLock);
1051     return uidp;
1052 }       
1053 void smb_ReleaseUID(smb_user_t *uidp)
1054 {
1055     smb_user_t *up;
1056     smb_user_t **lupp;
1057     cm_user_t *userp;
1058
1059     userp = NULL;
1060     lock_ObtainWrite(&smb_rctLock);
1061     osi_assert(uidp->refCount-- > 0);
1062     if (uidp->refCount == 0 && (uidp->flags & SMB_USERFLAG_DELETE)) {
1063         lupp = &uidp->vcp->usersp;
1064         for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1065             if (up == uidp) 
1066                 break;
1067         }
1068         osi_assert(up != NULL);
1069         *lupp = up->nextp;
1070         lock_FinalizeMutex(&uidp->mx);
1071         if (uidp->unp) {
1072             userp = uidp->unp->userp;   /* avoid deadlock by releasing */
1073             uidp->unp->userp = NULL;    /* after releasing the lock */
1074         }       
1075         smb_ReleaseVCNoLock(uidp->vcp);
1076         uidp->vcp = NULL;
1077     }           
1078     lock_ReleaseWrite(&smb_rctLock);
1079     if (userp) {
1080         cm_ReleaseUserVCRef(userp);
1081         cm_ReleaseUser(userp);
1082     }   
1083 }       
1084
1085
1086 /* retrieve a held reference to a user structure corresponding to an incoming
1087  * request.
1088  * corresponding release function is cm_ReleaseUser.
1089  */
1090 cm_user_t *smb_GetUser(smb_vc_t *vcp, smb_packet_t *inp)
1091 {
1092     smb_user_t *uidp;
1093     cm_user_t *up;
1094     smb_t *smbp;
1095
1096     smbp = (smb_t *) inp;
1097     uidp = smb_FindUID(vcp, smbp->uid, 0);
1098     if ((!uidp) ||  (!uidp->unp))
1099         return NULL;
1100
1101     lock_ObtainMutex(&uidp->mx);
1102     up = uidp->unp->userp;
1103     cm_HoldUser(up);
1104     lock_ReleaseMutex(&uidp->mx);
1105
1106     smb_ReleaseUID(uidp);
1107
1108     return up;
1109 }
1110
1111 /*
1112  * Return a pointer to a pathname extracted from a TID structure.  The
1113  * TID structure is not held; assume it won't go away.
1114  */
1115 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1116 {
1117     smb_tid_t *tidp;
1118     long code = 0;
1119
1120     tidp = smb_FindTID(vcp, tid, 0);
1121     if (!tidp) {
1122         *treepath = NULL;
1123     } else {
1124         if (tidp->flags & SMB_TIDFLAG_IPC) {
1125             code = CM_ERROR_TIDIPC;
1126             /* tidp->pathname would be NULL, but that's fine */
1127         }
1128         *treepath = tidp->pathname;
1129         smb_ReleaseTID(tidp);
1130     }
1131     return code;
1132 }
1133
1134 /* check to see if we have a chained fid, that is, a fid that comes from an
1135  * OpenAndX message that ran earlier in this packet.  In this case, the fid
1136  * field in a read, for example, request, isn't set, since the value is
1137  * supposed to be inherited from the openAndX call.
1138  */
1139 int smb_ChainFID(int fid, smb_packet_t *inp)
1140 {
1141     if (inp->fid == 0 || inp->inCount == 0) 
1142         return fid;
1143     else 
1144         return inp->fid;
1145 }
1146
1147 /* are we a priv'd user?  What does this mean on NT? */
1148 int smb_SUser(cm_user_t *userp)
1149 {
1150     return 1;
1151 }
1152
1153 /* find a file ID.  If we pass in 0 we select an unused File ID.
1154  * If the SMB_FLAG_CREATE flag is set, we allocate a new  
1155  * smb_fid_t data structure if desired File ID cannot be found.
1156  */
1157 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1158 {
1159     smb_fid_t *fidp;
1160     int newFid = 0;
1161         
1162     if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1163         return NULL;
1164
1165     lock_ObtainWrite(&smb_rctLock);
1166     /* figure out if we need to allocate a new file ID */
1167     if (fid == 0) {
1168         newFid = 1;
1169         fid = vcp->fidCounter;
1170     }
1171
1172   retry:
1173     for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1174         if (fid == fidp->fid) {
1175             if (newFid) {
1176                 fid++;
1177                 if (fid == 0) 
1178                     fid = 1;
1179                 goto retry;
1180             }
1181             fidp->refCount++;
1182             break;
1183         }
1184     }
1185
1186     if (!fidp && (flags & SMB_FLAG_CREATE)) {
1187         char eventName[MAX_PATH];
1188         EVENT_HANDLE event;
1189         sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1190         event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1191         if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1192             osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1193             thrd_CloseHandle(event);
1194             fid++;
1195             if (fid == 0)
1196                 fid = 1;
1197             goto retry;
1198         }
1199
1200         fidp = malloc(sizeof(*fidp));
1201         memset(fidp, 0, sizeof(*fidp));
1202         osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1203         fidp->refCount = 1;
1204         fidp->vcp = vcp;
1205         smb_HoldVCNoLock(vcp);
1206         lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1207         fidp->fid = fid;
1208         fidp->curr_chunk = fidp->prev_chunk = -2;
1209         fidp->raw_write_event = event;
1210         if (newFid) {
1211             vcp->fidCounter = fid+1;
1212             if (vcp->fidCounter == 0) 
1213                 vcp->fidCounter = 1;
1214         }
1215     }
1216
1217     lock_ReleaseWrite(&smb_rctLock);
1218     return fidp;
1219 }
1220
1221 void smb_ReleaseFID(smb_fid_t *fidp)
1222 {
1223     cm_scache_t *scp;
1224     smb_vc_t *vcp = NULL;
1225     smb_ioctl_t *ioctlp;
1226
1227     if (!fidp)
1228         return;
1229
1230     scp = NULL;
1231     lock_ObtainWrite(&smb_rctLock);
1232     osi_assert(fidp->refCount-- > 0);
1233     if (fidp->refCount == 0 && (fidp->flags & SMB_FID_DELETE)) {
1234         vcp = fidp->vcp;
1235         fidp->vcp = 0;
1236         scp = fidp->scp;    /* release after lock is released */
1237         fidp->scp = 0;
1238
1239         osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1240         thrd_CloseHandle(fidp->raw_write_event);
1241
1242         /* and see if there is ioctl stuff to free */
1243         ioctlp = fidp->ioctlp;
1244         if (ioctlp) {
1245             if (ioctlp->prefix)
1246                 cm_FreeSpace(ioctlp->prefix);
1247             if (ioctlp->inAllocp)
1248                 free(ioctlp->inAllocp);
1249             if (ioctlp->outAllocp)
1250                 free(ioctlp->outAllocp);
1251             free(ioctlp);
1252         }       
1253
1254         free(fidp);
1255
1256         smb_ReleaseVCNoLock(vcp);
1257     }
1258     lock_ReleaseWrite(&smb_rctLock);
1259
1260     /* now release the scache structure */
1261     if (scp) 
1262         cm_ReleaseSCache(scp);
1263 }       
1264
1265 /*
1266  * Case-insensitive search for one string in another;
1267  * used to find variable names in submount pathnames.
1268  */
1269 static char *smb_stristr(char *str1, char *str2)
1270 {
1271     char *cursor;
1272
1273     for (cursor = str1; *cursor; cursor++)
1274         if (stricmp(cursor, str2) == 0)
1275             return cursor;
1276
1277     return NULL;
1278 }
1279
1280 /*
1281  * Substitute a variable value for its name in a submount pathname.  Variable
1282  * name has been identified by smb_stristr() and is in substr.  Variable name
1283  * length (plus one) is in substr_size.  Variable value is in newstr.
1284  */
1285 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1286                       char *newstr)
1287 {
1288     char temp[1024];
1289
1290     strcpy(temp, substr + substr_size - 1);
1291     strcpy(substr, newstr);
1292     strcat(str1, temp);
1293 }       
1294
1295 char VNUserName[] = "%USERNAME%";
1296 char VNLCUserName[] = "%LCUSERNAME%";
1297 char VNComputerName[] = "%COMPUTERNAME%";
1298 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1299
1300 #ifdef DJGPP
1301 /* List available shares */
1302 int smb_ListShares()
1303 {
1304     char sbmtpath[256];
1305     char pathName[256];
1306     char shareBuf[4096];
1307     int num_shares=0;
1308     char *this_share;
1309     int len;
1310     char *p;
1311     int print_afs = 0;
1312     int code;
1313
1314     /*strcpy(shareNameList[num_shares], "all");
1315       strcpy(pathNameList[num_shares++], "/afs");*/
1316     fprintf(stderr, "The following shares are available:\n");
1317     fprintf(stderr, "Share Name (AFS Path)\n");
1318     fprintf(stderr, "---------------------\n");
1319     fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
1320
1321 #ifndef DJGPP
1322     code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1323     if (code == 0 || code > sizeof(sbmtpath)) return -1;
1324 #else
1325     strcpy(sbmtpath, cm_confDir);
1326 #endif /* !DJGPP */
1327     strcat(sbmtpath, "/afsdsbmt.ini");
1328     len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1329                                    shareBuf, sizeof(shareBuf),
1330                                    sbmtpath);
1331     if (len == 0) {
1332         return num_shares;
1333     }
1334
1335     this_share = shareBuf;
1336     do
1337     {
1338         print_afs = 0;
1339         /*strcpy(shareNameList[num_shares], this_share);*/
1340         len = GetPrivateProfileString("AFS Submounts", this_share,
1341                                        NULL,
1342                                        pathName, 256,
1343                                        sbmtpath);
1344         if (!len) 
1345             return num_shares;
1346         p = pathName;
1347         if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) != 0)
1348             print_afs = 1;
1349         while (*p) {
1350             if (*p == '\\') *p = '/';    /* change to / */
1351             p++;
1352         }
1353
1354         fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1355                  smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
1356                  pathName);
1357         num_shares++;
1358         while (*this_share != 0) this_share++;  /* find next NUL */
1359         this_share++;   /* skip past the NUL */
1360     } while (*this_share != 0);  /* stop at final NUL */
1361
1362     return num_shares;
1363 }
1364 #endif /* DJGPP */
1365
1366 typedef struct smb_findShare_rock {
1367     char * shareName;
1368     char * match;
1369     int matchType;
1370 } smb_findShare_rock_t;
1371
1372 #define SMB_FINDSHARE_EXACT_MATCH 1
1373 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1374
1375 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1376                        osi_hyper_t *offp)
1377 {
1378     int matchType = 0;
1379     smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1380     if (!strnicmp(dep->name, vrock->shareName, 12)) {
1381         if(!stricmp(dep->name, vrock->shareName))
1382             matchType = SMB_FINDSHARE_EXACT_MATCH;
1383         else
1384             matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1385         if(vrock->match) free(vrock->match);
1386         vrock->match = strdup(dep->name);
1387         vrock->matchType = matchType;
1388
1389         if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1390             return CM_ERROR_STOPNOW;
1391     }
1392     return 0;
1393 }
1394
1395
1396 /* find a shareName in the table of submounts */
1397 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1398         char **pathNamep)
1399 {
1400     DWORD len;
1401     char pathName[1024];
1402     char *var;
1403     char temp[1024];
1404     DWORD sizeTemp;
1405 #ifdef DJGPP
1406     char sbmtpath[MAX_PATH];
1407 #endif
1408     char *p, *q;
1409     HKEY parmKey;
1410     DWORD code;
1411     DWORD allSubmount = 1;
1412
1413     /* if allSubmounts == 0, only return the //mountRoot/all share 
1414      * if in fact it has been been created in the subMounts table.  
1415      * This is to allow sites that want to restrict access to the 
1416      * world to do so.
1417      */
1418     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1419                          0, KEY_QUERY_VALUE, &parmKey);
1420     if (code == ERROR_SUCCESS) {
1421         len = sizeof(allSubmount);
1422         code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1423                                 (BYTE *) &allSubmount, &len);
1424         if (code != ERROR_SUCCESS) {
1425             allSubmount = 1;
1426         }
1427         RegCloseKey (parmKey);
1428     }
1429
1430     if (allSubmount && _stricmp(shareName, "all") == 0) {
1431         *pathNamep = NULL;
1432         return 1;
1433     }
1434
1435     /* In case, the all share is disabled we need to still be able
1436      * to handle ioctl requests 
1437      */
1438     if (_stricmp(shareName, "ioctl$") == 0) {
1439         *pathNamep = strdup("/.__ioctl__");
1440         return 1;
1441     }
1442
1443     if (_stricmp(shareName, "IPC$") == 0 ||
1444         _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1445         _stricmp(shareName, "DESKTOP.INI") == 0
1446          ) {
1447         *pathNamep = NULL;
1448         return 0;
1449     }
1450
1451 #ifndef DJGPP
1452     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1453                          0, KEY_QUERY_VALUE, &parmKey);
1454     if (code == ERROR_SUCCESS) {
1455         len = sizeof(pathName);
1456         code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1457                                 (BYTE *) pathName, &len);
1458         if (code != ERROR_SUCCESS)
1459             len = 0;
1460         RegCloseKey (parmKey);
1461     } else {
1462         len = 0;
1463     }   
1464 #else /* DJGPP */
1465     strcpy(sbmtpath, cm_confDir);
1466     strcat(sbmtpath, "/afsdsbmt.ini");
1467     len = GetPrivateProfileString("AFS Submounts", shareName, "",
1468                                    pathName, sizeof(pathName), sbmtpath);
1469 #endif /* !DJGPP */
1470     if (len != 0 && len != sizeof(pathName) - 1) {
1471         /* We can accept either unix or PC style AFS pathnames.  Convert
1472          * Unix-style to PC style here for internal use. 
1473          */
1474         p = pathName;
1475         if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1476             p += strlen(cm_mountRoot);  /* skip mount path */
1477         q = p;
1478         while (*q) {
1479             if (*q == '/') *q = '\\';    /* change to \ */
1480             q++;
1481         }
1482
1483         while (1)
1484         {
1485             if (var = smb_stristr(p, VNUserName)) {
1486                 if (uidp && uidp->unp)
1487                     smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1488                 else
1489                     smb_subst(p, var, sizeof(VNUserName)," ");
1490             }
1491             else if (var = smb_stristr(p, VNLCUserName)) 
1492             {
1493                 if (uidp && uidp->unp)
1494                     strcpy(temp, uidp->unp->name);
1495                 else 
1496                     strcpy(temp, " ");
1497                 _strlwr(temp);
1498                 smb_subst(p, var, sizeof(VNLCUserName), temp);
1499             }
1500             else if (var = smb_stristr(p, VNComputerName)) 
1501             {
1502                 sizeTemp = sizeof(temp);
1503                 GetComputerName((LPTSTR)temp, &sizeTemp);
1504                 smb_subst(p, var, sizeof(VNComputerName), temp);
1505             }
1506             else if (var = smb_stristr(p, VNLCComputerName)) 
1507             {
1508                 sizeTemp = sizeof(temp);
1509                 GetComputerName((LPTSTR)temp, &sizeTemp);
1510                 _strlwr(temp);
1511                 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1512             }
1513             else     
1514                 break;
1515         }
1516         *pathNamep = strdup(p);
1517         return 1;
1518     } 
1519     else
1520     {
1521         /* First lookup shareName in root.afs */
1522         cm_req_t req;
1523         smb_findShare_rock_t vrock;
1524         osi_hyper_t thyper;
1525         char * p = shareName; 
1526         int rw = 0;
1527
1528         /*  attempt to locate a partial match in root.afs.  This is because
1529             when using the ANSI RAP calls, the share name is limited to 13 chars
1530             and hence is truncated. Of course we prefer exact matches. */
1531         cm_InitReq(&req);
1532         thyper.HighPart = 0;
1533         thyper.LowPart = 0;
1534
1535         vrock.shareName = shareName;
1536         vrock.match = NULL;
1537         vrock.matchType = 0;
1538
1539         cm_HoldSCache(cm_data.rootSCachep);
1540         code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1541             (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1542         cm_ReleaseSCache(cm_data.rootSCachep);
1543
1544         if (vrock.matchType) {
1545             sprintf(pathName,"/%s/",vrock.match);
1546             *pathNamep = strdup(strlwr(pathName));
1547             free(vrock.match);
1548             return 1;
1549         }
1550
1551         /* if we get here, there was no match for the share in root.afs */
1552         /* so try to create  \\<netbiosName>\<cellname>  */
1553         if ( *p == '.' ) {
1554             p++;
1555             rw = 1;
1556         }
1557         /* Get the full name for this cell */
1558         code = cm_SearchCellFile(p, temp, 0, 0);
1559 #ifdef AFS_AFSDB_ENV
1560         if (code && cm_dnsEnabled) {
1561             int ttl;
1562             code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1563         }
1564 #endif
1565         /* construct the path */
1566         if (code == 0) {     
1567             sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1568             *pathNamep = strdup(strlwr(pathName));
1569             return 1;
1570         }
1571     }
1572     /* failure */
1573     *pathNamep = NULL;
1574     return 0;
1575 }
1576
1577 /* Client-side offline caching policy types */
1578 #define CSC_POLICY_MANUAL 0
1579 #define CSC_POLICY_DOCUMENTS 1
1580 #define CSC_POLICY_PROGRAMS 2
1581 #define CSC_POLICY_DISABLE 3
1582
1583 int smb_FindShareCSCPolicy(char *shareName)
1584 {
1585     DWORD len;
1586     char policy[1024];
1587     DWORD dwType;
1588     HKEY hkCSCPolicy;
1589     int  retval = CSC_POLICY_MANUAL;
1590
1591     RegCreateKeyEx( HKEY_LOCAL_MACHINE, 
1592                     AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1593                     0, 
1594                     "AFS", 
1595                     REG_OPTION_NON_VOLATILE,
1596                     KEY_READ,
1597                     NULL, 
1598                     &hkCSCPolicy,
1599                     NULL );
1600
1601     len = sizeof(policy);
1602     if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1603          len == 0) {
1604         retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1605     }
1606     else if (stricmp(policy, "documents") == 0)
1607     {
1608         retval = CSC_POLICY_DOCUMENTS;
1609     }
1610     else if (stricmp(policy, "programs") == 0)
1611     {
1612         retval = CSC_POLICY_PROGRAMS;
1613     }
1614     else if (stricmp(policy, "disable") == 0)
1615     {
1616         retval = CSC_POLICY_DISABLE;
1617     }
1618         
1619     RegCloseKey(hkCSCPolicy);
1620     return retval;
1621 }
1622
1623 /* find a dir search structure by cookie value, and return it held.
1624  * Must be called with smb_globalLock held.
1625  */
1626 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
1627 {
1628     smb_dirSearch_t *dsp;
1629         
1630     for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1631         if (dsp->cookie == cookie) {
1632             if (dsp != smb_firstDirSearchp) {
1633                 /* move to head of LRU queue, too, if we're not already there */
1634                 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1635                     smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
1636                 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1637                 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1638                 if (!smb_lastDirSearchp)
1639                     smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1640             }
1641             lock_ObtainMutex(&dsp->mx);
1642             dsp->refCount++;
1643             lock_ReleaseMutex(&dsp->mx);
1644             break;
1645         }
1646     }
1647
1648     if (dsp == NULL) {
1649         osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
1650         for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1651             osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
1652         }
1653     }
1654     return dsp;
1655 }       
1656
1657 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1658 {
1659     lock_ObtainWrite(&smb_globalLock);
1660     lock_ObtainMutex(&dsp->mx);
1661     dsp->flags |= SMB_DIRSEARCH_DELETE;
1662     if (dsp->scp != NULL) {
1663         lock_ObtainMutex(&dsp->scp->mx);
1664         if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1665             dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1666             dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1667             dsp->scp->bulkStatProgress = hones;
1668         }       
1669         lock_ReleaseMutex(&dsp->scp->mx);
1670     }   
1671     lock_ReleaseMutex(&dsp->mx);
1672     lock_ReleaseWrite(&smb_globalLock);
1673 }               
1674
1675 /* Must be called with the smb_globalLock held */
1676 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
1677 {
1678     cm_scache_t *scp = NULL;
1679
1680     lock_ObtainMutex(&dsp->mx);
1681     osi_assert(dsp->refCount-- > 0);
1682     if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1683         if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1684             smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1685         osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1686         lock_ReleaseMutex(&dsp->mx);
1687         lock_FinalizeMutex(&dsp->mx);
1688         scp = dsp->scp;
1689         free(dsp);
1690     } else {
1691         lock_ReleaseMutex(&dsp->mx);
1692     }
1693     /* do this now to avoid spurious locking hierarchy creation */
1694     if (scp) 
1695         cm_ReleaseSCache(scp);
1696 }       
1697
1698 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1699 {
1700     lock_ObtainWrite(&smb_globalLock);
1701     smb_ReleaseDirSearchNoLock(dsp);
1702     lock_ReleaseWrite(&smb_globalLock);
1703 }       
1704
1705 /* find a dir search structure by cookie value, and return it held */
1706 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1707 {
1708     smb_dirSearch_t *dsp;
1709
1710     lock_ObtainWrite(&smb_globalLock);
1711     dsp = smb_FindDirSearchNoLock(cookie);
1712     lock_ReleaseWrite(&smb_globalLock);
1713     return dsp;
1714 }
1715
1716 /* GC some dir search entries, in the address space expected by the specific protocol.
1717  * Must be called with smb_globalLock held; release the lock temporarily.
1718  */
1719 #define SMB_DIRSEARCH_GCMAX     10      /* how many at once */
1720 void smb_GCDirSearches(int isV3)
1721 {
1722     smb_dirSearch_t *prevp;
1723     smb_dirSearch_t *tp;
1724     smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1725     int victimCount;
1726     int i;
1727         
1728     victimCount = 0;    /* how many have we got so far */
1729     for (tp = smb_lastDirSearchp; tp; tp=prevp) {
1730         /* we'll move tp from queue, so
1731          * do this early.
1732          */
1733         prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);  
1734         /* if no one is using this guy, and we're either in the new protocol,
1735          * or we're in the old one and this is a small enough ID to be useful
1736          * to the old protocol, GC this guy.
1737          */
1738         if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1739             /* hold and delete */
1740             tp->flags |= SMB_DIRSEARCH_DELETE;
1741             victimsp[victimCount++] = tp;
1742             tp->refCount++;
1743         }
1744
1745         /* don't do more than this */
1746         if (victimCount >= SMB_DIRSEARCH_GCMAX) 
1747             break;
1748     }
1749         
1750     /* now release them */
1751     for (i = 0; i < victimCount; i++) {
1752         smb_ReleaseDirSearchNoLock(victimsp[i]);
1753     }
1754 }
1755
1756 /* function for allocating a dir search entry.  We need these to remember enough context
1757  * since we don't get passed the path from call to call during a directory search.
1758  *
1759  * Returns a held dir search structure, and bumps the reference count on the vnode,
1760  * since it saves a pointer to the vnode.
1761  */
1762 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1763 {
1764     smb_dirSearch_t *dsp;
1765     int counter;
1766     int maxAllowed;
1767     int start;
1768     int wrapped = 0;
1769
1770     lock_ObtainWrite(&smb_globalLock);
1771     counter = 0;
1772
1773     /* what's the biggest ID allowed in this version of the protocol */
1774     maxAllowed = isV3 ? 65535 : 255;
1775     if (smb_dirSearchCounter > maxAllowed)
1776         smb_dirSearchCounter = 1;
1777
1778     start = smb_dirSearchCounter;
1779
1780     while (1) {
1781         /* twice so we have enough tries to find guys we GC after one pass;
1782          * 10 extra is just in case I mis-counted.
1783          */
1784         if (++counter > 2*maxAllowed+10) 
1785             osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
1786
1787         if (smb_dirSearchCounter > maxAllowed) {        
1788             smb_dirSearchCounter = 1;
1789         }
1790         if (smb_dirSearchCounter == start) {
1791             if (wrapped)
1792                 smb_GCDirSearches(isV3);
1793             wrapped++;
1794         }
1795         dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
1796         if (dsp) {
1797             /* don't need to watch for refcount zero and deleted, since
1798             * we haven't dropped the global lock.
1799             */
1800             lock_ObtainMutex(&dsp->mx);
1801             dsp->refCount--;
1802             lock_ReleaseMutex(&dsp->mx);
1803             ++smb_dirSearchCounter;
1804             continue;
1805         }       
1806
1807         dsp = malloc(sizeof(*dsp));
1808         memset(dsp, 0, sizeof(*dsp));
1809         dsp->cookie = smb_dirSearchCounter;
1810         ++smb_dirSearchCounter;
1811         dsp->refCount = 1;
1812         lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
1813         dsp->lastTime = osi_Time();
1814         osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1815         if (!smb_lastDirSearchp) 
1816             smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1817         break;
1818     }   
1819     lock_ReleaseWrite(&smb_globalLock);
1820     return dsp;
1821 }
1822
1823 static smb_packet_t *GetPacket(void)
1824 {
1825     smb_packet_t *tbp;
1826 #ifdef DJGPP
1827     unsigned int npar, seg, tb_sel;
1828 #endif
1829
1830     lock_ObtainWrite(&smb_globalLock);
1831     tbp = smb_packetFreeListp;
1832     if (tbp) 
1833         smb_packetFreeListp = tbp->nextp;
1834     lock_ReleaseWrite(&smb_globalLock);
1835     if (!tbp) {
1836 #ifndef DJGPP
1837         tbp = calloc(65540,1);
1838 #else /* DJGPP */
1839         tbp = malloc(sizeof(smb_packet_t));
1840 #endif /* !DJGPP */
1841         tbp->magic = SMB_PACKETMAGIC;
1842         tbp->ncbp = NULL;
1843         tbp->vcp = NULL;
1844         tbp->resumeCode = 0;
1845         tbp->inCount = 0;
1846         tbp->fid = 0;
1847         tbp->wctp = NULL;
1848         tbp->inCom = 0;
1849         tbp->oddByte = 0;
1850         tbp->ncb_length = 0;
1851         tbp->flags = 0;
1852         tbp->spacep = NULL;
1853         
1854 #ifdef DJGPP
1855         npar = SMB_PACKETSIZE >> 4;  /* number of paragraphs */
1856         {
1857             signed int retval =
1858                 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1859             if (retval == -1) {
1860                 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS memory",
1861                           npar);
1862                 osi_panic("",__FILE__,__LINE__);
1863             }
1864             else {
1865                 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X",
1866                           npar, retval);
1867                 seg = retval;
1868             }
1869         }
1870         tbp->dos_pkt = (seg * 16) + 0;  /* DOS physical address */
1871         tbp->dos_pkt_sel = tb_sel;
1872 #endif /* DJGPP */
1873     }
1874     osi_assert(tbp->magic == SMB_PACKETMAGIC);
1875
1876     return tbp;
1877 }
1878
1879 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
1880 {
1881     smb_packet_t *tbp;
1882     tbp = GetPacket();
1883     memcpy(tbp, pkt, sizeof(smb_packet_t));
1884     tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
1885     if (tbp->vcp)
1886         smb_HoldVC(tbp->vcp);
1887     return tbp;
1888 }
1889
1890 static NCB *GetNCB(void)
1891 {
1892     smb_ncb_t *tbp;
1893     NCB *ncbp;
1894 #ifdef DJGPP
1895     unsigned int npar, seg, tb_sel;
1896 #endif /* DJGPP */
1897
1898     lock_ObtainWrite(&smb_globalLock);
1899     tbp = smb_ncbFreeListp;
1900     if (tbp) 
1901         smb_ncbFreeListp = tbp->nextp;
1902     lock_ReleaseWrite(&smb_globalLock);
1903     if (!tbp) {
1904 #ifndef DJGPP
1905         tbp = calloc(sizeof(*tbp),1);
1906 #else /* DJGPP */
1907         tbp = malloc(sizeof(*tbp));
1908         npar = (sizeof(NCB)+15) >> 4;  /* number of paragraphs */
1909         {
1910             signed int retval =
1911                 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1912             if (retval == -1) {
1913                 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS mem in GetNCB",
1914                           npar);
1915                 osi_panic("",__FILE__,__LINE__);
1916             } else {
1917                 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
1918                           npar, retval);
1919                 seg = retval;
1920             }
1921         }
1922         tbp->dos_ncb = (seg * 16) + 0;  /* DOS physical address */
1923         tbp->dos_ncb_sel = tb_sel;
1924 #endif /* !DJGPP */
1925         tbp->magic = SMB_NCBMAGIC;
1926     }
1927         
1928     osi_assert(tbp->magic == SMB_NCBMAGIC);
1929
1930     memset(&tbp->ncb, 0, sizeof(NCB));
1931     ncbp = &tbp->ncb;
1932 #ifdef DJGPP
1933     dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
1934 #endif /* DJGPP */
1935     return ncbp;
1936 }
1937
1938 void smb_FreePacket(smb_packet_t *tbp)
1939 {
1940     smb_vc_t * vcp = NULL;
1941     osi_assert(tbp->magic == SMB_PACKETMAGIC);
1942         
1943     lock_ObtainWrite(&smb_globalLock);
1944     tbp->nextp = smb_packetFreeListp;
1945     smb_packetFreeListp = tbp;
1946     tbp->magic = SMB_PACKETMAGIC;
1947     tbp->ncbp = NULL;
1948     vcp = tbp->vcp;
1949     tbp->vcp = NULL;
1950     tbp->resumeCode = 0;
1951     tbp->inCount = 0;
1952     tbp->fid = 0;
1953     tbp->wctp = NULL;
1954     tbp->inCom = 0;
1955     tbp->oddByte = 0;
1956     tbp->ncb_length = 0;
1957     tbp->flags = 0;
1958     lock_ReleaseWrite(&smb_globalLock);
1959
1960     if (vcp)
1961         smb_ReleaseVC(vcp);
1962 }
1963
1964 static void FreeNCB(NCB *bufferp)
1965 {
1966     smb_ncb_t *tbp;
1967         
1968     tbp = (smb_ncb_t *) bufferp;
1969     osi_assert(tbp->magic == SMB_NCBMAGIC);
1970         
1971     lock_ObtainWrite(&smb_globalLock);
1972     tbp->nextp = smb_ncbFreeListp;
1973     smb_ncbFreeListp = tbp;
1974     lock_ReleaseWrite(&smb_globalLock);
1975 }
1976
1977 /* get a ptr to the data part of a packet, and its count */
1978 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
1979 {
1980     int parmBytes;
1981     int dataBytes;
1982     unsigned char *afterParmsp;
1983
1984     parmBytes = *smbp->wctp << 1;
1985     afterParmsp = smbp->wctp + parmBytes + 1;
1986         
1987     dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
1988     if (nbytesp) *nbytesp = dataBytes;
1989         
1990     /* don't forget to skip the data byte count, since it follows
1991      * the parameters; that's where the "2" comes from below.
1992      */
1993     return (unsigned char *) (afterParmsp + 2);
1994 }
1995
1996 /* must set all the returned parameters before playing around with the
1997  * data region, since the data region is located past the end of the
1998  * variable number of parameters.
1999  */
2000 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2001 {
2002     unsigned char *afterParmsp;
2003
2004     afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2005         
2006     *afterParmsp++ = dsize & 0xff;
2007     *afterParmsp = (dsize>>8) & 0xff;
2008 }       
2009
2010 /* return the parm'th parameter in the smbp packet */
2011 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
2012 {
2013     int parmCount;
2014     unsigned char *parmDatap;
2015
2016     parmCount = *smbp->wctp;
2017
2018     if (parm >= parmCount) {
2019         char s[100];
2020 #ifndef DJGPP
2021         HANDLE h;
2022         char *ptbuf[1];
2023         h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
2024 #endif  
2025         sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2026                  parm, parmCount, smbp->ncb_length);
2027 #ifndef DJGPP   
2028         ptbuf[0] = s;
2029         ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
2030                      1, smbp->ncb_length, ptbuf, smbp);
2031         DeregisterEventSource(h);
2032 #endif
2033         osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2034                  parm, parmCount, smbp->ncb_length);
2035         osi_panic(s, __FILE__, __LINE__);
2036     }
2037     parmDatap = smbp->wctp + (2*parm) + 1;
2038         
2039     return parmDatap[0] + (parmDatap[1] << 8);
2040 }
2041
2042 /* return the parm'th parameter in the smbp packet */
2043 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2044 {
2045     int parmCount;
2046     unsigned char *parmDatap;
2047
2048     parmCount = *smbp->wctp;
2049
2050     if (parm * 2 + offset >= parmCount * 2) {
2051         char s[100];
2052 #ifndef DJGPP
2053         HANDLE h;
2054         char *ptbuf[1];
2055         h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
2056 #endif
2057         sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2058                 parm, offset, parmCount, smbp->ncb_length);
2059 #ifndef DJGPP
2060         ptbuf[0] = s;
2061         ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
2062                     1, smbp->ncb_length, ptbuf, smbp);
2063         DeregisterEventSource(h);
2064 #endif
2065         osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2066                 parm, offset, parmCount, smbp->ncb_length);
2067         osi_panic(s, __FILE__, __LINE__);
2068     }
2069     parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2070         
2071     return parmDatap[0] + (parmDatap[1] << 8);
2072 }
2073
2074 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2075 {
2076     char *parmDatap;
2077
2078     /* make sure we have enough slots */
2079     if (*smbp->wctp <= slot) 
2080         *smbp->wctp = slot+1;
2081         
2082     parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2083     *parmDatap++ = parmValue & 0xff;
2084     *parmDatap = (parmValue>>8) & 0xff;
2085 }       
2086
2087 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2088 {
2089     char *parmDatap;
2090
2091     /* make sure we have enough slots */
2092     if (*smbp->wctp <= slot) 
2093         *smbp->wctp = slot+2;
2094
2095     parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2096     *parmDatap++ = parmValue & 0xff;
2097     *parmDatap++ = (parmValue>>8) & 0xff;
2098     *parmDatap++ = (parmValue>>16) & 0xff;
2099     *parmDatap++ = (parmValue>>24) & 0xff;
2100 }
2101
2102 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2103 {
2104     char *parmDatap;
2105     int i;
2106
2107     /* make sure we have enough slots */
2108     if (*smbp->wctp <= slot) 
2109         *smbp->wctp = slot+4;
2110
2111     parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2112     for (i=0; i<8; i++)
2113         *parmDatap++ = *parmValuep++;
2114 }       
2115
2116 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2117 {
2118     char *parmDatap;
2119
2120     /* make sure we have enough slots */
2121     if (*smbp->wctp <= slot) {
2122         if (smbp->oddByte) {
2123             smbp->oddByte = 0;
2124             *smbp->wctp = slot+1;
2125         } else
2126             smbp->oddByte = 1;
2127     }
2128
2129     parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2130     *parmDatap++ = parmValue & 0xff;
2131 }
2132
2133 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2134 {
2135     char *lastSlashp;
2136         
2137     lastSlashp = strrchr(inPathp, '\\');
2138     if (lastComponentp)
2139         *lastComponentp = lastSlashp;
2140     if (lastSlashp) {
2141         while (1) {
2142             if (inPathp == lastSlashp) 
2143                 break;
2144             *outPathp++ = *inPathp++;
2145         }
2146         *outPathp++ = 0;
2147     }
2148     else {
2149         *outPathp++ = 0;
2150     }
2151 }
2152
2153 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2154 {
2155     if (*inp++ != 0x4) 
2156         return NULL;
2157     if (chainpp) {
2158         *chainpp = inp + strlen(inp) + 1;       /* skip over null-terminated string */
2159     }
2160     return inp;
2161 }
2162
2163 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2164 {
2165     int tlen;
2166
2167     if (*inp++ != 0x5) 
2168         return NULL;
2169     tlen = inp[0] + (inp[1]<<8);
2170     inp += 2;           /* skip length field */
2171
2172     if (chainpp) {
2173         *chainpp = inp + tlen;
2174     }
2175         
2176     if (lengthp) 
2177         *lengthp = tlen;
2178         
2179     return inp;
2180 }       
2181
2182 /* format a packet as a response */
2183 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2184 {
2185     smb_t *outp;
2186     smb_t *inSmbp;
2187
2188     outp = (smb_t *) op;
2189         
2190     /* zero the basic structure through the smb_wct field, and zero the data
2191      * size field, assuming that wct stays zero; otherwise, you have to 
2192      * explicitly set the data size field, too.
2193      */
2194     inSmbp = (smb_t *) inp;
2195     memset(outp, 0, sizeof(smb_t)+2);
2196     outp->id[0] = 0xff;
2197     outp->id[1] = 'S';
2198     outp->id[2] = 'M';
2199     outp->id[3] = 'B';
2200     if (inp) {
2201         outp->com = inSmbp->com;
2202         outp->tid = inSmbp->tid;
2203         outp->pid = inSmbp->pid;
2204         outp->uid = inSmbp->uid;
2205         outp->mid = inSmbp->mid;
2206         outp->res[0] = inSmbp->res[0];
2207         outp->res[1] = inSmbp->res[1];
2208         op->inCom = inSmbp->com;
2209     }
2210     outp->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
2211     outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2212
2213     /* copy fields in generic packet area */
2214     op->wctp = &outp->wct;
2215 }       
2216
2217 /* send a (probably response) packet; vcp tells us to whom to send it.
2218  * we compute the length by looking at wct and bcc fields.
2219  */
2220 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2221 {
2222     NCB *ncbp;
2223     int extra;
2224     long code = 0;
2225     unsigned char *tp;
2226     int localNCB = 0;
2227 #ifdef DJGPP
2228     dos_ptr dos_ncb;
2229 #endif /* DJGPP */
2230         
2231     ncbp = inp->ncbp;
2232     if (ncbp == NULL) {
2233         ncbp = GetNCB();
2234         localNCB = 1;
2235     }
2236 #ifdef DJGPP
2237     dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2238 #endif /* DJGPP */
2239  
2240     memset((char *)ncbp, 0, sizeof(NCB));
2241
2242     extra = 2 * (*inp->wctp);   /* space used by parms, in bytes */
2243     tp = inp->wctp + 1+ extra;  /* points to count of data bytes */
2244     extra += tp[0] + (tp[1]<<8);
2245     extra += (unsigned int)(inp->wctp - inp->data);     /* distance to last wct field */
2246     extra += 3;                 /* wct and length fields */
2247         
2248     ncbp->ncb_length = extra;   /* bytes to send */
2249     ncbp->ncb_lsn = (unsigned char) vcp->lsn;   /* vc to use */
2250     ncbp->ncb_lana_num = vcp->lana;
2251     ncbp->ncb_command = NCBSEND;        /* op means send data */
2252 #ifndef DJGPP
2253     ncbp->ncb_buffer = (char *) inp;/* packet */
2254     code = Netbios(ncbp);
2255 #else /* DJGPP */
2256     ncbp->ncb_buffer = inp->dos_pkt;/* packet */
2257     ((smb_ncb_t*)ncbp)->orig_pkt = inp;
2258
2259     /* copy header information from virtual to DOS address space */
2260     dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
2261     code = Netbios(ncbp, dos_ncb);
2262 #endif /* !DJGPP */
2263         
2264     if (code != 0) {
2265         char * s;
2266         switch ( code ) {
2267         case 0x01: s = "llegal buffer length                     "; break; 
2268         case 0x03: s = "illegal command                          "; break; 
2269         case 0x05: s = "command timed out                        "; break; 
2270         case 0x06: s = "message incomplete, issue another command"; break; 
2271         case 0x07: s = "illegal buffer address                   "; break; 
2272         case 0x08: s = "session number out of range              "; break; 
2273         case 0x09: s = "no resource available                    "; break; 
2274         case 0x0a: s = "session closed                           "; break; 
2275         case 0x0b: s = "command cancelled                        "; break; 
2276         case 0x0d: s = "duplicate name                           "; break; 
2277         case 0x0e: s = "name table full                          "; break; 
2278         case 0x0f: s = "no deletions, name has active sessions   "; break; 
2279         case 0x11: s = "local session table full                 "; break; 
2280         case 0x12: s = "remote session table full                "; break; 
2281         case 0x13: s = "illegal name number                      "; break; 
2282         case 0x14: s = "no callname                              "; break; 
2283         case 0x15: s = "cannot put * in NCB_NAME                 "; break; 
2284         case 0x16: s = "name in use on remote adapter            "; break; 
2285         case 0x17: s = "name deleted                             "; break; 
2286         case 0x18: s = "session ended abnormally                 "; break; 
2287         case 0x19: s = "name conflict detected                   "; break; 
2288         case 0x21: s = "interface busy, IRET before retrying     "; break; 
2289         case 0x22: s = "too many commands outstanding, retry later"; break;
2290         case 0x23: s = "ncb_lana_num field invalid               "; break; 
2291         case 0x24: s = "command completed while cancel occurring "; break; 
2292         case 0x26: s = "command not valid to cancel              "; break; 
2293         case 0x30: s = "name defined by anther local process     "; break; 
2294         case 0x34: s = "environment undefined. RESET required    "; break; 
2295         case 0x35: s = "required OS resources exhausted          "; break; 
2296         case 0x36: s = "max number of applications exceeded      "; break; 
2297         case 0x37: s = "no saps available for netbios            "; break; 
2298         case 0x38: s = "requested resources are not available    "; break; 
2299         case 0x39: s = "invalid ncb address or length > segment  "; break; 
2300         case 0x3B: s = "invalid NCB DDID                         "; break; 
2301         case 0x3C: s = "lock of user area failed                 "; break; 
2302         case 0x3f: s = "NETBIOS not loaded                       "; break; 
2303         case 0x40: s = "system error                             "; break;                 
2304         default:
2305             s = "unknown error";
2306         }
2307         osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2308     }
2309
2310     if (localNCB)
2311         FreeNCB(ncbp);
2312 }
2313
2314 void smb_MapNTError(long code, unsigned long *NTStatusp)
2315 {
2316     unsigned long NTStatus;
2317
2318     /* map CM_ERROR_* errors to NT 32-bit status codes */
2319     /* NT Status codes are listed in ntstatus.h not winerror.h */
2320     if (code == CM_ERROR_NOSUCHCELL) {
2321         NTStatus = 0xC000000FL; /* No such file */
2322     }
2323     else if (code == CM_ERROR_NOSUCHVOLUME) {
2324         NTStatus = 0xC000000FL; /* No such file */
2325     }
2326     else if (code == CM_ERROR_TIMEDOUT) {
2327 #ifdef COMMENT
2328         NTStatus = 0xC00000CFL; /* Sharing Paused */
2329 #else
2330         NTStatus = 0x00000102L; /* Timeout */
2331 #endif
2332     }
2333     else if (code == CM_ERROR_RETRY) {
2334         NTStatus = 0xC000022DL; /* Retry */
2335     }
2336     else if (code == CM_ERROR_NOACCESS) {
2337         NTStatus = 0xC0000022L; /* Access denied */
2338     }
2339     else if (code == CM_ERROR_READONLY) {
2340         NTStatus = 0xC00000A2L; /* Write protected */
2341     }
2342     else if (code == CM_ERROR_NOSUCHFILE) {
2343         NTStatus = 0xC000000FL; /* No such file */
2344     }
2345     else if (code == CM_ERROR_NOSUCHPATH) {
2346         NTStatus = 0xC000003AL; /* Object path not found */
2347     }           
2348     else if (code == CM_ERROR_TOOBIG) {
2349         NTStatus = 0xC000007BL; /* Invalid image format */
2350     }
2351     else if (code == CM_ERROR_INVAL) {
2352         NTStatus = 0xC000000DL; /* Invalid parameter */
2353     }
2354     else if (code == CM_ERROR_BADFD) {
2355         NTStatus = 0xC0000008L; /* Invalid handle */
2356     }
2357     else if (code == CM_ERROR_BADFDOP) {
2358         NTStatus = 0xC0000022L; /* Access denied */
2359     }
2360     else if (code == CM_ERROR_EXISTS) {
2361         NTStatus = 0xC0000035L; /* Object name collision */
2362     }
2363     else if (code == CM_ERROR_NOTEMPTY) {
2364         NTStatus = 0xC0000101L; /* Directory not empty */
2365     }   
2366     else if (code == CM_ERROR_CROSSDEVLINK) {
2367         NTStatus = 0xC00000D4L; /* Not same device */
2368     }
2369     else if (code == CM_ERROR_NOTDIR) {
2370         NTStatus = 0xC0000103L; /* Not a directory */
2371     }
2372     else if (code == CM_ERROR_ISDIR) {
2373         NTStatus = 0xC00000BAL; /* File is a directory */
2374     }
2375     else if (code == CM_ERROR_BADOP) {
2376 #ifdef COMMENT
2377         /* I have no idea where this comes from */
2378         NTStatus = 0xC09820FFL; /* SMB no support */
2379 #else
2380         NTStatus = 0xC00000BBL;     /* Not supported */
2381 #endif /* COMMENT */
2382     }
2383     else if (code == CM_ERROR_BADSHARENAME) {
2384         NTStatus = 0xC00000CCL; /* Bad network name */
2385     }
2386     else if (code == CM_ERROR_NOIPC) {
2387 #ifdef COMMENT
2388         NTStatus = 0xC0000022L; /* Access Denied */
2389 #else   
2390         NTStatus = 0xC000013DL; /* Remote Resources */
2391 #endif
2392     }
2393     else if (code == CM_ERROR_CLOCKSKEW) {
2394         NTStatus = 0xC0000133L; /* Time difference at DC */
2395     }
2396     else if (code == CM_ERROR_BADTID) {
2397         NTStatus = 0xC0982005L; /* SMB bad TID */
2398     }
2399     else if (code == CM_ERROR_USESTD) {
2400         NTStatus = 0xC09820FBL; /* SMB use standard */
2401     }
2402     else if (code == CM_ERROR_QUOTA) {
2403 #ifdef COMMENT
2404         NTStatus = 0xC0000044L; /* Quota exceeded */
2405 #else
2406         NTStatus = 0xC000007FL; /* Disk full */
2407 #endif
2408     }
2409     else if (code == CM_ERROR_SPACE) {
2410         NTStatus = 0xC000007FL; /* Disk full */
2411     }
2412     else if (code == CM_ERROR_ATSYS) {
2413         NTStatus = 0xC0000033L; /* Object name invalid */
2414     }
2415     else if (code == CM_ERROR_BADNTFILENAME) {
2416         NTStatus = 0xC0000033L; /* Object name invalid */
2417     }
2418     else if (code == CM_ERROR_WOULDBLOCK) {
2419         NTStatus = 0xC0000055L; /* Lock not granted */
2420     }
2421     else if (code == CM_ERROR_SHARING_VIOLATION) {
2422         NTStatus = 0xC0000043L; /* Sharing violation */
2423     }
2424     else if (code == CM_ERROR_LOCK_CONFLICT) {
2425         NTStatus = 0xC0000054L; /* Lock conflict */
2426     }
2427     else if (code == CM_ERROR_PARTIALWRITE) {
2428         NTStatus = 0xC000007FL; /* Disk full */
2429     }
2430     else if (code == CM_ERROR_BUFFERTOOSMALL) {
2431         NTStatus = 0xC0000023L; /* Buffer too small */
2432     }
2433     else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2434         NTStatus = 0xC0000035L; /* Object name collision */
2435     }   
2436     else if (code == CM_ERROR_BADPASSWORD) {
2437         NTStatus = 0xC000006DL; /* unknown username or bad password */
2438     }
2439     else if (code == CM_ERROR_BADLOGONTYPE) {
2440         NTStatus = 0xC000015BL; /* logon type not granted */
2441     }
2442     else if (code == CM_ERROR_GSSCONTINUE) {
2443         NTStatus = 0xC0000016L; /* more processing required */
2444     }
2445     else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2446 #ifdef COMMENT
2447         NTStatus = 0xC0000280L; /* reparse point not resolved */
2448 #else
2449         NTStatus = 0xC0000022L; /* Access Denied */
2450 #endif
2451     }
2452     else if (code == CM_ERROR_PATH_NOT_COVERED) {
2453         NTStatus = 0xC0000257L; /* Path Not Covered */
2454     } 
2455 #ifdef COMMENT
2456     else if (code == CM_ERROR_ALLBUSY) {
2457         NTStatus = 0xC00000BFL; /* Network Busy */
2458     } 
2459     else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
2460         NTStatus = 0xC0000350L; /* Remote Host Down */
2461     } 
2462 #else
2463     /* we do not want to be telling the SMB/CIFS client that
2464      * the AFS Client Service is busy or down.  
2465      */
2466     else if (code == CM_ERROR_ALLBUSY || 
2467              code == CM_ERROR_ALLOFFLINE ||
2468              code == CM_ERROR_ALLDOWN) {
2469         NTStatus = 0xC00000BEL; /* Bad Network Path */
2470     }
2471 #endif
2472     else if (code == RXKADUNKNOWNKEY) {
2473         NTStatus = 0xC0000322L; /* Bad Kerberos key */
2474     } else {
2475         NTStatus = 0xC0982001L; /* SMB non-specific error */
2476     }
2477
2478     *NTStatusp = NTStatus;
2479     osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2480 }       
2481
2482 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2483                       unsigned char *classp)
2484 {
2485     unsigned char class;
2486     unsigned short error;
2487
2488     /* map CM_ERROR_* errors to SMB errors */
2489     if (code == CM_ERROR_NOSUCHCELL) {
2490         class = 1;
2491         error = 3;      /* bad path */
2492     }
2493     else if (code == CM_ERROR_NOSUCHVOLUME) {
2494         class = 1;
2495         error = 3;      /* bad path */
2496     }
2497     else if (code == CM_ERROR_TIMEDOUT) {
2498         class = 2;
2499         error = 81;     /* server is paused */
2500     }
2501     else if (code == CM_ERROR_RETRY) {
2502         class = 2;      /* shouldn't happen */
2503         error = 1;
2504     }
2505     else if (code == CM_ERROR_NOACCESS) {
2506         class = 2;
2507         error = 4;      /* bad access */
2508     }
2509     else if (code == CM_ERROR_READONLY) {
2510         class = 3;
2511         error = 19;     /* read only */
2512     }
2513     else if (code == CM_ERROR_NOSUCHFILE) {
2514         class = 1;
2515         error = 2;      /* ENOENT! */
2516     }
2517     else if (code == CM_ERROR_NOSUCHPATH) {
2518         class = 1;
2519         error = 3;      /* Bad path */
2520     }
2521     else if (code == CM_ERROR_TOOBIG) {
2522         class = 1;
2523         error = 11;     /* bad format */
2524     }
2525     else if (code == CM_ERROR_INVAL) {
2526         class = 2;      /* server non-specific error code */
2527         error = 1;
2528     }
2529     else if (code == CM_ERROR_BADFD) {
2530         class = 1;
2531         error = 6;      /* invalid file handle */
2532     }
2533     else if (code == CM_ERROR_BADFDOP) {
2534         class = 1;      /* invalid op on FD */
2535         error = 5;
2536     }
2537     else if (code == CM_ERROR_EXISTS) {
2538         class = 1;
2539         error = 80;     /* file already exists */
2540     }
2541     else if (code == CM_ERROR_NOTEMPTY) {
2542         class = 1;
2543         error = 5;      /* delete directory not empty */
2544     }
2545     else if (code == CM_ERROR_CROSSDEVLINK) {
2546         class = 1;
2547         error = 17;     /* EXDEV */
2548     }
2549     else if (code == CM_ERROR_NOTDIR) {
2550         class = 1;      /* bad path */
2551         error = 3;
2552     }
2553     else if (code == CM_ERROR_ISDIR) {
2554         class = 1;      /* access denied; DOS doesn't have a good match */
2555         error = 5;
2556     }       
2557     else if (code == CM_ERROR_BADOP) {
2558         class = 2;
2559         error = 65535;
2560     }
2561     else if (code == CM_ERROR_BADSHARENAME) {
2562         class = 2;
2563         error = 6;
2564     }
2565     else if (code == CM_ERROR_NOIPC) {
2566         class = 2;
2567         error = 4; /* bad access */
2568     }
2569     else if (code == CM_ERROR_CLOCKSKEW) {
2570         class = 1;      /* invalid function */
2571         error = 1;
2572     }
2573     else if (code == CM_ERROR_BADTID) {
2574         class = 2;
2575         error = 5;
2576     }
2577     else if (code == CM_ERROR_USESTD) {
2578         class = 2;
2579         error = 251;
2580     }
2581     else if (code == CM_ERROR_REMOTECONN) {
2582         class = 2;
2583         error = 82;
2584     }
2585     else if (code == CM_ERROR_QUOTA) {
2586         if (vcp->flags & SMB_VCFLAG_USEV3) {
2587             class = 3;
2588             error = 39; /* disk full */
2589         }
2590         else {
2591             class = 1;
2592             error = 5;  /* access denied */
2593         }
2594     }
2595     else if (code == CM_ERROR_SPACE) {
2596         if (vcp->flags & SMB_VCFLAG_USEV3) {
2597             class = 3;
2598             error = 39; /* disk full */
2599         }
2600         else {
2601             class = 1;
2602             error = 5;  /* access denied */
2603         }
2604     }
2605     else if (code == CM_ERROR_PARTIALWRITE) {
2606         class = 3;
2607         error = 39;     /* disk full */
2608     }
2609     else if (code == CM_ERROR_ATSYS) {
2610         class = 1;
2611         error = 2;      /* ENOENT */
2612     }
2613     else if (code == CM_ERROR_WOULDBLOCK) {
2614         class = 1;
2615         error = 33;     /* lock conflict */
2616     }
2617     else if (code == CM_ERROR_LOCK_CONFLICT) {
2618         class = 1;
2619         error = 33;     /* lock conflict */
2620     }
2621     else if (code == CM_ERROR_SHARING_VIOLATION) {
2622         class = 1;
2623         error = 33;     /* lock conflict */
2624     }
2625     else if (code == CM_ERROR_NOFILES) {
2626         class = 1;
2627         error = 18;     /* no files in search */
2628     }
2629     else if (code == CM_ERROR_RENAME_IDENTICAL) {
2630         class = 1;
2631         error = 183;     /* Samba uses this */
2632     }
2633     else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2634         /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2635         class = 2;
2636         error = 2; /* bad password */
2637     }
2638     else if (code == CM_ERROR_PATH_NOT_COVERED) {
2639         class = 2;
2640         error = 3;     /* bad path */
2641     }
2642     else {
2643         class = 2;
2644         error = 1;
2645     }
2646
2647     *scodep = error;
2648     *classp = class;
2649     osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2650 }       
2651
2652 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2653 {
2654     osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2655     return CM_ERROR_BADOP;
2656 }
2657
2658 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2659 {
2660     unsigned short EchoCount, i;
2661     char *data, *outdata;
2662     int dataSize;
2663
2664     EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2665
2666     for (i=1; i<=EchoCount; i++) {
2667         data = smb_GetSMBData(inp, &dataSize);
2668         smb_SetSMBParm(outp, 0, i);
2669         smb_SetSMBDataLength(outp, dataSize);
2670         outdata = smb_GetSMBData(outp, NULL);
2671         memcpy(outdata, data, dataSize);
2672         smb_SendPacket(vcp, outp);
2673     }
2674
2675     return 0;
2676 }
2677
2678 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2679 {
2680     osi_hyper_t offset;
2681     long count, minCount, finalCount;
2682     unsigned short fd;
2683     unsigned pid;
2684     smb_fid_t *fidp;
2685     long code = 0;
2686     cm_user_t *userp = NULL;
2687     NCB *ncbp;
2688     int rc;
2689 #ifndef DJGPP
2690     char *rawBuf = NULL;
2691 #else
2692     dos_ptr rawBuf = NULL;
2693     dos_ptr dos_ncb;
2694 #endif /* DJGPP */
2695
2696     rawBuf = NULL;
2697     finalCount = 0;
2698
2699     fd = smb_GetSMBParm(inp, 0);
2700     count = smb_GetSMBParm(inp, 3);
2701     minCount = smb_GetSMBParm(inp, 4);
2702     offset.HighPart = 0;        /* too bad */
2703     offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2704
2705     osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2706              fd, offset.LowPart, count);
2707
2708     fidp = smb_FindFID(vcp, fd, 0);
2709     if (!fidp)
2710         goto send1;
2711
2712     pid = ((smb_t *) inp)->pid;
2713     {
2714         LARGE_INTEGER LOffset, LLength;
2715         cm_key_t key;
2716
2717         key = cm_GenerateKey(vcp->vcID, pid, fd);
2718
2719         LOffset.HighPart = 0;
2720         LOffset.LowPart = offset.LowPart;
2721         LLength.HighPart = 0;
2722         LLength.LowPart = count;
2723
2724         lock_ObtainMutex(&fidp->scp->mx);
2725         code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
2726         lock_ReleaseMutex(&fidp->scp->mx);
2727     }    
2728     if (code) {
2729         goto send1a;
2730     }
2731
2732     lock_ObtainMutex(&smb_RawBufLock);
2733     if (smb_RawBufs) {
2734         /* Get a raw buf, from head of list */
2735         rawBuf = smb_RawBufs;
2736 #ifndef DJGPP
2737         smb_RawBufs = *(char **)smb_RawBufs;
2738 #else /* DJGPP */
2739         smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2740 #endif /* !DJGPP */
2741     }
2742     lock_ReleaseMutex(&smb_RawBufLock);
2743     if (!rawBuf)
2744         goto send1a;
2745
2746     if (fidp->flags & SMB_FID_IOCTL)
2747     {
2748 #ifndef DJGPP
2749         rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2750 #else
2751         rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2752 #endif
2753         if (rawBuf) {
2754             /* Give back raw buffer */
2755             lock_ObtainMutex(&smb_RawBufLock);
2756 #ifndef DJGPP
2757             *((char **) rawBuf) = smb_RawBufs;
2758 #else /* DJGPP */
2759             _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2760 #endif /* !DJGPP */
2761             
2762             smb_RawBufs = rawBuf;
2763             lock_ReleaseMutex(&smb_RawBufLock);
2764         }
2765
2766         smb_ReleaseFID(fidp);
2767         return rc;
2768     }
2769         
2770     userp = smb_GetUser(vcp, inp);
2771
2772 #ifndef DJGPP
2773     code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2774 #else /* DJGPP */
2775     /* have to give ReadData flag so it will treat buffer as DOS mem. */
2776     code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2777                         userp, &finalCount, TRUE /* rawFlag */);
2778 #endif /* !DJGPP */
2779
2780     if (code != 0)
2781         goto send;
2782
2783   send:
2784     cm_ReleaseUser(userp);
2785
2786   send1a:
2787     smb_ReleaseFID(fidp);
2788
2789   send1:
2790     ncbp = outp->ncbp;
2791 #ifdef DJGPP
2792     dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2793 #endif /* DJGPP */
2794     memset((char *)ncbp, 0, sizeof(NCB));
2795
2796     ncbp->ncb_length = (unsigned short) finalCount;
2797     ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2798     ncbp->ncb_lana_num = vcp->lana;
2799     ncbp->ncb_command = NCBSEND;
2800     ncbp->ncb_buffer = rawBuf;
2801
2802 #ifndef DJGPP
2803     code = Netbios(ncbp);
2804 #else /* DJGPP */
2805     code = Netbios(ncbp, dos_ncb);
2806 #endif /* !DJGPP */
2807     if (code != 0)
2808         osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2809
2810     if (rawBuf) {
2811         /* Give back raw buffer */
2812         lock_ObtainMutex(&smb_RawBufLock);
2813 #ifndef DJGPP
2814         *((char **) rawBuf) = smb_RawBufs;
2815 #else /* DJGPP */
2816         _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2817 #endif /* !DJGPP */
2818
2819         smb_RawBufs = rawBuf;
2820         lock_ReleaseMutex(&smb_RawBufLock);
2821     }
2822
2823     return 0;
2824 }
2825
2826 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2827 {
2828     osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
2829                          ongoingOps - 1);
2830     return 0;
2831 }
2832
2833 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2834 {
2835     osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
2836                          ongoingOps - 1);
2837     return 0;
2838 }
2839
2840 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2841 {
2842     char *namep;
2843     char *datap;
2844     int coreProtoIndex;
2845     int v3ProtoIndex;
2846     int NTProtoIndex;
2847     int protoIndex;                             /* index we're using */
2848     int namex;
2849     int dbytes;
2850     int entryLength;
2851     int tcounter;
2852     char protocol_array[10][1024];  /* protocol signature of the client */
2853     int caps;                       /* capabilities */
2854     time_t unixTime;
2855     afs_uint32 dosTime;
2856     TIME_ZONE_INFORMATION tzi;
2857
2858     osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2859                          ongoingOps - 1);
2860     if (!isGateway) {
2861         if (active_vcp) {
2862             DWORD now = GetCurrentTime();
2863             if (now - last_msg_time >= 30000
2864                  && now - last_msg_time <= 90000) {
2865                 osi_Log1(smb_logp,
2866                           "Setting dead_vcp %x", active_vcp);
2867                 if (dead_vcp) {
2868                     smb_ReleaseVC(dead_vcp);
2869                     osi_Log1(smb_logp,
2870                              "Previous dead_vcp %x", dead_vcp);
2871                 }
2872                 smb_HoldVC(active_vcp);
2873                 dead_vcp = active_vcp;
2874                 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2875             }
2876         }
2877     }
2878
2879     inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
2880
2881     namep = smb_GetSMBData(inp, &dbytes);
2882     namex = 0;
2883     tcounter = 0;
2884     coreProtoIndex = -1;                /* not found */
2885     v3ProtoIndex = -1;
2886     NTProtoIndex = -1;
2887     while(namex < dbytes) {
2888         osi_Log1(smb_logp, "Protocol %s",
2889                   osi_LogSaveString(smb_logp, namep+1));
2890         strcpy(protocol_array[tcounter], namep+1);
2891
2892         /* namep points at the first protocol, or really, a 0x02
2893          * byte preceding the null-terminated ASCII name.
2894          */
2895         if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2896             coreProtoIndex = tcounter;
2897         }       
2898         else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2899             v3ProtoIndex = tcounter;
2900         }
2901         else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
2902             NTProtoIndex = tcounter;
2903         }
2904
2905         /* compute size of protocol entry */
2906         entryLength = (int)strlen(namep+1);
2907         entryLength += 2;       /* 0x02 bytes and null termination */
2908
2909         /* advance over this protocol entry */
2910         namex += entryLength;
2911         namep += entryLength;
2912         tcounter++;             /* which proto entry we're looking at */
2913     }
2914
2915     if (NTProtoIndex != -1) {
2916         protoIndex = NTProtoIndex;
2917         vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2918     }
2919     else if (v3ProtoIndex != -1) {
2920         protoIndex = v3ProtoIndex;
2921         vcp->flags |= SMB_VCFLAG_USEV3;
2922     }   
2923     else if (coreProtoIndex != -1) {
2924         protoIndex = coreProtoIndex;
2925         vcp->flags |= SMB_VCFLAG_USECORE;
2926     }   
2927     else protoIndex = -1;
2928
2929     if (protoIndex == -1)
2930         return CM_ERROR_INVAL;
2931     else if (NTProtoIndex != -1) {
2932         smb_SetSMBParm(outp, 0, protoIndex);
2933         if (smb_authType != SMB_AUTH_NONE) {
2934             smb_SetSMBParmByte(outp, 1,
2935                                NEGOTIATE_SECURITY_USER_LEVEL |
2936                                NEGOTIATE_SECURITY_CHALLENGE_RESPONSE);  /* user level security, challenge response */
2937         } else {
2938             smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
2939         }
2940         smb_SetSMBParm(outp, 1, smb_maxMpxRequests);    /* max multiplexed requests */
2941         smb_SetSMBParm(outp, 2, smb_maxVCPerServer);    /* max VCs per consumer/server connection */
2942         smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE);    /* xmit buffer size */
2943         smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE);    /* raw buffer size */
2944         /* The session key is not a well documented field however most clients
2945          * will echo back the session key to the server.  Currently we are using
2946          * the same value for all sessions.  We should generate a random value
2947          * and store it into the vcp 
2948          */
2949         smb_SetSMBParm(outp, 7, 1);     /* next 2: session key */
2950         smb_SetSMBParm(outp, 8, 1);
2951         /* 
2952          * Tried changing the capabilities to support for W2K - defect 117695
2953          * Maybe something else needs to be changed here?
2954          */
2955         /*
2956         if (isWindows2000) 
2957         smb_SetSMBParmLong(outp, 9, 0x43fd);
2958         else 
2959         smb_SetSMBParmLong(outp, 9, 0x251);
2960         */
2961         /* Capabilities: *
2962          * 32-bit error codes *
2963          * and NT Find *
2964          * and NT SMB's *
2965          * and raw mode 
2966          * and DFS */
2967         caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
2968 #ifdef DFS_SUPPORT
2969                NTNEGOTIATE_CAPABILITY_DFS |
2970 #endif
2971                NTNEGOTIATE_CAPABILITY_NTFIND |
2972                NTNEGOTIATE_CAPABILITY_RAWMODE |
2973                NTNEGOTIATE_CAPABILITY_NTSMB;
2974
2975         if ( smb_authType == SMB_AUTH_EXTENDED )
2976             caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
2977
2978         smb_SetSMBParmLong(outp, 9, caps);
2979         time(&unixTime);
2980         smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2981         smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
2982         smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
2983
2984         GetTimeZoneInformation(&tzi);
2985         smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias);    /* server tzone */
2986
2987         if (smb_authType == SMB_AUTH_NTLM) {
2988             smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
2989             smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
2990             /* paste in encryption key */
2991             datap = smb_GetSMBData(outp, NULL);
2992             memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
2993             /* and the faux domain name */
2994             strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
2995         } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
2996             void * secBlob;
2997             int secBlobLength;
2998
2999             smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3000
3001             smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3002
3003             smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3004                         
3005             datap = smb_GetSMBData(outp, NULL);
3006             memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3007
3008             if (secBlob) {
3009                 datap += sizeof(smb_ServerGUID);
3010                 memcpy(datap, secBlob, secBlobLength);
3011                 free(secBlob);
3012             }
3013         } else {
3014             smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3015             smb_SetSMBDataLength(outp, 0);   /* Perhaps we should specify 8 bytes anyway */
3016         }
3017     }
3018     else if (v3ProtoIndex != -1) {
3019         smb_SetSMBParm(outp, 0, protoIndex);
3020
3021         /* NOTE: Extended authentication cannot be negotiated with v3
3022          * therefore we fail over to NTLM 
3023          */
3024         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3025             smb_SetSMBParm(outp, 1,
3026                            NEGOTIATE_SECURITY_USER_LEVEL |
3027                            NEGOTIATE_SECURITY_CHALLENGE_RESPONSE);      /* user level security, challenge response */
3028         } else {
3029             smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3030         }
3031         smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3032         smb_SetSMBParm(outp, 3, smb_maxMpxRequests);    /* max multiplexed requests */
3033         smb_SetSMBParm(outp, 4, smb_maxVCPerServer);    /* max VCs per consumer/server connection */
3034         smb_SetSMBParm(outp, 5, 0);     /* no support of block mode for read or write */
3035         smb_SetSMBParm(outp, 6, 1);     /* next 2: session key */
3036         smb_SetSMBParm(outp, 7, 1);
3037         time(&unixTime);
3038         smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3039         smb_SetSMBParm(outp, 8, LOWORD(dosTime));       /* server time */
3040         smb_SetSMBParm(outp, 9, HIWORD(dosTime));       /* server date */
3041
3042         GetTimeZoneInformation(&tzi);
3043         smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias);    /* server tzone */
3044
3045         /* NOTE: Extended authentication cannot be negotiated with v3
3046          * therefore we fail over to NTLM 
3047          */
3048         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3049             smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH);  /* encryption key length */
3050             smb_SetSMBParm(outp, 12, 0);        /* resvd */
3051             smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);   /* perhaps should specify 8 bytes anyway */
3052             datap = smb_GetSMBData(outp, NULL);
3053             /* paste in a new encryption key */
3054             memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3055             /* and the faux domain name */
3056             strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
3057         } else {
3058             smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3059             smb_SetSMBParm(outp, 12, 0); /* resvd */
3060             smb_SetSMBDataLength(outp, 0);
3061         }
3062     }
3063     else if (coreProtoIndex != -1) {     /* not really supported anymore */
3064         smb_SetSMBParm(outp, 0, protoIndex);
3065         smb_SetSMBDataLength(outp, 0);
3066     }
3067     return 0;
3068 }
3069
3070 void smb_Daemon(void *parmp)
3071 {
3072     afs_uint32 count = 0;
3073
3074     while(smbShutdownFlag == 0) {
3075         count++;
3076         thrd_Sleep(10000);
3077
3078         if (smbShutdownFlag == 1)
3079             break;
3080         
3081         if ((count % 72) == 0)  {       /* every five minutes */
3082             struct tm myTime;
3083             time_t old_localZero = smb_localZero;
3084                  
3085             /* Initialize smb_localZero */
3086             myTime.tm_isdst = -1;               /* compute whether on DST or not */
3087             myTime.tm_year = 70;
3088             myTime.tm_mon = 0;
3089             myTime.tm_mday = 1;
3090             myTime.tm_hour = 0;
3091             myTime.tm_min = 0;
3092             myTime.tm_sec = 0;
3093             smb_localZero = mktime(&myTime);
3094
3095 #ifndef USE_NUMERIC_TIME_CONV
3096             smb_CalculateNowTZ();
3097 #endif /* USE_NUMERIC_TIME_CONV */
3098 #ifdef AFS_FREELANCE
3099             if ( smb_localZero != old_localZero )
3100                 cm_noteLocalMountPointChange();
3101 #endif
3102         }
3103         /* XXX GC dir search entries */
3104     }
3105 }
3106
3107 void smb_WaitingLocksDaemon()
3108 {
3109     smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3110     smb_waitingLock_t *wl, *wlNext;
3111     int first;
3112     smb_vc_t *vcp;
3113     smb_packet_t *inp, *outp;
3114     NCB *ncbp;
3115     long code = 0;
3116
3117     while (smbShutdownFlag == 0) {
3118         lock_ObtainWrite(&smb_globalLock);
3119         nwlRequest = smb_allWaitingLocks;
3120         if (nwlRequest == NULL) {
3121             osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
3122             thrd_Sleep(1000);
3123             continue;
3124         } else 
3125             first = 1;
3126
3127         do {
3128             if (first)
3129                 first = 0;
3130             else
3131                 lock_ObtainWrite(&smb_globalLock);
3132
3133             wlRequest = nwlRequest;
3134             nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3135             lock_ReleaseWrite(&smb_globalLock);
3136
3137             code = 0;
3138
3139             for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3140                 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3141                     continue;
3142                 
3143                 /* wl->state is either _DONE or _WAITING.  _ERROR
3144                    would no longer be on the queue. */
3145                 code = cm_RetryLock( wl->lockp,
3146                                      !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3147
3148                 if (code == 0) {
3149                     wl->state = SMB_WAITINGLOCKSTATE_DONE;
3150                 } else if (code != CM_ERROR_WOULDBLOCK) {
3151                     wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3152                     break;
3153                 }
3154             }
3155
3156             if (code == CM_ERROR_WOULDBLOCK) {
3157
3158                 /* no progress */
3159                 if (wlRequest->timeRemaining != 0xffffffff
3160                      && (wlRequest->timeRemaining -= 1000) < 0)
3161                     goto endWait;
3162
3163                 continue;
3164             }
3165
3166           endWait:
3167
3168             if (code != 0) {
3169                 cm_scache_t * scp;
3170                 cm_req_t req;
3171
3172                 scp = wlRequest->scp;
3173
3174                 cm_InitReq(&req);
3175
3176                 lock_ObtainMutex(&scp->mx);
3177
3178                 for (wl = wlRequest->locks; wl; wl = wlNext) {
3179                     wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3180                     
3181                     cm_Unlock(scp, wlRequest->lockType, wl->LOffset, 
3182                               wl->LLength, wl->key, NULL, &req);
3183
3184                     osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3185
3186                     free(wl);
3187                 }
3188                 
3189                 lock_ReleaseMutex(&scp->mx);
3190
3191             } else {
3192                 for (wl = wlRequest->locks; wl; wl = wlNext) {
3193                     wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3194                     osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3195                     free(wl);
3196                 }
3197             }
3198
3199             vcp = wlRequest->vcp;
3200             inp = wlRequest->inp;
3201             outp = wlRequest->outp;
3202             ncbp = GetNCB();
3203             ncbp->ncb_length = inp->ncb_length;
3204             inp->spacep = cm_GetSpace();
3205
3206             /* Remove waitingLock from list */
3207             lock_ObtainWrite(&smb_globalLock);
3208             osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3209                          &wlRequest->q);
3210             lock_ReleaseWrite(&smb_globalLock);
3211
3212             /* Resume packet processing */
3213             if (code == 0)
3214                 smb_SetSMBDataLength(outp, 0);
3215             outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3216             outp->resumeCode = code;
3217             outp->ncbp = ncbp;
3218             smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3219
3220             /* Clean up */
3221             cm_FreeSpace(inp->spacep);
3222             smb_FreePacket(inp);
3223             smb_FreePacket(outp);
3224             smb_ReleaseVC(vcp);
3225             cm_ReleaseSCache(wlRequest->scp);
3226             FreeNCB(ncbp);
3227             free(wlRequest);
3228         } while (nwlRequest && smbShutdownFlag == 0);
3229         thrd_Sleep(1000);
3230     }
3231 }
3232
3233 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3234 {
3235     osi_Log0(smb_logp, "SMB receive get disk attributes");
3236
3237     smb_SetSMBParm(outp, 0, 32000);
3238     smb_SetSMBParm(outp, 1, 64);
3239     smb_SetSMBParm(outp, 2, 1024);
3240     smb_SetSMBParm(outp, 3, 30000);
3241     smb_SetSMBParm(outp, 4, 0);
3242     smb_SetSMBDataLength(outp, 0);
3243     return 0;
3244 }
3245
3246 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3247 {
3248     smb_tid_t *tidp;
3249     smb_user_t *uidp;
3250     unsigned short newTid;
3251     char shareName[256];
3252     char *sharePath;
3253     int shareFound;
3254     char *tp;
3255     char *pathp;
3256     char *passwordp;
3257     cm_user_t *userp;
3258
3259     osi_Log0(smb_logp, "SMB receive tree connect");
3260
3261     /* parse input parameters */
3262     tp = smb_GetSMBData(inp, NULL);
3263     pathp = smb_ParseASCIIBlock(tp, &tp);
3264     if (smb_StoreAnsiFilenames)
3265         OemToChar(pathp,pathp);
3266     passwordp = smb_ParseASCIIBlock(tp, &tp);
3267     tp = strrchr(pathp, '\\');
3268     if (!tp)
3269         return CM_ERROR_BADSMB;
3270     strcpy(shareName, tp+1);
3271
3272     userp = smb_GetUser(vcp, inp);
3273
3274     lock_ObtainMutex(&vcp->mx);
3275     newTid = vcp->tidCounter++;
3276     lock_ReleaseMutex(&vcp->mx);
3277
3278     tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3279     uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3280     shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3281     if (uidp)
3282         smb_ReleaseUID(uidp);
3283     if (!shareFound) {
3284         smb_ReleaseTID(tidp);
3285         return CM_ERROR_BADSHARENAME;
3286     }
3287     lock_ObtainMutex(&tidp->mx);
3288     tidp->userp = userp;
3289     tidp->pathname = sharePath;
3290     lock_ReleaseMutex(&tidp->mx);
3291     smb_ReleaseTID(tidp);
3292
3293     smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3294     smb_SetSMBParm(rsp, 1, newTid);
3295     smb_SetSMBDataLength(rsp, 0);
3296
3297     osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3298     return 0;
3299 }
3300
3301 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3302 {
3303     int tlen;
3304
3305     if (*inp++ != 0x1) return NULL;
3306     tlen = inp[0] + (inp[1]<<8);
3307     inp += 2;           /* skip length field */
3308         
3309     if (chainpp) {
3310         *chainpp = inp + tlen;
3311     }   
3312
3313     if (lengthp) *lengthp = tlen;
3314         
3315     return inp;
3316 }
3317
3318 /* set maskp to the mask part of the incoming path.
3319  * Mask is 11 bytes long (8.3 with the dot elided).
3320  * Returns true if succeeds with a valid name, otherwise it does
3321  * its best, but returns false.
3322  */
3323 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3324 {
3325     char *tp;
3326     char *up;
3327     int i;
3328     int tc;
3329     int valid8Dot3;
3330
3331     /* starts off valid */
3332     valid8Dot3 = 1;
3333
3334     /* mask starts out all blanks */
3335     memset(maskp, ' ', 11);
3336
3337     /* find last backslash, or use whole thing if there is none */
3338     tp = strrchr(pathp, '\\');
3339     if (!tp) tp = pathp;
3340     else tp++;  /* skip slash */
3341         
3342     up = maskp;
3343
3344     /* names starting with a dot are illegal */
3345     if (*tp == '.') valid8Dot3 = 0;
3346
3347     for(i=0;; i++) {
3348         tc = *tp++;
3349         if (tc == 0) return valid8Dot3;
3350         if (tc == '.' || tc == '"') break;
3351         if (i < 8) *up++ = tc;
3352         else valid8Dot3 = 0;
3353     }
3354         
3355     /* if we get here, tp point after the dot */
3356     up = maskp+8;       /* ext goes here */
3357     for(i=0;;i++) {
3358         tc = *tp++;
3359         if (tc == 0) 
3360             return valid8Dot3;
3361
3362         /* too many dots */
3363         if (tc == '.' || tc == '"') 
3364             valid8Dot3 = 0;
3365
3366         /* copy extension if not too long */
3367         if (i < 3) 
3368             *up++ = tc;
3369         else 
3370             valid8Dot3 = 0;
3371     }   
3372
3373     /* unreachable */
3374 }
3375
3376 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3377 {
3378     char umask[11];
3379     int valid;
3380     int i;
3381     char tc1;
3382     char tc2;
3383     char *tp1;
3384     char *tp2;
3385
3386     /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3387
3388     valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3389     if (!valid) 
3390         return 0;
3391  
3392     /* otherwise, we have a valid 8.3 name; see if we have a match,
3393      * treating '?' as a wildcard in maskp (but not in the file name).
3394      */
3395     tp1 = umask;        /* real name, in mask format */
3396     tp2 = maskp;        /* mask, in mask format */
3397     for(i=0; i<11; i++) {
3398         tc1 = *tp1++;   /* char from real name */
3399         tc2 = *tp2++;   /* char from mask */
3400         tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3401         tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3402         if (tc1 == tc2) 
3403             continue;
3404         if (tc2 == '?' && tc1 != ' ') 
3405             continue;
3406         if (tc2 == '>') 
3407             continue;
3408         return 0;
3409     }
3410
3411     /* we got a match */
3412     return 1;
3413 }
3414
3415 char *smb_FindMask(char *pathp)
3416 {
3417     char *tp;
3418         
3419     tp = strrchr(pathp, '\\');  /* find last slash */
3420
3421     if (tp) 
3422         return tp+1;    /* skip the slash */
3423     else 
3424         return pathp;   /* no slash, return the entire path */
3425 }       
3426
3427 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3428 {
3429     unsigned char *pathp;
3430     unsigned char *tp;
3431     unsigned char mask[11];
3432     unsigned char *statBlockp;
3433     unsigned char initStatBlock[21];
3434     int statLen;
3435         
3436     osi_Log0(smb_logp, "SMB receive search volume");
3437
3438     /* pull pathname and stat block out of request */
3439     tp = smb_GetSMBData(inp, NULL);
3440     pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3441     osi_assert(pathp != NULL);
3442     if (smb_StoreAnsiFilenames)
3443         OemToChar(pathp,pathp);
3444     statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3445     osi_assert(statBlockp != NULL);
3446     if (statLen == 0) {
3447         statBlockp = initStatBlock;
3448         statBlockp[0] = 8;
3449     }
3450         
3451     /* for returning to caller */
3452     smb_Get8Dot3MaskFromPath(mask, pathp);
3453
3454     smb_SetSMBParm(outp, 0, 1);         /* we're returning one entry */
3455     tp = smb_GetSMBData(outp, NULL);
3456     *tp++ = 5;
3457     *tp++ = 43; /* bytes in a dir entry */
3458     *tp++ = 0;  /* high byte in counter */
3459
3460     /* now marshall the dir entry, starting with the search status */
3461     *tp++ = statBlockp[0];              /* Reserved */
3462     memcpy(tp, mask, 11); tp += 11;     /* FileName */
3463
3464     /* now pass back server use info, with 1st byte non-zero */
3465     *tp++ = 1;
3466     memset(tp, 0, 4); tp += 4;  /* reserved for server use */
3467
3468     memcpy(tp, statBlockp+17, 4); tp += 4;      /* reserved for consumer */
3469
3470     *tp++ = 0x8;                /* attribute: volume */
3471
3472     /* copy out time */
3473     *tp++ = 0;
3474     *tp++ = 0;
3475
3476     /* copy out date */
3477     *tp++ = 18;
3478     *tp++ = 178;
3479
3480     /* 4 byte file size */
3481     *tp++ = 0;
3482     *tp++ = 0;
3483     *tp++ = 0;
3484     *tp++ = 0;
3485
3486     /* finally, null-terminated 8.3 pathname, which we set to AFS */
3487     memset(tp, ' ', 13);
3488     strcpy(tp, "AFS");
3489
3490     /* set the length of the data part of the packet to 43 + 3, for the dir
3491      * entry plus the 5 and the length fields.
3492      */
3493     smb_SetSMBDataLength(outp, 46);
3494     return 0;
3495 }       
3496
3497 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3498                              cm_user_t *userp, cm_req_t *reqp)
3499 {
3500     long code = 0;
3501     cm_scache_t *scp;
3502     char *dptr;
3503     afs_uint32 dosTime;
3504     u_short shortTemp;
3505     char attr;
3506     smb_dirListPatch_t *patchp;
3507     smb_dirListPatch_t *npatchp;
3508
3509     for (patchp = *dirPatchespp; patchp; patchp =
3510          (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3511
3512         dptr = patchp->dptr;
3513
3514         code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3515         if (code) {
3516             if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3517                 *dptr++ = SMB_ATTR_HIDDEN;
3518             continue;
3519         }
3520         lock_ObtainMutex(&scp->mx);
3521         code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3522                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3523         if (code) {     
3524             lock_ReleaseMutex(&scp->mx);
3525             cm_ReleaseSCache(scp);
3526             if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3527                 *dptr++ = SMB_ATTR_HIDDEN;
3528             continue;
3529         }
3530
3531         attr = smb_Attributes(scp);
3532         /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3533         if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3534             attr |= SMB_ATTR_HIDDEN;
3535         *dptr++ = attr;
3536
3537         /* get dos time */
3538         smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3539                 
3540         /* copy out time */
3541         shortTemp = (unsigned short) (dosTime & 0xffff);
3542         *((u_short *)dptr) = shortTemp;
3543         dptr += 2;
3544
3545         /* and copy out date */
3546         shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3547         *((u_short *)dptr) = shortTemp;
3548         dptr += 2;
3549                 
3550         /* copy out file length */
3551         *((u_long *)dptr) = scp->length.LowPart;
3552         dptr += 4;
3553         lock_ReleaseMutex(&scp->mx);
3554         cm_ReleaseSCache(scp);
3555     }
3556         
3557     /* now free the patches */
3558     for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3559         npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3560         free(patchp);
3561     }   
3562         
3563     /* and mark the list as empty */
3564     *dirPatchespp = NULL;
3565
3566     return code;
3567 }
3568
3569 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3570 {
3571     int attribute;
3572     long nextCookie;
3573     char *tp;
3574     long code = 0;
3575     char *pathp;
3576     cm_dirEntry_t *dep;
3577     int maxCount;
3578     smb_dirListPatch_t *dirListPatchesp;
3579     smb_dirListPatch_t *curPatchp;
3580     int dataLength;
3581     cm_buf_t *bufferp;
3582     long temp;
3583     osi_hyper_t dirLength;
3584     osi_hyper_t bufferOffset;
3585     osi_hyper_t curOffset;
3586     osi_hyper_t thyper;
3587     unsigned char *inCookiep;
3588     smb_dirSearch_t *dsp;
3589     cm_scache_t *scp;
3590     long entryInDir;
3591     long entryInBuffer;
3592     unsigned long clientCookie;
3593     cm_pageHeader_t *pageHeaderp;
3594     cm_user_t *userp = NULL;
3595     int slotInPage;
3596     char shortName[13];
3597     char *actualName;
3598     char *shortNameEnd;
3599     char mask[11];
3600     int returnedNames;
3601     long nextEntryCookie;
3602     int numDirChunks;           /* # of 32 byte dir chunks in this entry */
3603     char resByte;               /* reserved byte from the cookie */
3604     char *op;                   /* output data ptr */
3605     char *origOp;               /* original value of op */
3606     cm_space_t *spacep;         /* for pathname buffer */
3607     int starPattern;
3608     int rootPath = 0;
3609     int caseFold;
3610     char *tidPathp;
3611     cm_req_t req;
3612     cm_fid_t fid;
3613     int fileType;
3614
3615     cm_InitReq(&req);
3616
3617     maxCount = smb_GetSMBParm(inp, 0);
3618
3619     dirListPatchesp = NULL;
3620         
3621     caseFold = CM_FLAG_CASEFOLD;
3622
3623     tp = smb_GetSMBData(inp, NULL);
3624     pathp = smb_ParseASCIIBlock(tp, &tp);
3625     if (smb_StoreAnsiFilenames)
3626         OemToChar(pathp,pathp);
3627     inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3628
3629     /* bail out if request looks bad */
3630     if (!tp || !pathp) {
3631         return CM_ERROR_BADSMB;
3632     }
3633
3634     /* We can handle long names */
3635     if (vcp->flags & SMB_VCFLAG_USENT)
3636         ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
3637
3638     /* make sure we got a whole search status */
3639     if (dataLength < 21) {
3640         nextCookie = 0;         /* start at the beginning of the dir */
3641         resByte = 0;
3642         clientCookie = 0;
3643         attribute = smb_GetSMBParm(inp, 1);
3644
3645         /* handle volume info in another function */
3646         if (attribute & 0x8)
3647             return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3648
3649         osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3650                   maxCount, osi_LogSaveString(smb_logp, pathp));
3651
3652         if (*pathp == 0) {      /* null pathp, treat as root dir */
3653             if (!(attribute & SMB_ATTR_DIRECTORY))      /* exclude dirs */
3654                 return CM_ERROR_NOFILES;
3655             rootPath = 1;
3656         }
3657
3658         dsp = smb_NewDirSearch(0);
3659         dsp->attribute = attribute;
3660         smb_Get8Dot3MaskFromPath(mask, pathp);
3661         memcpy(dsp->mask, mask, 11);
3662
3663         /* track if this is likely to match a lot of entries */
3664         if (smb_IsStarMask(mask)) 
3665             starPattern = 1;
3666         else 
3667             starPattern = 0;
3668     } else {
3669         /* pull the next cookie value out of the search status block */
3670         nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3671             + (inCookiep[16]<<24);
3672         dsp = smb_FindDirSearch(inCookiep[12]);
3673         if (!dsp) {
3674             /* can't find dir search status; fatal error */
3675             osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%s]",
3676                      inCookiep[12], nextCookie, osi_LogSaveString(smb_logp, pathp));
3677             return CM_ERROR_BADFD;
3678         }
3679         attribute = dsp->attribute;
3680         resByte = inCookiep[0];
3681
3682         /* copy out client cookie, in host byte order.  Don't bother
3683          * interpreting it, since we're just passing it through, anyway.
3684          */
3685         memcpy(&clientCookie, &inCookiep[17], 4);
3686
3687         memcpy(mask, dsp->mask, 11);
3688
3689         /* assume we're doing a star match if it has continued for more
3690          * than one call.
3691          */
3692         starPattern = 1;
3693     }
3694
3695     osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
3696              nextCookie, dsp->cookie, attribute);
3697
3698     userp = smb_GetUser(vcp, inp);
3699
3700     /* try to get the vnode for the path name next */
3701     lock_ObtainMutex(&dsp->mx);
3702     if (dsp->scp) {
3703         scp = dsp->scp;
3704         cm_HoldSCache(scp);
3705         code = 0;
3706     } else {
3707         spacep = inp->spacep;
3708         smb_StripLastComponent(spacep->data, NULL, pathp);
3709         code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3710         if (code) {
3711             lock_ReleaseMutex(&dsp->mx);
3712             cm_ReleaseUser(userp);
3713             smb_DeleteDirSearch(dsp);
3714             smb_ReleaseDirSearch(dsp);
3715             return CM_ERROR_NOFILES;
3716         }
3717         code = cm_NameI(cm_data.rootSCachep, spacep->data,
3718                         caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3719         if (code == 0) {
3720 #ifdef DFS_SUPPORT
3721             if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3722                 cm_ReleaseSCache(scp);
3723                 lock_ReleaseMutex(&dsp->mx);
3724                 cm_ReleaseUser(userp);
3725                 smb_DeleteDirSearch(dsp);
3726                 smb_ReleaseDirSearch(dsp);
3727                 if ( WANTS_DFS_PATHNAMES(inp) )
3728                     return CM_ERROR_PATH_NOT_COVERED;
3729                 else
3730                     return CM_ERROR_BADSHARENAME;
3731             }
3732 #endif /* DFS_SUPPORT */
3733
3734             dsp->scp = scp;
3735             /* we need one hold for the entry we just stored into,
3736              * and one for our own processing.  When we're done with this
3737              * function, we'll drop the one for our own processing.
3738              * We held it once from the namei call, and so we do another hold
3739              * now.
3740              */
3741             cm_HoldSCache(scp);
3742             lock_ObtainMutex(&scp->mx);
3743             if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3744                  && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3745                 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3746                 dsp->flags |= SMB_DIRSEARCH_BULKST;
3747             }
3748             lock_ReleaseMutex(&scp->mx);
3749         }
3750     }
3751     lock_ReleaseMutex(&dsp->mx);
3752     if (code) {
3753         cm_ReleaseUser(userp);
3754         smb_DeleteDirSearch(dsp);
3755         smb_ReleaseDirSearch(dsp);
3756         return code;
3757     }
3758
3759     /* reserves space for parameter; we'll adjust it again later to the
3760      * real count of the # of entries we returned once we've actually
3761      * assembled the directory listing.
3762      */
3763     smb_SetSMBParm(outp, 0, 0);
3764
3765     /* get the directory size */
3766     lock_ObtainMutex(&scp->mx);
3767     code = cm_SyncOp(scp, NULL, userp, &req, 0,
3768                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3769     if (code) {
3770         lock_ReleaseMutex(&scp->mx);
3771         cm_ReleaseSCache(scp);
3772         cm_ReleaseUser(userp);
3773         smb_DeleteDirSearch(dsp);
3774         smb_ReleaseDirSearch(dsp);
3775         return code;
3776     }
3777         
3778     dirLength = scp->length;
3779     bufferp = NULL;
3780     bufferOffset.LowPart = bufferOffset.HighPart = 0;
3781     curOffset.HighPart = 0;
3782     curOffset.LowPart = nextCookie;
3783     origOp = op = smb_GetSMBData(outp, NULL);
3784     /* and write out the basic header */
3785     *op++ = 5;          /* variable block */
3786     op += 2;            /* skip vbl block length; we'll fill it in later */
3787     code = 0;
3788     returnedNames = 0;
3789     while (1) {
3790         /* make sure that curOffset.LowPart doesn't point to the first
3791          * 32 bytes in the 2nd through last dir page, and that it doesn't
3792          * point at the first 13 32-byte chunks in the first dir page,
3793          * since those are dir and page headers, and don't contain useful
3794          * information.
3795          */
3796         temp = curOffset.LowPart & (2048-1);
3797         if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3798             /* we're in the first page */
3799             if (temp < 13*32) temp = 13*32;
3800         }
3801         else {
3802             /* we're in a later dir page */
3803             if (temp < 32) temp = 32;
3804         }
3805
3806         /* make sure the low order 5 bits are zero */
3807         temp &= ~(32-1);
3808
3809         /* now put temp bits back ito curOffset.LowPart */
3810         curOffset.LowPart &= ~(2048-1);
3811         curOffset.LowPart |= temp;
3812
3813         /* check if we've returned all the names that will fit in the
3814          * response packet.
3815          */
3816         if (returnedNames >= maxCount) {
3817             osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
3818                       returnedNames, maxCount);
3819             break;
3820         }
3821                 
3822         /* check if we've passed the dir's EOF */
3823         if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
3824
3825         /* see if we can use the bufferp we have now; compute in which page
3826          * the current offset would be, and check whether that's the offset
3827          * of the buffer we have.  If not, get the buffer.
3828          */
3829         thyper.HighPart = curOffset.HighPart;
3830         thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
3831         if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3832             /* wrong buffer */
3833             if (bufferp) {
3834                 buf_Release(bufferp);
3835                 bufferp = NULL;
3836             }   
3837             lock_ReleaseMutex(&scp->mx);
3838             lock_ObtainRead(&scp->bufCreateLock);
3839             code = buf_Get(scp, &thyper, &bufferp);
3840             lock_ReleaseRead(&scp->bufCreateLock);
3841             lock_ObtainMutex(&dsp->mx);
3842
3843             /* now, if we're doing a star match, do bulk fetching of all of 
3844              * the status info for files in the dir.
3845              */
3846             if (starPattern) {
3847                 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3848                 lock_ObtainMutex(&scp->mx);
3849                 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
3850                      LargeIntegerGreaterThanOrEqualTo(thyper, 
3851                                                       scp->bulkStatProgress)) {
3852                     /* Don't bulk stat if risking timeout */
3853                     int now = GetCurrentTime();
3854                     if (now - req.startTime > 5000) {
3855                         scp->bulkStatProgress = thyper;
3856                         scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3857                         dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3858                     } else
3859                         cm_TryBulkStat(scp, &thyper, userp, &req);
3860                 }
3861             } else {
3862                 lock_ObtainMutex(&scp->mx);
3863             }
3864             lock_ReleaseMutex(&dsp->mx);
3865             if (code) {
3866                 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
3867                 break;
3868             }
3869
3870             bufferOffset = thyper;
3871
3872             /* now get the data in the cache */
3873             while (1) {
3874                 code = cm_SyncOp(scp, bufferp, userp, &req,
3875                                  PRSFS_LOOKUP,
3876                                  CM_SCACHESYNC_NEEDCALLBACK |
3877                                  CM_SCACHESYNC_READ);
3878                 if (code) {
3879                     osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
3880                     break;
3881                 }
3882                                 
3883                 if (cm_HaveBuffer(scp, bufferp, 0)) {
3884                     osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
3885                     break;
3886                 }
3887
3888                 /* otherwise, load the buffer and try again */
3889                 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
3890                 if (code) {
3891                     osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d", 
3892                               scp, bufferp, code);
3893                     break;
3894                 }
3895             }
3896             if (code) {
3897                 buf_Release(bufferp);
3898                 bufferp = NULL;
3899                 break;
3900             }
3901         }       /* if (wrong buffer) ... */
3902
3903         /* now we have the buffer containing the entry we're interested in; copy
3904          * it out if it represents a non-deleted entry.
3905          */
3906         entryInDir = curOffset.LowPart & (2048-1);
3907         entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
3908
3909         /* page header will help tell us which entries are free.  Page header
3910          * can change more often than once per buffer, since AFS 3 dir page size
3911          * may be less than (but not more than a buffer package buffer.
3912          */
3913         temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);  /* only look intra-buffer */
3914         temp &= ~(2048 - 1);    /* turn off intra-page bits */
3915         pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3916
3917         /* now determine which entry we're looking at in the page.  If it is
3918          * free (there's a free bitmap at the start of the dir), we should
3919          * skip these 32 bytes.
3920          */
3921         slotInPage = (entryInDir & 0x7e0) >> 5;
3922         if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
3923             /* this entry is free */
3924             numDirChunks = 1;           /* only skip this guy */
3925             goto nextEntry;
3926         }
3927
3928         tp = bufferp->datap + entryInBuffer;
3929         dep = (cm_dirEntry_t *) tp;             /* now points to AFS3 dir entry */
3930
3931         /* while we're here, compute the next entry's location, too,
3932          * since we'll need it when writing out the cookie into the dir
3933          * listing stream.
3934          *
3935          * XXXX Probably should do more sanity checking.
3936          */
3937         numDirChunks = cm_NameEntries(dep->name, NULL);
3938
3939         /* compute the offset of the cookie representing the next entry */
3940         nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3941
3942         /* Compute 8.3 name if necessary */
3943         actualName = dep->name;
3944         if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
3945             cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3946             actualName = shortName;
3947         }
3948
3949         osi_Log3(smb_logp, "SMB search dir vn %d name %s (%s)",
3950                   dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
3951                   osi_LogSaveString(smb_logp, actualName));
3952
3953         if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
3954             /* this is one of the entries to use: it is not deleted
3955              * and it matches the star pattern we're looking for.
3956              */
3957
3958             /* Eliminate entries that don't match requested
3959              * attributes */
3960
3961             /* no hidden files */
3962             if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
3963                 osi_Log0(smb_logp, "SMB search dir skipping hidden");
3964                 goto nextEntry;
3965             }
3966
3967             if (!(dsp->attribute & SMB_ATTR_DIRECTORY))  /* no directories */
3968             {
3969                 /* We have already done the cm_TryBulkStat above */
3970                 fid.cell = scp->fid.cell;
3971                 fid.volume = scp->fid.volume;
3972                 fid.vnode = ntohl(dep->fid.vnode);
3973                 fid.unique = ntohl(dep->fid.unique);
3974                 fileType = cm_FindFileType(&fid);
3975                 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
3976                          "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
3977                           fileType);
3978                 if (fileType == CM_SCACHETYPE_DIRECTORY ||
3979                     fileType == CM_SCACHETYPE_DFSLINK ||
3980                     fileType == CM_SCACHETYPE_INVALID)
3981                     osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
3982                 goto nextEntry;
3983             }
3984
3985             *op++ = resByte;
3986             memcpy(op, mask, 11); op += 11;
3987             *op++ = (char) dsp->cookie; /* they say it must be non-zero */
3988             *op++ = (char)(nextEntryCookie & 0xff);
3989             *op++ = (char)((nextEntryCookie>>8) & 0xff);
3990             *op++ = (char)((nextEntryCookie>>16) & 0xff);
3991             *op++ = (char)((nextEntryCookie>>24) & 0xff);
3992             memcpy(op, &clientCookie, 4); op += 4;
3993
3994             /* now we emit the attribute.  This is sort of tricky,
3995              * since we need to really stat the file to find out
3996              * what type of entry we've got.  Right now, we're
3997              * copying out data from a buffer, while holding the
3998              * scp locked, so it isn't really convenient to stat
3999              * something now.  We'll put in a place holder now,
4000              * and make a second pass before returning this to get
4001              * the real attributes.  So, we just skip the data for
4002              * now, and adjust it later.  We allocate a patch
4003              * record to make it easy to find this point later.
4004              * The replay will happen at a time when it is safe to
4005              * unlock the directory.
4006              */
4007             curPatchp = malloc(sizeof(*curPatchp));
4008             osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
4009             curPatchp->dptr = op;
4010             curPatchp->fid.cell = scp->fid.cell;
4011             curPatchp->fid.volume = scp->fid.volume;
4012             curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4013             curPatchp->fid.unique = ntohl(dep->fid.unique);
4014
4015             /* do hidden attribute here since name won't be around when applying
4016              * dir list patches
4017              */
4018
4019             if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
4020                 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4021             else
4022                 curPatchp->flags = 0;
4023
4024             op += 9;    /* skip attr, time, date and size */
4025
4026             /* zero out name area.  The spec says to pad with
4027              * spaces, but Samba doesn't, and neither do we.
4028              */
4029             memset(op, 0, 13);
4030
4031             /* finally, we get to copy out the name; we know that
4032              * it fits in 8.3 or the pattern wouldn't match, but it
4033              * never hurts to be sure.
4034              */
4035             strncpy(op, actualName, 13);
4036             if (smb_StoreAnsiFilenames)
4037                 CharToOem(op, op);
4038
4039             /* Uppercase if requested by client */
4040             if (!KNOWS_LONG_NAMES(inp))
4041                 _strupr(op);
4042
4043             op += 13;
4044
4045             /* now, adjust the # of entries copied */
4046             returnedNames++;
4047         }       /* if we're including this name */
4048
4049       nextEntry:
4050         /* and adjust curOffset to be where the new cookie is */
4051         thyper.HighPart = 0;
4052         thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4053         curOffset = LargeIntegerAdd(thyper, curOffset);
4054     }           /* while copying data for dir listing */
4055
4056     /* release the mutex */
4057     lock_ReleaseMutex(&scp->mx);
4058     if (bufferp) buf_Release(bufferp);
4059
4060     /* apply and free last set of patches; if not doing a star match, this
4061      * will be empty, but better safe (and freeing everything) than sorry.
4062      */
4063     smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
4064
4065     /* special return code for unsuccessful search */
4066     if (code == 0 && dataLength < 21 && returnedNames == 0)
4067         code = CM_ERROR_NOFILES;
4068
4069     osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
4070              returnedNames, code);
4071
4072     if (code != 0) {
4073         smb_DeleteDirSearch(dsp);
4074         smb_ReleaseDirSearch(dsp);
4075         cm_ReleaseSCache(scp);
4076         cm_ReleaseUser(userp);
4077         return code;
4078     }
4079
4080     /* finalize the output buffer */
4081     smb_SetSMBParm(outp, 0, returnedNames);
4082     temp = (long) (op - origOp);
4083     smb_SetSMBDataLength(outp, temp);
4084
4085     /* the data area is a variable block, which has a 5 (already there)
4086      * followed by the length of the # of data bytes.  We now know this to
4087      * be "temp," although that includes the 3 bytes of vbl block header.
4088      * Deduct for them and fill in the length field.
4089      */
4090     temp -= 3;          /* deduct vbl block info */
4091     osi_assert(temp == (43 * returnedNames));
4092     origOp[1] = (char)(temp & 0xff);
4093     origOp[2] = (char)((temp>>8) & 0xff);
4094     if (returnedNames == 0) 
4095         smb_DeleteDirSearch(dsp);
4096     smb_ReleaseDirSearch(dsp);
4097     cm_ReleaseSCache(scp);
4098     cm_ReleaseUser(userp);
4099     return code;
4100 }       
4101
4102 /* verify that this is a valid path to a directory.  I don't know why they
4103  * don't use the get file attributes call.
4104  */
4105 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4106 {
4107     char *pathp;
4108     long code = 0;
4109     cm_scache_t *rootScp;
4110     cm_scache_t *newScp;
4111     cm_user_t *userp;
4112     unsigned int attrs;
4113     int caseFold;
4114     char *tidPathp;
4115     cm_req_t req;
4116
4117     cm_InitReq(&req);
4118
4119     pathp = smb_GetSMBData(inp, NULL);
4120     pathp = smb_ParseASCIIBlock(pathp, NULL);
4121     if (!pathp)
4122         return CM_ERROR_BADFD;
4123     if (smb_StoreAnsiFilenames)
4124         OemToChar(pathp,pathp);
4125     osi_Log1(smb_logp, "SMB receive check path %s",
4126              osi_LogSaveString(smb_logp, pathp));
4127         
4128     rootScp = cm_data.rootSCachep;
4129         
4130     userp = smb_GetUser(vcp, inp);
4131
4132     caseFold = CM_FLAG_CASEFOLD;
4133
4134     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4135     if (code) {
4136         cm_ReleaseUser(userp);
4137         return CM_ERROR_NOSUCHPATH;
4138     }
4139     code = cm_NameI(rootScp, pathp,
4140                     caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
4141                     userp, tidPathp, &req, &newScp);
4142
4143     if (code) {
4144         cm_ReleaseUser(userp);
4145         return code;
4146     }
4147         
4148 #ifdef DFS_SUPPORT
4149     if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4150         cm_ReleaseSCache(newScp);
4151         cm_ReleaseUser(userp);
4152         if ( WANTS_DFS_PATHNAMES(inp) )
4153             return CM_ERROR_PATH_NOT_COVERED;
4154         else
4155             return CM_ERROR_BADSHARENAME;
4156     }
4157 #endif /* DFS_SUPPORT */
4158
4159     /* now lock the vnode with a callback; returns with newScp locked */
4160     lock_ObtainMutex(&newScp->mx);
4161     code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
4162                      CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4163     if (code && code != CM_ERROR_NOACCESS) {
4164         lock_ReleaseMutex(&newScp->mx);
4165         cm_ReleaseSCache(newScp);
4166         cm_ReleaseUser(userp);
4167         return code;
4168     }
4169
4170     attrs = smb_Attributes(newScp);
4171
4172     if (!(attrs & SMB_ATTR_DIRECTORY))
4173         code = CM_ERROR_NOTDIR;
4174
4175     lock_ReleaseMutex(&newScp->mx);
4176
4177     cm_ReleaseSCache(newScp);
4178     cm_ReleaseUser(userp);
4179     return code;
4180 }       
4181
4182 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4183 {
4184     char *pathp;
4185     long code = 0;
4186     cm_scache_t *rootScp;
4187     unsigned short attribute;
4188     cm_attr_t attr;
4189     cm_scache_t *newScp;
4190     afs_uint32 dosTime;
4191     cm_user_t *userp;
4192     int caseFold;
4193     char *tidPathp;
4194     cm_req_t req;
4195
4196     cm_InitReq(&req);
4197
4198     /* decode basic attributes we're passed */
4199     attribute = smb_GetSMBParm(inp, 0);
4200     dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4201
4202     pathp = smb_GetSMBData(inp, NULL);
4203     pathp = smb_ParseASCIIBlock(pathp, NULL);
4204     if (!pathp)
4205         return CM_ERROR_BADSMB;
4206     if (smb_StoreAnsiFilenames)
4207         OemToChar(pathp,pathp);
4208                
4209     osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
4210              dosTime, attribute);
4211
4212     rootScp = cm_data.rootSCachep;
4213         
4214     userp = smb_GetUser(vcp, inp);
4215
4216     caseFold = CM_FLAG_CASEFOLD;
4217
4218     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4219     if (code) {
4220         cm_ReleaseUser(userp);
4221         return CM_ERROR_NOSUCHFILE;
4222     }
4223     code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4224                     tidPathp, &req, &newScp);
4225
4226     if (code) {
4227         cm_ReleaseUser(userp);
4228         return code;
4229     }
4230         
4231 #ifdef DFS_SUPPORT
4232     if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4233         cm_ReleaseSCache(newScp);
4234         cm_ReleaseUser(userp);
4235         if ( WANTS_DFS_PATHNAMES(inp) )
4236             return CM_ERROR_PATH_NOT_COVERED;
4237         else
4238             return CM_ERROR_BADSHARENAME;
4239     }
4240 #endif /* DFS_SUPPORT */
4241
4242     /* now lock the vnode with a callback; returns with newScp locked; we
4243      * need the current status to determine what the new status is, in some
4244      * cases.
4245      */
4246     lock_ObtainMutex(&newScp->mx);
4247     code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4248                      CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4249     if (code) {
4250         lock_ReleaseMutex(&newScp->mx);
4251         cm_ReleaseSCache(newScp);
4252         cm_ReleaseUser(userp);
4253         return code;
4254     }
4255
4256     /* Check for RO volume */
4257     if (newScp->flags & CM_SCACHEFLAG_RO) {
4258         lock_ReleaseMutex(&newScp->mx);
4259         cm_ReleaseSCache(newScp);
4260         cm_ReleaseUser(userp);
4261         return CM_ERROR_READONLY;
4262     }
4263
4264     /* prepare for setattr call */
4265     attr.mask = 0;
4266     if (dosTime != 0) {
4267         attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
4268         smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
4269     }
4270     if ((newScp->unixModeBits & 0222) && (attribute & 1) != 0) {
4271         /* we're told to make a writable file read-only */
4272         attr.unixModeBits = newScp->unixModeBits & ~0222;
4273         attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4274     }
4275     else if ((newScp->unixModeBits & 0222) == 0 && (attribute & 1) == 0) {
4276         /* we're told to make a read-only file writable */
4277         attr.unixModeBits = newScp->unixModeBits | 0222;
4278         attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4279     }
4280     lock_ReleaseMutex(&newScp->mx);
4281
4282     /* now call setattr */
4283     if (attr.mask)
4284         code = cm_SetAttr(newScp, &attr, userp, &req);
4285     else
4286         code = 0;
4287         
4288     cm_ReleaseSCache(newScp);
4289     cm_ReleaseUser(userp);
4290
4291     return code;
4292 }
4293
4294 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4295 {
4296     char *pathp;
4297     long code = 0;
4298     cm_scache_t *rootScp;
4299     cm_scache_t *newScp, *dscp;
4300     afs_uint32 dosTime;
4301     int attrs;
4302     cm_user_t *userp;
4303     int caseFold;
4304     char *tidPathp;
4305     cm_space_t *spacep;
4306     char *lastComp;
4307     cm_req_t req;
4308
4309     cm_InitReq(&req);
4310
4311     pathp = smb_GetSMBData(inp, NULL);
4312     pathp = smb_ParseASCIIBlock(pathp, NULL);
4313     if (!pathp)
4314         return CM_ERROR_BADSMB;
4315         
4316     if (*pathp == 0)            /* null path */
4317         pathp = "\\";
4318     else
4319         if (smb_StoreAnsiFilenames)
4320             OemToChar(pathp,pathp);
4321
4322     osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
4323              osi_LogSaveString(smb_logp, pathp));
4324
4325     rootScp = cm_data.rootSCachep;
4326         
4327     userp = smb_GetUser(vcp, inp);
4328
4329     /* we shouldn't need this for V3 requests, but we seem to */
4330     caseFold = CM_FLAG_CASEFOLD;
4331
4332     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4333     if (code) {
4334         cm_ReleaseUser(userp);
4335         return CM_ERROR_NOSUCHFILE;
4336     }
4337
4338     /*
4339      * XXX Strange hack XXX
4340      *
4341      * As of Patch 5 (16 July 97), we are having the following problem:
4342      * In NT Explorer 4.0, whenever we click on a directory, AFS gets
4343      * requests to look up "desktop.ini" in all the subdirectories.
4344      * This can cause zillions of timeouts looking up non-existent cells
4345      * and volumes, especially in the top-level directory.
4346      *
4347      * We have not found any way to avoid this or work around it except
4348      * to explicitly ignore the requests for mount points that haven't
4349      * yet been evaluated and for directories that haven't yet been
4350      * fetched.
4351      *
4352      * We should modify this hack to provide a fake desktop.ini file
4353      * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
4354      */
4355     spacep = inp->spacep;
4356     smb_StripLastComponent(spacep->data, &lastComp, pathp);
4357 #ifndef SPECIAL_FOLDERS
4358     if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
4359         code = cm_NameI(rootScp, spacep->data,
4360                         caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
4361                         userp, tidPathp, &req, &dscp);
4362         if (code == 0) {
4363 #ifdef DFS_SUPPORT
4364             if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4365                 if ( WANTS_DFS_PATHNAMES(inp) )
4366                     return CM_ERROR_PATH_NOT_COVERED;
4367                 else
4368                     return CM_ERROR_BADSHARENAME;
4369             } else
4370 #endif /* DFS_SUPPORT */
4371             if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
4372                 code = CM_ERROR_NOSUCHFILE;
4373             else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
4374                 cm_buf_t *bp = buf_Find(dscp, &hzero);
4375                 if (bp)
4376                     buf_Release(bp);
4377                 else
4378                     code = CM_ERROR_NOSUCHFILE;
4379             }