windows-lock-data-versions-20060112
[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 void smb_CleanupDeadVC(smb_vc_t *vcp)
926 {
927     smb_fid_t *fidpIter;
928     smb_fid_t *fidpNext;
929     smb_fid_t *fidp;
930     unsigned short fid;
931     smb_tid_t *tidpIter;
932     smb_tid_t *tidpNext;
933     smb_tid_t *tidp;
934     unsigned short tid;
935     smb_user_t *userpIter;
936     smb_user_t *userpNext;
937     smb_user_t *userp;
938     unsigned short uid;
939
940     osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
941
942     lock_ObtainRead(&smb_rctLock);
943     for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
944         fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
945
946         if (fidpIter->flags & SMB_FID_DELETE)
947             continue;
948
949         fid = fidpIter->fid;
950         osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
951         lock_ReleaseRead(&smb_rctLock);
952
953         fidp = smb_FindFID(vcp, fid, 0);
954         osi_assert(fidp);
955         smb_CloseFID(vcp, fidp, NULL, 0);
956         smb_ReleaseFID(fidp);
957
958         lock_ObtainRead(&smb_rctLock);
959     }
960
961     for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
962         tidpNext = tidpIter->nextp;
963
964         if (tidpIter->flags & SMB_TIDFLAG_DELETE)
965             continue;
966
967         tid = tidpIter->tid;
968         osi_Log2(smb_logp, "  Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
969         lock_ReleaseRead(&smb_rctLock);
970
971         tidp = smb_FindTID(vcp, tid, 0);
972         osi_assert(tidp);
973
974         lock_ObtainMutex(&tidp->mx);
975         tidp->flags |= SMB_TIDFLAG_DELETE;
976         lock_ReleaseMutex(&tidp->mx);
977
978         smb_ReleaseTID(tidp);
979
980         lock_ObtainRead(&smb_rctLock);
981     }
982
983     for (userpIter = vcp->usersp; userpIter; userpIter = userpNext) {
984         userpNext = userpIter->nextp;
985
986         if (userpIter->flags & SMB_USERFLAG_DELETE)
987             continue;
988
989         uid = userpIter->userID;
990         osi_Log2(smb_logp, "  Cleanup UID %d (userp=0x%x)", uid, userpIter);
991         lock_ReleaseRead(&smb_rctLock);
992
993         userp = smb_FindUID(vcp, uid, 0);
994         osi_assert(userp);
995
996         lock_ObtainMutex(&userp->mx);
997         userp->flags |= SMB_USERFLAG_DELETE;
998         lock_ReleaseMutex(&userp->mx);
999
1000         smb_ReleaseUID(userp);
1001
1002         lock_ObtainRead(&smb_rctLock);
1003     }
1004
1005     lock_ReleaseRead(&smb_rctLock);
1006
1007     osi_Log0(smb_logp, "Done cleaning up dead vcp");
1008 }
1009
1010 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1011 {
1012     smb_tid_t *tidp;
1013
1014     lock_ObtainWrite(&smb_rctLock);
1015     for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1016         if (tid == tidp->tid) {
1017             tidp->refCount++;
1018             break;
1019         }       
1020     }
1021     if (!tidp && (flags & SMB_FLAG_CREATE)) {
1022         tidp = malloc(sizeof(*tidp));
1023         memset(tidp, 0, sizeof(*tidp));
1024         tidp->nextp = vcp->tidsp;
1025         tidp->refCount = 1;
1026         tidp->vcp = vcp;
1027         smb_HoldVCNoLock(vcp);
1028         vcp->tidsp = tidp;
1029         lock_InitializeMutex(&tidp->mx, "tid_t mutex");
1030         tidp->tid = tid;
1031     }
1032     lock_ReleaseWrite(&smb_rctLock);
1033     return tidp;
1034 }               
1035
1036 void smb_ReleaseTID(smb_tid_t *tidp)
1037 {
1038     smb_tid_t *tp;
1039     smb_tid_t **ltpp;
1040     cm_user_t *userp;
1041
1042     userp = NULL;
1043     lock_ObtainWrite(&smb_rctLock);
1044     osi_assert(tidp->refCount-- > 0);
1045     if (tidp->refCount == 0 && (tidp->flags & SMB_TIDFLAG_DELETE)) {
1046         ltpp = &tidp->vcp->tidsp;
1047         for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1048             if (tp == tidp) 
1049                 break;
1050         }
1051         osi_assert(tp != NULL);
1052         *ltpp = tp->nextp;
1053         lock_FinalizeMutex(&tidp->mx);
1054         userp = tidp->userp;    /* remember to drop ref later */
1055         tidp->userp = NULL;
1056         smb_ReleaseVCNoLock(tidp->vcp);
1057         tidp->vcp = 0;
1058     }
1059     lock_ReleaseWrite(&smb_rctLock);
1060     if (userp)
1061         cm_ReleaseUser(userp);
1062 }               
1063
1064 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1065 {
1066     smb_user_t *uidp = NULL;
1067
1068     lock_ObtainWrite(&smb_rctLock);
1069     for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1070         if (uid == uidp->userID) {
1071             uidp->refCount++;
1072             osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%s]",
1073                      vcp, uidp->userID, 
1074                      osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
1075             break;
1076         }
1077     }
1078     if (!uidp && (flags & SMB_FLAG_CREATE)) {
1079         uidp = malloc(sizeof(*uidp));
1080         memset(uidp, 0, sizeof(*uidp));
1081         uidp->nextp = vcp->usersp;
1082         uidp->refCount = 1;
1083         uidp->vcp = vcp;
1084         smb_HoldVCNoLock(vcp);
1085         vcp->usersp = uidp;
1086         lock_InitializeMutex(&uidp->mx, "user_t mutex");
1087         uidp->userID = uid;
1088         osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%s]",
1089                  vcp, uidp->userID, 
1090                  osi_LogSaveString(smb_logp,uidp->unp ? uidp->unp->name : ""));
1091     }
1092     lock_ReleaseWrite(&smb_rctLock);
1093     return uidp;
1094 }               
1095
1096 smb_username_t *smb_FindUserByName(char *usern, char *machine, int flags)
1097 {
1098     smb_username_t *unp= NULL;
1099
1100     lock_ObtainWrite(&smb_rctLock);
1101     for(unp = usernamesp; unp; unp = unp->nextp) {
1102         if (stricmp(unp->name, usern) == 0 &&
1103              stricmp(unp->machine, machine) == 0) {
1104             unp->refCount++;
1105             break;
1106         }
1107     }
1108     if (!unp && (flags & SMB_FLAG_CREATE)) {
1109         unp = malloc(sizeof(*unp));
1110         memset(unp, 0, sizeof(*unp));
1111         unp->refCount = 1;
1112         unp->nextp = usernamesp;
1113         unp->name = strdup(usern);
1114         unp->machine = strdup(machine);
1115         usernamesp = unp;
1116         lock_InitializeMutex(&unp->mx, "username_t mutex");
1117     }
1118     lock_ReleaseWrite(&smb_rctLock);
1119     return unp;
1120 }       
1121
1122 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
1123 {
1124     smb_user_t *uidp= NULL;
1125
1126     lock_ObtainWrite(&smb_rctLock);
1127     for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1128         if (!uidp->unp) 
1129             continue;
1130         if (stricmp(uidp->unp->name, usern) == 0) {
1131             uidp->refCount++;
1132             osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%s]",
1133                      vcp,uidp->userID,osi_LogSaveString(smb_logp,usern));
1134             break;
1135         } else
1136             continue;
1137     }           
1138     lock_ReleaseWrite(&smb_rctLock);
1139     return uidp;
1140 }       
1141
1142 void smb_ReleaseUsername(smb_username_t *unp)
1143 {
1144     smb_username_t *up;
1145     smb_username_t **lupp;
1146     cm_user_t *userp = NULL;
1147
1148     lock_ObtainWrite(&smb_rctLock);
1149     osi_assert(unp->refCount-- > 0);
1150     if (unp->refCount == 0) {
1151         lupp = &usernamesp;
1152         for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1153             if (up == unp) 
1154                 break;
1155         }
1156         osi_assert(up != NULL);
1157         *lupp = up->nextp;
1158         lock_FinalizeMutex(&unp->mx);
1159         userp = unp->userp;
1160         free(unp->name);
1161         free(unp->machine);
1162         free(unp);
1163     }           
1164     lock_ReleaseWrite(&smb_rctLock);
1165
1166     if (userp) {
1167         cm_ReleaseUserVCRef(userp);
1168         cm_ReleaseUser(userp);
1169     }   
1170 }       
1171
1172 void smb_ReleaseUID(smb_user_t *uidp)
1173 {
1174     smb_user_t *up;
1175     smb_user_t **lupp;
1176     smb_username_t *unp = NULL;
1177
1178     lock_ObtainWrite(&smb_rctLock);
1179     osi_assert(uidp->refCount-- > 0);
1180     if (uidp->refCount == 0 && (uidp->flags & SMB_USERFLAG_DELETE)) {
1181         lupp = &uidp->vcp->usersp;
1182         for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1183             if (up == uidp) 
1184                 break;
1185         }
1186         osi_assert(up != NULL);
1187         *lupp = up->nextp;
1188         lock_FinalizeMutex(&uidp->mx);
1189         unp = uidp->unp;
1190         smb_ReleaseVCNoLock(uidp->vcp);
1191         free(uidp);
1192     }           
1193     lock_ReleaseWrite(&smb_rctLock);
1194
1195     if (unp)
1196         smb_ReleaseUsername(unp);
1197 }       
1198
1199 /* retrieve a held reference to a user structure corresponding to an incoming
1200  * request.
1201  * corresponding release function is cm_ReleaseUser.
1202  */
1203 cm_user_t *smb_GetUser(smb_vc_t *vcp, smb_packet_t *inp)
1204 {
1205     smb_user_t *uidp;
1206     cm_user_t *up;
1207     smb_t *smbp;
1208
1209     smbp = (smb_t *) inp;
1210     uidp = smb_FindUID(vcp, smbp->uid, 0);
1211     if ((!uidp) ||  (!uidp->unp))
1212         return NULL;
1213
1214     lock_ObtainMutex(&uidp->mx);
1215     up = uidp->unp->userp;
1216     cm_HoldUser(up);
1217     lock_ReleaseMutex(&uidp->mx);
1218
1219     smb_ReleaseUID(uidp);
1220
1221     return up;
1222 }
1223
1224 /*
1225  * Return a pointer to a pathname extracted from a TID structure.  The
1226  * TID structure is not held; assume it won't go away.
1227  */
1228 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1229 {
1230     smb_tid_t *tidp;
1231     long code = 0;
1232
1233     tidp = smb_FindTID(vcp, tid, 0);
1234     if (!tidp) {
1235         *treepath = NULL;
1236     } else {
1237         if (tidp->flags & SMB_TIDFLAG_IPC) {
1238             code = CM_ERROR_TIDIPC;
1239             /* tidp->pathname would be NULL, but that's fine */
1240         }
1241         *treepath = tidp->pathname;
1242         smb_ReleaseTID(tidp);
1243     }
1244     return code;
1245 }
1246
1247 /* check to see if we have a chained fid, that is, a fid that comes from an
1248  * OpenAndX message that ran earlier in this packet.  In this case, the fid
1249  * field in a read, for example, request, isn't set, since the value is
1250  * supposed to be inherited from the openAndX call.
1251  */
1252 int smb_ChainFID(int fid, smb_packet_t *inp)
1253 {
1254     if (inp->fid == 0 || inp->inCount == 0) 
1255         return fid;
1256     else 
1257         return inp->fid;
1258 }
1259
1260 /* are we a priv'd user?  What does this mean on NT? */
1261 int smb_SUser(cm_user_t *userp)
1262 {
1263     return 1;
1264 }
1265
1266 /* find a file ID.  If we pass in 0 we select an unused File ID.
1267  * If the SMB_FLAG_CREATE flag is set, we allocate a new  
1268  * smb_fid_t data structure if desired File ID cannot be found.
1269  */
1270 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1271 {
1272     smb_fid_t *fidp;
1273     int newFid = 0;
1274         
1275     if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1276         return NULL;
1277
1278     lock_ObtainWrite(&smb_rctLock);
1279     /* figure out if we need to allocate a new file ID */
1280     if (fid == 0) {
1281         newFid = 1;
1282         fid = vcp->fidCounter;
1283     }
1284
1285   retry:
1286     for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1287         if (fid == fidp->fid) {
1288             if (newFid) {
1289                 fid++;
1290                 if (fid == 0) {
1291                     osi_Log1(smb_logp,
1292                              "New FID number wraps on vcp 0x%x", vcp);
1293                     fid = 1;
1294                 }
1295                 goto retry;
1296             }
1297             fidp->refCount++;
1298             break;
1299         }
1300     }
1301
1302     if (!fidp && (flags & SMB_FLAG_CREATE)) {
1303         char eventName[MAX_PATH];
1304         EVENT_HANDLE event;
1305         sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1306         event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1307         if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1308             osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1309             thrd_CloseHandle(event);
1310             fid++;
1311             if (fid == 0) {
1312                 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1313                 fid = 1;
1314             }
1315             goto retry;
1316         }
1317
1318         fidp = malloc(sizeof(*fidp));
1319         memset(fidp, 0, sizeof(*fidp));
1320         osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1321         fidp->refCount = 1;
1322         fidp->vcp = vcp;
1323         smb_HoldVCNoLock(vcp);
1324         lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1325         fidp->fid = fid;
1326         fidp->curr_chunk = fidp->prev_chunk = -2;
1327         fidp->raw_write_event = event;
1328         if (newFid) {
1329             vcp->fidCounter = fid+1;
1330             if (vcp->fidCounter == 0) {
1331                 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1332                          vcp);
1333                 vcp->fidCounter = 1;
1334         }
1335     }
1336     }
1337
1338     lock_ReleaseWrite(&smb_rctLock);
1339     return fidp;
1340 }
1341
1342 void smb_ReleaseFID(smb_fid_t *fidp)
1343 {
1344     cm_scache_t *scp;
1345     cm_user_t *userp;
1346     smb_vc_t *vcp = NULL;
1347     smb_ioctl_t *ioctlp;
1348
1349     if (!fidp)
1350         return;
1351
1352     scp = NULL;
1353     userp = NULL;
1354     lock_ObtainWrite(&smb_rctLock);
1355     osi_assert(fidp->refCount-- > 0);
1356     if (fidp->refCount == 0 && (fidp->flags & SMB_FID_DELETE)) {
1357         vcp = fidp->vcp;
1358         fidp->vcp = NULL;
1359         scp = fidp->scp;    /* release after lock is released */
1360         fidp->scp = NULL;
1361         userp = fidp->userp;
1362         fidp->userp = NULL;
1363
1364         osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1365         thrd_CloseHandle(fidp->raw_write_event);
1366
1367         /* and see if there is ioctl stuff to free */
1368         ioctlp = fidp->ioctlp;
1369         if (ioctlp) {
1370             if (ioctlp->prefix)
1371                 cm_FreeSpace(ioctlp->prefix);
1372             if (ioctlp->inAllocp)
1373                 free(ioctlp->inAllocp);
1374             if (ioctlp->outAllocp)
1375                 free(ioctlp->outAllocp);
1376             free(ioctlp);
1377         }       
1378
1379         free(fidp);
1380
1381         smb_ReleaseVCNoLock(vcp);
1382     }
1383     lock_ReleaseWrite(&smb_rctLock);
1384
1385     /* now release the scache structure */
1386     if (scp) 
1387         cm_ReleaseSCache(scp);
1388
1389     if (userp)
1390         cm_ReleaseUser(userp);
1391 }       
1392
1393 /*
1394  * Case-insensitive search for one string in another;
1395  * used to find variable names in submount pathnames.
1396  */
1397 static char *smb_stristr(char *str1, char *str2)
1398 {
1399     char *cursor;
1400
1401     for (cursor = str1; *cursor; cursor++)
1402         if (stricmp(cursor, str2) == 0)
1403             return cursor;
1404
1405     return NULL;
1406 }
1407
1408 /*
1409  * Substitute a variable value for its name in a submount pathname.  Variable
1410  * name has been identified by smb_stristr() and is in substr.  Variable name
1411  * length (plus one) is in substr_size.  Variable value is in newstr.
1412  */
1413 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1414                       char *newstr)
1415 {
1416     char temp[1024];
1417
1418     strcpy(temp, substr + substr_size - 1);
1419     strcpy(substr, newstr);
1420     strcat(str1, temp);
1421 }       
1422
1423 char VNUserName[] = "%USERNAME%";
1424 char VNLCUserName[] = "%LCUSERNAME%";
1425 char VNComputerName[] = "%COMPUTERNAME%";
1426 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1427
1428 #ifdef DJGPP
1429 /* List available shares */
1430 int smb_ListShares()
1431 {
1432     char sbmtpath[256];
1433     char pathName[256];
1434     char shareBuf[4096];
1435     int num_shares=0;
1436     char *this_share;
1437     int len;
1438     char *p;
1439     int print_afs = 0;
1440     int code;
1441
1442     /*strcpy(shareNameList[num_shares], "all");
1443       strcpy(pathNameList[num_shares++], "/afs");*/
1444     fprintf(stderr, "The following shares are available:\n");
1445     fprintf(stderr, "Share Name (AFS Path)\n");
1446     fprintf(stderr, "---------------------\n");
1447     fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
1448
1449 #ifndef DJGPP
1450     code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1451     if (code == 0 || code > sizeof(sbmtpath)) return -1;
1452 #else
1453     strcpy(sbmtpath, cm_confDir);
1454 #endif /* !DJGPP */
1455     strcat(sbmtpath, "/afsdsbmt.ini");
1456     len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1457                                    shareBuf, sizeof(shareBuf),
1458                                    sbmtpath);
1459     if (len == 0) {
1460         return num_shares;
1461     }
1462
1463     this_share = shareBuf;
1464     do
1465     {
1466         print_afs = 0;
1467         /*strcpy(shareNameList[num_shares], this_share);*/
1468         len = GetPrivateProfileString("AFS Submounts", this_share,
1469                                        NULL,
1470                                        pathName, 256,
1471                                        sbmtpath);
1472         if (!len) 
1473             return num_shares;
1474         p = pathName;
1475         if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) != 0)
1476             print_afs = 1;
1477         while (*p) {
1478             if (*p == '\\') *p = '/';    /* change to / */
1479             p++;
1480         }
1481
1482         fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1483                  smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
1484                  pathName);
1485         num_shares++;
1486         while (*this_share != 0) this_share++;  /* find next NUL */
1487         this_share++;   /* skip past the NUL */
1488     } while (*this_share != 0);  /* stop at final NUL */
1489
1490     return num_shares;
1491 }
1492 #endif /* DJGPP */
1493
1494 typedef struct smb_findShare_rock {
1495     char * shareName;
1496     char * match;
1497     int matchType;
1498 } smb_findShare_rock_t;
1499
1500 #define SMB_FINDSHARE_EXACT_MATCH 1
1501 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1502
1503 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1504                        osi_hyper_t *offp)
1505 {
1506     int matchType = 0;
1507     smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1508     if (!strnicmp(dep->name, vrock->shareName, 12)) {
1509         if(!stricmp(dep->name, vrock->shareName))
1510             matchType = SMB_FINDSHARE_EXACT_MATCH;
1511         else
1512             matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1513         if(vrock->match) free(vrock->match);
1514         vrock->match = strdup(dep->name);
1515         vrock->matchType = matchType;
1516
1517         if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1518             return CM_ERROR_STOPNOW;
1519     }
1520     return 0;
1521 }
1522
1523
1524 /* find a shareName in the table of submounts */
1525 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1526         char **pathNamep)
1527 {
1528     DWORD len;
1529     char pathName[1024];
1530     char *var;
1531     char temp[1024];
1532     DWORD sizeTemp;
1533 #ifdef DJGPP
1534     char sbmtpath[MAX_PATH];
1535 #endif
1536     char *p, *q;
1537     HKEY parmKey;
1538     DWORD code;
1539     DWORD allSubmount = 1;
1540
1541     /* if allSubmounts == 0, only return the //mountRoot/all share 
1542      * if in fact it has been been created in the subMounts table.  
1543      * This is to allow sites that want to restrict access to the 
1544      * world to do so.
1545      */
1546     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1547                          0, KEY_QUERY_VALUE, &parmKey);
1548     if (code == ERROR_SUCCESS) {
1549         len = sizeof(allSubmount);
1550         code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1551                                 (BYTE *) &allSubmount, &len);
1552         if (code != ERROR_SUCCESS) {
1553             allSubmount = 1;
1554         }
1555         RegCloseKey (parmKey);
1556     }
1557
1558     if (allSubmount && _stricmp(shareName, "all") == 0) {
1559         *pathNamep = NULL;
1560         return 1;
1561     }
1562
1563     /* In case, the all share is disabled we need to still be able
1564      * to handle ioctl requests 
1565      */
1566     if (_stricmp(shareName, "ioctl$") == 0) {
1567         *pathNamep = strdup("/.__ioctl__");
1568         return 1;
1569     }
1570
1571     if (_stricmp(shareName, "IPC$") == 0 ||
1572         _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1573         _stricmp(shareName, "DESKTOP.INI") == 0
1574          ) {
1575         *pathNamep = NULL;
1576         return 0;
1577     }
1578
1579 #ifndef DJGPP
1580     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1581                          0, KEY_QUERY_VALUE, &parmKey);
1582     if (code == ERROR_SUCCESS) {
1583         len = sizeof(pathName);
1584         code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1585                                 (BYTE *) pathName, &len);
1586         if (code != ERROR_SUCCESS)
1587             len = 0;
1588         RegCloseKey (parmKey);
1589     } else {
1590         len = 0;
1591     }   
1592 #else /* DJGPP */
1593     strcpy(sbmtpath, cm_confDir);
1594     strcat(sbmtpath, "/afsdsbmt.ini");
1595     len = GetPrivateProfileString("AFS Submounts", shareName, "",
1596                                    pathName, sizeof(pathName), sbmtpath);
1597 #endif /* !DJGPP */
1598     if (len != 0 && len != sizeof(pathName) - 1) {
1599         /* We can accept either unix or PC style AFS pathnames.  Convert
1600          * Unix-style to PC style here for internal use. 
1601          */
1602         p = pathName;
1603         if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1604             p += strlen(cm_mountRoot);  /* skip mount path */
1605         q = p;
1606         while (*q) {
1607             if (*q == '/') *q = '\\';    /* change to \ */
1608             q++;
1609         }
1610
1611         while (1)
1612         {
1613             if (var = smb_stristr(p, VNUserName)) {
1614                 if (uidp && uidp->unp)
1615                     smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1616                 else
1617                     smb_subst(p, var, sizeof(VNUserName)," ");
1618             }
1619             else if (var = smb_stristr(p, VNLCUserName)) 
1620             {
1621                 if (uidp && uidp->unp)
1622                     strcpy(temp, uidp->unp->name);
1623                 else 
1624                     strcpy(temp, " ");
1625                 _strlwr(temp);
1626                 smb_subst(p, var, sizeof(VNLCUserName), temp);
1627             }
1628             else if (var = smb_stristr(p, VNComputerName)) 
1629             {
1630                 sizeTemp = sizeof(temp);
1631                 GetComputerName((LPTSTR)temp, &sizeTemp);
1632                 smb_subst(p, var, sizeof(VNComputerName), temp);
1633             }
1634             else if (var = smb_stristr(p, VNLCComputerName)) 
1635             {
1636                 sizeTemp = sizeof(temp);
1637                 GetComputerName((LPTSTR)temp, &sizeTemp);
1638                 _strlwr(temp);
1639                 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1640             }
1641             else     
1642                 break;
1643         }
1644         *pathNamep = strdup(p);
1645         return 1;
1646     } 
1647     else
1648     {
1649         /* First lookup shareName in root.afs */
1650         cm_req_t req;
1651         smb_findShare_rock_t vrock;
1652         osi_hyper_t thyper;
1653         char * p = shareName; 
1654         int rw = 0;
1655
1656         /*  attempt to locate a partial match in root.afs.  This is because
1657             when using the ANSI RAP calls, the share name is limited to 13 chars
1658             and hence is truncated. Of course we prefer exact matches. */
1659         cm_InitReq(&req);
1660         thyper.HighPart = 0;
1661         thyper.LowPart = 0;
1662
1663         vrock.shareName = shareName;
1664         vrock.match = NULL;
1665         vrock.matchType = 0;
1666
1667         cm_HoldSCache(cm_data.rootSCachep);
1668         code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1669             (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1670         cm_ReleaseSCache(cm_data.rootSCachep);
1671
1672         if (vrock.matchType) {
1673             sprintf(pathName,"/%s/",vrock.match);
1674             *pathNamep = strdup(strlwr(pathName));
1675             free(vrock.match);
1676             return 1;
1677         }
1678
1679         /* if we get here, there was no match for the share in root.afs */
1680         /* so try to create  \\<netbiosName>\<cellname>  */
1681         if ( *p == '.' ) {
1682             p++;
1683             rw = 1;
1684         }
1685         /* Get the full name for this cell */
1686         code = cm_SearchCellFile(p, temp, 0, 0);
1687 #ifdef AFS_AFSDB_ENV
1688         if (code && cm_dnsEnabled) {
1689             int ttl;
1690             code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1691         }
1692 #endif
1693         /* construct the path */
1694         if (code == 0) {     
1695             sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1696             *pathNamep = strdup(strlwr(pathName));
1697             return 1;
1698         }
1699     }
1700     /* failure */
1701     *pathNamep = NULL;
1702     return 0;
1703 }
1704
1705 /* Client-side offline caching policy types */
1706 #define CSC_POLICY_MANUAL 0
1707 #define CSC_POLICY_DOCUMENTS 1
1708 #define CSC_POLICY_PROGRAMS 2
1709 #define CSC_POLICY_DISABLE 3
1710
1711 int smb_FindShareCSCPolicy(char *shareName)
1712 {
1713     DWORD len;
1714     char policy[1024];
1715     DWORD dwType;
1716     HKEY hkCSCPolicy;
1717     int  retval = CSC_POLICY_MANUAL;
1718
1719     RegCreateKeyEx( HKEY_LOCAL_MACHINE, 
1720                     AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1721                     0, 
1722                     "AFS", 
1723                     REG_OPTION_NON_VOLATILE,
1724                     KEY_READ,
1725                     NULL, 
1726                     &hkCSCPolicy,
1727                     NULL );
1728
1729     len = sizeof(policy);
1730     if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1731          len == 0) {
1732         retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1733     }
1734     else if (stricmp(policy, "documents") == 0)
1735     {
1736         retval = CSC_POLICY_DOCUMENTS;
1737     }
1738     else if (stricmp(policy, "programs") == 0)
1739     {
1740         retval = CSC_POLICY_PROGRAMS;
1741     }
1742     else if (stricmp(policy, "disable") == 0)
1743     {
1744         retval = CSC_POLICY_DISABLE;
1745     }
1746         
1747     RegCloseKey(hkCSCPolicy);
1748     return retval;
1749 }
1750
1751 /* find a dir search structure by cookie value, and return it held.
1752  * Must be called with smb_globalLock held.
1753  */
1754 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
1755 {
1756     smb_dirSearch_t *dsp;
1757         
1758     for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1759         if (dsp->cookie == cookie) {
1760             if (dsp != smb_firstDirSearchp) {
1761                 /* move to head of LRU queue, too, if we're not already there */
1762                 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1763                     smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
1764                 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1765                 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1766                 if (!smb_lastDirSearchp)
1767                     smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1768             }
1769             lock_ObtainMutex(&dsp->mx);
1770             dsp->refCount++;
1771             lock_ReleaseMutex(&dsp->mx);
1772             break;
1773         }
1774     }
1775
1776     if (dsp == NULL) {
1777         osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
1778         for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1779             osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
1780         }
1781     }
1782     return dsp;
1783 }       
1784
1785 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1786 {
1787     lock_ObtainWrite(&smb_globalLock);
1788     lock_ObtainMutex(&dsp->mx);
1789     dsp->flags |= SMB_DIRSEARCH_DELETE;
1790     if (dsp->scp != NULL) {
1791         lock_ObtainMutex(&dsp->scp->mx);
1792         if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1793             dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1794             dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1795             dsp->scp->bulkStatProgress = hones;
1796         }       
1797         lock_ReleaseMutex(&dsp->scp->mx);
1798     }   
1799     lock_ReleaseMutex(&dsp->mx);
1800     lock_ReleaseWrite(&smb_globalLock);
1801 }               
1802
1803 /* Must be called with the smb_globalLock held */
1804 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
1805 {
1806     cm_scache_t *scp = NULL;
1807
1808     lock_ObtainMutex(&dsp->mx);
1809     osi_assert(dsp->refCount-- > 0);
1810     if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1811         if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1812             smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1813         osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1814         lock_ReleaseMutex(&dsp->mx);
1815         lock_FinalizeMutex(&dsp->mx);
1816         scp = dsp->scp;
1817         free(dsp);
1818     } else {
1819         lock_ReleaseMutex(&dsp->mx);
1820     }
1821     /* do this now to avoid spurious locking hierarchy creation */
1822     if (scp) 
1823         cm_ReleaseSCache(scp);
1824 }       
1825
1826 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1827 {
1828     lock_ObtainWrite(&smb_globalLock);
1829     smb_ReleaseDirSearchNoLock(dsp);
1830     lock_ReleaseWrite(&smb_globalLock);
1831 }       
1832
1833 /* find a dir search structure by cookie value, and return it held */
1834 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1835 {
1836     smb_dirSearch_t *dsp;
1837
1838     lock_ObtainWrite(&smb_globalLock);
1839     dsp = smb_FindDirSearchNoLock(cookie);
1840     lock_ReleaseWrite(&smb_globalLock);
1841     return dsp;
1842 }
1843
1844 /* GC some dir search entries, in the address space expected by the specific protocol.
1845  * Must be called with smb_globalLock held; release the lock temporarily.
1846  */
1847 #define SMB_DIRSEARCH_GCMAX     10      /* how many at once */
1848 void smb_GCDirSearches(int isV3)
1849 {
1850     smb_dirSearch_t *prevp;
1851     smb_dirSearch_t *tp;
1852     smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1853     int victimCount;
1854     int i;
1855         
1856     victimCount = 0;    /* how many have we got so far */
1857     for (tp = smb_lastDirSearchp; tp; tp=prevp) {
1858         /* we'll move tp from queue, so
1859          * do this early.
1860          */
1861         prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);  
1862         /* if no one is using this guy, and we're either in the new protocol,
1863          * or we're in the old one and this is a small enough ID to be useful
1864          * to the old protocol, GC this guy.
1865          */
1866         if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1867             /* hold and delete */
1868             tp->flags |= SMB_DIRSEARCH_DELETE;
1869             victimsp[victimCount++] = tp;
1870             tp->refCount++;
1871         }
1872
1873         /* don't do more than this */
1874         if (victimCount >= SMB_DIRSEARCH_GCMAX) 
1875             break;
1876     }
1877         
1878     /* now release them */
1879     for (i = 0; i < victimCount; i++) {
1880         smb_ReleaseDirSearchNoLock(victimsp[i]);
1881     }
1882 }
1883
1884 /* function for allocating a dir search entry.  We need these to remember enough context
1885  * since we don't get passed the path from call to call during a directory search.
1886  *
1887  * Returns a held dir search structure, and bumps the reference count on the vnode,
1888  * since it saves a pointer to the vnode.
1889  */
1890 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1891 {
1892     smb_dirSearch_t *dsp;
1893     int counter;
1894     int maxAllowed;
1895     int start;
1896     int wrapped = 0;
1897
1898     lock_ObtainWrite(&smb_globalLock);
1899     counter = 0;
1900
1901     /* what's the biggest ID allowed in this version of the protocol */
1902     maxAllowed = isV3 ? 65535 : 255;
1903     if (smb_dirSearchCounter > maxAllowed)
1904         smb_dirSearchCounter = 1;
1905
1906     start = smb_dirSearchCounter;
1907
1908     while (1) {
1909         /* twice so we have enough tries to find guys we GC after one pass;
1910          * 10 extra is just in case I mis-counted.
1911          */
1912         if (++counter > 2*maxAllowed+10) 
1913             osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
1914
1915         if (smb_dirSearchCounter > maxAllowed) {        
1916             smb_dirSearchCounter = 1;
1917         }
1918         if (smb_dirSearchCounter == start) {
1919             if (wrapped)
1920                 smb_GCDirSearches(isV3);
1921             wrapped++;
1922         }
1923         dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
1924         if (dsp) {
1925             /* don't need to watch for refcount zero and deleted, since
1926             * we haven't dropped the global lock.
1927             */
1928             lock_ObtainMutex(&dsp->mx);
1929             dsp->refCount--;
1930             lock_ReleaseMutex(&dsp->mx);
1931             ++smb_dirSearchCounter;
1932             continue;
1933         }       
1934
1935         dsp = malloc(sizeof(*dsp));
1936         memset(dsp, 0, sizeof(*dsp));
1937         dsp->cookie = smb_dirSearchCounter;
1938         ++smb_dirSearchCounter;
1939         dsp->refCount = 1;
1940         lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
1941         dsp->lastTime = osi_Time();
1942         osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1943         if (!smb_lastDirSearchp) 
1944             smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1945         break;
1946     }   
1947     lock_ReleaseWrite(&smb_globalLock);
1948     return dsp;
1949 }
1950
1951 static smb_packet_t *GetPacket(void)
1952 {
1953     smb_packet_t *tbp;
1954 #ifdef DJGPP
1955     unsigned int npar, seg, tb_sel;
1956 #endif
1957
1958     lock_ObtainWrite(&smb_globalLock);
1959     tbp = smb_packetFreeListp;
1960     if (tbp) 
1961         smb_packetFreeListp = tbp->nextp;
1962     lock_ReleaseWrite(&smb_globalLock);
1963     if (!tbp) {
1964 #ifndef DJGPP
1965         tbp = calloc(65540,1);
1966 #else /* DJGPP */
1967         tbp = malloc(sizeof(smb_packet_t));
1968 #endif /* !DJGPP */
1969         tbp->magic = SMB_PACKETMAGIC;
1970         tbp->ncbp = NULL;
1971         tbp->vcp = NULL;
1972         tbp->resumeCode = 0;
1973         tbp->inCount = 0;
1974         tbp->fid = 0;
1975         tbp->wctp = NULL;
1976         tbp->inCom = 0;
1977         tbp->oddByte = 0;
1978         tbp->ncb_length = 0;
1979         tbp->flags = 0;
1980         tbp->spacep = NULL;
1981         
1982 #ifdef DJGPP
1983         npar = SMB_PACKETSIZE >> 4;  /* number of paragraphs */
1984         {
1985             signed int retval =
1986                 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1987             if (retval == -1) {
1988                 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS memory",
1989                           npar);
1990                 osi_panic("",__FILE__,__LINE__);
1991             }
1992             else {
1993                 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X",
1994                           npar, retval);
1995                 seg = retval;
1996             }
1997         }
1998         tbp->dos_pkt = (seg * 16) + 0;  /* DOS physical address */
1999         tbp->dos_pkt_sel = tb_sel;
2000 #endif /* DJGPP */
2001     }
2002     osi_assert(tbp->magic == SMB_PACKETMAGIC);
2003
2004     return tbp;
2005 }
2006
2007 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2008 {
2009     smb_packet_t *tbp;
2010     tbp = GetPacket();
2011     memcpy(tbp, pkt, sizeof(smb_packet_t));
2012     tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2013     if (tbp->vcp)
2014         smb_HoldVC(tbp->vcp);
2015     return tbp;
2016 }
2017
2018 static NCB *GetNCB(void)
2019 {
2020     smb_ncb_t *tbp;
2021     NCB *ncbp;
2022 #ifdef DJGPP
2023     unsigned int npar, seg, tb_sel;
2024 #endif /* DJGPP */
2025
2026     lock_ObtainWrite(&smb_globalLock);
2027     tbp = smb_ncbFreeListp;
2028     if (tbp) 
2029         smb_ncbFreeListp = tbp->nextp;
2030     lock_ReleaseWrite(&smb_globalLock);
2031     if (!tbp) {
2032 #ifndef DJGPP
2033         tbp = calloc(sizeof(*tbp),1);
2034 #else /* DJGPP */
2035         tbp = malloc(sizeof(*tbp));
2036         npar = (sizeof(NCB)+15) >> 4;  /* number of paragraphs */
2037         {
2038             signed int retval =
2039                 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
2040             if (retval == -1) {
2041                 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS mem in GetNCB",
2042                           npar);
2043                 osi_panic("",__FILE__,__LINE__);
2044             } else {
2045                 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
2046                           npar, retval);
2047                 seg = retval;
2048             }
2049         }
2050         tbp->dos_ncb = (seg * 16) + 0;  /* DOS physical address */
2051         tbp->dos_ncb_sel = tb_sel;
2052 #endif /* !DJGPP */
2053         tbp->magic = SMB_NCBMAGIC;
2054     }
2055         
2056     osi_assert(tbp->magic == SMB_NCBMAGIC);
2057
2058     memset(&tbp->ncb, 0, sizeof(NCB));
2059     ncbp = &tbp->ncb;
2060 #ifdef DJGPP
2061     dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
2062 #endif /* DJGPP */
2063     return ncbp;
2064 }
2065
2066 void smb_FreePacket(smb_packet_t *tbp)
2067 {
2068     smb_vc_t * vcp = NULL;
2069     osi_assert(tbp->magic == SMB_PACKETMAGIC);
2070         
2071     lock_ObtainWrite(&smb_globalLock);
2072     tbp->nextp = smb_packetFreeListp;
2073     smb_packetFreeListp = tbp;
2074     tbp->magic = SMB_PACKETMAGIC;
2075     tbp->ncbp = NULL;
2076     vcp = tbp->vcp;
2077     tbp->vcp = NULL;
2078     tbp->resumeCode = 0;
2079     tbp->inCount = 0;
2080     tbp->fid = 0;
2081     tbp->wctp = NULL;
2082     tbp->inCom = 0;
2083     tbp->oddByte = 0;
2084     tbp->ncb_length = 0;
2085     tbp->flags = 0;
2086     lock_ReleaseWrite(&smb_globalLock);
2087
2088     if (vcp)
2089         smb_ReleaseVC(vcp);
2090 }
2091
2092 static void FreeNCB(NCB *bufferp)
2093 {
2094     smb_ncb_t *tbp;
2095         
2096     tbp = (smb_ncb_t *) bufferp;
2097     osi_assert(tbp->magic == SMB_NCBMAGIC);
2098         
2099     lock_ObtainWrite(&smb_globalLock);
2100     tbp->nextp = smb_ncbFreeListp;
2101     smb_ncbFreeListp = tbp;
2102     lock_ReleaseWrite(&smb_globalLock);
2103 }
2104
2105 /* get a ptr to the data part of a packet, and its count */
2106 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2107 {
2108     int parmBytes;
2109     int dataBytes;
2110     unsigned char *afterParmsp;
2111
2112     parmBytes = *smbp->wctp << 1;
2113     afterParmsp = smbp->wctp + parmBytes + 1;
2114         
2115     dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2116     if (nbytesp) *nbytesp = dataBytes;
2117         
2118     /* don't forget to skip the data byte count, since it follows
2119      * the parameters; that's where the "2" comes from below.
2120      */
2121     return (unsigned char *) (afterParmsp + 2);
2122 }
2123
2124 /* must set all the returned parameters before playing around with the
2125  * data region, since the data region is located past the end of the
2126  * variable number of parameters.
2127  */
2128 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2129 {
2130     unsigned char *afterParmsp;
2131
2132     afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2133         
2134     *afterParmsp++ = dsize & 0xff;
2135     *afterParmsp = (dsize>>8) & 0xff;
2136 }       
2137
2138 /* return the parm'th parameter in the smbp packet */
2139 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
2140 {
2141     int parmCount;
2142     unsigned char *parmDatap;
2143
2144     parmCount = *smbp->wctp;
2145
2146     if (parm >= parmCount) {
2147         char s[100];
2148
2149         sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2150                 parm, parmCount, smbp->ncb_length);
2151         osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2152                  parm, parmCount, smbp->ncb_length);
2153 #ifndef DJGPP
2154         LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM, 
2155                  __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2156 #endif /* !DJGPP */
2157         osi_panic(s, __FILE__, __LINE__);
2158     }
2159     parmDatap = smbp->wctp + (2*parm) + 1;
2160         
2161     return parmDatap[0] + (parmDatap[1] << 8);
2162 }
2163
2164 /* return the parm'th parameter in the smbp packet */
2165 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2166 {
2167     int parmCount;
2168     unsigned char *parmDatap;
2169
2170     parmCount = *smbp->wctp;
2171
2172     if (parm * 2 + offset >= parmCount * 2) {
2173         char s[100];
2174
2175         sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2176                 parm, offset, parmCount, smbp->ncb_length);
2177 #ifndef DJGPP
2178         LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET, 
2179                  __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2180 #endif /* !DJGPP */
2181         osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2182                 parm, offset, parmCount, smbp->ncb_length);
2183         osi_panic(s, __FILE__, __LINE__);
2184     }
2185     parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2186         
2187     return parmDatap[0] + (parmDatap[1] << 8);
2188 }
2189
2190 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2191 {
2192     char *parmDatap;
2193
2194     /* make sure we have enough slots */
2195     if (*smbp->wctp <= slot) 
2196         *smbp->wctp = slot+1;
2197         
2198     parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2199     *parmDatap++ = parmValue & 0xff;
2200     *parmDatap = (parmValue>>8) & 0xff;
2201 }       
2202
2203 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2204 {
2205     char *parmDatap;
2206
2207     /* make sure we have enough slots */
2208     if (*smbp->wctp <= slot) 
2209         *smbp->wctp = slot+2;
2210
2211     parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2212     *parmDatap++ = parmValue & 0xff;
2213     *parmDatap++ = (parmValue>>8) & 0xff;
2214     *parmDatap++ = (parmValue>>16) & 0xff;
2215     *parmDatap++ = (parmValue>>24) & 0xff;
2216 }
2217
2218 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2219 {
2220     char *parmDatap;
2221     int i;
2222
2223     /* make sure we have enough slots */
2224     if (*smbp->wctp <= slot) 
2225         *smbp->wctp = slot+4;
2226
2227     parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2228     for (i=0; i<8; i++)
2229         *parmDatap++ = *parmValuep++;
2230 }       
2231
2232 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2233 {
2234     char *parmDatap;
2235
2236     /* make sure we have enough slots */
2237     if (*smbp->wctp <= slot) {
2238         if (smbp->oddByte) {
2239             smbp->oddByte = 0;
2240             *smbp->wctp = slot+1;
2241         } else
2242             smbp->oddByte = 1;
2243     }
2244
2245     parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2246     *parmDatap++ = parmValue & 0xff;
2247 }
2248
2249 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2250 {
2251     char *lastSlashp;
2252         
2253     lastSlashp = strrchr(inPathp, '\\');
2254     if (lastComponentp)
2255         *lastComponentp = lastSlashp;
2256     if (lastSlashp) {
2257         while (1) {
2258             if (inPathp == lastSlashp) 
2259                 break;
2260             *outPathp++ = *inPathp++;
2261         }
2262         *outPathp++ = 0;
2263     }
2264     else {
2265         *outPathp++ = 0;
2266     }
2267 }
2268
2269 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2270 {
2271     if (*inp++ != 0x4) 
2272         return NULL;
2273     if (chainpp) {
2274         *chainpp = inp + strlen(inp) + 1;       /* skip over null-terminated string */
2275     }
2276     return inp;
2277 }
2278
2279 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2280 {
2281     int tlen;
2282
2283     if (*inp++ != 0x5) 
2284         return NULL;
2285     tlen = inp[0] + (inp[1]<<8);
2286     inp += 2;           /* skip length field */
2287
2288     if (chainpp) {
2289         *chainpp = inp + tlen;
2290     }
2291         
2292     if (lengthp) 
2293         *lengthp = tlen;
2294         
2295     return inp;
2296 }       
2297
2298 /* format a packet as a response */
2299 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2300 {
2301     smb_t *outp;
2302     smb_t *inSmbp;
2303
2304     outp = (smb_t *) op;
2305         
2306     /* zero the basic structure through the smb_wct field, and zero the data
2307      * size field, assuming that wct stays zero; otherwise, you have to 
2308      * explicitly set the data size field, too.
2309      */
2310     inSmbp = (smb_t *) inp;
2311     memset(outp, 0, sizeof(smb_t)+2);
2312     outp->id[0] = 0xff;
2313     outp->id[1] = 'S';
2314     outp->id[2] = 'M';
2315     outp->id[3] = 'B';
2316     if (inp) {
2317         outp->com = inSmbp->com;
2318         outp->tid = inSmbp->tid;
2319         outp->pid = inSmbp->pid;
2320         outp->uid = inSmbp->uid;
2321         outp->mid = inSmbp->mid;
2322         outp->res[0] = inSmbp->res[0];
2323         outp->res[1] = inSmbp->res[1];
2324         op->inCom = inSmbp->com;
2325     }
2326     outp->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
2327     outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2328
2329     /* copy fields in generic packet area */
2330     op->wctp = &outp->wct;
2331 }       
2332
2333 /* send a (probably response) packet; vcp tells us to whom to send it.
2334  * we compute the length by looking at wct and bcc fields.
2335  */
2336 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2337 {
2338     NCB *ncbp;
2339     int extra;
2340     long code = 0;
2341     unsigned char *tp;
2342     int localNCB = 0;
2343 #ifdef DJGPP
2344     dos_ptr dos_ncb;
2345 #endif /* DJGPP */
2346         
2347     ncbp = inp->ncbp;
2348     if (ncbp == NULL) {
2349         ncbp = GetNCB();
2350         localNCB = 1;
2351     }
2352 #ifdef DJGPP
2353     dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2354 #endif /* DJGPP */
2355  
2356     memset((char *)ncbp, 0, sizeof(NCB));
2357
2358     extra = 2 * (*inp->wctp);   /* space used by parms, in bytes */
2359     tp = inp->wctp + 1+ extra;  /* points to count of data bytes */
2360     extra += tp[0] + (tp[1]<<8);
2361     extra += (unsigned int)(inp->wctp - inp->data);     /* distance to last wct field */
2362     extra += 3;                 /* wct and length fields */
2363         
2364     ncbp->ncb_length = extra;   /* bytes to send */
2365     ncbp->ncb_lsn = (unsigned char) vcp->lsn;   /* vc to use */
2366     ncbp->ncb_lana_num = vcp->lana;
2367     ncbp->ncb_command = NCBSEND;        /* op means send data */
2368 #ifndef DJGPP
2369     ncbp->ncb_buffer = (char *) inp;/* packet */
2370     code = Netbios(ncbp);
2371 #else /* DJGPP */
2372     ncbp->ncb_buffer = inp->dos_pkt;/* packet */
2373     ((smb_ncb_t*)ncbp)->orig_pkt = inp;
2374
2375     /* copy header information from virtual to DOS address space */
2376     dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
2377     code = Netbios(ncbp, dos_ncb);
2378 #endif /* !DJGPP */
2379         
2380     if (code != 0) {
2381         char * s;
2382         switch ( code ) {
2383         case 0x01: s = "llegal buffer length                     "; break; 
2384         case 0x03: s = "illegal command                          "; break; 
2385         case 0x05: s = "command timed out                        "; break; 
2386         case 0x06: s = "message incomplete, issue another command"; break; 
2387         case 0x07: s = "illegal buffer address                   "; break; 
2388         case 0x08: s = "session number out of range              "; break; 
2389         case 0x09: s = "no resource available                    "; break; 
2390         case 0x0a: s = "session closed                           "; break; 
2391         case 0x0b: s = "command cancelled                        "; break; 
2392         case 0x0d: s = "duplicate name                           "; break; 
2393         case 0x0e: s = "name table full                          "; break; 
2394         case 0x0f: s = "no deletions, name has active sessions   "; break; 
2395         case 0x11: s = "local session table full                 "; break; 
2396         case 0x12: s = "remote session table full                "; break; 
2397         case 0x13: s = "illegal name number                      "; break; 
2398         case 0x14: s = "no callname                              "; break; 
2399         case 0x15: s = "cannot put * in NCB_NAME                 "; break; 
2400         case 0x16: s = "name in use on remote adapter            "; break; 
2401         case 0x17: s = "name deleted                             "; break; 
2402         case 0x18: s = "session ended abnormally                 "; break; 
2403         case 0x19: s = "name conflict detected                   "; break; 
2404         case 0x21: s = "interface busy, IRET before retrying     "; break; 
2405         case 0x22: s = "too many commands outstanding, retry later"; break;
2406         case 0x23: s = "ncb_lana_num field invalid               "; break; 
2407         case 0x24: s = "command completed while cancel occurring "; break; 
2408         case 0x26: s = "command not valid to cancel              "; break; 
2409         case 0x30: s = "name defined by anther local process     "; break; 
2410         case 0x34: s = "environment undefined. RESET required    "; break; 
2411         case 0x35: s = "required OS resources exhausted          "; break; 
2412         case 0x36: s = "max number of applications exceeded      "; break; 
2413         case 0x37: s = "no saps available for netbios            "; break; 
2414         case 0x38: s = "requested resources are not available    "; break; 
2415         case 0x39: s = "invalid ncb address or length > segment  "; break; 
2416         case 0x3B: s = "invalid NCB DDID                         "; break; 
2417         case 0x3C: s = "lock of user area failed                 "; break; 
2418         case 0x3f: s = "NETBIOS not loaded                       "; break; 
2419         case 0x40: s = "system error                             "; break;                 
2420         default:
2421             s = "unknown error";
2422         }
2423         osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2424     }
2425
2426     if (localNCB)
2427         FreeNCB(ncbp);
2428 }
2429
2430 void smb_MapNTError(long code, unsigned long *NTStatusp)
2431 {
2432     unsigned long NTStatus;
2433
2434     /* map CM_ERROR_* errors to NT 32-bit status codes */
2435     /* NT Status codes are listed in ntstatus.h not winerror.h */
2436     if (code == CM_ERROR_NOSUCHCELL) {
2437         NTStatus = 0xC000000FL; /* No such file */
2438     }
2439     else if (code == CM_ERROR_NOSUCHVOLUME) {
2440         NTStatus = 0xC000000FL; /* No such file */
2441     }
2442     else if (code == CM_ERROR_TIMEDOUT) {
2443 #ifdef COMMENT
2444         NTStatus = 0xC00000CFL; /* Sharing Paused */
2445 #else
2446         NTStatus = 0x00000102L; /* Timeout */
2447 #endif
2448     }
2449     else if (code == CM_ERROR_RETRY) {
2450         NTStatus = 0xC000022DL; /* Retry */
2451     }
2452     else if (code == CM_ERROR_NOACCESS) {
2453         NTStatus = 0xC0000022L; /* Access denied */
2454     }
2455     else if (code == CM_ERROR_READONLY) {
2456         NTStatus = 0xC00000A2L; /* Write protected */
2457     }
2458     else if (code == CM_ERROR_NOSUCHFILE) {
2459         NTStatus = 0xC000000FL; /* No such file */
2460     }
2461     else if (code == CM_ERROR_NOSUCHPATH) {
2462         NTStatus = 0xC000003AL; /* Object path not found */
2463     }           
2464     else if (code == CM_ERROR_TOOBIG) {
2465         NTStatus = 0xC000007BL; /* Invalid image format */
2466     }
2467     else if (code == CM_ERROR_INVAL) {
2468         NTStatus = 0xC000000DL; /* Invalid parameter */
2469     }
2470     else if (code == CM_ERROR_BADFD) {
2471         NTStatus = 0xC0000008L; /* Invalid handle */
2472     }
2473     else if (code == CM_ERROR_BADFDOP) {
2474         NTStatus = 0xC0000022L; /* Access denied */
2475     }
2476     else if (code == CM_ERROR_EXISTS) {
2477         NTStatus = 0xC0000035L; /* Object name collision */
2478     }
2479     else if (code == CM_ERROR_NOTEMPTY) {
2480         NTStatus = 0xC0000101L; /* Directory not empty */
2481     }   
2482     else if (code == CM_ERROR_CROSSDEVLINK) {
2483         NTStatus = 0xC00000D4L; /* Not same device */
2484     }
2485     else if (code == CM_ERROR_NOTDIR) {
2486         NTStatus = 0xC0000103L; /* Not a directory */
2487     }
2488     else if (code == CM_ERROR_ISDIR) {
2489         NTStatus = 0xC00000BAL; /* File is a directory */
2490     }
2491     else if (code == CM_ERROR_BADOP) {
2492 #ifdef COMMENT
2493         /* I have no idea where this comes from */
2494         NTStatus = 0xC09820FFL; /* SMB no support */
2495 #else
2496         NTStatus = 0xC00000BBL;     /* Not supported */
2497 #endif /* COMMENT */
2498     }
2499     else if (code == CM_ERROR_BADSHARENAME) {
2500         NTStatus = 0xC00000CCL; /* Bad network name */
2501     }
2502     else if (code == CM_ERROR_NOIPC) {
2503 #ifdef COMMENT
2504         NTStatus = 0xC0000022L; /* Access Denied */
2505 #else   
2506         NTStatus = 0xC000013DL; /* Remote Resources */
2507 #endif
2508     }
2509     else if (code == CM_ERROR_CLOCKSKEW) {
2510         NTStatus = 0xC0000133L; /* Time difference at DC */
2511     }
2512     else if (code == CM_ERROR_BADTID) {
2513         NTStatus = 0xC0982005L; /* SMB bad TID */
2514     }
2515     else if (code == CM_ERROR_USESTD) {
2516         NTStatus = 0xC09820FBL; /* SMB use standard */
2517     }
2518     else if (code == CM_ERROR_QUOTA) {
2519 #ifdef COMMENT
2520         NTStatus = 0xC0000044L; /* Quota exceeded */
2521 #else
2522         NTStatus = 0xC000007FL; /* Disk full */
2523 #endif
2524     }
2525     else if (code == CM_ERROR_SPACE) {
2526         NTStatus = 0xC000007FL; /* Disk full */
2527     }
2528     else if (code == CM_ERROR_ATSYS) {
2529         NTStatus = 0xC0000033L; /* Object name invalid */
2530     }
2531     else if (code == CM_ERROR_BADNTFILENAME) {
2532         NTStatus = 0xC0000033L; /* Object name invalid */
2533     }
2534     else if (code == CM_ERROR_WOULDBLOCK) {
2535         NTStatus = 0xC0000055L; /* Lock not granted */
2536     }
2537     else if (code == CM_ERROR_SHARING_VIOLATION) {
2538         NTStatus = 0xC0000043L; /* Sharing violation */
2539     }
2540     else if (code == CM_ERROR_LOCK_CONFLICT) {
2541         NTStatus = 0xC0000054L; /* Lock conflict */
2542     }
2543     else if (code == CM_ERROR_PARTIALWRITE) {
2544         NTStatus = 0xC000007FL; /* Disk full */
2545     }
2546     else if (code == CM_ERROR_BUFFERTOOSMALL) {
2547         NTStatus = 0xC0000023L; /* Buffer too small */
2548     }
2549     else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2550         NTStatus = 0xC0000035L; /* Object name collision */
2551     }   
2552     else if (code == CM_ERROR_BADPASSWORD) {
2553         NTStatus = 0xC000006DL; /* unknown username or bad password */
2554     }
2555     else if (code == CM_ERROR_BADLOGONTYPE) {
2556         NTStatus = 0xC000015BL; /* logon type not granted */
2557     }
2558     else if (code == CM_ERROR_GSSCONTINUE) {
2559         NTStatus = 0xC0000016L; /* more processing required */
2560     }
2561     else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2562 #ifdef COMMENT
2563         NTStatus = 0xC0000280L; /* reparse point not resolved */
2564 #else
2565         NTStatus = 0xC0000022L; /* Access Denied */
2566 #endif
2567     }
2568     else if (code == CM_ERROR_PATH_NOT_COVERED) {
2569         NTStatus = 0xC0000257L; /* Path Not Covered */
2570     } 
2571 #ifdef COMMENT
2572     else if (code == CM_ERROR_ALLBUSY) {
2573         NTStatus = 0xC00000BFL; /* Network Busy */
2574     } 
2575     else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
2576         NTStatus = 0xC0000350L; /* Remote Host Down */
2577     } 
2578 #else
2579     /* we do not want to be telling the SMB/CIFS client that
2580      * the AFS Client Service is busy or down.  
2581      */
2582     else if (code == CM_ERROR_ALLBUSY || 
2583              code == CM_ERROR_ALLOFFLINE ||
2584              code == CM_ERROR_ALLDOWN) {
2585         NTStatus = 0xC00000BEL; /* Bad Network Path */
2586     }
2587 #endif
2588     else if (code == RXKADUNKNOWNKEY) {
2589         NTStatus = 0xC0000322L; /* Bad Kerberos key */
2590     } else {
2591         NTStatus = 0xC0982001L; /* SMB non-specific error */
2592     }
2593
2594     *NTStatusp = NTStatus;
2595     osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2596 }       
2597
2598 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2599                       unsigned char *classp)
2600 {
2601     unsigned char class;
2602     unsigned short error;
2603
2604     /* map CM_ERROR_* errors to SMB errors */
2605     if (code == CM_ERROR_NOSUCHCELL) {
2606         class = 1;
2607         error = 3;      /* bad path */
2608     }
2609     else if (code == CM_ERROR_NOSUCHVOLUME) {
2610         class = 1;
2611         error = 3;      /* bad path */
2612     }
2613     else if (code == CM_ERROR_TIMEDOUT) {
2614         class = 2;
2615         error = 81;     /* server is paused */
2616     }
2617     else if (code == CM_ERROR_RETRY) {
2618         class = 2;      /* shouldn't happen */
2619         error = 1;
2620     }
2621     else if (code == CM_ERROR_NOACCESS) {
2622         class = 2;
2623         error = 4;      /* bad access */
2624     }
2625     else if (code == CM_ERROR_READONLY) {
2626         class = 3;
2627         error = 19;     /* read only */
2628     }
2629     else if (code == CM_ERROR_NOSUCHFILE) {
2630         class = 1;
2631         error = 2;      /* ENOENT! */
2632     }
2633     else if (code == CM_ERROR_NOSUCHPATH) {
2634         class = 1;
2635         error = 3;      /* Bad path */
2636     }
2637     else if (code == CM_ERROR_TOOBIG) {
2638         class = 1;
2639         error = 11;     /* bad format */
2640     }
2641     else if (code == CM_ERROR_INVAL) {
2642         class = 2;      /* server non-specific error code */
2643         error = 1;
2644     }
2645     else if (code == CM_ERROR_BADFD) {
2646         class = 1;
2647         error = 6;      /* invalid file handle */
2648     }
2649     else if (code == CM_ERROR_BADFDOP) {
2650         class = 1;      /* invalid op on FD */
2651         error = 5;
2652     }
2653     else if (code == CM_ERROR_EXISTS) {
2654         class = 1;
2655         error = 80;     /* file already exists */
2656     }
2657     else if (code == CM_ERROR_NOTEMPTY) {
2658         class = 1;
2659         error = 5;      /* delete directory not empty */
2660     }
2661     else if (code == CM_ERROR_CROSSDEVLINK) {
2662         class = 1;
2663         error = 17;     /* EXDEV */
2664     }
2665     else if (code == CM_ERROR_NOTDIR) {
2666         class = 1;      /* bad path */
2667         error = 3;
2668     }
2669     else if (code == CM_ERROR_ISDIR) {
2670         class = 1;      /* access denied; DOS doesn't have a good match */
2671         error = 5;
2672     }       
2673     else if (code == CM_ERROR_BADOP) {
2674         class = 2;
2675         error = 65535;
2676     }
2677     else if (code == CM_ERROR_BADSHARENAME) {
2678         class = 2;
2679         error = 6;
2680     }
2681     else if (code == CM_ERROR_NOIPC) {
2682         class = 2;
2683         error = 4; /* bad access */
2684     }
2685     else if (code == CM_ERROR_CLOCKSKEW) {
2686         class = 1;      /* invalid function */
2687         error = 1;
2688     }
2689     else if (code == CM_ERROR_BADTID) {
2690         class = 2;
2691         error = 5;
2692     }
2693     else if (code == CM_ERROR_USESTD) {
2694         class = 2;
2695         error = 251;
2696     }
2697     else if (code == CM_ERROR_REMOTECONN) {
2698         class = 2;
2699         error = 82;
2700     }
2701     else if (code == CM_ERROR_QUOTA) {
2702         if (vcp->flags & SMB_VCFLAG_USEV3) {
2703             class = 3;
2704             error = 39; /* disk full */
2705         }
2706         else {
2707             class = 1;
2708             error = 5;  /* access denied */
2709         }
2710     }
2711     else if (code == CM_ERROR_SPACE) {
2712         if (vcp->flags & SMB_VCFLAG_USEV3) {
2713             class = 3;
2714             error = 39; /* disk full */
2715         }
2716         else {
2717             class = 1;
2718             error = 5;  /* access denied */
2719         }
2720     }
2721     else if (code == CM_ERROR_PARTIALWRITE) {
2722         class = 3;
2723         error = 39;     /* disk full */
2724     }
2725     else if (code == CM_ERROR_ATSYS) {
2726         class = 1;
2727         error = 2;      /* ENOENT */
2728     }
2729     else if (code == CM_ERROR_WOULDBLOCK) {
2730         class = 1;
2731         error = 33;     /* lock conflict */
2732     }
2733     else if (code == CM_ERROR_LOCK_CONFLICT) {
2734         class = 1;
2735         error = 33;     /* lock conflict */
2736     }
2737     else if (code == CM_ERROR_SHARING_VIOLATION) {
2738         class = 1;
2739         error = 33;     /* lock conflict */
2740     }
2741     else if (code == CM_ERROR_NOFILES) {
2742         class = 1;
2743         error = 18;     /* no files in search */
2744     }
2745     else if (code == CM_ERROR_RENAME_IDENTICAL) {
2746         class = 1;
2747         error = 183;     /* Samba uses this */
2748     }
2749     else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2750         /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2751         class = 2;
2752         error = 2; /* bad password */
2753     }
2754     else if (code == CM_ERROR_PATH_NOT_COVERED) {
2755         class = 2;
2756         error = 3;     /* bad path */
2757     }
2758     else {
2759         class = 2;
2760         error = 1;
2761     }
2762
2763     *scodep = error;
2764     *classp = class;
2765     osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2766 }       
2767
2768 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2769 {
2770     osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2771     return CM_ERROR_BADOP;
2772 }
2773
2774 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2775 {
2776     unsigned short EchoCount, i;
2777     char *data, *outdata;
2778     int dataSize;
2779
2780     EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2781
2782     for (i=1; i<=EchoCount; i++) {
2783         data = smb_GetSMBData(inp, &dataSize);
2784         smb_SetSMBParm(outp, 0, i);
2785         smb_SetSMBDataLength(outp, dataSize);
2786         outdata = smb_GetSMBData(outp, NULL);
2787         memcpy(outdata, data, dataSize);
2788         smb_SendPacket(vcp, outp);
2789     }
2790
2791     return 0;
2792 }
2793
2794 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2795 {
2796     osi_hyper_t offset;
2797     long count, minCount, finalCount;
2798     unsigned short fd;
2799     unsigned pid;
2800     smb_fid_t *fidp;
2801     long code = 0;
2802     cm_user_t *userp = NULL;
2803     NCB *ncbp;
2804     int rc;
2805 #ifndef DJGPP
2806     char *rawBuf = NULL;
2807 #else
2808     dos_ptr rawBuf = NULL;
2809     dos_ptr dos_ncb;
2810 #endif /* DJGPP */
2811
2812     rawBuf = NULL;
2813     finalCount = 0;
2814
2815     fd = smb_GetSMBParm(inp, 0);
2816     count = smb_GetSMBParm(inp, 3);
2817     minCount = smb_GetSMBParm(inp, 4);
2818     offset.HighPart = 0;        /* too bad */
2819     offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2820
2821     osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2822              fd, offset.LowPart, count);
2823
2824     fidp = smb_FindFID(vcp, fd, 0);
2825     if (!fidp)
2826         goto send1;
2827
2828     pid = ((smb_t *) inp)->pid;
2829     {
2830         LARGE_INTEGER LOffset, LLength;
2831         cm_key_t key;
2832
2833         key = cm_GenerateKey(vcp->vcID, pid, fd);
2834
2835         LOffset.HighPart = 0;
2836         LOffset.LowPart = offset.LowPart;
2837         LLength.HighPart = 0;
2838         LLength.LowPart = count;
2839
2840         lock_ObtainMutex(&fidp->scp->mx);
2841         code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
2842         lock_ReleaseMutex(&fidp->scp->mx);
2843     }    
2844     if (code) {
2845         goto send1a;
2846     }
2847
2848     lock_ObtainMutex(&smb_RawBufLock);
2849     if (smb_RawBufs) {
2850         /* Get a raw buf, from head of list */
2851         rawBuf = smb_RawBufs;
2852 #ifndef DJGPP
2853         smb_RawBufs = *(char **)smb_RawBufs;
2854 #else /* DJGPP */
2855         smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2856 #endif /* !DJGPP */
2857     }
2858     lock_ReleaseMutex(&smb_RawBufLock);
2859     if (!rawBuf)
2860         goto send1a;
2861
2862     if (fidp->flags & SMB_FID_IOCTL)
2863     {
2864 #ifndef DJGPP
2865         rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2866 #else
2867         rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2868 #endif
2869         if (rawBuf) {
2870             /* Give back raw buffer */
2871             lock_ObtainMutex(&smb_RawBufLock);
2872 #ifndef DJGPP
2873             *((char **) rawBuf) = smb_RawBufs;
2874 #else /* DJGPP */
2875             _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2876 #endif /* !DJGPP */
2877             
2878             smb_RawBufs = rawBuf;
2879             lock_ReleaseMutex(&smb_RawBufLock);
2880         }
2881
2882         smb_ReleaseFID(fidp);
2883         return rc;
2884     }
2885         
2886     userp = smb_GetUser(vcp, inp);
2887
2888 #ifndef DJGPP
2889     code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2890 #else /* DJGPP */
2891     /* have to give ReadData flag so it will treat buffer as DOS mem. */
2892     code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2893                         userp, &finalCount, TRUE /* rawFlag */);
2894 #endif /* !DJGPP */
2895
2896     if (code != 0)
2897         goto send;
2898
2899   send:
2900     cm_ReleaseUser(userp);
2901
2902   send1a:
2903     smb_ReleaseFID(fidp);
2904
2905   send1:
2906     ncbp = outp->ncbp;
2907 #ifdef DJGPP
2908     dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2909 #endif /* DJGPP */
2910     memset((char *)ncbp, 0, sizeof(NCB));
2911
2912     ncbp->ncb_length = (unsigned short) finalCount;
2913     ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2914     ncbp->ncb_lana_num = vcp->lana;
2915     ncbp->ncb_command = NCBSEND;
2916     ncbp->ncb_buffer = rawBuf;
2917
2918 #ifndef DJGPP
2919     code = Netbios(ncbp);
2920 #else /* DJGPP */
2921     code = Netbios(ncbp, dos_ncb);
2922 #endif /* !DJGPP */
2923     if (code != 0)
2924         osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2925
2926     if (rawBuf) {
2927         /* Give back raw buffer */
2928         lock_ObtainMutex(&smb_RawBufLock);
2929 #ifndef DJGPP
2930         *((char **) rawBuf) = smb_RawBufs;
2931 #else /* DJGPP */
2932         _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2933 #endif /* !DJGPP */
2934
2935         smb_RawBufs = rawBuf;
2936         lock_ReleaseMutex(&smb_RawBufLock);
2937     }
2938
2939     return 0;
2940 }
2941
2942 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2943 {
2944     osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
2945                          ongoingOps - 1);
2946     return 0;
2947 }
2948
2949 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2950 {
2951     osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
2952                          ongoingOps - 1);
2953     return 0;
2954 }
2955
2956 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2957 {
2958     char *namep;
2959     char *datap;
2960     int coreProtoIndex;
2961     int v3ProtoIndex;
2962     int NTProtoIndex;
2963     int protoIndex;                             /* index we're using */
2964     int namex;
2965     int dbytes;
2966     int entryLength;
2967     int tcounter;
2968     char protocol_array[10][1024];  /* protocol signature of the client */
2969     int caps;                       /* capabilities */
2970     time_t unixTime;
2971     afs_uint32 dosTime;
2972     TIME_ZONE_INFORMATION tzi;
2973
2974     osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2975                          ongoingOps - 1);
2976     if (!isGateway) {
2977         if (active_vcp) {
2978             DWORD now = GetCurrentTime();
2979             if (now - last_msg_time >= 30000
2980                  && now - last_msg_time <= 90000) {
2981                 osi_Log1(smb_logp,
2982                           "Setting dead_vcp %x", active_vcp);
2983                 if (dead_vcp) {
2984                     smb_ReleaseVC(dead_vcp);
2985                     osi_Log1(smb_logp,
2986                              "Previous dead_vcp %x", dead_vcp);
2987                 }
2988                 smb_HoldVC(active_vcp);
2989                 dead_vcp = active_vcp;
2990                 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2991             }
2992         }
2993     }
2994
2995     inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
2996
2997     namep = smb_GetSMBData(inp, &dbytes);
2998     namex = 0;
2999     tcounter = 0;
3000     coreProtoIndex = -1;                /* not found */
3001     v3ProtoIndex = -1;
3002     NTProtoIndex = -1;
3003     while(namex < dbytes) {
3004         osi_Log1(smb_logp, "Protocol %s",
3005                   osi_LogSaveString(smb_logp, namep+1));
3006         strcpy(protocol_array[tcounter], namep+1);
3007
3008         /* namep points at the first protocol, or really, a 0x02
3009          * byte preceding the null-terminated ASCII name.
3010          */
3011         if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3012             coreProtoIndex = tcounter;
3013         }       
3014         else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3015             v3ProtoIndex = tcounter;
3016         }
3017         else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3018             NTProtoIndex = tcounter;
3019         }
3020
3021         /* compute size of protocol entry */
3022         entryLength = (int)strlen(namep+1);
3023         entryLength += 2;       /* 0x02 bytes and null termination */
3024
3025         /* advance over this protocol entry */
3026         namex += entryLength;
3027         namep += entryLength;
3028         tcounter++;             /* which proto entry we're looking at */
3029     }
3030
3031     if (NTProtoIndex != -1) {
3032         protoIndex = NTProtoIndex;
3033         vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3034     }
3035     else if (v3ProtoIndex != -1) {
3036         protoIndex = v3ProtoIndex;
3037         vcp->flags |= SMB_VCFLAG_USEV3;
3038     }   
3039     else if (coreProtoIndex != -1) {
3040         protoIndex = coreProtoIndex;
3041         vcp->flags |= SMB_VCFLAG_USECORE;
3042     }   
3043     else protoIndex = -1;
3044
3045     if (protoIndex == -1)
3046         return CM_ERROR_INVAL;
3047     else if (NTProtoIndex != -1) {
3048         smb_SetSMBParm(outp, 0, protoIndex);
3049         if (smb_authType != SMB_AUTH_NONE) {
3050             smb_SetSMBParmByte(outp, 1,
3051                                NEGOTIATE_SECURITY_USER_LEVEL |
3052                                NEGOTIATE_SECURITY_CHALLENGE_RESPONSE);  /* user level security, challenge response */
3053         } else {
3054             smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3055         }
3056         smb_SetSMBParm(outp, 1, smb_maxMpxRequests);    /* max multiplexed requests */
3057         smb_SetSMBParm(outp, 2, smb_maxVCPerServer);    /* max VCs per consumer/server connection */
3058         smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE);    /* xmit buffer size */
3059         smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE);    /* raw buffer size */
3060         /* The session key is not a well documented field however most clients
3061          * will echo back the session key to the server.  Currently we are using
3062          * the same value for all sessions.  We should generate a random value
3063          * and store it into the vcp 
3064          */
3065         smb_SetSMBParm(outp, 7, 1);     /* next 2: session key */
3066         smb_SetSMBParm(outp, 8, 1);
3067         /* 
3068          * Tried changing the capabilities to support for W2K - defect 117695
3069          * Maybe something else needs to be changed here?
3070          */
3071         /*
3072         if (isWindows2000) 
3073         smb_SetSMBParmLong(outp, 9, 0x43fd);
3074         else 
3075         smb_SetSMBParmLong(outp, 9, 0x251);
3076         */
3077         /* Capabilities: *
3078          * 32-bit error codes *
3079          * and NT Find *
3080          * and NT SMB's *
3081          * and raw mode 
3082          * and DFS */
3083         caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3084 #ifdef DFS_SUPPORT
3085                NTNEGOTIATE_CAPABILITY_DFS |
3086 #endif
3087                NTNEGOTIATE_CAPABILITY_NTFIND |
3088                NTNEGOTIATE_CAPABILITY_RAWMODE |
3089                NTNEGOTIATE_CAPABILITY_NTSMB;
3090
3091         if ( smb_authType == SMB_AUTH_EXTENDED )
3092             caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3093
3094         smb_SetSMBParmLong(outp, 9, caps);
3095         time(&unixTime);
3096         smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3097         smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3098         smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3099
3100         GetTimeZoneInformation(&tzi);
3101         smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias);    /* server tzone */
3102
3103         if (smb_authType == SMB_AUTH_NTLM) {
3104             smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3105             smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3106             /* paste in encryption key */
3107             datap = smb_GetSMBData(outp, NULL);
3108             memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3109             /* and the faux domain name */
3110             strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
3111         } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3112             void * secBlob;
3113             int secBlobLength;
3114
3115             smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3116
3117             smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3118
3119             smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3120                         
3121             datap = smb_GetSMBData(outp, NULL);
3122             memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3123
3124             if (secBlob) {
3125                 datap += sizeof(smb_ServerGUID);
3126                 memcpy(datap, secBlob, secBlobLength);
3127                 free(secBlob);
3128             }
3129         } else {
3130             smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3131             smb_SetSMBDataLength(outp, 0);   /* Perhaps we should specify 8 bytes anyway */
3132         }
3133     }
3134     else if (v3ProtoIndex != -1) {
3135         smb_SetSMBParm(outp, 0, protoIndex);
3136
3137         /* NOTE: Extended authentication cannot be negotiated with v3
3138          * therefore we fail over to NTLM 
3139          */
3140         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3141             smb_SetSMBParm(outp, 1,
3142                            NEGOTIATE_SECURITY_USER_LEVEL |
3143                            NEGOTIATE_SECURITY_CHALLENGE_RESPONSE);      /* user level security, challenge response */
3144         } else {
3145             smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3146         }
3147         smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3148         smb_SetSMBParm(outp, 3, smb_maxMpxRequests);    /* max multiplexed requests */
3149         smb_SetSMBParm(outp, 4, smb_maxVCPerServer);    /* max VCs per consumer/server connection */
3150         smb_SetSMBParm(outp, 5, 0);     /* no support of block mode for read or write */
3151         smb_SetSMBParm(outp, 6, 1);     /* next 2: session key */
3152         smb_SetSMBParm(outp, 7, 1);
3153         time(&unixTime);
3154         smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3155         smb_SetSMBParm(outp, 8, LOWORD(dosTime));       /* server time */
3156         smb_SetSMBParm(outp, 9, HIWORD(dosTime));       /* server date */
3157
3158         GetTimeZoneInformation(&tzi);
3159         smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias);    /* server tzone */
3160
3161         /* NOTE: Extended authentication cannot be negotiated with v3
3162          * therefore we fail over to NTLM 
3163          */
3164         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3165             smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH);  /* encryption key length */
3166             smb_SetSMBParm(outp, 12, 0);        /* resvd */
3167             smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);   /* perhaps should specify 8 bytes anyway */
3168             datap = smb_GetSMBData(outp, NULL);
3169             /* paste in a new encryption key */
3170             memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3171             /* and the faux domain name */
3172             strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
3173         } else {
3174             smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3175             smb_SetSMBParm(outp, 12, 0); /* resvd */
3176             smb_SetSMBDataLength(outp, 0);
3177         }
3178     }
3179     else if (coreProtoIndex != -1) {     /* not really supported anymore */
3180         smb_SetSMBParm(outp, 0, protoIndex);
3181         smb_SetSMBDataLength(outp, 0);
3182     }
3183     return 0;
3184 }
3185
3186 void smb_Daemon(void *parmp)
3187 {
3188     afs_uint32 count = 0;
3189
3190     while(smbShutdownFlag == 0) {
3191         count++;
3192         thrd_Sleep(10000);
3193
3194         if (smbShutdownFlag == 1)
3195             break;
3196         
3197         if ((count % 72) == 0)  {       /* every five minutes */
3198             struct tm myTime;
3199             time_t old_localZero = smb_localZero;
3200                  
3201             /* Initialize smb_localZero */
3202             myTime.tm_isdst = -1;               /* compute whether on DST or not */
3203             myTime.tm_year = 70;
3204             myTime.tm_mon = 0;
3205             myTime.tm_mday = 1;
3206             myTime.tm_hour = 0;
3207             myTime.tm_min = 0;
3208             myTime.tm_sec = 0;
3209             smb_localZero = mktime(&myTime);
3210
3211 #ifndef USE_NUMERIC_TIME_CONV
3212             smb_CalculateNowTZ();
3213 #endif /* USE_NUMERIC_TIME_CONV */
3214 #ifdef AFS_FREELANCE
3215             if ( smb_localZero != old_localZero )
3216                 cm_noteLocalMountPointChange();
3217 #endif
3218         }
3219         /* XXX GC dir search entries */
3220     }
3221 }
3222
3223 void smb_WaitingLocksDaemon()
3224 {
3225     smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3226     smb_waitingLock_t *wl, *wlNext;
3227     int first;
3228     smb_vc_t *vcp;
3229     smb_packet_t *inp, *outp;
3230     NCB *ncbp;
3231     long code = 0;
3232
3233     while (smbShutdownFlag == 0) {
3234         lock_ObtainWrite(&smb_globalLock);
3235         nwlRequest = smb_allWaitingLocks;
3236         if (nwlRequest == NULL) {
3237             osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
3238             thrd_Sleep(1000);
3239             continue;
3240         } else {
3241             first = 1;
3242             osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
3243         }
3244
3245         do {
3246             if (first)
3247                 first = 0;
3248             else
3249                 lock_ObtainWrite(&smb_globalLock);
3250
3251             osi_Log1(smb_logp, "    Checking waiting lock request %p", nwlRequest);
3252
3253             wlRequest = nwlRequest;
3254             nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3255             lock_ReleaseWrite(&smb_globalLock);
3256
3257             code = 0;
3258
3259             for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3260                 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3261                     continue;
3262
3263                 osi_assert(wl->state != SMB_WAITINGLOCKSTATE_ERROR);
3264                 
3265                 /* wl->state is either _DONE or _WAITING.  _ERROR
3266                    would no longer be on the queue. */
3267                 code = cm_RetryLock( wl->lockp,
3268                                      !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3269
3270                 if (code == 0) {
3271                     wl->state = SMB_WAITINGLOCKSTATE_DONE;
3272                 } else if (code != CM_ERROR_WOULDBLOCK) {
3273                     wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3274                     break;
3275                 }
3276             }
3277
3278             if (code == CM_ERROR_WOULDBLOCK) {
3279
3280                 /* no progress */
3281                 if (wlRequest->timeRemaining != 0xffffffff
3282                      && (wlRequest->timeRemaining -= 1000) < 0)
3283                     goto endWait;
3284
3285                 continue;
3286             }
3287
3288           endWait:
3289
3290             if (code != 0) {
3291                 cm_scache_t * scp;
3292                 cm_req_t req;
3293
3294                 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
3295                          wlRequest);
3296
3297                 scp = wlRequest->scp;
3298
3299                 cm_InitReq(&req);
3300
3301                 lock_ObtainMutex(&scp->mx);
3302
3303                 for (wl = wlRequest->locks; wl; wl = wlNext) {
3304                     wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3305                     
3306                     cm_Unlock(scp, wlRequest->lockType, wl->LOffset, 
3307                               wl->LLength, wl->key, NULL, &req);
3308
3309                     osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3310
3311                     free(wl);
3312                 }
3313                 
3314                 lock_ReleaseMutex(&scp->mx);
3315
3316             } else {
3317
3318                 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
3319                          wlRequest);
3320
3321                 for (wl = wlRequest->locks; wl; wl = wlNext) {
3322                     wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3323                     osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3324                     free(wl);
3325                 }
3326             }
3327
3328             vcp = wlRequest->vcp;
3329             inp = wlRequest->inp;
3330             outp = wlRequest->outp;
3331             ncbp = GetNCB();
3332             ncbp->ncb_length = inp->ncb_length;
3333             inp->spacep = cm_GetSpace();
3334
3335             /* Remove waitingLock from list */
3336             lock_ObtainWrite(&smb_globalLock);
3337             osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3338                          &wlRequest->q);
3339             lock_ReleaseWrite(&smb_globalLock);
3340
3341             /* Resume packet processing */
3342             if (code == 0)
3343                 smb_SetSMBDataLength(outp, 0);
3344             outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3345             outp->resumeCode = code;
3346             outp->ncbp = ncbp;
3347             smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3348
3349             /* Clean up */
3350             cm_FreeSpace(inp->spacep);
3351             smb_FreePacket(inp);
3352             smb_FreePacket(outp);
3353             smb_ReleaseVC(vcp);
3354             cm_ReleaseSCache(wlRequest->scp);
3355             FreeNCB(ncbp);
3356             free(wlRequest);
3357         } while (nwlRequest && smbShutdownFlag == 0);
3358         thrd_Sleep(1000);
3359     }
3360 }
3361
3362 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3363 {
3364     osi_Log0(smb_logp, "SMB receive get disk attributes");
3365
3366     smb_SetSMBParm(outp, 0, 32000);
3367     smb_SetSMBParm(outp, 1, 64);
3368     smb_SetSMBParm(outp, 2, 1024);
3369     smb_SetSMBParm(outp, 3, 30000);
3370     smb_SetSMBParm(outp, 4, 0);
3371     smb_SetSMBDataLength(outp, 0);
3372     return 0;
3373 }
3374
3375 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3376 {
3377     smb_tid_t *tidp;
3378     smb_user_t *uidp;
3379     unsigned short newTid;
3380     char shareName[256];
3381     char *sharePath;
3382     int shareFound;
3383     char *tp;
3384     char *pathp;
3385     char *passwordp;
3386     cm_user_t *userp;
3387
3388     osi_Log0(smb_logp, "SMB receive tree connect");
3389
3390     /* parse input parameters */
3391     tp = smb_GetSMBData(inp, NULL);
3392     pathp = smb_ParseASCIIBlock(tp, &tp);
3393     if (smb_StoreAnsiFilenames)
3394         OemToChar(pathp,pathp);
3395     passwordp = smb_ParseASCIIBlock(tp, &tp);
3396     tp = strrchr(pathp, '\\');
3397     if (!tp)
3398         return CM_ERROR_BADSMB;
3399     strcpy(shareName, tp+1);
3400
3401     userp = smb_GetUser(vcp, inp);
3402
3403     lock_ObtainMutex(&vcp->mx);
3404     newTid = vcp->tidCounter++;
3405     lock_ReleaseMutex(&vcp->mx);
3406
3407     tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3408     uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3409     shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3410     if (uidp)
3411         smb_ReleaseUID(uidp);
3412     if (!shareFound) {
3413         smb_ReleaseTID(tidp);
3414         return CM_ERROR_BADSHARENAME;
3415     }
3416     lock_ObtainMutex(&tidp->mx);
3417     tidp->userp = userp;
3418     tidp->pathname = sharePath;
3419     lock_ReleaseMutex(&tidp->mx);
3420     smb_ReleaseTID(tidp);
3421
3422     smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3423     smb_SetSMBParm(rsp, 1, newTid);
3424     smb_SetSMBDataLength(rsp, 0);
3425
3426     osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3427     return 0;
3428 }
3429
3430 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3431 {
3432     int tlen;
3433
3434     if (*inp++ != 0x1) return NULL;
3435     tlen = inp[0] + (inp[1]<<8);
3436     inp += 2;           /* skip length field */
3437         
3438     if (chainpp) {
3439         *chainpp = inp + tlen;
3440     }   
3441
3442     if (lengthp) *lengthp = tlen;
3443         
3444     return inp;
3445 }
3446
3447 /* set maskp to the mask part of the incoming path.
3448  * Mask is 11 bytes long (8.3 with the dot elided).
3449  * Returns true if succeeds with a valid name, otherwise it does
3450  * its best, but returns false.
3451  */
3452 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3453 {
3454     char *tp;
3455     char *up;
3456     int i;
3457     int tc;
3458     int valid8Dot3;
3459
3460     /* starts off valid */
3461     valid8Dot3 = 1;
3462
3463     /* mask starts out all blanks */
3464     memset(maskp, ' ', 11);
3465
3466     /* find last backslash, or use whole thing if there is none */
3467     tp = strrchr(pathp, '\\');
3468     if (!tp) tp = pathp;
3469     else tp++;  /* skip slash */
3470         
3471     up = maskp;
3472
3473     /* names starting with a dot are illegal */
3474     if (*tp == '.') valid8Dot3 = 0;
3475
3476     for(i=0;; i++) {
3477         tc = *tp++;
3478         if (tc == 0) return valid8Dot3;
3479         if (tc == '.' || tc == '"') break;
3480         if (i < 8) *up++ = tc;
3481         else valid8Dot3 = 0;
3482     }
3483         
3484     /* if we get here, tp point after the dot */
3485     up = maskp+8;       /* ext goes here */
3486     for(i=0;;i++) {
3487         tc = *tp++;
3488         if (tc == 0) 
3489             return valid8Dot3;
3490
3491         /* too many dots */
3492         if (tc == '.' || tc == '"') 
3493             valid8Dot3 = 0;
3494
3495         /* copy extension if not too long */
3496         if (i < 3) 
3497             *up++ = tc;
3498         else 
3499             valid8Dot3 = 0;
3500     }   
3501
3502     /* unreachable */
3503 }
3504
3505 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3506 {
3507     char umask[11];
3508     int valid;
3509     int i;
3510     char tc1;
3511     char tc2;
3512     char *tp1;
3513     char *tp2;
3514
3515     /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3516
3517     valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3518     if (!valid) 
3519         return 0;
3520  
3521     /* otherwise, we have a valid 8.3 name; see if we have a match,
3522      * treating '?' as a wildcard in maskp (but not in the file name).
3523      */
3524     tp1 = umask;        /* real name, in mask format */
3525     tp2 = maskp;        /* mask, in mask format */
3526     for(i=0; i<11; i++) {
3527         tc1 = *tp1++;   /* char from real name */
3528         tc2 = *tp2++;   /* char from mask */
3529         tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3530         tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3531         if (tc1 == tc2) 
3532             continue;
3533         if (tc2 == '?' && tc1 != ' ') 
3534             continue;
3535         if (tc2 == '>') 
3536             continue;
3537         return 0;
3538     }
3539
3540     /* we got a match */
3541     return 1;
3542 }
3543
3544 char *smb_FindMask(char *pathp)
3545 {
3546     char *tp;
3547         
3548     tp = strrchr(pathp, '\\');  /* find last slash */
3549
3550     if (tp) 
3551         return tp+1;    /* skip the slash */
3552     else 
3553         return pathp;   /* no slash, return the entire path */
3554 }       
3555
3556 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3557 {
3558     unsigned char *pathp;
3559     unsigned char *tp;
3560     unsigned char mask[11];
3561     unsigned char *statBlockp;
3562     unsigned char initStatBlock[21];
3563     int statLen;
3564         
3565     osi_Log0(smb_logp, "SMB receive search volume");
3566
3567     /* pull pathname and stat block out of request */
3568     tp = smb_GetSMBData(inp, NULL);
3569     pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3570     osi_assert(pathp != NULL);
3571     if (smb_StoreAnsiFilenames)
3572         OemToChar(pathp,pathp);
3573     statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3574     osi_assert(statBlockp != NULL);
3575     if (statLen == 0) {
3576         statBlockp = initStatBlock;
3577         statBlockp[0] = 8;
3578     }
3579         
3580     /* for returning to caller */
3581     smb_Get8Dot3MaskFromPath(mask, pathp);
3582
3583     smb_SetSMBParm(outp, 0, 1);         /* we're returning one entry */
3584     tp = smb_GetSMBData(outp, NULL);
3585     *tp++ = 5;
3586     *tp++ = 43; /* bytes in a dir entry */
3587     *tp++ = 0;  /* high byte in counter */
3588
3589     /* now marshall the dir entry, starting with the search status */
3590     *tp++ = statBlockp[0];              /* Reserved */
3591     memcpy(tp, mask, 11); tp += 11;     /* FileName */
3592
3593     /* now pass back server use info, with 1st byte non-zero */
3594     *tp++ = 1;
3595     memset(tp, 0, 4); tp += 4;  /* reserved for server use */
3596
3597     memcpy(tp, statBlockp+17, 4); tp += 4;      /* reserved for consumer */
3598
3599     *tp++ = 0x8;                /* attribute: volume */
3600
3601     /* copy out time */
3602     *tp++ = 0;
3603     *tp++ = 0;
3604
3605     /* copy out date */
3606     *tp++ = 18;
3607     *tp++ = 178;
3608
3609     /* 4 byte file size */
3610     *tp++ = 0;
3611     *tp++ = 0;
3612     *tp++ = 0;
3613     *tp++ = 0;
3614
3615     /* finally, null-terminated 8.3 pathname, which we set to AFS */
3616     memset(tp, ' ', 13);
3617     strcpy(tp, "AFS");
3618
3619     /* set the length of the data part of the packet to 43 + 3, for the dir
3620      * entry plus the 5 and the length fields.
3621      */
3622     smb_SetSMBDataLength(outp, 46);
3623     return 0;
3624 }       
3625
3626 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3627                              cm_user_t *userp, cm_req_t *reqp)
3628 {
3629     long code = 0;
3630     cm_scache_t *scp;
3631     char *dptr;
3632     afs_uint32 dosTime;
3633     u_short shortTemp;
3634     char attr;
3635     smb_dirListPatch_t *patchp;
3636     smb_dirListPatch_t *npatchp;
3637
3638     for (patchp = *dirPatchespp; patchp; patchp =
3639          (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3640
3641         dptr = patchp->dptr;
3642
3643         code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3644         if (code) {
3645             if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3646                 *dptr++ = SMB_ATTR_HIDDEN;
3647             continue;
3648         }
3649         lock_ObtainMutex(&scp->mx);
3650         code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3651                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3652         if (code) {     
3653             lock_ReleaseMutex(&scp->mx);
3654             cm_ReleaseSCache(scp);
3655             if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3656                 *dptr++ = SMB_ATTR_HIDDEN;
3657             continue;
3658         }
3659
3660         attr = smb_Attributes(scp);
3661         /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3662         if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3663             attr |= SMB_ATTR_HIDDEN;
3664         *dptr++ = attr;
3665
3666         /* get dos time */
3667         smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3668                 
3669         /* copy out time */
3670         shortTemp = (unsigned short) (dosTime & 0xffff);
3671         *((u_short *)dptr) = shortTemp;
3672         dptr += 2;
3673
3674         /* and copy out date */
3675         shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3676         *((u_short *)dptr) = shortTemp;
3677         dptr += 2;
3678                 
3679         /* copy out file length */
3680         *((u_long *)dptr) = scp->length.LowPart;
3681         dptr += 4;
3682         lock_ReleaseMutex(&scp->mx);
3683         cm_ReleaseSCache(scp);
3684     }
3685         
3686     /* now free the patches */
3687     for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3688         npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3689         free(patchp);
3690     }   
3691         
3692     /* and mark the list as empty */
3693     *dirPatchespp = NULL;
3694
3695     return code;
3696 }
3697
3698 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3699 {
3700     int attribute;
3701     long nextCookie;
3702     char *tp;
3703     long code = 0;
3704     char *pathp;
3705     cm_dirEntry_t *dep;
3706     int maxCount;
3707     smb_dirListPatch_t *dirListPatchesp;
3708     smb_dirListPatch_t *curPatchp;
3709     int dataLength;
3710     cm_buf_t *bufferp;
3711     long temp;
3712     osi_hyper_t dirLength;
3713     osi_hyper_t bufferOffset;
3714     osi_hyper_t curOffset;
3715     osi_hyper_t thyper;
3716     unsigned char *inCookiep;
3717     smb_dirSearch_t *dsp;
3718     cm_scache_t *scp;
3719     long entryInDir;
3720     long entryInBuffer;
3721     unsigned long clientCookie;
3722     cm_pageHeader_t *pageHeaderp;
3723     cm_user_t *userp = NULL;
3724     int slotInPage;
3725     char shortName[13];
3726     char *actualName;
3727     char *shortNameEnd;
3728     char mask[11];
3729     int returnedNames;
3730     long nextEntryCookie;
3731     int numDirChunks;           /* # of 32 byte dir chunks in this entry */
3732     char resByte;               /* reserved byte from the cookie */
3733     char *op;                   /* output data ptr */
3734     char *origOp;               /* original value of op */
3735     cm_space_t *spacep;         /* for pathname buffer */
3736     int starPattern;
3737     int rootPath = 0;
3738     int caseFold;
3739     char *tidPathp;
3740     cm_req_t req;
3741     cm_fid_t fid;
3742     int fileType;
3743
3744     cm_InitReq(&req);
3745
3746     maxCount = smb_GetSMBParm(inp, 0);
3747
3748     dirListPatchesp = NULL;
3749         
3750     caseFold = CM_FLAG_CASEFOLD;
3751
3752     tp = smb_GetSMBData(inp, NULL);
3753     pathp = smb_ParseASCIIBlock(tp, &tp);
3754     if (smb_StoreAnsiFilenames)
3755         OemToChar(pathp,pathp);
3756     inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3757
3758     /* bail out if request looks bad */
3759     if (!tp || !pathp) {
3760         return CM_ERROR_BADSMB;
3761     }
3762
3763     /* We can handle long names */
3764     if (vcp->flags & SMB_VCFLAG_USENT)
3765         ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
3766
3767     /* make sure we got a whole search status */
3768     if (dataLength < 21) {
3769         nextCookie = 0;         /* start at the beginning of the dir */
3770         resByte = 0;
3771         clientCookie = 0;
3772         attribute = smb_GetSMBParm(inp, 1);
3773
3774         /* handle volume info in another function */
3775         if (attribute & 0x8)
3776             return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3777
3778         osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3779                   maxCount, osi_LogSaveString(smb_logp, pathp));
3780
3781         if (*pathp == 0) {      /* null pathp, treat as root dir */
3782             if (!(attribute & SMB_ATTR_DIRECTORY))      /* exclude dirs */
3783                 return CM_ERROR_NOFILES;
3784             rootPath = 1;
3785         }
3786
3787         dsp = smb_NewDirSearch(0);
3788         dsp->attribute = attribute;
3789         smb_Get8Dot3MaskFromPath(mask, pathp);
3790         memcpy(dsp->mask, mask, 11);
3791
3792         /* track if this is likely to match a lot of entries */
3793         if (smb_IsStarMask(mask)) 
3794             starPattern = 1;
3795         else 
3796             starPattern = 0;
3797     } else {
3798         /* pull the next cookie value out of the search status block */
3799         nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3800             + (inCookiep[16]<<24);
3801         dsp = smb_FindDirSearch(inCookiep[12]);
3802         if (!dsp) {
3803             /* can't find dir search status; fatal error */
3804             osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%s]",
3805                      inCookiep[12], nextCookie, osi_LogSaveString(smb_logp, pathp));
3806             return CM_ERROR_BADFD;
3807         }
3808         attribute = dsp->attribute;
3809         resByte = inCookiep[0];
3810
3811         /* copy out client cookie, in host byte order.  Don't bother
3812          * interpreting it, since we're just passing it through, anyway.
3813          */
3814         memcpy(&clientCookie, &inCookiep[17], 4);
3815
3816         memcpy(mask, dsp->mask, 11);
3817
3818         /* assume we're doing a star match if it has continued for more
3819          * than one call.
3820          */
3821         starPattern = 1;
3822     }
3823
3824     osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
3825              nextCookie, dsp->cookie, attribute);
3826
3827     userp = smb_GetUser(vcp, inp);
3828
3829     /* try to get the vnode for the path name next */
3830     lock_ObtainMutex(&dsp->mx);
3831     if (dsp->scp) {
3832         scp = dsp->scp;
3833         cm_HoldSCache(scp);
3834         code = 0;
3835     } else {
3836         spacep = inp->spacep;
3837         smb_StripLastComponent(spacep->data, NULL, pathp);
3838         code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3839         if (code) {
3840             lock_ReleaseMutex(&dsp->mx);
3841             cm_ReleaseUser(userp);
3842             smb_DeleteDirSearch(dsp);
3843             smb_ReleaseDirSearch(dsp);
3844             return CM_ERROR_NOFILES;
3845         }
3846         code = cm_NameI(cm_data.rootSCachep, spacep->data,
3847                         caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3848         if (code == 0) {
3849 #ifdef DFS_SUPPORT
3850             if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3851                 cm_ReleaseSCache(scp);
3852                 lock_ReleaseMutex(&dsp->mx);
3853                 cm_ReleaseUser(userp);
3854                 smb_DeleteDirSearch(dsp);
3855                 smb_ReleaseDirSearch(dsp);
3856                 if ( WANTS_DFS_PATHNAMES(inp) )
3857                     return CM_ERROR_PATH_NOT_COVERED;
3858                 else
3859                     return CM_ERROR_BADSHARENAME;
3860             }
3861 #endif /* DFS_SUPPORT */
3862
3863             dsp->scp = scp;
3864             /* we need one hold for the entry we just stored into,
3865              * and one for our own processing.  When we're done with this
3866              * function, we'll drop the one for our own processing.
3867              * We held it once from the namei call, and so we do another hold
3868              * now.
3869              */
3870             cm_HoldSCache(scp);
3871             lock_ObtainMutex(&scp->mx);
3872             if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3873                  && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3874                 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3875                 dsp->flags |= SMB_DIRSEARCH_BULKST;
3876             }
3877             lock_ReleaseMutex(&scp->mx);
3878         }
3879     }
3880     lock_ReleaseMutex(&dsp->mx);
3881     if (code) {
3882         cm_ReleaseUser(userp);
3883         smb_DeleteDirSearch(dsp);
3884         smb_ReleaseDirSearch(dsp);
3885         return code;
3886     }
3887
3888     /* reserves space for parameter; we'll adjust it again later to the
3889      * real count of the # of entries we returned once we've actually
3890      * assembled the directory listing.
3891      */
3892     smb_SetSMBParm(outp, 0, 0);
3893
3894     /* get the directory size */
3895     lock_ObtainMutex(&scp->mx);
3896     code = cm_SyncOp(scp, NULL, userp, &req, 0,
3897                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3898     if (code) {
3899         lock_ReleaseMutex(&scp->mx);
3900         cm_ReleaseSCache(scp);
3901         cm_ReleaseUser(userp);
3902         smb_DeleteDirSearch(dsp);
3903         smb_ReleaseDirSearch(dsp);
3904         return code;
3905     }
3906         
3907     dirLength = scp->length;
3908     bufferp = NULL;
3909     bufferOffset.LowPart = bufferOffset.HighPart = 0;
3910     curOffset.HighPart = 0;
3911     curOffset.LowPart = nextCookie;
3912     origOp = op = smb_GetSMBData(outp, NULL);
3913     /* and write out the basic header */
3914     *op++ = 5;          /* variable block */
3915     op += 2;            /* skip vbl block length; we'll fill it in later */
3916     code = 0;
3917     returnedNames = 0;
3918     while (1) {
3919         /* make sure that curOffset.LowPart doesn't point to the first
3920          * 32 bytes in the 2nd through last dir page, and that it doesn't
3921          * point at the first 13 32-byte chunks in the first dir page,
3922          * since those are dir and page headers, and don't contain useful
3923          * information.
3924          */
3925         temp = curOffset.LowPart & (2048-1);
3926         if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3927             /* we're in the first page */
3928             if (temp < 13*32) temp = 13*32;
3929         }
3930         else {
3931             /* we're in a later dir page */
3932             if (temp < 32) temp = 32;
3933         }
3934
3935         /* make sure the low order 5 bits are zero */
3936         temp &= ~(32-1);
3937
3938         /* now put temp bits back ito curOffset.LowPart */
3939         curOffset.LowPart &= ~(2048-1);
3940         curOffset.LowPart |= temp;
3941
3942         /* check if we've returned all the names that will fit in the
3943          * response packet.
3944          */
3945         if (returnedNames >= maxCount) {
3946             osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
3947                       returnedNames, maxCount);
3948             break;
3949         }
3950                 
3951         /* check if we've passed the dir's EOF */
3952         if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
3953
3954         /* see if we can use the bufferp we have now; compute in which page
3955          * the current offset would be, and check whether that's the offset
3956          * of the buffer we have.  If not, get the buffer.
3957          */
3958         thyper.HighPart = curOffset.HighPart;
3959         thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
3960         if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3961             /* wrong buffer */
3962             if (bufferp) {
3963                 buf_Release(bufferp);
3964                 bufferp = NULL;
3965             }   
3966             lock_ReleaseMutex(&scp->mx);
3967             lock_ObtainRead(&scp->bufCreateLock);
3968             code = buf_Get(scp, &thyper, &bufferp);
3969             lock_ReleaseRead(&scp->bufCreateLock);
3970             lock_ObtainMutex(&dsp->mx);
3971
3972             /* now, if we're doing a star match, do bulk fetching of all of 
3973              * the status info for files in the dir.
3974              */
3975             if (starPattern) {
3976                 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3977                 lock_ObtainMutex(&scp->mx);
3978                 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
3979                      LargeIntegerGreaterThanOrEqualTo(thyper, 
3980                                                       scp->bulkStatProgress)) {
3981                     /* Don't bulk stat if risking timeout */
3982                     int now = GetCurrentTime();
3983                     if (now - req.startTime > 5000) {
3984                         scp->bulkStatProgress = thyper;
3985                         scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3986                         dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3987                     } else
3988                         cm_TryBulkStat(scp, &thyper, userp, &req);
3989                 }
3990             } else {
3991                 lock_ObtainMutex(&scp->mx);
3992             }
3993             lock_ReleaseMutex(&dsp->mx);
3994             if (code) {
3995                 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
3996                 break;
3997             }
3998
3999             bufferOffset = thyper;
4000
4001             /* now get the data in the cache */
4002             while (1) {
4003                 code = cm_SyncOp(scp, bufferp, userp, &req,
4004                                  PRSFS_LOOKUP,
4005                                  CM_SCACHESYNC_NEEDCALLBACK |
4006                                  CM_SCACHESYNC_READ);
4007                 if (code) {
4008                     osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
4009                     break;
4010                 }
4011                                 
4012                 if (cm_HaveBuffer(scp, bufferp, 0)) {
4013                     osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4014                     break;
4015                 }
4016
4017                 /* otherwise, load the buffer and try again */
4018                 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
4019                 if (code) {
4020                     osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d", 
4021                               scp, bufferp, code);
4022                     break;
4023                 }
4024             }
4025             if (code) {
4026                 buf_Release(bufferp);
4027                 bufferp = NULL;
4028                 break;
4029             }
4030         }       /* if (wrong buffer) ... */
4031
4032         /* now we have the buffer containing the entry we're interested in; copy
4033          * it out if it represents a non-deleted entry.
4034          */
4035         entryInDir = curOffset.LowPart & (2048-1);
4036         entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4037
4038         /* page header will help tell us which entries are free.  Page header
4039          * can change more often than once per buffer, since AFS 3 dir page size
4040          * may be less than (but not more than a buffer package buffer.
4041          */
4042         temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);  /* only look intra-buffer */
4043         temp &= ~(2048 - 1);    /* turn off intra-page bits */
4044         pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4045
4046         /* now determine which entry we're looking at in the page.  If it is
4047          * free (there's a free bitmap at the start of the dir), we should
4048          * skip these 32 bytes.
4049          */
4050         slotInPage = (entryInDir & 0x7e0) >> 5;
4051         if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
4052             /* this entry is free */
4053             numDirChunks = 1;           /* only skip this guy */
4054             goto nextEntry;
4055         }
4056
4057         tp = bufferp->datap + entryInBuffer;
4058         dep = (cm_dirEntry_t *) tp;             /* now points to AFS3 dir entry */
4059
4060         /* while we're here, compute the next entry's location, too,
4061          * since we'll need it when writing out the cookie into the dir
4062          * listing stream.
4063          *
4064          * XXXX Probably should do more sanity checking.
4065          */
4066         numDirChunks = cm_NameEntries(dep->name, NULL);
4067
4068         /* compute the offset of the cookie representing the next entry */
4069         nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4070
4071         /* Compute 8.3 name if necessary */
4072         actualName = dep->name;
4073         if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
4074             cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
4075             actualName = shortName;
4076         }
4077
4078         osi_Log3(smb_logp, "SMB search dir vn %d name %s (%s)",
4079                   dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
4080                   osi_LogSaveString(smb_logp, actualName));
4081
4082         if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
4083             /* this is one of the entries to use: it is not deleted
4084              * and it matches the star pattern we're looking for.
4085              */
4086
4087             /* Eliminate entries that don't match requested
4088              * attributes */
4089
4090             /* no hidden files */
4091             if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
4092                 osi_Log0(smb_logp, "SMB search dir skipping hidden");
4093                 goto nextEntry;
4094             }
4095
4096             if (!(dsp->attribute & SMB_ATTR_DIRECTORY))  /* no directories */
4097             {
4098                 /* We have already done the cm_TryBulkStat above */
4099                 fid.cell = scp->fid.cell;
4100                 fid.volume = scp->fid.volume;
4101                 fid.vnode = ntohl(dep->fid.vnode);
4102                 fid.unique = ntohl(dep->fid.unique);
4103                 fileType = cm_FindFileType(&fid);
4104                 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
4105                          "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
4106                           fileType);
4107                 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4108                     fileType == CM_SCACHETYPE_DFSLINK ||
4109                     fileType == CM_SCACHETYPE_INVALID)
4110                     osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
4111                 goto nextEntry;
4112             }
4113
4114             *op++ = resByte;
4115             memcpy(op, mask, 11); op += 11;
4116             *op++ = (char) dsp->cookie; /* they say it must be non-zero */
4117             *op++ = (char)(nextEntryCookie & 0xff);
4118             *op++ = (char)((nextEntryCookie>>8) & 0xff);
4119             *op++ = (char)((nextEntryCookie>>16) & 0xff);
4120             *op++ = (char)((nextEntryCookie>>24) & 0xff);
4121             memcpy(op, &clientCookie, 4); op += 4;
4122
4123             /* now we emit the attribute.  This is sort of tricky,
4124              * since we need to really stat the file to find out
4125              * what type of entry we've got.  Right now, we're
4126              * copying out data from a buffer, while holding the
4127              * scp locked, so it isn't really convenient to stat
4128              * something now.  We'll put in a place holder now,
4129              * and make a second pass before returning this to get
4130              * the real attributes.  So, we just skip the data for
4131              * now, and adjust it later.  We allocate a patch
4132              * record to make it easy to find this point later.
4133              * The replay will happen at a time when it is safe to
4134              * unlock the directory.
4135              */
4136             curPatchp = malloc(sizeof(*curPatchp));
4137             osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
4138             curPatchp->dptr = op;
4139             curPatchp->fid.cell = scp->fid.cell;
4140             curPatchp->fid.volume = scp->fid.volume;
4141             curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4142             curPatchp->fid.unique = ntohl(dep->fid.unique);
4143
4144             /* do hidden attribute here since name won't be around when applying
4145              * dir list patches
4146              */
4147
4148             if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
4149                 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4150             else
4151                 curPatchp->flags = 0;
4152
4153             op += 9;    /* skip attr, time, date and size */
4154
4155             /* zero out name area.  The spec says to pad with
4156              * spaces, but Samba doesn't, and neither do we.
4157              */
4158             memset(op, 0, 13);
4159
4160             /* finally, we get to copy out the name; we know that
4161              * it fits in 8.3 or the pattern wouldn't match, but it
4162              * never hurts to be sure.
4163              */
4164             strncpy(op, actualName, 13);
4165             if (smb_StoreAnsiFilenames)
4166                 CharToOem(op, op);
4167
4168             /* Uppercase if requested by client */
4169             if (!KNOWS_LONG_NAMES(inp))
4170                 _strupr(op);
4171
4172             op += 13;
4173
4174             /* now, adjust the # of entries copied */
4175             returnedNames++;
4176         }       /* if we're including this name */
4177
4178       nextEntry:
4179         /* and adjust curOffset to be where the new cookie is */
4180         thyper.HighPart = 0;
4181         thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4182         curOffset = LargeIntegerAdd(thyper, curOffset);
4183     }           /* while copying data for dir listing */
4184
4185     /* release the mutex */
4186     lock_ReleaseMutex(&scp->mx);
4187     if (bufferp) buf_Release(bufferp);
4188
4189     /* apply and free last set of patches; if not doing a star match, this
4190      * will be empty, but better safe (and freeing everything) than sorry.
4191      */
4192     smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
4193
4194     /* special return code for unsuccessful search */
4195     if (code == 0 && dataLength < 21 && returnedNames == 0)
4196         code = CM_ERROR_NOFILES;
4197
4198     osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
4199              returnedNames, code);
4200
4201     if (code != 0) {
4202         smb_DeleteDirSearch(dsp);
4203         smb_ReleaseDirSearch(dsp);
4204         cm_ReleaseSCache(scp);
4205         cm_ReleaseUser(userp);
4206         return code;
4207     }
4208
4209     /* finalize the output buffer */
4210     smb_SetSMBParm(outp, 0, returnedNames);
4211     temp = (long) (op - origOp);
4212     smb_SetSMBDataLength(outp, temp);
4213
4214     /* the data area is a variable block, which has a 5 (already there)
4215      * followed by the length of the # of data bytes.  We now know this to
4216      * be "temp," although that includes the 3 bytes of vbl block header.
4217      * Deduct for them and fill in the length field.
4218      */
4219     temp -= 3;          /* deduct vbl block info */
4220     osi_assert(temp == (43 * returnedNames));
4221     origOp[1] = (char)(temp & 0xff);
4222     origOp[2] = (char)((temp>>8) & 0xff);
4223     if (returnedNames == 0) 
4224         smb_DeleteDirSearch(dsp);
4225     smb_ReleaseDirSearch(dsp);
4226     cm_ReleaseSCache(scp);
4227     cm_ReleaseUser(userp);
4228     return code;
4229 }       
4230
4231 /* verify that this is a valid path to a directory.  I don't know why they
4232  * don't use the get file attributes call.
4233  */
4234 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4235 {
4236     char *pathp;
4237     long code = 0;
4238     cm_scache_t *rootScp;
4239     cm_scache_t *newScp;
4240     cm_user_t *userp;
4241     unsigned int attrs;
4242     int caseFold;
4243     char *tidPathp;
4244     cm_req_t req;
4245
4246     cm_InitReq(&req);
4247
4248     pathp = smb_GetSMBData(inp, NULL);
4249     pathp = smb_ParseASCIIBlock(pathp, NULL);
4250     if (!pathp)
4251         return CM_ERROR_BADFD;
4252     if (smb_StoreAnsiFilenames)
4253         OemToChar(pathp,pathp);
4254     osi_Log1(smb_logp, "SMB receive check path %s",
4255              osi_LogSaveString(smb_logp, pathp));
4256         
4257     rootScp = cm_data.rootSCachep;
4258         
4259     userp = smb_GetUser(vcp, inp);
4260
4261     caseFold = CM_FLAG_CASEFOLD;
4262
4263     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4264     if (code) {
4265         cm_ReleaseUser(userp);
4266         return CM_ERROR_NOSUCHPATH;
4267     }
4268     code = cm_NameI(rootScp, pathp,
4269                     caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
4270                     userp, tidPathp, &req, &newScp);
4271
4272     if (code) {
4273         cm_ReleaseUser(userp);
4274         return code;
4275     }
4276         
4277 #ifdef DFS_SUPPORT
4278     if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4279         cm_ReleaseSCache(newScp);
4280         cm_ReleaseUser(userp);
4281         if ( WANTS_DFS_PATHNAMES(inp) )
4282             return CM_ERROR_PATH_NOT_COVERED;
4283         else
4284             return CM_ERROR_BADSHARENAME;
4285     }
4286 #endif /* DFS_SUPPORT */
4287
4288     /* now lock the vnode with a callback; returns with newScp locked */
4289     lock_ObtainMutex(&newScp->mx);
4290     code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
4291                      CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4292     if (code && code != CM_ERROR_NOACCESS) {
4293         lock_ReleaseMutex(&newScp->mx);
4294         cm_ReleaseSCache(newScp);
4295         cm_ReleaseUser(userp);
4296         return code;
4297     }
4298
4299     attrs = smb_Attributes(newScp);
4300
4301     if (!(attrs & SMB_ATTR_DIRECTORY))
4302         code = CM_ERROR_NOTDIR;
4303
4304     lock_ReleaseMutex(&newScp->mx);
4305
4306     cm_ReleaseSCache(newScp);
4307     cm_ReleaseUser(userp);
4308     return code;
4309 }       
4310
4311 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4312 {
4313     char *pathp;
4314     long code = 0;
4315     cm_scache_t *rootScp;
4316     unsigned short attribute;
4317     cm_attr_t attr;
4318     cm_scache_t *newScp;
4319     afs_uint32 dosTime;
4320     cm_user_t *userp;
4321     int caseFold;
4322     char *tidPathp;
4323     cm_req_t req;
4324
4325     cm_InitReq(&req);
4326
4327     /* decode basic attributes we're passed */
4328     attribute = smb_GetSMBParm(inp, 0);
4329     dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4330
4331     pathp = smb_GetSMBData(inp, NULL);
4332     pathp = smb_ParseASCIIBlock(pathp, NULL);
4333     if (!pathp)
4334         return CM_ERROR_BADSMB;
4335     if (smb_StoreAnsiFilenames)
4336         OemToChar(pathp,pathp);
4337                
4338     osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
4339              dosTime, attribute);
4340
4341     rootScp = cm_data.rootSCachep;
4342         
4343     userp = smb_GetUser(vcp, inp);
4344
4345     caseFold = CM_FLAG_CASEFOLD;
4346
4347     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4348     if (code) {
4349         cm_ReleaseUser(userp);
4350         return CM_ERROR_NOSUCHFILE;
4351     }
4352     code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4353                     tidPathp, &req, &newScp);
4354
4355     if (code) {
4356         cm_ReleaseUser(userp);
4357         return code;
4358     }
4359         
4360 #ifdef DFS_SUPPORT
4361     if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4362         cm_ReleaseSCache(newScp);
4363         cm_ReleaseUser(userp);
4364         if ( WANTS_DFS_PATHNAMES(inp) )
4365             return CM_ERROR_PATH_NOT_COVERED;
4366         else
4367             return CM_ERROR_BADSHARENAME;
4368     }
4369 #endif /* DFS_SUPPORT */
4370
4371     /* now lock the vnode with a callback; returns with newScp locked; we
4372      * need the current status to determine what the new status is, in some
4373      * cases.
4374      */
4375     lock_ObtainMutex(&newScp->mx);
4376     code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4377                      CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4378     if (code) {
4379         lock_ReleaseMutex(&newScp->mx);
4380         cm_ReleaseSCache(newScp);
4381         cm_ReleaseUser(userp);
4382         return code;
4383     }
4384
4385     /* Check for RO volume */
4386     if (newScp->flags & CM_SCACHEFLAG_RO) {
4387         lock_ReleaseMutex(&newScp->mx);
4388         cm_ReleaseSCache(newScp);
4389         cm_ReleaseUser(userp);
4390         return CM_ERROR_READONLY;
4391     }
4392
4393     /* prepare for setattr call */
4394     attr.mask = 0;
4395     if (dosTime != 0) {
4396         attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
4397         smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
4398     }
4399     if ((newScp->unixModeBits & 0222) && (attribute & 1) != 0) {
4400         /* we're told to make a writable file read-only */
4401         attr.unixModeBits = newScp->unixModeBits & ~0222;
4402         attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4403     }
4404     else if ((newScp->unixModeBits & 0222) == 0 && (attribute & 1) == 0) {
4405         /* we're told to make a read-only file writable */
4406         attr.unixModeBits = newScp->unixModeBits | 0222;
4407         attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4408     }
4409     lock_ReleaseMutex(&newScp->mx);
4410
4411     /* now call setattr */
4412     if (attr.mask)
4413         code = cm_SetAttr(newScp, &attr, userp, &req);
4414     else
4415         code = 0;
4416         
4417     cm_ReleaseSCache(newScp);
4418     cm_ReleaseUser(userp);
4419
4420     return code;
4421 }
4422
4423 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4424 {
4425     char *pathp;
4426     long code = 0;
4427     cm_scache_t *rootScp;
4428     cm_scache_t *newScp, *dscp;
4429     afs_uint32 dosTime;
4430     int attrs;
4431     cm_user_t *userp;
4432     int caseFold;
4433     char *tidPathp;
4434     cm_space_t *spacep;
4435     char *lastComp;
4436     cm_req_t req;
4437
4438     cm_InitReq(&req);
4439
4440     pathp = smb_GetSMBData(inp, NULL);
4441     pathp = smb_ParseASCIIBlock(pathp, NULL);
4442     if (!pathp)
4443         return CM_ERROR_BADSMB;
4444         
4445     if (*pathp == 0)            /* null path */
4446         pathp = "\\";
4447     else
4448         if (smb_StoreAnsiFilenames)
4449             OemToChar(pathp,pathp);
4450
4451     osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
4452              osi_LogSaveString(smb_logp, pathp));
4453
4454     rootScp = cm_data.rootSCachep;
4455         
4456     userp = smb_GetUser(vcp, inp);
4457
4458     /* we shouldn't need this for V3 requests, but we seem to */
4459     caseFold = CM_FLAG_CASEFOLD;
4460
4461     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4462     if (code) {
4463         cm_ReleaseUser(userp);
4464         return CM_ERROR_NOSUCHFILE;
4465     }
4466
4467     /*
4468      * XXX Strange hack XXX
4469      *
4470      * As of Patch 5 (16 July 97), we are having the following problem:
4471      * In NT Explorer 4.0, whenever we click on a directory, AFS gets
4472      * requests to look up "desktop.ini" in all the subdirectories.
4473      * This can cause zillions of timeouts looking up non-existent cells
4474      * and volumes, especially in the top-level directory.
4475      *
4476      * We have not found any way to avoid this or work around it except
4477      * to explicitly ignore the requests for mount points that haven't
4478      * yet been evaluated and for directories that haven't yet been
4479      * fetched.
4480      *
4481      * We should modify this hack to provide a fake desktop.ini file
4482      * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
4483      */
4484     spacep = inp->spacep;
4485     smb_StripLastComponent(spacep->data, &lastComp, pathp);
4486 #ifndef SPECIAL_FOLDERS
4487     if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
4488         code = cm_NameI(rootScp, spacep->data,
4489                         caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
4490                         userp, tidPathp, &req, &dscp);
4491         if (code == 0) {
4492 #ifdef DFS_SUPPORT
4493             if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4494                 if ( WANTS_DFS_PATHNAMES(inp) )
4495                     return CM_ERROR_PATH_NOT_COVERED;
4496                 else
4497                     return CM_ERROR_BADSHARENAME;
4498             } else
4499 #endif /* DFS_SUPPORT */
4500             if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
4501                 code = CM_ERROR_NOSUCHFILE;
4502             else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
4503                 cm_buf_t *bp = buf_Find(dscp, &hzero);
4504                 if (bp)
4505                     buf_Release(bp);
4506                 else
4507                     code = CM_ERROR_NOSUCHFILE;
4508             }
4509             cm_ReleaseSCache(dscp);
4510             if (code) {
4511                 cm_ReleaseUser(userp);
4512                 return code;
4513             }
4514         }
4515     }
4516 #endif /* SPECIAL_FOLDERS */
4517
4518     code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4519                     tidPathp, &req, &newScp);
4520     if (code) {
4521         cm_ReleaseUser(userp);
4522         return code;
4523     }
4524         
4525 #ifdef DFS_SUPPORT
4526     if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4527         cm_ReleaseSCache(newScp);
4528         cm_ReleaseUser(userp);
4529         if ( WANTS_DFS_PATHNAMES(inp) )
4530             return CM_ERROR_PATH_NOT_COVERED;
4531         else
4532             return CM_ERROR_BADSHARENAME;
4533     }
4534 #endif /* DFS_SUPPORT */
4535
4536     /* now lock the vnode with a callback; returns with newScp locked */
4537     lock_ObtainMutex(&newScp->mx);
4538     code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4539                      CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4540     if (code) {
4541         lock_ReleaseMutex(&newScp->mx);
4542         cm_ReleaseSCache(newScp);
4543         cm_ReleaseUser(userp);
4544         return code;
4545     }
4546
4547 #ifdef undef
4548     /* use smb_Attributes instead.   Also the fact that a file is 
4549      * in a readonly volume doesn't mean it shojuld be marked as RO 
4550      */
4551     if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
4552         newScp->fileType == CM_SCACHETYPE_MOUNTPOINT)
4553         attrs = SMB_ATTR_DIRECTORY;
4554     else
4555         attrs = 0;
4556     if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
4557         attrs |= SMB_ATTR_READONLY;     /* turn on read-only flag */
4558 #else
4559     attrs = smb_Attributes(newScp);
4560 #endif
4561
4562     smb_SetSMBParm(outp, 0, attrs);
4563         
4564     smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
4565     smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
4566     smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
4567     smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
4568     smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
4569     smb_SetSMBParm(outp, 5, 0);
4570     smb_SetSMBParm(outp, 6, 0);
4571     smb_SetSMBParm(outp, 7, 0);
4572     smb_SetSMBParm(outp, 8, 0);
4573     smb_SetSMBParm(outp, 9, 0);
4574     smb_SetSMBDataLength(outp, 0);
4575     lock_ReleaseMutex(&newScp->mx);
4576
4577     cm_ReleaseSCache(newScp);
4578     cm_ReleaseUser(userp);
4579
4580     return 0;
4581 }       
4582
4583 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4584 {
4585     smb_tid_t *tidp;
4586         
4587     osi_Log0(smb_logp, "SMB receive tree disconnect");
4588
4589     /* find the tree and free it */
4590     tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
4591     if (tidp) {
4592         lock_ObtainMutex(&tidp->mx);
4593         tidp->flags |= SMB_TIDFLAG_DELETE;
4594         lock_ReleaseMutex(&tidp->mx);
4595         smb_ReleaseTID(tidp);
4596     }
4597
4598     return 0;
4599 }
4600
4601 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4602 {
4603     smb_fid_t *fidp;
4604     char *pathp;
4605     char *lastNamep;
4606     int share;
4607     int attribute;
4608     long code = 0;
4609     cm_user_t *userp;
4610     cm_scache_t *scp;
4611     afs_uint32 dosTime;
4612     int caseFold;
4613     cm_space_t *spacep;
4614     char *tidPathp;
4615     cm_req_t req;
4616
4617     cm_InitReq(&req);
4618
4619     pathp = smb_GetSMBData(inp, NULL);
4620     pathp = smb_ParseASCIIBlock(pathp, NULL);
4621     if (smb_StoreAnsiFilenames)
4622         OemToChar(pathp,pathp);
4623         
4624     osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
4625
4626 #ifdef DEBUG_VERBOSE
4627     {
4628         char *hexpath;
4629
4630         hexpath = osi_HexifyString( pathp );
4631         DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
4632         free(hexpath);
4633     }
4634 #endif
4635
4636     share = smb_GetSMBParm(inp, 0);
4637     attribute = smb_GetSMBParm(inp, 1);
4638
4639     spacep = inp->spacep;
4640     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4641     if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4642         /* special case magic file name for receiving IOCTL requests
4643          * (since IOCTL calls themselves aren't getting through).
4644          */
4645         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4646         smb_SetupIoctlFid(fidp, spacep);
4647         smb_SetSMBParm(outp, 0, fidp->fid);
4648         smb_SetSMBParm(outp, 1, 0);     /* attrs */
4649         smb_SetSMBParm(outp, 2, 0);     /* next 2 are DOS time */
4650         smb_SetSMBParm(outp, 3, 0);
4651         smb_SetSMBParm(outp, 4, 0);     /* next 2 are length */
4652         smb_SetSMBParm(outp, 5, 0x7fff);
4653         /* pass the open mode back */
4654         smb_SetSMBParm(outp, 6, (share & 0xf));
4655         smb_SetSMBDataLength(outp, 0);
4656         smb_ReleaseFID(fidp);
4657         return 0;
4658     }
4659
4660     userp = smb_GetUser(vcp, inp);
4661
4662     caseFold = CM_FLAG_CASEFOLD;
4663
4664     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4665     if (code) {
4666         cm_ReleaseUser(userp);
4667         return CM_ERROR_NOSUCHPATH;
4668     }
4669     code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4670                     tidPathp, &req, &scp);
4671         
4672     if (code) {
4673         cm_ReleaseUser(userp);
4674         return code;
4675     }
4676
4677 #ifdef DFS_SUPPORT
4678     if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4679         cm_ReleaseSCache(scp);
4680         cm_ReleaseUser(userp);
4681         if ( WANTS_DFS_PATHNAMES(inp) )
4682             return CM_ERROR_PATH_NOT_COVERED;
4683         else
4684             return CM_ERROR_BADSHARENAME;
4685     }
4686 #endif /* DFS_SUPPORT */
4687
4688     code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
4689     if (code) {
4690         cm_ReleaseSCache(scp);
4691         cm_ReleaseUser(userp);
4692         return code;
4693     }
4694
4695     /* don't need callback to check file type, since file types never
4696      * change, and namei and cm_Lookup all stat the object at least once on
4697      * a successful return.
4698      */
4699     if (scp->fileType != CM_SCACHETYPE_FILE) {
4700         cm_ReleaseSCache(scp);
4701         cm_ReleaseUser(userp);
4702         return CM_ERROR_ISDIR;
4703     }
4704
4705     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4706     osi_assert(fidp);
4707
4708     /* save a pointer to the vnode */
4709     fidp->scp = scp;
4710     /* and the user */
4711     cm_HoldUser(userp);
4712     fidp->userp = userp;
4713
4714     if ((share & 0xf) == 0)
4715         fidp->flags |= SMB_FID_OPENREAD;
4716     else if ((share & 0xf) == 1)
4717         fidp->flags |= SMB_FID_OPENWRITE;
4718     else 
4719         fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
4720
4721     lock_ObtainMutex(&scp->mx);
4722     smb_SetSMBParm(outp, 0, fidp->fid);
4723     smb_SetSMBParm(outp, 1, smb_Attributes(scp));
4724     smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4725     smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
4726     smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
4727     smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
4728     smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
4729     /* pass the open mode back; XXXX add access checks */
4730     smb_SetSMBParm(outp, 6, (share & 0xf));
4731     smb_SetSMBDataLength(outp, 0);
4732     lock_ReleaseMutex(&scp->mx);
4733         
4734     /* notify open */
4735     cm_Open(scp, 0, userp);
4736
4737     /* send and free packet */
4738     smb_ReleaseFID(fidp);
4739     cm_ReleaseUser(userp);
4740     /* don't release scp, since we've squirreled away the pointer in the fid struct */
4741     return 0;
4742 }
4743
4744 typedef struct smb_unlinkRock {
4745     cm_scache_t *dscp;
4746     cm_user_t *userp;
4747     cm_req_t *reqp;
4748     smb_vc_t *vcp;
4749     char *maskp;                /* pointer to the star pattern */
4750     int flags;
4751     int any;
4752 } smb_unlinkRock_t;
4753
4754 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4755 {
4756     long code = 0;
4757     smb_unlinkRock_t *rockp;
4758     int caseFold;
4759     int match;
4760     char shortName[13];
4761     char *matchName;
4762         
4763     rockp = vrockp;
4764
4765     caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4766     if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4767         caseFold |= CM_FLAG_8DOT3;
4768
4769     matchName = dep->name;
4770     match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
4771     if (!match &&
4772          (rockp->flags & SMB_MASKFLAG_TILDE) &&
4773          !cm_Is8Dot3(dep->name)) {
4774         cm_Gen8Dot3Name(dep, shortName, NULL);
4775         matchName = shortName;
4776         /* 8.3 matches are always case insensitive */
4777         match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
4778     }
4779     if (match) {
4780         osi_Log1(smb_logp, "Unlinking %s",
4781                  osi_LogSaveString(smb_logp, matchName));
4782         code = cm_Unlink(dscp, dep->name, rockp->userp, rockp->reqp);
4783         if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4784             smb_NotifyChange(FILE_ACTION_REMOVED,
4785                              FILE_NOTIFY_CHANGE_FILE_NAME,
4786                              dscp, dep->name, NULL, TRUE);
4787         if (code == 0) {
4788             rockp->any = 1;
4789
4790             /* If we made a case sensitive exact match, we might as well quit now. */
4791             if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
4792                 code = CM_ERROR_STOPNOW;
4793         }
4794     }
4795     else code = 0;
4796
4797     return code;
4798 }
4799
4800 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4801 {
4802     int attribute;
4803     long code = 0;
4804     char *pathp;
4805     char *tp;
4806     cm_space_t *spacep;
4807     cm_scache_t *dscp;
4808     char *lastNamep;
4809     smb_unlinkRock_t rock;
4810     cm_user_t *userp;
4811     osi_hyper_t thyper;
4812     int caseFold;
4813     char *tidPathp;
4814     cm_req_t req;
4815
4816     cm_InitReq(&req);
4817
4818     attribute = smb_GetSMBParm(inp, 0);
4819         
4820     tp = smb_GetSMBData(inp, NULL);
4821     pathp = smb_ParseASCIIBlock(tp, &tp);
4822     if (smb_StoreAnsiFilenames)
4823         OemToChar(pathp,pathp);
4824
4825     osi_Log1(smb_logp, "SMB receive unlink %s",
4826              osi_LogSaveString(smb_logp, pathp));
4827
4828     spacep = inp->spacep;
4829     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4830
4831     userp = smb_GetUser(vcp, inp);
4832
4833     caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4834
4835     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4836     if (code) {
4837         cm_ReleaseUser(userp);
4838         return CM_ERROR_NOSUCHPATH;
4839     }
4840     code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
4841                     &req, &dscp);
4842     if (code) {
4843         cm_ReleaseUser(userp);
4844         return code;
4845     }
4846         
4847 #ifdef DFS_SUPPORT
4848     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4849         cm_ReleaseSCache(dscp);
4850         cm_ReleaseUser(userp);
4851         if ( WANTS_DFS_PATHNAMES(inp) )
4852             return CM_ERROR_PATH_NOT_COVERED;
4853         else
4854             return CM_ERROR_BADSHARENAME;
4855     }
4856 #endif /* DFS_SUPPORT */
4857
4858     /* otherwise, scp points to the parent directory. */
4859     if (!lastNamep) 
4860         lastNamep = pathp;
4861     else 
4862         lastNamep++;
4863
4864     rock.any = 0;
4865     rock.maskp = smb_FindMask(pathp);
4866     rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4867
4868     thyper.LowPart = 0;
4869     thyper.HighPart = 0;
4870     rock.userp = userp;
4871     rock.reqp = &req;
4872     rock.dscp = dscp;
4873     rock.vcp = vcp;
4874
4875     /* Now, if we aren't dealing with a wildcard match, we first try an exact 
4876      * match.  If that fails, we do a case insensitve match. 
4877      */
4878     if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
4879         !smb_IsStarMask(rock.maskp)) {
4880         code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4881         if (!rock.any) {
4882             thyper.LowPart = 0;
4883             thyper.HighPart = 0;
4884             rock.flags |= SMB_MASKFLAG_CASEFOLD;
4885         }
4886     }
4887  
4888     if (!rock.any)
4889         code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4890     
4891     if (code == CM_ERROR_STOPNOW) 
4892         code = 0;
4893
4894     cm_ReleaseUser(userp);
4895         
4896     cm_ReleaseSCache(dscp);
4897
4898     if (code == 0 && !rock.any)
4899         code = CM_ERROR_NOSUCHFILE;
4900     return code;
4901 }       
4902
4903 typedef struct smb_renameRock {
4904     cm_scache_t *odscp; /* old dir */
4905     cm_scache_t *ndscp; /* new dir */
4906     cm_user_t *userp;   /* user */
4907     cm_req_t *reqp;             /* request struct */
4908     smb_vc_t *vcp;              /* virtual circuit */
4909     char *maskp;                /* pointer to star pattern of old file name */
4910     int flags;              /* tilde, casefold, etc */
4911     char *newNamep;             /* ptr to the new file's name */
4912 } smb_renameRock_t;
4913
4914 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4915 {
4916     long code = 0;
4917     smb_renameRock_t *rockp;
4918     int caseFold;
4919     int match;
4920     char shortName[13];
4921
4922     rockp = (smb_renameRock_t *) vrockp;
4923
4924     caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4925     if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4926         caseFold |= CM_FLAG_8DOT3;
4927
4928     match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
4929     if (!match &&
4930         (rockp->flags & SMB_MASKFLAG_TILDE) &&
4931          !cm_Is8Dot3(dep->name)) {
4932         cm_Gen8Dot3Name(dep, shortName, NULL);
4933         match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
4934     }
4935     if (match) {
4936         code = cm_Rename(rockp->odscp, dep->name,
4937                          rockp->ndscp, rockp->newNamep, rockp->userp,
4938                          rockp->reqp);  
4939         /* if the call worked, stop doing the search now, since we
4940          * really only want to rename one file.
4941          */
4942         if (code == 0) 
4943             code = CM_ERROR_STOPNOW;
4944     }       
4945     else code = 0;
4946
4947     return code;
4948 }
4949
4950
4951 long 
4952 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, int attrs)
4953 {
4954     long code = 0;
4955     cm_space_t *spacep = NULL;
4956     smb_renameRock_t rock;
4957     cm_scache_t *oldDscp = NULL;
4958     cm_scache_t *newDscp = NULL;
4959     cm_scache_t *tmpscp= NULL;
4960     cm_scache_t *tmpscp2 = NULL;
4961     char *oldLastNamep;
4962     char *newLastNamep;
4963     osi_hyper_t thyper;
4964     cm_user_t *userp;
4965     int caseFold;
4966     char *tidPathp;
4967     DWORD filter;
4968     cm_req_t req;
4969
4970     userp = smb_GetUser(vcp, inp);
4971     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4972     if (code) {
4973         cm_ReleaseUser(userp);
4974         return CM_ERROR_NOSUCHPATH;
4975     }
4976
4977     cm_InitReq(&req);
4978     spacep = inp->spacep;
4979     smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
4980
4981     caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4982     code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
4983                     userp, tidPathp, &req, &oldDscp);
4984     if (code) {
4985         cm_ReleaseUser(userp);
4986         return code;
4987     }
4988         
4989 #ifdef DFS_SUPPORT
4990     if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
4991         cm_ReleaseSCache(oldDscp);
4992         cm_ReleaseUser(userp);
4993         if ( WANTS_DFS_PATHNAMES(inp) )
4994             return CM_ERROR_PATH_NOT_COVERED;
4995         else
4996             return CM_ERROR_BADSHARENAME;
4997     }
4998 #endif /* DFS_SUPPORT */
4999
5000     smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5001     code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5002                     userp, tidPathp, &req, &newDscp);
5003
5004     if (code) {
5005         cm_ReleaseSCache(oldDscp);
5006         cm_ReleaseUser(userp);
5007         return code;
5008     }
5009
5010 #ifdef DFS_SUPPORT
5011     if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5012         cm_ReleaseSCache(oldDscp);
5013         cm_ReleaseSCache(newDscp);
5014         cm_ReleaseUser(userp);
5015         if ( WANTS_DFS_PATHNAMES(inp) )
5016             return CM_ERROR_PATH_NOT_COVERED;
5017         else
5018             return CM_ERROR_BADSHARENAME;
5019     }
5020 #endif /* DFS_SUPPORT */
5021
5022
5023     /* otherwise, oldDscp and newDscp point to the corresponding directories.
5024      * next, get the component names, and lower case them.
5025      */
5026
5027     /* handle the old name first */
5028     if (!oldLastNamep) 
5029         oldLastNamep = oldPathp;
5030     else 
5031         oldLastNamep++;
5032
5033     /* and handle the new name, too */
5034     if (!newLastNamep) 
5035         newLastNamep = newPathp;
5036     else 
5037         newLastNamep++;
5038
5039     /* TODO: The old name could be a wildcard.  The new name must not be */
5040
5041     /* do the vnode call */
5042     rock.odscp = oldDscp;
5043     rock.ndscp = newDscp;
5044     rock.userp = userp;
5045     rock.reqp = &req;
5046     rock.vcp = vcp;
5047     rock.maskp = oldLastNamep;
5048     rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5049     rock.newNamep = newLastNamep;
5050
5051     /* Check if the file already exists; if so return error */
5052     code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5053     if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
5054         osi_Log2(smb_logp, "  lookup returns %ld for [%s]", code,
5055                  osi_LogSaveString(afsd_logp, newLastNamep));
5056
5057         /* Check if the old and the new names differ only in case. If so return
5058          * success, else return CM_ERROR_EXISTS 
5059          */
5060         if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
5061
5062             /* This would be a success only if the old file is *as same as* the new file */
5063             code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
5064             if (!code) {
5065                 if (tmpscp == tmpscp2) 
5066                     code = 0;
5067                 else 
5068                     code = CM_ERROR_EXISTS;
5069                 cm_ReleaseSCache(tmpscp2);
5070                 tmpscp2 = NULL;
5071             } else {
5072                 code = CM_ERROR_NOSUCHFILE;
5073             }
5074         } else {
5075             /* file exist, do not rename, also fixes move */
5076             osi_Log0(smb_logp, "Can't rename.  Target already exists");
5077             code = CM_ERROR_EXISTS;
5078         }
5079
5080         if (tmpscp != NULL)
5081             cm_ReleaseSCache(tmpscp);
5082         cm_ReleaseSCache(newDscp);
5083         cm_ReleaseSCache(oldDscp);
5084         cm_ReleaseUser(userp);
5085         return code; 
5086     }
5087
5088     /* Now search the directory for the pattern, and do the appropriate rename when found */
5089     thyper.LowPart = 0;         /* search dir from here */
5090     thyper.HighPart = 0;
5091
5092     code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5093     osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
5094
5095     if (code == CM_ERROR_STOPNOW)
5096         code = 0;
5097     else if (code == 0)
5098         code = CM_ERROR_NOSUCHFILE;
5099
5100     /* Handle Change Notification */
5101     /*
5102     * Being lazy, not distinguishing between files and dirs in this
5103     * filter, since we'd have to do a lookup.
5104     */
5105     filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
5106     if (oldDscp == newDscp) {
5107         if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5108             smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5109                              filter, oldDscp, oldLastNamep,
5110                              newLastNamep, TRUE);
5111     } else {
5112         if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5113             smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5114                              filter, oldDscp, oldLastNamep,
5115                              NULL, TRUE);
5116         if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5117             smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
5118                              filter, newDscp, newLastNamep,
5119                              NULL, TRUE);
5120     }
5121
5122     if (tmpscp != NULL) 
5123         cm_ReleaseSCache(tmpscp);
5124     cm_ReleaseUser(userp);
5125     cm_ReleaseSCache(oldDscp);
5126     cm_ReleaseSCache(newDscp);
5127     return code;
5128 }       
5129
5130 long 
5131 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp) 
5132 {
5133     long code = 0;
5134     cm_space_t *spacep = NULL;
5135     cm_scache_t *oldDscp = NULL;
5136     cm_scache_t *newDscp = NULL;
5137     cm_scache_t *tmpscp= NULL;
5138     cm_scache_t *tmpscp2 = NULL;
5139     cm_scache_t *sscp = NULL;
5140     char *oldLastNamep;
5141     char *newLastNamep;
5142     cm_user_t *userp;
5143     int caseFold;
5144     char *tidPathp;
5145     DWORD filter;
5146     cm_req_t req;
5147
5148     userp = smb_GetUser(vcp, inp);
5149
5150     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5151     if (code) {
5152         cm_ReleaseUser(userp);
5153         return CM_ERROR_NOSUCHPATH;
5154     }
5155
5156     cm_InitReq(&req);
5157
5158     caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5159
5160     spacep = inp->spacep;
5161     smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5162     
5163     code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5164                     userp, tidPathp, &req, &oldDscp);
5165     if (code) {
5166         cm_ReleaseUser(userp);
5167         return code;
5168     }
5169         
5170 #ifdef DFS_SUPPORT
5171     if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5172         cm_ReleaseSCache(oldDscp);
5173         cm_ReleaseUser(userp);
5174         if ( WANTS_DFS_PATHNAMES(inp) )
5175             return CM_ERROR_PATH_NOT_COVERED;
5176         else
5177             return CM_ERROR_BADSHARENAME;
5178     }
5179 #endif /* DFS_SUPPORT */
5180
5181     smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5182     code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5183                     userp, tidPathp, &req, &newDscp);
5184     if (code) {
5185         cm_ReleaseSCache(oldDscp);
5186         cm_ReleaseUser(userp);
5187         return code;
5188     }
5189
5190 #ifdef DFS_SUPPORT
5191     if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5192         cm_ReleaseSCache(newDscp);
5193         cm_ReleaseSCache(oldDscp);
5194         cm_ReleaseUser(userp);
5195         if ( WANTS_DFS_PATHNAMES(inp) )
5196             return CM_ERROR_PATH_NOT_COVERED;
5197         else
5198             return CM_ERROR_BADSHARENAME;
5199     }
5200 #endif /* DFS_SUPPORT */
5201
5202     /* Now, although we did two lookups for the two directories (because the same
5203      * directory can be referenced through different paths), we only allow hard links
5204      * within the same directory. */
5205     if (oldDscp != newDscp) {
5206         cm_ReleaseSCache(oldDscp);
5207         cm_ReleaseSCache(newDscp);
5208         cm_ReleaseUser(userp);
5209         return CM_ERROR_CROSSDEVLINK;
5210     }
5211
5212     /* handle the old name first */
5213     if (!oldLastNamep) 
5214         oldLastNamep = oldPathp;
5215     else 
5216         oldLastNamep++;
5217
5218     /* and handle the new name, too */
5219     if (!newLastNamep) 
5220         newLastNamep = newPathp;
5221     else 
5222         newLastNamep++;
5223
5224     /* now lookup the old name */
5225     osi_Log1(smb_logp,"  looking up [%s]", osi_LogSaveString(smb_logp,oldLastNamep));
5226     code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
5227     if (code) {
5228         cm_ReleaseSCache(oldDscp);
5229         cm_ReleaseSCache(newDscp);
5230         cm_ReleaseUser(userp);
5231         return code;
5232     }
5233
5234     /* Check if the file already exists; if so return error */
5235     code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5236     if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
5237         osi_Log2(smb_logp, "  lookup returns %ld for [%s]", code,
5238                  osi_LogSaveString(afsd_logp, newLastNamep));
5239
5240         /* if the existing link is to the same file, then we return success */
5241         if (!code) {
5242             if(sscp == tmpscp) {
5243                 code = 0;
5244             } else {
5245                 osi_Log0(smb_logp, "Can't create hardlink.  Target already exists");
5246                 code = CM_ERROR_EXISTS;
5247             }
5248         }
5249
5250         if (tmpscp != NULL)
5251             cm_ReleaseSCache(tmpscp);
5252         cm_ReleaseSCache(sscp);
5253         cm_ReleaseSCache(newDscp);
5254         cm_ReleaseSCache(oldDscp);
5255         cm_ReleaseUser(userp);
5256         return code; 
5257     }
5258
5259     /* now create the hardlink */
5260     osi_Log1(smb_logp,"  Attempting to create new link [%s]", osi_LogSaveString(smb_logp, newLastNamep));
5261     code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
5262     osi_Log1(smb_logp,"  Link returns %d", code);
5263
5264     /* Handle Change Notification */
5265     if (code == 0) {
5266         filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
5267         if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5268             smb_NotifyChange(FILE_ACTION_ADDED,
5269                              filter, newDscp, newLastNamep,
5270                              NULL, TRUE);
5271     }
5272
5273     if (tmpscp != NULL) 
5274         cm_ReleaseSCache(tmpscp);
5275     cm_ReleaseUser(userp);
5276     cm_ReleaseSCache(sscp);
5277     cm_ReleaseSCache(oldDscp);
5278     cm_ReleaseSCache(newDscp);
5279     return code;
5280 }
5281
5282 long 
5283 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5284 {
5285     char *oldPathp;
5286     char *newPathp;
5287     char *tp;
5288
5289     tp = smb_GetSMBData(inp, NULL);
5290     oldPathp = smb_ParseASCIIBlock(tp, &tp);
5291     if (smb_StoreAnsiFilenames)
5292         OemToChar(oldPathp,oldPathp);
5293     newPathp = smb_ParseASCIIBlock(tp, &tp);
5294     if (smb_StoreAnsiFilenames)
5295         OemToChar(newPathp,newPathp);
5296
5297     osi_Log2(smb_logp, "smb rename [%s] to [%s]",
5298               osi_LogSaveString(smb_logp, oldPathp),
5299               osi_LogSaveString(smb_logp, newPathp));
5300
5301     return smb_Rename(vcp,inp,oldPathp,newPathp,0);
5302 }
5303
5304
5305
5306 typedef struct smb_rmdirRock {
5307     cm_scache_t *dscp;
5308     cm_user_t *userp;
5309     cm_req_t *reqp;
5310     char *maskp;                /* pointer to the star pattern */
5311     int flags;
5312     int any;
5313 } smb_rmdirRock_t;
5314
5315 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5316 {       
5317     long code = 0;
5318     smb_rmdirRock_t *rockp;
5319     int match;
5320     char shortName[13];
5321     char *matchName;
5322         
5323     rockp = (smb_rmdirRock_t *) vrockp;
5324
5325     matchName = dep->name;
5326     if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
5327         match = (cm_stricmp(matchName, rockp->maskp) == 0);
5328     else
5329         match = (strcmp(matchName, rockp->maskp) == 0);
5330     if (!match &&
5331          (rockp->flags & SMB_MASKFLAG_TILDE) &&
5332          !cm_Is8Dot3(dep->name)) {
5333         cm_Gen8Dot3Name(dep, shortName, NULL);
5334         matchName = shortName;
5335         match = (cm_stricmp(matchName, rockp->maskp) == 0);
5336     }       
5337     if (match) {
5338         osi_Log1(smb_logp, "Removing directory %s",
5339                  osi_LogSaveString(smb_logp, matchName));
5340         code = cm_RemoveDir(dscp, dep->name, rockp->userp, rockp->reqp);
5341         if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5342             smb_NotifyChange(FILE_ACTION_REMOVED,
5343                              FILE_NOTIFY_CHANGE_DIR_NAME,
5344                              dscp, dep->name, NULL, TRUE);
5345         if (code == 0)
5346             rockp->any = 1;
5347     }
5348     else code = 0;
5349
5350     return code;
5351 }
5352
5353 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5354 {
5355     long code = 0;
5356     char *pathp;
5357     char *tp;
5358     cm_space_t *spacep;
5359     cm_scache_t *dscp;
5360     char *lastNamep;
5361     smb_rmdirRock_t rock;
5362     cm_user_t *userp;
5363     osi_hyper_t thyper;
5364     int caseFold;
5365     char *tidPathp;
5366     cm_req_t req;
5367
5368     cm_InitReq(&req);
5369
5370     tp = smb_GetSMBData(inp, NULL);
5371     pathp = smb_ParseASCIIBlock(tp, &tp);
5372     if (smb_StoreAnsiFilenames)
5373         OemToChar(pathp,pathp);
5374
5375     spacep = inp->spacep;
5376     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5377
5378     userp = smb_GetUser(vcp, inp);
5379
5380     caseFold = CM_FLAG_CASEFOLD;
5381
5382     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5383     if (code) {
5384         cm_ReleaseUser(userp);
5385         return CM_ERROR_NOSUCHPATH;
5386     }
5387     code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5388                     userp, tidPathp, &req, &dscp);
5389
5390     if (code) {
5391         cm_ReleaseUser(userp);
5392         return code;
5393     }
5394         
5395 #ifdef DFS_SUPPORT
5396     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5397         cm_ReleaseSCache(dscp);
5398         cm_ReleaseUser(userp);
5399         if ( WANTS_DFS_PATHNAMES(inp) )
5400             return CM_ERROR_PATH_NOT_COVERED;
5401         else
5402             return CM_ERROR_BADSHARENAME;
5403     }
5404 #endif /* DFS_SUPPORT */
5405
5406     /* otherwise, scp points to the parent directory. */
5407     if (!lastNamep) 
5408         lastNamep = pathp;
5409     else 
5410         lastNamep++;
5411         
5412     rock.any = 0;
5413     rock.maskp = lastNamep;
5414     rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5415
5416     thyper.LowPart = 0;
5417     thyper.HighPart = 0;
5418     rock.userp = userp;
5419     rock.reqp = &req;
5420     rock.dscp = dscp;
5421     /* First do a case sensitive match, and if that fails, do a case insensitive match */
5422     code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5423     if (code == 0 && !rock.any) {
5424         thyper.LowPart = 0;
5425         thyper.HighPart = 0;
5426         rock.flags |= SMB_MASKFLAG_CASEFOLD;
5427         code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5428     }
5429
5430     cm_ReleaseUser(userp);
5431         
5432     cm_ReleaseSCache(dscp);
5433
5434     if (code == 0 && !rock.any)
5435         code = CM_ERROR_NOSUCHFILE;        
5436     return code;
5437 }
5438
5439 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5440 {
5441     unsigned short fid;
5442     smb_fid_t *fidp;
5443     cm_user_t *userp;
5444     long code = 0;
5445     cm_req_t req;
5446
5447     cm_InitReq(&req);
5448
5449     fid = smb_GetSMBParm(inp, 0);
5450
5451     osi_Log1(smb_logp, "SMB flush fid %d", fid);
5452
5453     fid = smb_ChainFID(fid, inp);
5454     fidp = smb_FindFID(vcp, fid, 0);
5455     if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
5456         if (fidp)
5457             smb_ReleaseFID(fidp);
5458         return CM_ERROR_BADFD;
5459     }
5460         
5461     userp = smb_GetUser(vcp, inp);
5462
5463     lock_ObtainMutex(&fidp->mx);
5464     if (fidp->flags & SMB_FID_OPENWRITE)
5465         code = cm_FSync(fidp->scp, userp, &req);
5466     else 
5467         code = 0;
5468     lock_ReleaseMutex(&fidp->mx);
5469         
5470     smb_ReleaseFID(fidp);
5471         
5472     cm_ReleaseUser(userp);
5473         
5474     return code;
5475 }
5476
5477 struct smb_FullNameRock {
5478     char *name;
5479     cm_scache_t *vnode;
5480     char *fullName;
5481 };
5482
5483 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
5484                      osi_hyper_t *offp)
5485 {
5486     char shortName[13];
5487     struct smb_FullNameRock *vrockp;
5488
5489     vrockp = (struct smb_FullNameRock *)rockp;
5490
5491     if (!cm_Is8Dot3(dep->name)) {
5492         cm_Gen8Dot3Name(dep, shortName, NULL);
5493
5494         if (cm_stricmp(shortName, vrockp->name) == 0) {
5495             vrockp->fullName = strdup(dep->name);
5496             return CM_ERROR_STOPNOW;
5497         }
5498     }
5499     if (cm_stricmp(dep->name, vrockp->name) == 0 &&
5500         ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
5501         ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
5502         vrockp->fullName = strdup(dep->name);
5503         return CM_ERROR_STOPNOW;
5504     }
5505     return 0;
5506 }
5507
5508 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
5509                   char **newPathp, cm_user_t *userp, cm_req_t *reqp)
5510 {
5511     struct smb_FullNameRock rock;
5512     long code = 0;
5513
5514     rock.name = pathp;
5515     rock.vnode = scp;
5516
5517     code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL); 
5518     if (code == CM_ERROR_STOPNOW)
5519         *newPathp = rock.fullName;
5520     else
5521         *newPathp = strdup(pathp);
5522 }
5523
5524 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
5525                   afs_uint32 dosTime) {
5526     long code = 0;
5527     cm_req_t req;
5528
5529     osi_Log3(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d vcp=0x%x)",
5530              fidp, fidp->fid, vcp);
5531
5532     if (!userp) {
5533         if (!fidp->userp) {
5534             osi_Log0(smb_logp, "  No user specified.  Not closing fid");
5535         return CM_ERROR_BADFD;
5536     }
5537         
5538         userp = fidp->userp;    /* no hold required since fidp is held
5539                                    throughout the function */
5540     }
5541
5542     cm_InitReq(&req);
5543
5544     lock_ObtainMutex(&fidp->mx);
5545
5546     /* Don't jump the gun on an async raw write */
5547     while (fidp->raw_writers) {
5548         lock_ReleaseMutex(&fidp->mx);
5549         thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
5550         lock_ObtainMutex(&fidp->mx);
5551     }
5552
5553     fidp->flags |= SMB_FID_DELETE;
5554         
5555     /* watch for ioctl closes, and read-only opens */
5556     if (fidp->scp != NULL &&
5557         (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
5558          == SMB_FID_OPENWRITE) {
5559         if (dosTime != 0 && dosTime != -1) {
5560             fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5561             /* This fixes defect 10958 */
5562             CompensateForSmbClientLastWriteTimeBugs(&dosTime);
5563             smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
5564         }
5565         code = cm_FSync(fidp->scp, userp, &req);
5566     }
5567     else 
5568         code = 0;
5569
5570     /* unlock any pending locks */
5571     if (!(fidp->flags & SMB_FID_IOCTL) && fidp->scp &&
5572         fidp->scp->fileType == CM_SCACHETYPE_FILE) {
5573         cm_key_t key;
5574         cm_scache_t * scp;
5575         long tcode;
5576
5577         /* CM_UNLOCK_BY_FID doesn't look at the process ID.  We pass
5578            in zero. */
5579         key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
5580         scp = fidp->scp;
5581         cm_HoldSCache(scp);
5582         lock_ObtainMutex(&scp->mx);
5583
5584         tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
5585                           CM_SCACHESYNC_NEEDCALLBACK
5586                           | CM_SCACHESYNC_GETSTATUS
5587                           | CM_SCACHESYNC_LOCK);
5588
5589         if (tcode) {
5590             osi_Log1(smb_logp,
5591                      "smb CoreClose SyncOp failure code 0x%x", tcode);
5592             goto post_syncopdone;
5593         }
5594
5595         cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
5596
5597         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
5598
5599     post_syncopdone:
5600
5601         lock_ReleaseMutex(&scp->mx);
5602         cm_ReleaseSCache(scp);
5603     }
5604
5605     if (fidp->flags & SMB_FID_DELONCLOSE) {
5606         cm_scache_t *dscp = fidp->NTopen_dscp;
5607         char *pathp = fidp->NTopen_pathp;
5608         char *fullPathp;
5609
5610         smb_FullName(dscp, fidp->scp, pathp, &fullPathp, userp, &req);
5611         if (fidp->scp->fileType == CM_SCACHETYPE_DIRECTORY) {
5612             code = cm_RemoveDir(dscp, fullPathp, userp, &req);
5613             if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5614                 smb_NotifyChange(FILE_ACTION_REMOVED,
5615                                  FILE_NOTIFY_CHANGE_DIR_NAME,
5616                                  dscp, fullPathp, NULL, TRUE);
5617         } else {
5618             code = cm_Unlink(dscp, fullPathp, userp, &req);
5619             if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5620                 smb_NotifyChange(FILE_ACTION_REMOVED,
5621                                  FILE_NOTIFY_CHANGE_FILE_NAME,
5622                                  dscp, fullPathp, NULL, TRUE);
5623         }
5624         free(fullPathp);
5625     }
5626     lock_ReleaseMutex(&fidp->mx);
5627
5628     if (fidp->flags & SMB_FID_NTOPEN) {
5629         cm_ReleaseSCache(fidp->NTopen_dscp);
5630         free(fidp->NTopen_pathp);
5631         fidp->NTopen_pathp = NULL;
5632     }
5633     if (fidp->NTopen_wholepathp) {
5634         free(fidp->NTopen_wholepathp);
5635         fidp->NTopen_wholepathp = NULL;
5636     }
5637
5638     return code;
5639 }
5640
5641 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5642 {
5643     unsigned short fid;
5644     smb_fid_t *fidp;
5645     cm_user_t *userp;
5646     long code = 0;
5647     afs_uint32 dosTime;
5648
5649     fid = smb_GetSMBParm(inp, 0);
5650     dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5651
5652     osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
5653
5654     fid = smb_ChainFID(fid, inp);
5655     fidp = smb_FindFID(vcp, fid, 0);
5656     if (!fidp) {
5657         return CM_ERROR_BADFD;
5658     }
5659         
5660     userp = smb_GetUser(vcp, inp);
5661
5662     code = smb_CloseFID(vcp, fidp, userp, dosTime);
5663     
5664     smb_ReleaseFID(fidp);
5665     cm_ReleaseUser(userp);
5666     return code;
5667 }
5668
5669 /*
5670  * smb_ReadData -- common code for Read, Read And X, and Raw Read
5671  */
5672 #ifndef DJGPP
5673 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5674         cm_user_t *userp, long *readp)
5675 #else /* DJGPP */
5676 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5677         cm_user_t *userp, long *readp, int dosflag)
5678 #endif /* !DJGPP */
5679 {
5680     osi_hyper_t offset;
5681     long code = 0;
5682     cm_scache_t *scp;
5683     cm_buf_t *bufferp;
5684     osi_hyper_t fileLength;
5685     osi_hyper_t thyper;
5686     osi_hyper_t lastByte;
5687     osi_hyper_t bufferOffset;
5688     long bufIndex, nbytes;
5689     int chunk;
5690     int sequential = 0;
5691     cm_req_t req;
5692
5693     cm_InitReq(&req);
5694
5695     bufferp = NULL;
5696     offset = *offsetp;
5697
5698     lock_ObtainMutex(&fidp->mx);
5699     scp = fidp->scp;
5700     lock_ObtainMutex(&scp->mx);
5701
5702     if (offset.HighPart == 0) {
5703         chunk = offset.LowPart >> cm_logChunkSize;
5704         if (chunk != fidp->curr_chunk) {
5705             fidp->prev_chunk = fidp->curr_chunk;
5706             fidp->curr_chunk = chunk;
5707         }
5708         if (fidp->curr_chunk == fidp->prev_chunk + 1)
5709             sequential = 1;
5710     }
5711
5712     /* start by looking up the file's end */
5713     code = cm_SyncOp(scp, NULL, userp, &req, 0,
5714                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5715     if (code) goto done;
5716
5717     /* now we have the entry locked, look up the length */
5718     fileLength = scp->length;
5719
5720     /* adjust count down so that it won't go past EOF */
5721     thyper.LowPart = count;
5722     thyper.HighPart = 0;
5723     thyper = LargeIntegerAdd(offset, thyper);   /* where read should end */
5724     lastByte = thyper;
5725     if (LargeIntegerGreaterThan(thyper, fileLength)) {
5726         /* we'd read past EOF, so just stop at fileLength bytes.
5727          * Start by computing how many bytes remain in the file.
5728          */
5729         thyper = LargeIntegerSubtract(fileLength, offset);
5730
5731         /* if we are past EOF, read 0 bytes */
5732         if (LargeIntegerLessThanZero(thyper))
5733             count = 0;
5734         else
5735             count = thyper.LowPart;
5736     }       
5737
5738     *readp = count;
5739
5740     /* now, copy the data one buffer at a time,
5741      * until we've filled the request packet
5742      */
5743     while (1) {
5744         /* if we've copied all the data requested, we're done */
5745         if (count <= 0) break;
5746
5747         /* otherwise, load up a buffer of data */
5748         thyper.HighPart = offset.HighPart;
5749         thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
5750         if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5751             /* wrong buffer */
5752             if (bufferp) {
5753                 buf_Release(bufferp);
5754                 bufferp = NULL;
5755             }
5756             lock_ReleaseMutex(&scp->mx);
5757
5758             lock_ObtainRead(&scp->bufCreateLock);
5759             code = buf_Get(scp, &thyper, &bufferp);
5760             lock_ReleaseRead(&scp->bufCreateLock);
5761
5762             lock_ObtainMutex(&scp->mx);
5763             if (code) goto done;
5764             bufferOffset = thyper;
5765
5766             /* now get the data in the cache */
5767             while (1) {
5768                 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
5769                                  CM_SCACHESYNC_NEEDCALLBACK |
5770                                  CM_SCACHESYNC_READ);
5771                 if (code) goto done;
5772                                 
5773                 if (cm_HaveBuffer(scp, bufferp, 0)) break;
5774
5775                 /* otherwise, load the buffer and try again */
5776                 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
5777                 if (code) break;
5778             }
5779             if (code) {
5780                 buf_Release(bufferp);
5781                 bufferp = NULL;
5782                 goto done;
5783             }
5784         }       /* if (wrong buffer) ... */
5785
5786         /* now we have the right buffer loaded.  Copy out the
5787          * data from here to the user's buffer.
5788          */
5789         bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
5790
5791         /* and figure out how many bytes we want from this buffer */
5792         nbytes = cm_data.buf_blockSize - bufIndex;      /* what remains in buffer */
5793         if (nbytes > count) nbytes = count;     /* don't go past EOF */
5794
5795         /* now copy the data */
5796 #ifdef DJGPP
5797         if (dosflag)
5798             dosmemput(bufferp->datap + bufIndex, nbytes, (dos_ptr)op);
5799         else
5800 #endif /* DJGPP */
5801             memcpy(op, bufferp->datap + bufIndex, nbytes);
5802                 
5803         /* adjust counters, pointers, etc. */
5804         op += nbytes;
5805         count -= nbytes;
5806         thyper.LowPart = nbytes;
5807         thyper.HighPart = 0;
5808         offset = LargeIntegerAdd(thyper, offset);
5809     } /* while 1 */
5810
5811   done:
5812     lock_ReleaseMutex(&scp->mx);
5813     lock_ReleaseMutex(&fidp->mx);
5814     if (bufferp) 
5815         buf_Release(bufferp);
5816
5817     if (code == 0 && sequential)
5818         cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
5819
5820     return code;
5821 }
5822
5823 /*
5824  * smb_WriteData -- common code for Write and Raw Write
5825  */
5826 #ifndef DJGPP
5827 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5828         cm_user_t *userp, long *writtenp)
5829 #else /* DJGPP */
5830 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5831         cm_user_t *userp, long *writtenp, int dosflag)
5832 #endif /* !DJGPP */
5833 {
5834     osi_hyper_t offset;
5835     long code = 0;
5836     long written = 0;
5837     cm_scache_t *scp;
5838     osi_hyper_t fileLength;     /* file's length at start of write */
5839     osi_hyper_t minLength;      /* don't read past this */
5840     long nbytes;                /* # of bytes to transfer this iteration */
5841     cm_buf_t *bufferp;
5842     osi_hyper_t thyper;         /* hyper tmp variable */
5843     osi_hyper_t bufferOffset;
5844     long bufIndex;              /* index in buffer where our data is */
5845     int doWriteBack;
5846     osi_hyper_t writeBackOffset;/* offset of region to write back when
5847                                  * I/O is done */
5848     DWORD filter = 0;
5849     cm_req_t req;
5850
5851     osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
5852               fidp->fid, offsetp->LowPart, count);
5853
5854     *writtenp = 0;
5855
5856     cm_InitReq(&req);
5857
5858     bufferp = NULL;
5859     doWriteBack = 0;
5860     offset = *offsetp;
5861
5862     lock_ObtainMutex(&fidp->mx);
5863     scp = fidp->scp;
5864     lock_ObtainMutex(&scp->mx);
5865
5866     /* start by looking up the file's end */
5867     code = cm_SyncOp(scp, NULL, userp, &req, 0,
5868                       CM_SCACHESYNC_NEEDCALLBACK
5869                       | CM_SCACHESYNC_SETSTATUS
5870                       | CM_SCACHESYNC_GETSTATUS);
5871     if (code) 
5872         goto done;
5873         
5874     /* make sure we have a writable FD */
5875     if (!(fidp->flags & SMB_FID_OPENWRITE)) {
5876         code = CM_ERROR_BADFDOP;
5877         goto done;
5878     }
5879
5880     /* now we have the entry locked, look up the length */
5881     fileLength = scp->length;
5882     minLength = fileLength;
5883     if (LargeIntegerGreaterThan(minLength, scp->serverLength))
5884         minLength = scp->serverLength;
5885
5886     /* adjust file length if we extend past EOF */
5887     thyper.LowPart = count;
5888     thyper.HighPart = 0;
5889     thyper = LargeIntegerAdd(offset, thyper);   /* where write should end */
5890     if (LargeIntegerGreaterThan(thyper, fileLength)) {
5891         /* we'd write past EOF, so extend the file */
5892         scp->mask |= CM_SCACHEMASK_LENGTH;
5893         scp->length = thyper;
5894         filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
5895     } else
5896         filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
5897
5898     /* now, if the new position (thyper) and the old (offset) are in
5899      * different storeback windows, remember to store back the previous
5900      * storeback window when we're done with the write.
5901      */
5902     if ((thyper.LowPart & (-cm_chunkSize)) !=
5903          (offset.LowPart & (-cm_chunkSize))) {
5904         /* they're different */
5905         doWriteBack = 1;
5906         writeBackOffset.HighPart = offset.HighPart;
5907         writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
5908     }
5909         
5910     *writtenp = count;
5911
5912     /* now, copy the data one buffer at a time, until we've filled the
5913      * request packet */
5914     while (1) {
5915         /* if we've copied all the data requested, we're done */
5916         if (count <= 0) 
5917             break;
5918
5919         /* handle over quota or out of space */
5920         if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
5921             *writtenp = written;
5922             code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
5923             break;
5924         }
5925
5926         /* otherwise, load up a buffer of data */
5927         thyper.HighPart = offset.HighPart;
5928         thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
5929         if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5930             /* wrong buffer */
5931             if (bufferp) {
5932                 lock_ReleaseMutex(&bufferp->mx);
5933                 buf_Release(bufferp);
5934                 bufferp = NULL;
5935             }   
5936             lock_ReleaseMutex(&scp->mx);
5937
5938             lock_ObtainRead(&scp->bufCreateLock);
5939             code = buf_Get(scp, &thyper, &bufferp);
5940             lock_ReleaseRead(&scp->bufCreateLock);
5941
5942             lock_ObtainMutex(&bufferp->mx);
5943             lock_ObtainMutex(&scp->mx);
5944             if (code) goto done;
5945
5946             bufferOffset = thyper;
5947
5948             /* now get the data in the cache */
5949             while (1) {
5950                 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
5951                                   CM_SCACHESYNC_NEEDCALLBACK
5952                                   | CM_SCACHESYNC_WRITE
5953                                   | CM_SCACHESYNC_BUFLOCKED);
5954                 if (code) 
5955                     goto done;
5956
5957                 /* If we're overwriting the entire buffer, or
5958                  * if we're writing at or past EOF, mark the
5959                  * buffer as current so we don't call
5960                  * cm_GetBuffer.  This skips the fetch from the
5961                  * server in those cases where we're going to 
5962                  * obliterate all the data in the buffer anyway,
5963                  * or in those cases where there is no useful
5964                  * data at the server to start with.
5965                  *
5966                  * Use minLength instead of scp->length, since
5967                  * the latter has already been updated by this
5968                  * call.
5969                  */
5970                 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
5971                      || LargeIntegerEqualTo(offset, bufferp->offset)
5972                      && (count >= cm_data.buf_blockSize
5973                           || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
5974                                                                                ConvertLongToLargeInteger(count)),
5975                                                                minLength))) {
5976                     if (count < cm_data.buf_blockSize
5977                          && bufferp->dataVersion == -1)
5978                         memset(bufferp->datap, 0,
5979                                 cm_data.buf_blockSize);
5980                     bufferp->dataVersion = scp->dataVersion;
5981                 }
5982
5983                 if (cm_HaveBuffer(scp, bufferp, 1)) break;
5984
5985                 /* otherwise, load the buffer and try again */
5986                 lock_ReleaseMutex(&bufferp->mx);
5987                 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5988                                      &req);
5989                 lock_ReleaseMutex(&scp->mx);
5990                 lock_ObtainMutex(&bufferp->mx);
5991                 lock_ObtainMutex(&scp->mx);
5992                 if (code) break;
5993             }
5994             if (code) {
5995                 lock_ReleaseMutex(&bufferp->mx);
5996                 buf_Release(bufferp);
5997                 bufferp = NULL;
5998                 goto done;
5999             }
6000         }       /* if (wrong buffer) ... */
6001
6002         /* now we have the right buffer loaded.  Copy out the
6003          * data from here to the user's buffer.
6004          */
6005         bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6006
6007         /* and figure out how many bytes we want from this buffer */
6008         nbytes = cm_data.buf_blockSize - bufIndex;      /* what remains in buffer */
6009         if (nbytes > count) 
6010             nbytes = count;     /* don't go past end of request */
6011
6012         /* now copy the data */
6013 #ifdef DJGPP
6014         if (dosflag)
6015             dosmemget((dos_ptr)op, nbytes, bufferp->datap + bufIndex);
6016         else
6017 #endif /* DJGPP */
6018             memcpy(bufferp->datap + bufIndex, op, nbytes);
6019         buf_SetDirty(bufferp);
6020
6021         /* and record the last writer */
6022         if (bufferp->userp != userp) {
6023             cm_HoldUser(userp);
6024             if (bufferp->userp) 
6025                 cm_ReleaseUser(bufferp->userp);
6026             bufferp->userp = userp;
6027         }
6028
6029         /* adjust counters, pointers, etc. */
6030         op += nbytes;
6031         count -= nbytes;
6032         written += nbytes;
6033         thyper.LowPart = nbytes;
6034         thyper.HighPart = 0;
6035         offset = LargeIntegerAdd(thyper, offset);
6036     } /* while 1 */
6037
6038   done:
6039     lock_ReleaseMutex(&scp->mx);
6040     lock_ReleaseMutex(&fidp->mx);
6041     if (bufferp) {
6042         lock_ReleaseMutex(&bufferp->mx);
6043         buf_Release(bufferp);
6044     }
6045
6046     if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
6047          && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
6048         smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
6049                           fidp->NTopen_dscp, fidp->NTopen_pathp,
6050                           NULL, TRUE);
6051     }       
6052
6053     if (code == 0 && doWriteBack) {
6054         long code2;
6055         lock_ObtainMutex(&scp->mx);
6056         osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
6057                   fidp->fid);
6058         code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
6059         osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns %d",
6060                   fidp->fid,code2);
6061         lock_ReleaseMutex(&scp->mx);
6062         cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
6063                             writeBackOffset.HighPart, cm_chunkSize, 0, userp);
6064     }
6065
6066     osi_Log3(smb_logp, "smb_WriteData fid %d returns %d written %d",
6067               fidp->fid, code, *writtenp);
6068     return code;
6069 }
6070
6071 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6072 {
6073     osi_hyper_t offset;
6074     long count, written = 0, total_written = 0;
6075     unsigned short fd;
6076     unsigned pid;
6077     smb_fid_t *fidp;
6078     long code = 0;
6079     cm_user_t *userp;
6080     cm_attr_t truncAttr;        /* attribute struct used for truncating file */
6081     char *op;
6082     int inDataBlockCount;
6083
6084     fd = smb_GetSMBParm(inp, 0);
6085     count = smb_GetSMBParm(inp, 1);
6086     offset.HighPart = 0;        /* too bad */
6087     offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6088
6089     op = smb_GetSMBData(inp, NULL);
6090     op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
6091
6092     osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
6093              fd, offset.LowPart, count);
6094         
6095     fd = smb_ChainFID(fd, inp);
6096     fidp = smb_FindFID(vcp, fd, 0);
6097     if (!fidp) {
6098         return CM_ERROR_BADFD;
6099     }
6100         
6101     if (fidp->flags & SMB_FID_IOCTL)
6102         return smb_IoctlWrite(fidp, vcp, inp, outp);
6103         
6104     userp = smb_GetUser(vcp, inp);
6105
6106     /* special case: 0 bytes transferred means truncate to this position */
6107     if (count == 0) {
6108         cm_req_t req;
6109
6110         cm_InitReq(&req);
6111
6112         truncAttr.mask = CM_ATTRMASK_LENGTH;
6113         truncAttr.length.LowPart = offset.LowPart;
6114         truncAttr.length.HighPart = 0;
6115         lock_ObtainMutex(&fidp->mx);
6116         code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
6117         lock_ReleaseMutex(&fidp->mx);
6118         smb_SetSMBParm(outp, 0, /* count */ 0);
6119         smb_SetSMBDataLength(outp, 0);
6120         fidp->flags |= SMB_FID_LENGTHSETDONE;
6121         goto done;
6122     }
6123
6124     {
6125         cm_key_t key;
6126         LARGE_INTEGER LOffset;
6127         LARGE_INTEGER LLength;
6128
6129         pid = ((smb_t *) inp)->pid;
6130         key = cm_GenerateKey(vcp->vcID, pid, fd);
6131
6132         LOffset.HighPart = offset.HighPart;
6133         LOffset.LowPart = offset.LowPart;
6134         LLength.HighPart = 0;
6135         LLength.LowPart = count;
6136
6137         lock_ObtainMutex(&fidp->scp->mx);
6138         code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6139         lock_ReleaseMutex(&fidp->scp->mx);
6140
6141         if (code)
6142             goto done;
6143     }
6144
6145     /*
6146      * Work around bug in NT client
6147      *
6148      * When copying a file, the NT client should first copy the data,
6149      * then copy the last write time.  But sometimes the NT client does
6150      * these in the wrong order, so the data copies would inadvertently
6151      * cause the last write time to be overwritten.  We try to detect this,
6152      * and don't set client mod time if we think that would go against the
6153      * intention.
6154      */
6155     if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6156         fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6157         fidp->scp->clientModTime = time(NULL);
6158     }
6159
6160     code = 0;
6161     while ( code == 0 && count > 0 ) {
6162 #ifndef DJGPP
6163         code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6164 #else /* DJGPP */
6165         code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
6166 #endif /* !DJGPP */
6167         if (code == 0 && written == 0)
6168             code = CM_ERROR_PARTIALWRITE;
6169
6170         offset.LowPart += written;
6171         count -= written;
6172         total_written += written;
6173         written = 0;
6174     }
6175     
6176     /* set the packet data length to 3 bytes for the data block header,
6177      * plus the size of the data.
6178      */
6179     smb_SetSMBParm(outp, 0, total_written);
6180     smb_SetSMBDataLength(outp, 0);
6181
6182   done:
6183     smb_ReleaseFID(fidp);
6184     cm_ReleaseUser(userp);
6185
6186     return code;
6187 }
6188
6189 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6190                           NCB *ncbp, raw_write_cont_t *rwcp)
6191 {
6192     unsigned short fd;
6193     smb_fid_t *fidp;
6194     cm_user_t *userp;
6195 #ifndef DJGPP
6196     char *rawBuf;
6197 #else /* DJGPP */
6198     dos_ptr rawBuf;
6199 #endif /* !DJGPP */
6200     long written = 0;
6201     long code = 0;
6202
6203     fd = smb_GetSMBParm(inp, 0);
6204     fidp = smb_FindFID(vcp, fd, 0);
6205
6206     osi_Log2(smb_logp, "Completing Raw Write offset %x count %x",
6207              rwcp->offset.LowPart, rwcp->count);
6208
6209     userp = smb_GetUser(vcp, inp);
6210
6211 #ifndef DJGPP
6212     rawBuf = rwcp->buf;
6213     code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
6214                                                  &written);
6215 #else /* DJGPP */
6216     rawBuf = (dos_ptr) rwcp->buf;
6217     code = smb_WriteData(fidp, &rwcp->offset, rwcp->count,
6218                          (unsigned char *) rawBuf, userp,
6219                          &written, TRUE);
6220 #endif /* !DJGPP */
6221
6222     if (rwcp->writeMode & 0x1) {        /* synchronous */
6223         smb_t *op;
6224
6225         smb_FormatResponsePacket(vcp, inp, outp);
6226         op = (smb_t *) outp;
6227         op->com = 0x20;         /* SMB_COM_WRITE_COMPLETE */
6228         smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
6229         smb_SetSMBDataLength(outp,  0);
6230         smb_SendPacket(vcp, outp);
6231         smb_FreePacket(outp);
6232     }
6233     else {                              /* asynchronous */
6234         lock_ObtainMutex(&fidp->mx);
6235         fidp->raw_writers--;
6236         if (fidp->raw_writers == 0)
6237             thrd_SetEvent(fidp->raw_write_event);
6238         lock_ReleaseMutex(&fidp->mx);
6239     }
6240
6241     /* Give back raw buffer */
6242     lock_ObtainMutex(&smb_RawBufLock);
6243 #ifndef DJGPP
6244     *((char **)rawBuf) = smb_RawBufs;
6245 #else /* DJGPP */
6246     _farpokel(_dos_ds, rawBuf, smb_RawBufs);
6247 #endif /* !DJGPP */
6248     smb_RawBufs = rawBuf;
6249     lock_ReleaseMutex(&smb_RawBufLock);
6250
6251     smb_ReleaseFID(fidp);
6252     cm_ReleaseUser(userp);
6253 }
6254
6255 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6256 {
6257     return 0;
6258 }
6259
6260 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
6261 {
6262     osi_hyper_t offset;
6263     long count, written = 0, total_written = 0;
6264     long totalCount;
6265     unsigned short fd;
6266     smb_fid_t *fidp;
6267     long code = 0;
6268     cm_user_t *userp;
6269     char *op;
6270     unsigned short writeMode;
6271 #ifndef DJGPP
6272     char *rawBuf;
6273 #else /* DJGPP */
6274     dos_ptr rawBuf;
6275 #endif /* !DJGPP */
6276
6277     fd = smb_GetSMBParm(inp, 0);
6278     totalCount = smb_GetSMBParm(inp, 1);
6279     count = smb_GetSMBParm(inp, 10);
6280     offset.HighPart = 0;        /* too bad */
6281     offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6282     writeMode = smb_GetSMBParm(inp, 7);
6283
6284     op = (char *) inp->data;
6285     op += smb_GetSMBParm(inp, 11);
6286
6287     osi_Log4(smb_logp,
6288              "smb_ReceiveCoreWriteRaw fd %d, off 0x%x, size 0x%x, WriteMode 0x%x",
6289              fd, offset.LowPart, count, writeMode);
6290         
6291     fd = smb_ChainFID(fd, inp);
6292     fidp = smb_FindFID(vcp, fd, 0);
6293     if (!fidp) {
6294         return CM_ERROR_BADFD;
6295     }
6296
6297     {
6298         unsigned pid;
6299         cm_key_t key;
6300         LARGE_INTEGER LOffset;
6301         LARGE_INTEGER LLength;
6302
6303         pid = ((smb_t *) inp)->pid;
6304         key = cm_GenerateKey(vcp->vcID, pid, fd);
6305
6306         LOffset.HighPart = offset.HighPart;
6307         LOffset.LowPart = offset.LowPart;
6308         LLength.HighPart = 0;
6309         LLength.LowPart = count;
6310
6311         lock_ObtainMutex(&fidp->scp->mx);
6312         code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6313         lock_ReleaseMutex(&fidp->scp->mx);
6314
6315         if (code) {
6316             smb_ReleaseFID(fidp);
6317             return code;
6318         }
6319     }
6320         
6321     userp = smb_GetUser(vcp, inp);
6322
6323     /*
6324      * Work around bug in NT client
6325      *
6326      * When copying a file, the NT client should first copy the data,
6327      * then copy the last write time.  But sometimes the NT client does
6328      * these in the wrong order, so the data copies would inadvertently
6329      * cause the last write time to be overwritten.  We try to detect this,
6330      * and don't set client mod time if we think that would go against the
6331      * intention.
6332      */
6333     if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
6334         fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6335         fidp->scp->clientModTime = time(NULL);
6336     }
6337
6338     code = 0;
6339     while ( code == 0 && count > 0 ) {
6340 #ifndef DJGPP
6341         code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6342 #else /* DJGPP */
6343         code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
6344 #endif /* !DJGPP */
6345         if (code == 0 && written == 0)
6346             code = CM_ERROR_PARTIALWRITE;
6347
6348         offset.LowPart += written;
6349         count -= written;
6350         total_written += written;
6351         written = 0;
6352     }
6353
6354     /* Get a raw buffer */
6355     if (code == 0) {
6356         rawBuf = NULL;
6357         lock_ObtainMutex(&smb_RawBufLock);
6358         if (smb_RawBufs) {
6359             /* Get a raw buf, from head of list */
6360             rawBuf = smb_RawBufs;
6361 #ifndef DJGPP
6362             smb_RawBufs = *(char **)smb_RawBufs;
6363 #else /* DJGPP */
6364             smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
6365 #endif /* !DJGPP */
6366         }
6367         else
6368             code = CM_ERROR_USESTD;
6369                 
6370         lock_ReleaseMutex(&smb_RawBufLock);
6371     }
6372
6373     /* Don't allow a premature Close */
6374     if (code == 0 && (writeMode & 1) == 0) {
6375         lock_ObtainMutex(&fidp->mx);
6376         fidp->raw_writers++;
6377         thrd_ResetEvent(fidp->raw_write_event);
6378         lock_ReleaseMutex(&fidp->mx);
6379     }
6380
6381     smb_ReleaseFID(fidp);
6382     cm_ReleaseUser(userp);
6383
6384     if (code) {
6385         smb_SetSMBParm(outp, 0, total_written);
6386         smb_SetSMBDataLength(outp, 0);
6387         ((smb_t *)outp)->com = 0x20;    /* SMB_COM_WRITE_COMPLETE */
6388         rwcp->code = code;
6389         return code;
6390     }
6391
6392     rwcp->code = 0;
6393     rwcp->buf = rawBuf;
6394     rwcp->offset.HighPart = 0;
6395     rwcp->offset.LowPart = offset.LowPart + count;
6396     rwcp->count = totalCount - count;
6397     rwcp->writeMode = writeMode;
6398     rwcp->alreadyWritten = total_written;
6399
6400     /* set the packet data length to 3 bytes for the data block header,
6401      * plus the size of the data.
6402      */
6403     smb_SetSMBParm(outp, 0, 0xffff);
6404     smb_SetSMBDataLength(outp, 0);
6405
6406     return 0;
6407 }
6408
6409 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6410 {
6411     osi_hyper_t offset;
6412     long count, finalCount;
6413     unsigned short fd;
6414     unsigned pid;
6415     smb_fid_t *fidp;
6416     long code = 0;
6417     cm_user_t *userp;
6418     char *op;
6419         
6420     fd = smb_GetSMBParm(inp, 0);
6421     count = smb_GetSMBParm(inp, 1);
6422     offset.HighPart = 0;        /* too bad */
6423     offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6424         
6425     osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
6426              fd, offset.LowPart, count);
6427         
6428     fd = smb_ChainFID(fd, inp);
6429     fidp = smb_FindFID(vcp, fd, 0);
6430     if (!fidp) {
6431         return CM_ERROR_BADFD;
6432     }
6433         
6434     if (fidp->flags & SMB_FID_IOCTL) {
6435         return smb_IoctlRead(fidp, vcp, inp, outp);
6436     }
6437
6438     {
6439         LARGE_INTEGER LOffset, LLength;
6440         cm_key_t key;
6441
6442         pid = ((smb_t *) inp)->pid;
6443         key = cm_GenerateKey(vcp->vcID, pid, fd);
6444
6445         LOffset.HighPart = 0;
6446         LOffset.LowPart = offset.LowPart;
6447         LLength.HighPart = 0;
6448         LLength.LowPart = count;
6449         
6450         lock_ObtainMutex(&fidp->scp->mx);
6451         code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
6452         lock_ReleaseMutex(&fidp->scp->mx);
6453     }
6454     if (code) {
6455         smb_ReleaseFID(fidp);
6456         return code;
6457     }
6458         
6459     userp = smb_GetUser(vcp, inp);
6460
6461     /* remember this for final results */
6462     smb_SetSMBParm(outp, 0, count);
6463     smb_SetSMBParm(outp, 1, 0);
6464     smb_SetSMBParm(outp, 2, 0);
6465     smb_SetSMBParm(outp, 3, 0);
6466     smb_SetSMBParm(outp, 4, 0);
6467
6468     /* set the packet data length to 3 bytes for the data block header,
6469      * plus the size of the data.
6470      */
6471     smb_SetSMBDataLength(outp, count+3);
6472         
6473     /* get op ptr after putting in the parms, since otherwise we don't
6474      * know where the data really is.
6475      */
6476     op = smb_GetSMBData(outp, NULL);
6477
6478     /* now emit the data block header: 1 byte of type and 2 bytes of length */
6479     *op++ = 1;  /* data block marker */
6480     *op++ = (unsigned char) (count & 0xff);
6481     *op++ = (unsigned char) ((count >> 8) & 0xff);
6482                 
6483 #ifndef DJGPP
6484     code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6485 #else /* DJGPP */
6486     code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
6487 #endif /* !DJGPP */
6488
6489     /* fix some things up */
6490     smb_SetSMBParm(outp, 0, finalCount);
6491     smb_SetSMBDataLength(outp, finalCount+3);
6492
6493     smb_ReleaseFID(fidp);
6494         
6495     cm_ReleaseUser(userp);
6496     return code;
6497 }
6498
6499 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6500 {
6501     char *pathp;
6502     long code = 0;
6503     cm_space_t *spacep;
6504     char *tp;
6505     cm_user_t *userp;
6506     cm_scache_t *dscp;                  /* dir we're dealing with */
6507     cm_scache_t *scp;                   /* file we're creating */
6508     cm_attr_t setAttr;
6509     int initialModeBits;
6510     char *lastNamep;
6511     int caseFold;
6512     char *tidPathp;
6513     cm_req_t req;
6514
6515     cm_InitReq(&req);
6516
6517     scp = NULL;
6518         
6519     /* compute initial mode bits based on read-only flag in attributes */
6520     initialModeBits = 0777;
6521         
6522     tp = smb_GetSMBData(inp, NULL);
6523     pathp = smb_ParseASCIIBlock(tp, &tp);
6524     if (smb_StoreAnsiFilenames)
6525         OemToChar(pathp,pathp);
6526
6527     if (strcmp(pathp, "\\") == 0)
6528         return CM_ERROR_EXISTS;
6529
6530     spacep = inp->spacep;
6531     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6532
6533     userp = smb_GetUser(vcp, inp);
6534
6535     caseFold = CM_FLAG_CASEFOLD;
6536
6537     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6538     if (code) {
6539         cm_ReleaseUser(userp);
6540         return CM_ERROR_NOSUCHPATH;
6541     }
6542
6543     code = cm_NameI(cm_data.rootSCachep, spacep->data,
6544                     caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
6545                     userp, tidPathp, &req, &dscp);
6546
6547     if (code) {
6548         cm_ReleaseUser(userp);
6549         return code;
6550     }
6551         
6552 #ifdef DFS_SUPPORT
6553     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6554         cm_ReleaseSCache(dscp);
6555         cm_ReleaseUser(userp);
6556         if ( WANTS_DFS_PATHNAMES(inp) )
6557             return CM_ERROR_PATH_NOT_COVERED;
6558         else
6559             return CM_ERROR_BADSHARENAME;
6560     }
6561 #endif /* DFS_SUPPORT */
6562
6563     /* otherwise, scp points to the parent directory.  Do a lookup, and
6564      * fail if we find it.  Otherwise, we do the create.
6565      */
6566     if (!lastNamep) 
6567         lastNamep = pathp;
6568     else 
6569         lastNamep++;
6570     code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6571     if (scp) cm_ReleaseSCache(scp);
6572     if (code != CM_ERROR_NOSUCHFILE) {
6573         if (code == 0) code = CM_ERROR_EXISTS;
6574         cm_ReleaseSCache(dscp);
6575         cm_ReleaseUser(userp);
6576         return code;
6577     }
6578         
6579     setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6580     setAttr.clientModTime = time(NULL);
6581     code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
6582     if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6583         smb_NotifyChange(FILE_ACTION_ADDED,
6584                          FILE_NOTIFY_CHANGE_DIR_NAME,
6585                          dscp, lastNamep, NULL, TRUE);
6586         
6587     /* we don't need this any longer */
6588     cm_ReleaseSCache(dscp);
6589
6590     if (code) {
6591         /* something went wrong creating or truncating the file */
6592         cm_ReleaseUser(userp);
6593         return code;
6594     }
6595         
6596     /* otherwise we succeeded */
6597     smb_SetSMBDataLength(outp, 0);
6598     cm_ReleaseUser(userp);
6599
6600     return 0;
6601 }
6602
6603 BOOL smb_IsLegalFilename(char *filename)
6604 {
6605     /* 
6606      *  Find the longest substring of filename that does not contain
6607      *  any of the chars in illegalChars.  If that substring is less
6608      *  than the length of the whole string, then one or more of the
6609      *  illegal chars is in filename. 
6610      */
6611     if (strcspn(filename, illegalChars) < strlen(filename))
6612         return FALSE;
6613
6614     return TRUE;
6615 }        
6616
6617 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6618 {
6619     char *pathp;
6620     long code = 0;
6621     cm_space_t *spacep;
6622     char *tp;
6623     int excl;
6624     cm_user_t *userp;
6625     cm_scache_t *dscp;                  /* dir we're dealing with */
6626     cm_scache_t *scp;                   /* file we're creating */
6627     cm_attr_t setAttr;
6628     int initialModeBits;
6629     smb_fid_t *fidp;
6630     int attributes;
6631     char *lastNamep;
6632     int caseFold;
6633     afs_uint32 dosTime;
6634     char *tidPathp;
6635     cm_req_t req;
6636
6637     cm_InitReq(&req);
6638
6639     scp = NULL;
6640     excl = (inp->inCom == 0x03)? 0 : 1;
6641         
6642     attributes = smb_GetSMBParm(inp, 0);
6643     dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6644         
6645     /* compute initial mode bits based on read-only flag in attributes */
6646     initialModeBits = 0666;
6647     if (attributes & 1) initialModeBits &= ~0222;
6648         
6649     tp = smb_GetSMBData(inp, NULL);
6650     pathp = smb_ParseASCIIBlock(tp, &tp);
6651     if (smb_StoreAnsiFilenames)
6652         OemToChar(pathp,pathp);
6653
6654     spacep = inp->spacep;
6655     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6656
6657     userp = smb_GetUser(vcp, inp);
6658
6659     caseFold = CM_FLAG_CASEFOLD;
6660
6661     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6662     if (code) {
6663         cm_ReleaseUser(userp);
6664         return CM_ERROR_NOSUCHPATH;
6665     }
6666     code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
6667                     userp, tidPathp, &req, &dscp);
6668
6669     if (code) {
6670         cm_ReleaseUser(userp);
6671         return code;
6672     }
6673         
6674 #ifdef DFS_SUPPORT
6675     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6676         cm_ReleaseSCache(dscp);
6677         cm_ReleaseUser(userp);
6678         if ( WANTS_DFS_PATHNAMES(inp) )
6679             return CM_ERROR_PATH_NOT_COVERED;
6680         else
6681             return CM_ERROR_BADSHARENAME;
6682     }
6683 #endif /* DFS_SUPPORT */
6684
6685     /* otherwise, scp points to the parent directory.  Do a lookup, and
6686      * truncate the file if we find it, otherwise we create the file.
6687      */
6688     if (!lastNamep) 
6689         lastNamep = pathp;
6690     else 
6691         lastNamep++;
6692
6693     if (!smb_IsLegalFilename(lastNamep))
6694         return CM_ERROR_BADNTFILENAME;
6695
6696     osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
6697 #ifdef DEBUG_VERBOSE
6698     {
6699         char *hexp;
6700         hexp = osi_HexifyString( lastNamep );
6701         DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
6702         free(hexp);
6703     }
6704 #endif    
6705
6706     code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6707     if (code && code != CM_ERROR_NOSUCHFILE) {
6708         cm_ReleaseSCache(dscp);
6709         cm_ReleaseUser(userp);
6710         return code;
6711     }
6712         
6713     /* if we get here, if code is 0, the file exists and is represented by
6714      * scp.  Otherwise, we have to create it.
6715      */
6716     if (code == 0) {
6717         if (excl) {
6718             /* oops, file shouldn't be there */
6719             cm_ReleaseSCache(dscp);
6720             cm_ReleaseSCache(scp);
6721             cm_ReleaseUser(userp);
6722             return CM_ERROR_EXISTS;
6723         }
6724
6725         setAttr.mask = CM_ATTRMASK_LENGTH;
6726         setAttr.length.LowPart = 0;
6727         setAttr.length.HighPart = 0;
6728         code = cm_SetAttr(scp, &setAttr, userp, &req);
6729     }
6730     else {
6731         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6732         smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
6733         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
6734                          &req);
6735         if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6736             smb_NotifyChange(FILE_ACTION_ADDED,
6737                              FILE_NOTIFY_CHANGE_FILE_NAME,
6738                              dscp, lastNamep, NULL, TRUE);
6739         if (!excl && code == CM_ERROR_EXISTS) {
6740             /* not an exclusive create, and someone else tried
6741              * creating it already, then we open it anyway.  We
6742              * don't bother retrying after this, since if this next
6743              * fails, that means that the file was deleted after
6744              * we started this call.
6745              */
6746             code = cm_Lookup(dscp, lastNamep, caseFold, userp,
6747                              &req, &scp);
6748             if (code == 0) {
6749                 setAttr.mask = CM_ATTRMASK_LENGTH;
6750                 setAttr.length.LowPart = 0;
6751                 setAttr.length.HighPart = 0;
6752                 code = cm_SetAttr(scp, &setAttr, userp, &req);
6753             }
6754         }
6755     }
6756         
6757     /* we don't need this any longer */
6758     cm_ReleaseSCache(dscp);
6759
6760     if (code) {
6761         /* something went wrong creating or truncating the file */
6762         if (scp) cm_ReleaseSCache(scp);
6763         cm_ReleaseUser(userp);
6764         return code;
6765     }
6766
6767     /* make sure we only open files */
6768     if (scp->fileType != CM_SCACHETYPE_FILE) {
6769         cm_ReleaseSCache(scp);
6770         cm_ReleaseUser(userp);
6771         return CM_ERROR_ISDIR;
6772     }
6773
6774     /* now all we have to do is open the file itself */
6775     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6776     osi_assert(fidp);
6777         
6778     /* save a pointer to the vnode */
6779     fidp->scp = scp;
6780     /* and the user */
6781     cm_HoldUser(userp);
6782     fidp->userp = userp;
6783         
6784     /* always create it open for read/write */
6785     fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
6786
6787     smb_ReleaseFID(fidp);
6788         
6789     smb_SetSMBParm(outp, 0, fidp->fid);
6790     smb_SetSMBDataLength(outp, 0);
6791
6792     cm_Open(scp, 0, userp);
6793
6794     cm_ReleaseUser(userp);
6795     /* leave scp held since we put it in fidp->scp */
6796     return 0;
6797 }
6798
6799 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6800 {
6801     long code = 0;
6802     long offset;
6803     int whence;
6804     unsigned short fd;
6805     smb_fid_t *fidp;
6806     cm_scache_t *scp;
6807     cm_user_t *userp;
6808     cm_req_t req;
6809
6810     cm_InitReq(&req);
6811         
6812     fd = smb_GetSMBParm(inp, 0);
6813     whence = smb_GetSMBParm(inp, 1);
6814     offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6815         
6816     /* try to find the file descriptor */
6817     fd = smb_ChainFID(fd, inp);
6818     fidp = smb_FindFID(vcp, fd, 0);
6819     if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
6820         return CM_ERROR_BADFD;
6821     }
6822         
6823     userp = smb_GetUser(vcp, inp);
6824
6825     lock_ObtainMutex(&fidp->mx);
6826     scp = fidp->scp;
6827     lock_ObtainMutex(&scp->mx);
6828     code = cm_SyncOp(scp, NULL, userp, &req, 0,
6829                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6830     if (code == 0) {
6831         if (whence == 1) {
6832             /* offset from current offset */
6833             offset += fidp->offset;
6834         }
6835         else if (whence == 2) {
6836             /* offset from current EOF */
6837             offset += scp->length.LowPart;
6838         }
6839         fidp->offset = offset;
6840         smb_SetSMBParm(outp, 0, offset & 0xffff);
6841         smb_SetSMBParm(outp, 1, (offset>>16) & 0xffff);
6842         smb_SetSMBDataLength(outp, 0);
6843     }
6844     lock_ReleaseMutex(&scp->mx);
6845     lock_ReleaseMutex(&fidp->mx);
6846     smb_ReleaseFID(fidp);
6847     cm_ReleaseUser(userp);
6848     return code;
6849 }
6850
6851 /* dispatch all of the requests received in a packet.  Due to chaining, this may
6852  * be more than one request.
6853  */
6854 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6855                         NCB *ncbp, raw_write_cont_t *rwcp)
6856 {
6857     smb_dispatch_t *dp;
6858     smb_t *smbp;
6859     unsigned long code = 0;
6860     unsigned char *outWctp;
6861     int nparms;                 /* # of bytes of parameters */
6862     char tbuffer[200];
6863     int nbytes;                 /* bytes of data, excluding count */
6864     int temp;
6865     unsigned char *tp;
6866     unsigned short errCode;
6867     unsigned long NTStatus;
6868     int noSend;
6869     unsigned char errClass;
6870     unsigned int oldGen;
6871     DWORD oldTime, newTime;
6872
6873     /* get easy pointer to the data */
6874     smbp = (smb_t *) inp->data;
6875
6876     if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
6877         /* setup the basic parms for the initial request in the packet */
6878         inp->inCom = smbp->com;
6879         inp->wctp = &smbp->wct;
6880         inp->inCount = 0;
6881         inp->ncb_length = ncbp->ncb_length;
6882     }
6883     noSend = 0;
6884
6885     /* Sanity check */
6886     if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
6887         /* log it and discard it */
6888 #ifndef DJGPP
6889         LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT, 
6890                  __FILE__, __LINE__, ncbp->ncb_length);
6891 #endif /* !DJGPP */
6892         osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
6893         return;
6894     }
6895
6896     /* We are an ongoing op */
6897     thrd_Increment(&ongoingOps);
6898
6899     /* set up response packet for receiving output */
6900     if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
6901         smb_FormatResponsePacket(vcp, inp, outp);
6902     outWctp = outp->wctp;
6903
6904     /* Remember session generation number and time */
6905     oldGen = sessionGen;
6906     oldTime = GetCurrentTime();
6907
6908     while (inp->inCom != 0xff) {
6909         dp = &smb_dispatchTable[inp->inCom];
6910
6911         if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
6912             outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
6913             code = outp->resumeCode;
6914             goto resume;
6915         }
6916
6917         /* process each request in the packet; inCom, wctp and inCount
6918          * are already set up.
6919          */
6920         osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
6921                   ncbp->ncb_lsn);
6922
6923         /* now do the dispatch */
6924         /* start by formatting the response record a little, as a default */
6925         if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
6926             outWctp[0] = 2;
6927             outWctp[1] = 0xff;  /* no operation */
6928             outWctp[2] = 0;             /* padding */
6929             outWctp[3] = 0;
6930             outWctp[4] = 0;
6931         }
6932         else {
6933             /* not a chained request, this is a more reasonable default */
6934             outWctp[0] = 0;     /* wct of zero */
6935             outWctp[1] = 0;     /* and bcc (word) of zero */
6936             outWctp[2] = 0;
6937         }   
6938
6939         /* once set, stays set.  Doesn't matter, since we never chain
6940          * "no response" calls.
6941          */
6942         if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
6943             noSend = 1;
6944
6945         if (dp->procp) {
6946             /* we have a recognized operation */
6947
6948             if (inp->inCom == 0x1d)
6949                 /* Raw Write */
6950                 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp,
6951                                                  rwcp);
6952             else {
6953                 osi_Log4(smb_logp,"Dispatch %s vcp 0x%p lana %d lsn %d",myCrt_Dispatch(inp->inCom),vcp,vcp->lana,vcp->lsn);
6954                 code = (*(dp->procp)) (vcp, inp, outp);
6955                 osi_Log4(smb_logp,"Dispatch return  code 0x%x vcp 0x%p lana %d lsn %d",code,vcp,vcp->lana,vcp->lsn);
6956 #ifdef LOG_PACKET
6957                 if ( code == CM_ERROR_BADSMB ||
6958                      code == CM_ERROR_BADOP )
6959                 smb_LogPacket(inp);
6960 #endif /* LOG_PACKET */
6961             }   
6962
6963             if (oldGen != sessionGen) {
6964                 newTime = GetCurrentTime();
6965 #ifndef DJGPP
6966                 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION, 
6967                          newTime - oldTime, ncbp->ncb_length);
6968 #endif /* !DJGPP */
6969                 osi_Log2(smb_logp, "Pkt straddled session startup, "
6970                           "took %d ms, ncb length %d", newTime - oldTime, ncbp->ncb_length);
6971             }
6972         }
6973         else {
6974             /* bad opcode, fail the request, after displaying it */
6975             osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
6976 #ifdef LOG_PACKET
6977             smb_LogPacket(inp);
6978 #endif  /* LOG_PACKET */
6979
6980 #ifndef DJGPP
6981             if (showErrors) {
6982                 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
6983                 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
6984                                       MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
6985                 if (code == IDCANCEL) 
6986                     showErrors = 0;
6987             }
6988 #endif /* DJGPP */
6989             code = CM_ERROR_BADOP;
6990         }
6991
6992         /* catastrophic failure:  log as much as possible */
6993         if (code == CM_ERROR_BADSMB) {
6994 #ifndef DJGPP
6995             LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID, 
6996                      ncbp->ncb_length);
6997 #endif /* !DJGPP */
6998 #ifdef LOG_PACKET
6999             smb_LogPacket(inp);
7000 #endif /* LOG_PACKET */
7001             osi_Log1(smb_logp, "Invalid SMB message, length %d",
7002                      ncbp->ncb_length);
7003
7004             code = CM_ERROR_INVAL;
7005         }
7006
7007         if (outp->flags & SMB_PACKETFLAG_NOSEND) {
7008             thrd_Decrement(&ongoingOps);
7009             return;
7010         }
7011
7012       resume:
7013         /* now, if we failed, turn the current response into an empty
7014          * one, and fill in the response packet's error code.
7015          */
7016         if (code) {
7017             if (vcp->flags & SMB_VCFLAG_STATUS32) {
7018                 smb_MapNTError(code, &NTStatus);
7019                 outWctp = outp->wctp;
7020                 smbp = (smb_t *) &outp->data;
7021                 if (code != CM_ERROR_PARTIALWRITE
7022                      && code != CM_ERROR_BUFFERTOOSMALL 
7023                      && code != CM_ERROR_GSSCONTINUE) {
7024                     /* nuke wct and bcc.  For a partial
7025                      * write or an in-process authentication handshake, 
7026                      * assume they're OK.
7027                      */
7028                     *outWctp++ = 0;
7029                     *outWctp++ = 0;
7030                     *outWctp++ = 0;
7031                 }
7032                 smbp->rcls = (unsigned char) (NTStatus & 0xff);
7033                 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
7034                 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
7035                 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
7036                 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7037                 break;
7038             }
7039             else {
7040                 smb_MapCoreError(code, vcp, &errCode, &errClass);
7041                 outWctp = outp->wctp;
7042                 smbp = (smb_t *) &outp->data;
7043                 if (code != CM_ERROR_PARTIALWRITE) {
7044                     /* nuke wct and bcc.  For a partial
7045                      * write, assume they're OK.
7046                      */
7047                     *outWctp++ = 0;
7048                     *outWctp++ = 0;
7049                     *outWctp++ = 0;
7050                 }
7051                 smbp->errLow = (unsigned char) (errCode & 0xff);
7052                 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
7053                 smbp->rcls = errClass;
7054                 break;
7055             }
7056         }       /* error occurred */
7057
7058         /* if we're here, we've finished one request.  Look to see if
7059          * this is a chained opcode.  If it is, setup things to process
7060          * the chained request, and setup the output buffer to hold the
7061          * chained response.  Start by finding the next input record.
7062          */
7063         if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
7064             break;              /* not a chained req */
7065         tp = inp->wctp;         /* points to start of last request */
7066         /* in a chained request, the first two
7067          * parm fields are required, and are
7068          * AndXCommand/AndXReserved and
7069          * AndXOffset. */
7070         if (tp[0] < 2) break;   
7071         if (tp[1] == 0xff) break;       /* no more chained opcodes */
7072         inp->inCom = tp[1];
7073         inp->wctp = inp->data + tp[3] + (tp[4] << 8);
7074         inp->inCount++;
7075
7076         /* and now append the next output request to the end of this
7077          * last request.  Begin by finding out where the last response
7078          * ends, since that's where we'll put our new response.
7079          */
7080         outWctp = outp->wctp;           /* ptr to out parameters */
7081         osi_assert (outWctp[0] >= 2);   /* need this for all chained requests */
7082         nparms = outWctp[0] << 1;
7083         tp = outWctp + nparms + 1;      /* now points to bcc field */
7084         nbytes = tp[0] + (tp[1] << 8);  /* # of data bytes */
7085         tp += 2 /* for the count itself */ + nbytes;
7086         /* tp now points to the new output record; go back and patch the
7087          * second parameter (off2) to point to the new record.
7088          */
7089         temp = (unsigned int)(tp - outp->data);
7090         outWctp[3] = (unsigned char) (temp & 0xff);
7091         outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
7092         outWctp[2] = 0; /* padding */
7093         outWctp[1] = inp->inCom;        /* next opcode */
7094
7095         /* finally, setup for the next iteration */
7096         outp->wctp = tp;
7097         outWctp = tp;
7098     }   /* while loop over all requests in the packet */
7099
7100     /* done logging out, turn off logging-out flag */
7101     if (!(inp->flags & SMB_PACKETFLAG_PROFILE_UPDATE_OK)) {
7102         vcp->justLoggedOut = NULL;
7103         if (loggedOut) {
7104             loggedOut = 0;
7105             free(loggedOutName);
7106             loggedOutName = NULL;
7107             smb_ReleaseUID(loggedOutUserp);
7108             loggedOutUserp = NULL;
7109         }
7110     }
7111  
7112     /* now send the output packet, and return */
7113     if (!noSend)
7114         smb_SendPacket(vcp, outp);
7115     thrd_Decrement(&ongoingOps);
7116
7117     if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7118         if (active_vcp != vcp) {
7119             if (active_vcp) {
7120                 smb_ReleaseVC(active_vcp);
7121                 osi_Log2(smb_logp,
7122                       "Replacing active_vcp %x with %x", active_vcp, vcp);
7123             }
7124             smb_HoldVC(vcp);
7125             active_vcp = vcp;
7126         }
7127         last_msg_time = GetCurrentTime();
7128     } else if (active_vcp == vcp) {
7129         smb_ReleaseVC(active_vcp);
7130         active_vcp = NULL;
7131     }
7132
7133     return;
7134 }
7135
7136 #ifndef DJGPP
7137 /* Wait for Netbios() calls to return, and make the results available to server
7138  * threads.  Note that server threads can't wait on the NCBevents array
7139  * themselves, because NCB events are manual-reset, and the servers would race
7140  * each other to reset them.
7141  */
7142 void smb_ClientWaiter(void *parmp)
7143 {
7144     DWORD code;
7145     int   idx;
7146
7147     while (smbShutdownFlag == 0) {
7148         code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
7149                                                  FALSE, INFINITE);
7150         if (code == WAIT_OBJECT_0)
7151             continue;
7152
7153         /* error checking */
7154         if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7155         {
7156             int abandonIdx = code - WAIT_ABANDONED_0;
7157             osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7158         }
7159
7160         if (code == WAIT_IO_COMPLETION)
7161         {
7162             osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
7163             continue;
7164         }
7165         
7166         if (code == WAIT_TIMEOUT)
7167         {
7168             osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
7169         }
7170
7171         if (code == WAIT_FAILED)
7172         {
7173             osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
7174         }
7175
7176         idx = code - WAIT_OBJECT_0;
7177  
7178         /* check idx range! */
7179         if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
7180         {
7181             /* this is fatal - log as much as possible */
7182             osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
7183             osi_assert(0);
7184         }
7185         
7186         thrd_ResetEvent(NCBevents[idx]);
7187         thrd_SetEvent(NCBreturns[0][idx]);
7188     }
7189 }
7190 #endif /* !DJGPP */
7191
7192 /*
7193  * Try to have one NCBRECV request waiting for every live session.  Not more
7194  * than one, because if there is more than one, it's hard to handle Write Raw.
7195  */
7196 void smb_ServerWaiter(void *parmp)
7197 {
7198     DWORD code;
7199     int idx_session, idx_NCB;
7200     NCB *ncbp;
7201 #ifdef DJGPP
7202     dos_ptr dos_ncb;
7203 #endif /* DJGPP */
7204
7205     while (smbShutdownFlag == 0) {
7206         /* Get a session */
7207         code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
7208                                                  FALSE, INFINITE);
7209         if (code == WAIT_OBJECT_0)
7210             continue;
7211
7212         if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
7213         {
7214             int abandonIdx = code - WAIT_ABANDONED_0;
7215             osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7216         }
7217         
7218         if (code == WAIT_IO_COMPLETION)
7219         {
7220             osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
7221             continue;
7222         }
7223         
7224         if (code == WAIT_TIMEOUT)
7225         {
7226             osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
7227         }
7228         
7229         if (code == WAIT_FAILED)
7230         {
7231             osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
7232         }
7233         
7234         idx_session = code - WAIT_OBJECT_0;
7235
7236         /* check idx range! */
7237         if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
7238         {
7239             /* this is fatal - log as much as possible */
7240             osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
7241             osi_assert(0);
7242         }
7243
7244                 /* Get an NCB */
7245       NCBretry:
7246         code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
7247                                                  FALSE, INFINITE);
7248         if (code == WAIT_OBJECT_0) {
7249             if (smbShutdownFlag == 1) 
7250                 break;
7251             else
7252                 goto NCBretry;
7253         }
7254
7255         /* error checking */
7256         if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7257         {
7258             int abandonIdx = code - WAIT_ABANDONED_0;
7259             osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7260         }
7261         
7262         if (code == WAIT_IO_COMPLETION)
7263         {
7264             osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
7265             continue;
7266         }
7267         
7268         if (code == WAIT_TIMEOUT)
7269         {
7270             osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
7271         }
7272         
7273         if (code == WAIT_FAILED)
7274         {
7275             osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
7276         }
7277                 
7278         idx_NCB = code - WAIT_OBJECT_0;
7279
7280         /* check idx range! */
7281         if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
7282         {
7283             /* this is fatal - log as much as possible */
7284             osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
7285             osi_assert(0);
7286         }
7287
7288         /* Link them together */
7289         NCBsessions[idx_NCB] = idx_session;
7290
7291         /* Fire it up */
7292         ncbp = NCBs[idx_NCB];
7293         ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
7294         ncbp->ncb_command = NCBRECV | ASYNCH;
7295         ncbp->ncb_lana_num = lanas[idx_session];
7296 #ifndef DJGPP
7297         ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
7298         ncbp->ncb_event = NCBevents[idx_NCB];
7299         ncbp->ncb_length = SMB_PACKETSIZE;
7300         Netbios(ncbp);
7301 #else /* DJGPP */
7302         ncbp->ncb_buffer = bufs[idx_NCB]->dos_pkt;
7303         ((smb_ncb_t*)ncbp)->orig_pkt = bufs[idx_NCB];
7304         ncbp->ncb_event = NCBreturns[0][idx_NCB];
7305         ncbp->ncb_length = SMB_PACKETSIZE;
7306         dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7307         Netbios(ncbp, dos_ncb);
7308 #endif /* !DJGPP */
7309     }
7310 }
7311
7312 /*
7313  * The top level loop for handling SMB request messages.  Each server thread
7314  * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
7315  * NCB and buffer for the incoming request are loaned to us.
7316  *
7317  * Write Raw trickery starts here.  When we get a Write Raw, we are supposed
7318  * to immediately send a request for the rest of the data.  This must come
7319  * before any other traffic for that session, so we delay setting the session
7320  * event until that data has come in.
7321  */
7322 void smb_Server(VOID *parmp)
7323 {
7324     INT_PTR myIdx = (INT_PTR) parmp;
7325     NCB *ncbp;
7326     NCB *outncbp;
7327     smb_packet_t *bufp;
7328     smb_packet_t *outbufp;
7329     DWORD code, rcode;
7330     int idx_NCB, idx_session;
7331     UCHAR rc;
7332     smb_vc_t *vcp = NULL;
7333     smb_t *smbp;
7334 #ifdef DJGPP
7335     dos_ptr dos_ncb;
7336 #endif /* DJGPP */
7337
7338     rx_StartClientThread();
7339
7340     outncbp = GetNCB();
7341     outbufp = GetPacket();
7342     outbufp->ncbp = outncbp;
7343
7344     while (1) {
7345         code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
7346                                                  FALSE, INFINITE);
7347
7348         /* terminate silently if shutdown flag is set */
7349         if (code == WAIT_OBJECT_0) {
7350             if (smbShutdownFlag == 1) {
7351                 thrd_SetEvent(smb_ServerShutdown[myIdx]);
7352                 break;
7353             } else
7354                 continue;
7355         }
7356
7357         /* error checking */
7358         if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7359         {
7360             int abandonIdx = code - WAIT_ABANDONED_0;
7361             osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
7362         }
7363         
7364         if (code == WAIT_IO_COMPLETION)
7365         {
7366             osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
7367             continue;
7368         }
7369         
7370         if (code == WAIT_TIMEOUT)
7371         {
7372             osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
7373         }
7374         
7375         if (code == WAIT_FAILED)
7376         {
7377             osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
7378         }
7379
7380         idx_NCB = code - WAIT_OBJECT_0;
7381         
7382         /* check idx range! */
7383         if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
7384         {
7385             /* this is fatal - log as much as possible */
7386             osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
7387             osi_assert(0);
7388         }
7389
7390         ncbp = NCBs[idx_NCB];
7391 #ifdef DJGPP
7392         dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7393 #endif /* DJGPP */
7394         idx_session = NCBsessions[idx_NCB];
7395         rc = ncbp->ncb_retcode;
7396
7397         if (rc != NRC_PENDING && rc != NRC_GOODRET) {
7398             switch (rc) {
7399             case 0x01:
7400                 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal buffer length", ncbp->ncb_lsn, idx_session);
7401                 break;
7402             case 0x03:
7403                 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal command", ncbp->ncb_lsn, idx_session);
7404                 break;
7405             case 0x05:
7406                 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command timed out", ncbp->ncb_lsn, idx_session);
7407                 break;
7408             case 0x06:
7409                 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: message incomplete, issue another command", ncbp->ncb_lsn, idx_session);
7410                 break;
7411             case 0x07:
7412                 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal buffer address", ncbp->ncb_lsn, idx_session);
7413                 break;
7414             case 0x08:
7415                 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: session number out of range", ncbp->ncb_lsn, idx_session);
7416                 break;
7417             case 0x09:
7418                 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no resource available", ncbp->ncb_lsn, idx_session);
7419                 break;
7420             case 0x0a:
7421                 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: session closed", ncbp->ncb_lsn, idx_session);
7422                 break;
7423             case 0x0b:
7424                 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command cancelled", ncbp->ncb_lsn, idx_session);
7425                 break;
7426             case 0x0d:
7427                 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: duplicate name", ncbp->ncb_lsn, idx_session);
7428                 break;
7429             case 0x0e:
7430                 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name table full", ncbp->ncb_lsn, idx_session);
7431                 break;
7432             case 0x0f:
7433                 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no deletions, name has active lsn %d sessions", ncbp->ncb_lsn, idx_session);
7434                 break;
7435             case 0x11:
7436                 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: local session table full", ncbp->ncb_lsn, idx_session);
7437                 break;
7438             case 0x12:
7439                 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: remote session table full", ncbp->ncb_lsn, idx_session);
7440                 break;
7441             case 0x13:
7442                 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal name number", ncbp->ncb_lsn, idx_session);
7443                 break;
7444             case 0x14:
7445                 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no callname", ncbp->ncb_lsn, idx_session);
7446                 break;
7447             case 0x15:
7448                 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: cannot put * in NCB_NAME", ncbp->ncb_lsn, idx_session);
7449                 break;
7450             case 0x16:
7451                 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name in use on remote adapter", ncbp->ncb_lsn, idx_session);
7452                 break;
7453             case 0x17:
7454                 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name deleted", ncbp->ncb_lsn, idx_session);
7455                 break;
7456             case 0x18:
7457                 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: session ended abnormally", ncbp->ncb_lsn, idx_session);
7458                 break;
7459             case 0x19:
7460                 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name conflict detected", ncbp->ncb_lsn, idx_session);
7461                 break;
7462             case 0x21:
7463                 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: interface busy, IRET before retrying", ncbp->ncb_lsn, idx_session);
7464                 break;
7465             case 0x22:
7466                 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: too many commands outstanding, retry later", ncbp->ncb_lsn, idx_session);
7467                 break;
7468             case 0x23:
7469                 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: ncb_lana_num field invalid", ncbp->ncb_lsn, idx_session);
7470                 break;
7471             case 0x24:
7472                 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command completed while cancel occurring", ncbp->ncb_lsn, idx_session);
7473                 break;
7474             case 0x26:
7475                 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command not valid to cancel", ncbp->ncb_lsn, idx_session);
7476                 break;
7477             case 0x30:
7478                 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name defined by anther local process", ncbp->ncb_lsn, idx_session);
7479                 break;
7480             case 0x34:
7481                 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: environment undefined. RESET required", ncbp->ncb_lsn, idx_session);
7482                 break;
7483             case 0x35:
7484                 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: required OS resources exhausted", ncbp->ncb_lsn, idx_session);
7485                 break;
7486             case 0x36:
7487                 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: max number of applications exceeded", ncbp->ncb_lsn, idx_session);
7488                 break;
7489             case 0x37:
7490                 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no saps available for netbios", ncbp->ncb_lsn, idx_session);
7491                 break;
7492             case 0x38:
7493                 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: requested resources are not available", ncbp->ncb_lsn, idx_session);
7494                 break;
7495             case 0x39:
7496                 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: invalid ncb address or length > segment", ncbp->ncb_lsn, idx_session);
7497                 break;
7498             case 0x3B:
7499                 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: invalid NCB DDID", ncbp->ncb_lsn, idx_session);
7500                 break;
7501             case 0x3C:
7502                 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: lock of user area failed", ncbp->ncb_lsn, idx_session);
7503                 break;
7504             case 0x3f:
7505                 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: NETBIOS not loaded", ncbp->ncb_lsn, idx_session);
7506                 break;
7507             case 0x40:
7508                 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: system error", ncbp->ncb_lsn, idx_session);
7509                 break;
7510             default:
7511                 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d code %d", ncbp->ncb_lsn, idx_session, rc);
7512                 break;
7513             }
7514         }
7515
7516         switch (rc) {
7517         case NRC_GOODRET: 
7518             break;
7519
7520         case NRC_PENDING:
7521             /* Can this happen? Or is it just my UNIX paranoia? */
7522             osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
7523             continue;
7524
7525         case NRC_SCLOSED:
7526         case NRC_SNUMOUT:
7527         case NRC_SABORT:
7528             /* Client closed session */
7529             dead_sessions[idx_session] = TRUE;
7530             if (vcp)
7531                 smb_ReleaseVC(vcp);
7532             vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7533             /* Should also release vcp.  [done] 2004-05-11 jaltman
7534              * Also, should do
7535              * sanity check that all TID's are gone. 
7536              *
7537              * TODO: check if we could use LSNs[idx_session] instead, 
7538              * also cleanup after dead vcp 
7539              */
7540             if (vcp) {
7541                 if (dead_vcp == vcp)
7542                     osi_Log1(smb_logp, "dead_vcp already set, 0x%x", dead_vcp);
7543                 else if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7544                     osi_Log2(smb_logp, "setting dead_vcp 0x%x, user struct 0x%x",
7545                              vcp, vcp->usersp);
7546                     smb_HoldVC(vcp);
7547                     if (dead_vcp) {
7548                         smb_ReleaseVC(dead_vcp);
7549                         osi_Log1(smb_logp,
7550                                   "Previous dead_vcp %x", dead_vcp);
7551                     }
7552                     dead_vcp = vcp;
7553                     vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7554                 }
7555
7556                 smb_CleanupDeadVC(vcp);
7557
7558                 if (vcp->justLoggedOut) {
7559                     loggedOut = 1;
7560                     loggedOutTime = vcp->logoffTime;
7561                     loggedOutName = strdup(vcp->justLoggedOut->unp->name);
7562                     loggedOutUserp = vcp->justLoggedOut;
7563                     lock_ObtainWrite(&smb_rctLock);
7564                     loggedOutUserp->refCount++;
7565                     lock_ReleaseWrite(&smb_rctLock);
7566                 }
7567             }
7568             goto doneWithNCB;
7569
7570         case NRC_INCOMP:
7571             /* Treat as transient error */
7572             {
7573 #ifndef DJGPP
7574                 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE, 
7575                          ncbp->ncb_length);
7576 #endif /* !DJGPP */
7577                 osi_Log1(smb_logp,
7578                           "dispatch smb recv failed, message incomplete, ncb_length %d",
7579                           ncbp->ncb_length);
7580                 osi_Log1(smb_logp,
7581                           "SMB message incomplete, "
7582                           "length %d", ncbp->ncb_length);
7583
7584                 /*
7585                  * We used to discard the packet.
7586                  * Instead, try handling it normally.
7587                  *
7588                  continue;
7589                  */
7590                 break;
7591             }
7592
7593         default:
7594             /* A weird error code.  Log it, sleep, and
7595             * continue. */
7596             if (vcp && vcp->errorCount++ > 3) {
7597                 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
7598                 dead_sessions[idx_session] = TRUE;
7599             }
7600             else {
7601                 thrd_Sleep(1000);
7602                 thrd_SetEvent(SessionEvents[idx_session]);
7603             }
7604             continue;
7605         }
7606
7607         /* Success, so now dispatch on all the data in the packet */
7608
7609         smb_concurrentCalls++;
7610         if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
7611             smb_maxObsConcurrentCalls = smb_concurrentCalls;
7612
7613         if (vcp)
7614             smb_ReleaseVC(vcp);
7615         vcp = smb_FindVC(ncbp->ncb_lsn, 0, ncbp->ncb_lana_num);
7616         /*
7617          * If at this point vcp is NULL (implies that packet was invalid)
7618          * then we are in big trouble. This means either :
7619          *   a) we have the wrong NCB.
7620          *   b) Netbios screwed up the call.
7621          * Obviously this implies that 
7622          *   ( LSNs[idx_session] != ncbp->ncb_lsn ||
7623          *   lanas[idx_session] != ncbp->ncb_lana_num )
7624          * Either way, we can't do anything with this packet.
7625          * Log, sleep and resume.
7626          */
7627         if (!vcp) {
7628             LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
7629                      LSNs[idx_session],
7630                      lanas[idx_session],
7631                      ncbp->ncb_lsn,
7632                      ncbp->ncb_lana_num);
7633
7634             /* Also log in the trace log. */
7635             osi_Log4(smb_logp, "Server: BAD VCP!"
7636                       "LSNs[idx_session]=[%d],"
7637                       "lanas[idx_session]=[%d],"
7638                       "ncbp->ncb_lsn=[%d],"
7639                       "ncbp->ncb_lana_num=[%d]",
7640                       LSNs[idx_session],
7641                       lanas[idx_session],
7642                       ncbp->ncb_lsn,
7643                       ncbp->ncb_lana_num);
7644
7645             /* thrd_Sleep(1000); Don't bother sleeping */
7646             thrd_SetEvent(SessionEvents[idx_session]);
7647             smb_concurrentCalls--;
7648             continue;
7649         }
7650
7651
7652         vcp->errorCount = 0;
7653         bufp = (struct smb_packet *) ncbp->ncb_buffer;
7654 #ifdef DJGPP
7655         bufp = ((smb_ncb_t *) ncbp)->orig_pkt;
7656         /* copy whole packet to virtual memory */
7657         /*fprintf(stderr, "smb_Server: copying dos packet at 0x%x, "
7658         "bufp=0x%x\n",
7659         bufp->dos_pkt / 16, bufp);*/
7660         fflush(stderr);
7661         dosmemget(bufp->dos_pkt, ncbp->ncb_length, bufp->data);
7662 #endif /* DJGPP */
7663         smbp = (smb_t *)bufp->data;
7664         outbufp->flags = 0;
7665
7666 #if !defined(DJGPP) && !defined(AFS_WIN32_ENV)
7667         __try
7668         {
7669 #endif
7670             if (smbp->com == 0x1d) {
7671                 /* Special handling for Write Raw */
7672                 raw_write_cont_t rwc;
7673                 EVENT_HANDLE rwevent;
7674                 char eventName[MAX_PATH];
7675             
7676                 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
7677                 if (rwc.code == 0) {
7678                     rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
7679                     if ( GetLastError() == ERROR_ALREADY_EXISTS )
7680                         osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7681                     ncbp->ncb_command = NCBRECV | ASYNCH;
7682                     ncbp->ncb_lsn = (unsigned char) vcp->lsn;
7683                     ncbp->ncb_lana_num = vcp->lana;
7684                     ncbp->ncb_buffer = rwc.buf;
7685                     ncbp->ncb_length = 65535;
7686                     ncbp->ncb_event = rwevent;
7687 #ifndef DJGPP
7688                     Netbios(ncbp);
7689 #else
7690                     Netbios(ncbp, dos_ncb);
7691 #endif /* !DJGPP */
7692                     rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
7693                     thrd_CloseHandle(rwevent);
7694                 }
7695                 thrd_SetEvent(SessionEvents[idx_session]);
7696                 if (rwc.code == 0)
7697                     smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
7698             } 
7699             else if (smbp->com == 0xa0) {
7700                 /* 
7701                  * Serialize the handling for NT Transact 
7702                  * (defect 11626)
7703                  */
7704                 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7705                 thrd_SetEvent(SessionEvents[idx_session]);
7706             } else {
7707                 thrd_SetEvent(SessionEvents[idx_session]);
7708                 /* TODO: what else needs to be serialized? */
7709                 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7710             }
7711 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
7712         }
7713         __except( smb_ServerExceptionFilter() ) {
7714         }
7715 #endif
7716
7717         smb_concurrentCalls--;
7718
7719       doneWithNCB:
7720         thrd_SetEvent(NCBavails[idx_NCB]);
7721     }
7722     if (vcp)
7723         smb_ReleaseVC(vcp);
7724 }
7725
7726 /*
7727  * Exception filter for the server threads.  If an exception occurs in the
7728  * dispatch routines, which is where exceptions are most common, then do a
7729  * force trace and give control to upstream exception handlers. Useful for
7730  * debugging.
7731  */
7732 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
7733 DWORD smb_ServerExceptionFilter(void) {
7734     /* While this is not the best time to do a trace, if it succeeds, then
7735      * we have a trace (assuming tracing was enabled). Otherwise, this should
7736      * throw a second exception.
7737      */
7738     LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
7739     afsd_ForceTrace(TRUE);
7740     buf_ForceTrace(TRUE);
7741     return EXCEPTION_CONTINUE_SEARCH;
7742 }       
7743 #endif
7744
7745 /*
7746  * Create a new NCB and associated events, packet buffer, and "space" buffer.
7747  * If the number of server threads is M, and the number of live sessions is
7748  * N, then the number of NCB's in use at any time either waiting for, or
7749  * holding, received messages is M + N, so that is how many NCB's get created.
7750  */
7751 void InitNCBslot(int idx)
7752 {
7753     struct smb_packet *bufp;
7754     EVENT_HANDLE retHandle;
7755     int i;
7756     char eventName[MAX_PATH];
7757
7758     osi_assert( idx < (sizeof(NCBs) / sizeof(NCBs[0])) );
7759
7760     NCBs[idx] = GetNCB();
7761     sprintf(eventName,"NCBavails[%d]", idx);
7762     NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7763     if ( GetLastError() == ERROR_ALREADY_EXISTS )
7764         osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7765 #ifndef DJGPP
7766     sprintf(eventName,"NCBevents[%d]", idx);
7767     NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
7768     if ( GetLastError() == ERROR_ALREADY_EXISTS )
7769         osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7770 #endif /* !DJGPP */
7771     sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
7772     retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7773     if ( GetLastError() == ERROR_ALREADY_EXISTS )
7774         osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7775     for (i=0; i<smb_NumServerThreads; i++)
7776         NCBreturns[i][idx] = retHandle;
7777     bufp = GetPacket();
7778     bufp->spacep = cm_GetSpace();
7779     bufs[idx] = bufp;
7780 }
7781
7782 /* listen for new connections */
7783 void smb_Listener(void *parmp)
7784 {
7785     NCB *ncbp;
7786     long code = 0;
7787     long len;
7788     long i, j;
7789     smb_vc_t *vcp = 0;
7790     int flags = 0;
7791     char rname[NCBNAMSZ+1];
7792     char cname[MAX_COMPUTERNAME_LENGTH+1];
7793     int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
7794 #ifdef DJGPP
7795     dos_ptr dos_ncb;
7796     time_t now;
7797 #endif /* DJGPP */
7798     INT_PTR lana = (INT_PTR) parmp;
7799
7800     ncbp = GetNCB();
7801 #ifdef DJGPP
7802     dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7803 #endif /* DJGPP */
7804
7805     /* retrieve computer name */
7806     GetComputerName(cname, &cnamelen);
7807     _strupr(cname);
7808
7809     while (1) {
7810         memset(ncbp, 0, sizeof(NCB));
7811         flags = 0;
7812
7813         ncbp->ncb_command = NCBLISTEN;
7814         ncbp->ncb_rto = 0;      /* No receive timeout */
7815         ncbp->ncb_sto = 0;      /* No send timeout */
7816
7817         /* pad out with spaces instead of null termination */
7818         len = (long)strlen(smb_localNamep);
7819         strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
7820         for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
7821         
7822         strcpy(ncbp->ncb_callname, "*");
7823         for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
7824         
7825         ncbp->ncb_lana_num = (UCHAR)lana;
7826
7827 #ifndef DJGPP
7828         code = Netbios(ncbp);
7829 #else /* DJGPP */
7830         code = Netbios(ncbp, dos_ncb);
7831 #endif
7832
7833         if (code != 0)
7834         {
7835 #ifndef DJGPP
7836             char tbuffer[256];
7837 #endif
7838
7839             /* terminate silently if shutdown flag is set */
7840             if (smbShutdownFlag == 1) {
7841 #ifndef DJGPP
7842                 ExitThread(1);
7843 #else
7844                 thrd_Exit(1);
7845 #endif
7846             }
7847
7848             osi_Log2(smb_logp, 
7849                      "NCBLISTEN lana=%d failed with code %d",
7850                      ncbp->ncb_lana_num, code);
7851             osi_Log0(smb_logp, 
7852                      "Client exiting due to network failure. Please restart client.\n");
7853
7854 #ifndef DJGPP
7855             sprintf(tbuffer, 
7856                      "Client exiting due to network failure.  Please restart client.\n"
7857                      "NCBLISTEN lana=%d failed with code %d",
7858                      ncbp->ncb_lana_num, code);
7859             if (showErrors)
7860                 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
7861                                       MB_OK|MB_SERVICE_NOTIFICATION);
7862             osi_assert(tbuffer);
7863             ExitThread(1);
7864 #else
7865             fprintf(stderr, "NCBLISTEN lana=%d failed with code %d\n",
7866                      ncbp->ncb_lana_num, code);
7867             fprintf(stderr, "\nClient exiting due to network failure "
7868                      "(possibly due to power-saving mode)\n");
7869             fprintf(stderr, "Please restart client.\n");
7870             afs_exit(AFS_EXITCODE_NETWORK_FAILURE);
7871 #endif /* !DJGPP */
7872         }
7873
7874         /* check for remote conns */
7875         /* first get remote name and insert null terminator */
7876         memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
7877         for (i=NCBNAMSZ; i>0; i--) {
7878             if (rname[i-1] != ' ' && rname[i-1] != 0) {
7879                 rname[i] = 0;
7880                 break;
7881             }
7882         }
7883
7884         /* compare with local name */
7885         if (!isGateway)
7886             if (strncmp(rname, cname, NCBNAMSZ) != 0)
7887                 flags |= SMB_VCFLAG_REMOTECONN;
7888
7889         osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
7890         /* lock */
7891         lock_ObtainMutex(&smb_ListenerLock);
7892
7893         /* New generation */
7894         sessionGen++;
7895
7896         /* Log session startup */
7897 #ifdef NOTSERVICE
7898         fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host "
7899                  "%s\n",
7900                  ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
7901 #endif /* NOTSERVICE */
7902         osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
7903                   ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
7904
7905         if (reportSessionStartups) {
7906 #ifndef DJGPP
7907             LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
7908 #else /* DJGPP */
7909             time(&now);
7910             fprintf(stderr, "%s: New session %d starting from host %s\n",
7911                     asctime(localtime(&now)), ncbp->ncb_lsn, rname);
7912             fflush(stderr);
7913 #endif /* !DJGPP */
7914         }
7915         osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
7916         osi_Log1(smb_logp, "SMB session startup, %d ongoing ops",
7917                   ongoingOps);
7918
7919         /* now ncbp->ncb_lsn is the connection ID */
7920         vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
7921         vcp->flags |= flags;
7922         strcpy(vcp->rname, rname);
7923
7924         /* Allocate slot in session arrays */
7925         /* Re-use dead session if possible, otherwise add one more */
7926         /* But don't look at session[0], it is reserved */
7927         for (i = 1; i < numSessions; i++) {
7928             if (dead_sessions[i]) {
7929                 osi_Log1(smb_logp, "connecting to dead session [ %d ]", i);
7930                 dead_sessions[i] = FALSE;
7931                 break;
7932             }
7933         }
7934
7935         if (i >= Sessionmax - 1  || numNCBs >= NCBmax - 1) {
7936             unsigned long code = CM_ERROR_ALLBUSY;
7937             smb_packet_t * outp = GetPacket();
7938             unsigned char *outWctp;
7939             smb_t *smbp;
7940             
7941             outp->ncbp = ncbp;
7942
7943             if (vcp->flags & SMB_VCFLAG_STATUS32) {
7944                 unsigned long NTStatus;
7945                 smb_MapNTError(code, &NTStatus);
7946                 outWctp = outp->wctp;
7947                 smbp = (smb_t *) &outp->data;
7948                 *outWctp++ = 0;
7949                 *outWctp++ = 0;
7950                 *outWctp++ = 0;
7951                 smbp->rcls = (unsigned char) (NTStatus & 0xff);
7952                 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
7953                 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
7954                 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
7955                 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7956             } else {
7957                 unsigned short errCode;
7958                 unsigned char errClass;
7959                 smb_MapCoreError(code, vcp, &errCode, &errClass);
7960                 outWctp = outp->wctp;
7961                 smbp = (smb_t *) &outp->data;
7962                 *outWctp++ = 0;
7963                 *outWctp++ = 0;
7964                 *outWctp++ = 0;
7965                 smbp->errLow = (unsigned char) (errCode & 0xff);
7966                 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
7967                 smbp->rcls = errClass;
7968             }
7969             smb_SendPacket(vcp, outp);
7970             smb_FreePacket(outp);
7971         } else {
7972             /* assert that we do not exceed the maximum number of sessions or NCBs.
7973             * we should probably want to wait for a session to be freed in case
7974             * we run out.
7975             */
7976             osi_assert(i < Sessionmax - 1);
7977             osi_assert(numNCBs < NCBmax - 1);   /* if we pass this test we can allocate one more */
7978
7979             LSNs[i] = ncbp->ncb_lsn;
7980             lanas[i] = ncbp->ncb_lana_num;
7981                 
7982             if (i == numSessions) {
7983                 /* Add new NCB for new session */
7984                 char eventName[MAX_PATH];
7985
7986                 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
7987
7988                 InitNCBslot(numNCBs);
7989                 numNCBs++;
7990                 thrd_SetEvent(NCBavails[0]);
7991                 thrd_SetEvent(NCBevents[0]);
7992                 for (j = 0; j < smb_NumServerThreads; j++)
7993                     thrd_SetEvent(NCBreturns[j][0]);
7994                 /* Also add new session event */
7995                 sprintf(eventName, "SessionEvents[%d]", i);
7996                 SessionEvents[i] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7997                 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7998                     osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7999                 numSessions++;
8000                 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
8001                 thrd_SetEvent(SessionEvents[0]);
8002             } else {
8003                 thrd_SetEvent(SessionEvents[i]);
8004             }
8005         }
8006         
8007         smb_ReleaseVC(vcp);
8008
8009         /* unlock */
8010         lock_ReleaseMutex(&smb_ListenerLock);
8011     }   /* dispatch while loop */
8012 }
8013
8014 /* initialize Netbios */
8015 void smb_NetbiosInit()
8016 {
8017     NCB *ncbp;
8018 #ifdef DJGPP
8019     dos_ptr dos_ncb;
8020 #endif /* DJGPP */
8021     int i, lana, code, l;
8022     char s[100];
8023     int delname_tried=0;
8024     int len;
8025     int lana_found = 0;
8026     OSVERSIONINFO Version;
8027
8028     /* Get the version of Windows */
8029     memset(&Version, 0x00, sizeof(Version));
8030     Version.dwOSVersionInfoSize = sizeof(Version);
8031     GetVersionEx(&Version);
8032
8033     /* setup the NCB system */
8034     ncbp = GetNCB();
8035 #ifdef DJGPP
8036     dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
8037 #endif /* DJGPP */
8038
8039 #ifndef DJGPP
8040     if (smb_LANadapter == -1) {
8041         ncbp->ncb_command = NCBENUM;
8042         ncbp->ncb_buffer = (PUCHAR)&lana_list;
8043         ncbp->ncb_length = sizeof(lana_list);
8044         code = Netbios(ncbp);
8045         if (code != 0) {
8046             afsi_log("Netbios NCBENUM error code %d", code);
8047             osi_panic(s, __FILE__, __LINE__);
8048         }
8049     }
8050     else {
8051         lana_list.length = 1;
8052         lana_list.lana[0] = smb_LANadapter;
8053     }
8054           
8055     for (i = 0; i < lana_list.length; i++) {
8056         /* reset the adaptor: in Win32, this is required for every process, and
8057          * acts as an init call, not as a real hardware reset.
8058          */
8059         ncbp->ncb_command = NCBRESET;
8060         ncbp->ncb_callname[0] = 100;
8061         ncbp->ncb_callname[2] = 100;
8062         ncbp->ncb_lana_num = lana_list.lana[i];
8063         code = Netbios(ncbp);
8064         if (code == 0) 
8065             code = ncbp->ncb_retcode;
8066         if (code != 0) {
8067             afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
8068             lana_list.lana[i] = 255;  /* invalid lana */
8069         } else {
8070             afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
8071         }
8072     }
8073 #else
8074     /* for DJGPP, there is no NCBENUM and NCBRESET is a real reset.  so
8075        we will just fake the LANA list */
8076     if (smb_LANadapter == -1) {
8077         for (i = 0; i < 8; i++)
8078             lana_list.lana[i] = i;
8079         lana_list.length = 8;
8080     }
8081     else {
8082         lana_list.length = 1;
8083         lana_list.lana[0] = smb_LANadapter;
8084     }
8085 #endif /* !DJGPP */
8086
8087     /* and declare our name so we can receive connections */
8088     memset(ncbp, 0, sizeof(*ncbp));
8089     len=lstrlen(smb_localNamep);
8090     memset(smb_sharename,' ',NCBNAMSZ);
8091     memcpy(smb_sharename,smb_localNamep,len);
8092     afsi_log("lana_list.length %d", lana_list.length);
8093
8094     /* Keep the name so we can unregister it later */
8095     for (l = 0; l < lana_list.length; l++) {
8096         lana = lana_list.lana[l];
8097
8098         ncbp->ncb_command = NCBADDNAME;
8099         ncbp->ncb_lana_num = lana;
8100         memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8101 #ifndef DJGPP
8102         code = Netbios(ncbp);
8103 #else /* DJGPP */
8104         code = Netbios(ncbp, dos_ncb);
8105 #endif /* !DJGPP */
8106           
8107         afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
8108                  lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
8109         {
8110             char name[NCBNAMSZ+1];
8111             name[NCBNAMSZ]=0;
8112             memcpy(name,ncbp->ncb_name,NCBNAMSZ);
8113             afsi_log("Netbios NCBADDNAME added new name >%s<",name);
8114         }
8115
8116         if (code == 0) code = ncbp->ncb_retcode;
8117         if (code == 0) {
8118             afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
8119 #ifdef DJGPP
8120             /* we only use one LANA with djgpp */
8121             lana_list.lana[0] = lana;
8122             lana_list.length = 1;
8123 #endif    
8124         }
8125         else {
8126             afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8127             if (code == NRC_BRIDGE) {    /* invalid LANA num */
8128                 lana_list.lana[l] = 255;
8129                 continue;
8130             }
8131             else if (code == NRC_DUPNAME) {
8132                 afsi_log("Name already exists; try to delete it");
8133                 memset(ncbp, 0, sizeof(*ncbp));
8134                 ncbp->ncb_command = NCBDELNAME;
8135                 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8136                 ncbp->ncb_lana_num = lana;
8137 #ifndef DJGPP
8138                 code = Netbios(ncbp);
8139 #else
8140                 code = Netbios(ncbp, dos_ncb);
8141 #endif /* DJGPP */
8142                 if (code == 0) 
8143                     code = ncbp->ncb_retcode;
8144                 else {
8145                     afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
8146                 }
8147                 if (code != 0 || delname_tried) {
8148                     lana_list.lana[l] = 255;
8149                 }
8150                 else if (code == 0) {
8151                     if (!delname_tried) {
8152                         lana--;
8153                         delname_tried = 1;
8154                         continue;
8155                     }
8156                 }
8157             }
8158             else {
8159                 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8160                 lana_list.lana[l] = 255;  /* invalid lana */
8161                 osi_panic(s, __FILE__, __LINE__);
8162             }
8163         }
8164         if (code == 0) {
8165             lana_found = 1;   /* at least one worked */
8166 #ifdef DJGPP
8167             break;
8168 #endif
8169         }
8170     }
8171
8172     osi_assert(lana_list.length >= 0);
8173     if (!lana_found) {
8174         osi_panic("No valid LANA numbers found!", __FILE__, __LINE__);
8175     }
8176         
8177     /* we're done with the NCB now */
8178     FreeNCB(ncbp);
8179 }
8180
8181 void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
8182               int nThreads
8183 #ifndef DJGPP
8184               , void *aMBfunc
8185 #endif
8186   )
8187
8188 {
8189     thread_t phandle;
8190     int lpid;
8191     INT_PTR i;
8192     int len;
8193     struct tm myTime;
8194 #ifdef DJGPP
8195     int npar, seg, sel;
8196     dos_ptr rawBuf;
8197 #endif /* DJGPP */
8198     EVENT_HANDLE retHandle;
8199     char eventName[MAX_PATH];
8200
8201 #ifndef DJGPP
8202     smb_MBfunc = aMBfunc;
8203 #endif /* DJGPP */
8204
8205     smb_useV3 = useV3;
8206     smb_LANadapter = LANadapt;
8207
8208     /* Initialize smb_localZero */
8209     myTime.tm_isdst = -1;               /* compute whether on DST or not */
8210     myTime.tm_year = 70;
8211     myTime.tm_mon = 0;
8212     myTime.tm_mday = 1;
8213     myTime.tm_hour = 0;
8214     myTime.tm_min = 0;
8215     myTime.tm_sec = 0;
8216     smb_localZero = mktime(&myTime);
8217
8218 #ifndef USE_NUMERIC_TIME_CONV
8219     /* Initialize kludge-GMT */
8220     smb_CalculateNowTZ();
8221 #endif /* USE_NUMERIC_TIME_CONV */
8222 #ifdef AFS_FREELANCE_CLIENT
8223     /* Make sure the root.afs volume has the correct time */
8224     cm_noteLocalMountPointChange();
8225 #endif
8226
8227     /* initialize the remote debugging log */
8228     smb_logp = logp;
8229         
8230     /* remember the name */
8231     len = (int)strlen(snamep);
8232     smb_localNamep = malloc(len+1);
8233     strcpy(smb_localNamep, snamep);
8234     afsi_log("smb_localNamep is >%s<", smb_localNamep);
8235
8236     /* and the global lock */
8237     lock_InitializeRWLock(&smb_globalLock, "smb global lock");
8238     lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
8239
8240     /* Raw I/O data structures */
8241     lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
8242
8243     lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
8244         
8245     /* 4 Raw I/O buffers */
8246 #ifndef DJGPP
8247     smb_RawBufs = calloc(65536,1);
8248     *((char **)smb_RawBufs) = NULL;
8249     for (i=0; i<3; i++) {
8250         char *rawBuf = calloc(65536,1);
8251         *((char **)rawBuf) = smb_RawBufs;
8252         smb_RawBufs = rawBuf;
8253     }
8254 #else /* DJGPP */
8255     npar = 65536 >> 4;  /* number of paragraphs */
8256     seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[0]);
8257     if (seg == -1) {
8258         afsi_log("Cannot allocate %d paragraphs of DOS memory",
8259                   npar);
8260         osi_panic("",__FILE__,__LINE__);
8261     }
8262     else {
8263         afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
8264                   npar, seg);
8265     }
8266     smb_RawBufs = (seg * 16) + 0;  /* DOS physical address */
8267         
8268     _farpokel(_dos_ds, smb_RawBufs, NULL);
8269     for (i=0; i<SMB_RAW_BUFS-1; i++) {
8270         npar = 65536 >> 4;  /* number of paragraphs */
8271         seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[i+1]);
8272         if (seg == -1) {
8273             afsi_log("Cannot allocate %d paragraphs of DOS memory",
8274                       npar);
8275             osi_panic("",__FILE__,__LINE__);
8276         }
8277         else {
8278             afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
8279                       npar, seg);
8280         }
8281         rawBuf = (seg * 16) + 0;  /* DOS physical address */
8282         /*_farpokel(_dos_ds, smb_RawBufs, smb_RawBufs);*/
8283         _farpokel(_dos_ds, rawBuf, smb_RawBufs);
8284         smb_RawBufs = rawBuf;
8285     }
8286 #endif /* !DJGPP */
8287
8288     /* global free lists */
8289     smb_ncbFreeListp = NULL;
8290     smb_packetFreeListp = NULL;
8291
8292     smb_NetbiosInit();
8293
8294     /* Initialize listener and server structures */
8295     numVCs = 0;
8296     memset(dead_sessions, 0, sizeof(dead_sessions));
8297     sprintf(eventName, "SessionEvents[0]");
8298     SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8299     if ( GetLastError() == ERROR_ALREADY_EXISTS )
8300         afsi_log("Event Object Already Exists: %s", eventName);
8301     numSessions = 1;
8302     smb_NumServerThreads = nThreads;
8303     sprintf(eventName, "NCBavails[0]");
8304     NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8305     if ( GetLastError() == ERROR_ALREADY_EXISTS )
8306         afsi_log("Event Object Already Exists: %s", eventName);
8307     sprintf(eventName, "NCBevents[0]");
8308     NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8309     if ( GetLastError() == ERROR_ALREADY_EXISTS )
8310         afsi_log("Event Object Already Exists: %s", eventName);
8311     NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
8312     sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
8313     retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8314     if ( GetLastError() == ERROR_ALREADY_EXISTS )
8315         afsi_log("Event Object Already Exists: %s", eventName);
8316     for (i = 0; i < smb_NumServerThreads; i++) {
8317         NCBreturns[i] = malloc(NCBmax * sizeof(EVENT_HANDLE));
8318         NCBreturns[i][0] = retHandle;
8319     }
8320
8321     smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
8322     for (i = 0; i < smb_NumServerThreads; i++) {
8323         sprintf(eventName, "smb_ServerShutdown[%d]", i);
8324         smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8325         if ( GetLastError() == ERROR_ALREADY_EXISTS )
8326             afsi_log("Event Object Already Exists: %s", eventName);
8327         InitNCBslot((int)(i+1));
8328     }
8329     numNCBs = smb_NumServerThreads + 1;
8330
8331     /* Initialize dispatch table */
8332     memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
8333     /* Prepare the table for unknown operations */
8334     for(i=0; i<= SMB_NOPCODES; i++) {
8335         smb_dispatchTable[i].procp = smb_SendCoreBadOp;
8336     }
8337     /* Fill in the ones we do know */
8338     smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
8339     smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
8340     smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
8341     smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
8342     smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
8343     smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
8344     smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
8345     smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
8346     smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
8347     smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
8348     smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
8349     smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
8350     smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
8351     smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
8352     smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
8353     smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
8354     smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
8355     smb_dispatchTable[0x11].procp = smb_SendCoreBadOp;  /* process exit */
8356     smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
8357     smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
8358     /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
8359     smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8360     smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
8361     smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
8362     smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
8363     smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
8364     smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
8365     smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
8366     smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8367     smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
8368     smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8369     smb_dispatchTable[0x29].procp = smb_SendCoreBadOp;  /* copy file */
8370     smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
8371     /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
8372     smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8373     smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
8374     smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
8375     smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
8376     smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
8377     smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A;        /* both are same */
8378     smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8379     smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
8380     smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8381     smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
8382     smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
8383     smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
8384     smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
8385     smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
8386     smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
8387     smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
8388     smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
8389     smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
8390     smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
8391     smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
8392     smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
8393     smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
8394     smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
8395     smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
8396     smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
8397     smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
8398     smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
8399     smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
8400     smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
8401     smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8402     smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
8403     smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp;  /* Open Print File */
8404     smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp;  /* Write Print File */
8405     smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp;  /* Close Print File */
8406     smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp;  /* Get Print Queue */
8407     smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp;  /* Read Bulk */
8408     smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp;  /* Write Bulk */
8409     smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp;  /* Write Bulk Data */
8410
8411     /* setup tran 2 dispatch table */
8412     smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
8413     smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir;        /* FindFirst */
8414     smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir;        /* FindNext */
8415     smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
8416     smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
8417     smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
8418     smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
8419     smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
8420     smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
8421     smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
8422     smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
8423     smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
8424     smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
8425     smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
8426     smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
8427     smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
8428     smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
8429
8430     /* setup the rap dispatch table */
8431     memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
8432     smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
8433     smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
8434     smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
8435     smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
8436
8437     smb3_Init();
8438
8439     /* if we are doing SMB authentication we have register outselves as a logon process */
8440     if (smb_authType != SMB_AUTH_NONE) {
8441         NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
8442         LSA_STRING afsProcessName;
8443         LSA_OPERATIONAL_MODE dummy; /*junk*/
8444
8445         afsProcessName.Buffer = "OpenAFSClientDaemon";
8446         afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
8447         afsProcessName.MaximumLength = afsProcessName.Length + 1;
8448
8449         nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
8450
8451         if (nts == STATUS_SUCCESS) {
8452             LSA_STRING packageName;
8453             /* we are registered. Find out the security package id */
8454             packageName.Buffer = MSV1_0_PACKAGE_NAME;
8455             packageName.Length = (USHORT)strlen(packageName.Buffer);
8456             packageName.MaximumLength = packageName.Length + 1;
8457             nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
8458             if (nts == STATUS_SUCCESS) {
8459                 /* BEGIN 
8460                  * This code forces Windows to authenticate against the Logon Cache 
8461                  * first instead of attempting to authenticate against the Domain 
8462                  * Controller.  When the Windows logon cache is enabled this improves
8463                  * performance by removing the network access and works around a bug
8464                  * seen at sites which are using a MIT Kerberos principal to login
8465                  * to machines joined to a non-root domain in a multi-domain forest.
8466                  */
8467                 PVOID pResponse = NULL;
8468                 ULONG cbResponse = 0;
8469                 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
8470
8471                 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
8472                 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
8473                 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST; 
8474                 OptionsRequest.DisableOptions = FALSE;
8475
8476                 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
8477                                                     smb_lsaSecPackage,
8478                                                     &OptionsRequest,
8479                                                     sizeof(OptionsRequest),
8480                                                     &pResponse,
8481                                                     &cbResponse,
8482                                                     &ntsEx
8483                                                     );
8484
8485                 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
8486                     char message[256];
8487                     sprintf(message,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
8488                                        nts, ntsEx);
8489                     OutputDebugString(message);
8490                     afsi_log(message);
8491                 } else {
8492                     OutputDebugString("MsV1_0SetProcessOption success");
8493                     afsi_log("MsV1_0SetProcessOption success");
8494                 }
8495                 /* END - code from Larry */
8496
8497                 smb_lsaLogonOrigin.Buffer = "OpenAFS";
8498                 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
8499                 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
8500             } else {
8501                 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
8502
8503                 /* something went wrong. We report the error and revert back to no authentication
8504                 because we can't perform any auth requests without a successful lsa handle
8505                 or sec package id. */
8506                 afsi_log("Reverting to NO SMB AUTH");
8507                 smb_authType = SMB_AUTH_NONE;
8508             }
8509         } else {
8510             afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
8511
8512             /* something went wrong. We report the error and revert back to no authentication
8513             because we can't perform any auth requests without a successful lsa handle
8514             or sec package id. */
8515             afsi_log("Reverting to NO SMB AUTH");
8516             smb_authType = SMB_AUTH_NONE;
8517         }
8518
8519 #ifdef COMMENT
8520         /* Don't fallback to SMB_AUTH_NTLM.  Apparently, allowing SPNEGO to be used each
8521          * time prevents the failure of authentication when logged into Windows with an
8522          * external Kerberos principal mapped to a local account.
8523          */
8524         else if ( smb_authType == SMB_AUTH_EXTENDED) {
8525             /* Test to see if there is anything to negotiate.  If SPNEGO is not going to be used 
8526              * then the only option is NTLMSSP anyway; so just fallback. 
8527              */
8528             void * secBlob;
8529             int secBlobLength;
8530
8531             smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
8532             if (secBlobLength == 0) {
8533                 smb_authType = SMB_AUTH_NTLM;
8534                 afsi_log("Reverting to SMB AUTH NTLM");
8535             } else
8536                 free(secBlob);
8537         }
8538 #endif
8539     }
8540
8541     {
8542         DWORD bufsize;
8543         /* Now get ourselves a domain name. */
8544         /* For now we are using the local computer name as the domain name.
8545          * It is actually the domain for local logins, and we are acting as
8546          * a local SMB server. 
8547          */
8548         bufsize = sizeof(smb_ServerDomainName) - 1;
8549         GetComputerName(smb_ServerDomainName, &bufsize);
8550         smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
8551         afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
8552     }
8553
8554     /* Start listeners, waiters, servers, and daemons */
8555
8556     for (i = 0; i < lana_list.length; i++) {
8557         if (lana_list.lana[i] == 255) 
8558             continue;
8559         phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
8560                                (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
8561         osi_assert(phandle != NULL);
8562         thrd_CloseHandle(phandle);
8563     }
8564
8565 #ifndef DJGPP
8566     phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
8567                           NULL, 0, &lpid, "smb_ClientWaiter");
8568     osi_assert(phandle != NULL);
8569     thrd_CloseHandle(phandle);
8570 #endif /* !DJGPP */
8571
8572     phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
8573                           NULL, 0, &lpid, "smb_ServerWaiter");
8574     osi_assert(phandle != NULL);
8575     thrd_CloseHandle(phandle);
8576
8577     for (i=0; i<smb_NumServerThreads; i++) {
8578         phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
8579                               (void *) i, 0, &lpid, "smb_Server");
8580         osi_assert(phandle != NULL);
8581         thrd_CloseHandle(phandle);
8582     }
8583
8584     phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
8585                           NULL, 0, &lpid, "smb_Daemon");
8586     osi_assert(phandle != NULL);
8587     thrd_CloseHandle(phandle);
8588
8589     phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
8590                           NULL, 0, &lpid, "smb_WaitingLocksDaemon");
8591     osi_assert(phandle != NULL);
8592     thrd_CloseHandle(phandle);
8593
8594 #ifdef DJGPP
8595     smb_ListShares();
8596 #endif
8597
8598     return;
8599 }
8600
8601 void smb_Shutdown(void)
8602 {
8603     NCB *ncbp;
8604 #ifdef DJGPP
8605     dos_ptr dos_ncb;
8606 #endif
8607     long code = 0;
8608     int i;
8609     smb_vc_t *vcp;
8610
8611     /*fprintf(stderr, "Entering smb_Shutdown\n");*/
8612         
8613     /* setup the NCB system */
8614     ncbp = GetNCB();
8615 #ifdef DJGPP
8616     dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
8617 #endif
8618
8619     /* Block new sessions by setting shutdown flag */
8620     smbShutdownFlag = 1;
8621
8622     /* Hang up all sessions */
8623     memset((char *)ncbp, 0, sizeof(NCB));
8624     for (i = 1; i < numSessions; i++)
8625     {
8626         if (dead_sessions[i])
8627             continue;
8628       
8629         /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8630         ncbp->ncb_command = NCBHANGUP;
8631         ncbp->ncb_lana_num = lanas[i];  /*smb_LANadapter;*/
8632         ncbp->ncb_lsn = (UCHAR)LSNs[i];
8633 #ifndef DJGPP
8634         code = Netbios(ncbp);
8635 #else
8636         code = Netbios(ncbp, dos_ncb);
8637 #endif
8638         /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8639         if (code == 0) code = ncbp->ncb_retcode;
8640         if (code != 0) {
8641             osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
8642             fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
8643         }
8644     }
8645
8646     /* Trigger the shutdown of all SMB threads */                                
8647     for (i = 0; i < smb_NumServerThreads; i++)                                   
8648         thrd_SetEvent(NCBreturns[i][0]);                                         
8649                                                                                  
8650     thrd_SetEvent(NCBevents[0]);                                                 
8651     thrd_SetEvent(SessionEvents[0]);                                             
8652     thrd_SetEvent(NCBavails[0]);                                                 
8653                                                                                  
8654     for (i = 0;i < smb_NumServerThreads; i++) {                                  
8655         DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500); 
8656         if (code == WAIT_OBJECT_0) {                                             
8657             continue;                                                            
8658         } else {                                                                 
8659             afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);      
8660             thrd_SetEvent(NCBreturns[i--][0]);                                   
8661         }                                                                        
8662     }                                                                            
8663
8664     /* Delete Netbios name */
8665     memset((char *)ncbp, 0, sizeof(NCB));
8666     for (i = 0; i < lana_list.length; i++) {
8667         if (lana_list.lana[i] == 255) continue;
8668         ncbp->ncb_command = NCBDELNAME;
8669         ncbp->ncb_lana_num = lana_list.lana[i];
8670         memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8671 #ifndef DJGPP
8672         code = Netbios(ncbp);
8673 #else
8674         code = Netbios(ncbp, dos_ncb);
8675 #endif
8676         if (code == 0) 
8677             code = ncbp->ncb_retcode;
8678         if (code != 0) {
8679             fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
8680                      ncbp->ncb_lana_num, code);
8681         }       
8682         fflush(stderr);
8683     }
8684
8685     /* Release the reference counts held by the VCs */
8686     lock_ObtainWrite(&smb_rctLock);
8687     for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) 
8688     {
8689         smb_fid_t *fidp;
8690         smb_tid_t *tidp;
8691      
8692         for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8693         {
8694             if (fidp->scp != NULL) {
8695                 cm_scache_t * scp;
8696
8697                 lock_ObtainMutex(&fidp->mx);
8698                 if (fidp->scp != NULL) {
8699                     scp = fidp->scp;
8700                     fidp->scp = NULL;
8701                     cm_ReleaseSCache(scp);
8702                 }
8703                 lock_ReleaseMutex(&fidp->mx);
8704             }
8705         }
8706
8707         for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
8708             if (tidp->vcp)
8709                 smb_ReleaseVCNoLock(tidp->vcp);
8710             if (tidp->userp) {
8711                 cm_user_t *userp = tidp->userp;
8712                 tidp->userp = NULL;
8713                 lock_ReleaseWrite(&smb_rctLock);
8714                 cm_ReleaseUser(userp);
8715                 lock_ObtainWrite(&smb_rctLock);
8716             }
8717         }
8718     }
8719     lock_ReleaseWrite(&smb_rctLock);
8720 }
8721
8722 /* Get the UNC \\<servername>\<sharename> prefix. */
8723 char *smb_GetSharename()
8724 {
8725     char *name;
8726
8727     /* Make sure we have been properly initialized. */
8728     if (smb_localNamep == NULL)
8729         return NULL;
8730
8731     /* Allocate space for \\<servername>\<sharename>, plus the
8732      * terminator.
8733      */
8734     name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
8735     sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
8736     return name;
8737 }   
8738
8739
8740 #ifdef LOG_PACKET
8741 void smb_LogPacket(smb_packet_t *packet)
8742 {
8743     BYTE *vp, *cp;
8744     unsigned length, paramlen, datalen, i, j;
8745     char buf[81];
8746     char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
8747
8748     if (!packet) return;
8749
8750     osi_Log0(smb_logp, "*** SMB packet dump ***");
8751
8752     vp = (BYTE *) packet->data;
8753
8754     datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
8755     length = paramlen + 2 + datalen;
8756
8757
8758     for (i=0;i < length; i+=16)
8759     {
8760         memset( buf, ' ', 80 );
8761         buf[80] = 0;
8762
8763         itoa( i, buf, 16 );
8764
8765         buf[strlen(buf)] = ' ';
8766
8767         cp = (BYTE*) buf + 7;
8768
8769         for (j=0;j < 16 && (i+j)<length; j++)
8770         {
8771             *(cp++) = hex[vp[i+j] >> 4];
8772             *(cp++) = hex[vp[i+j] & 0xf];
8773             *(cp++) = ' ';
8774
8775             if (j==7)
8776             {
8777                 *(cp++) = '-';
8778                 *(cp++) = ' ';
8779             }
8780         }
8781
8782         for (j=0;j < 16 && (i+j)<length;j++)
8783         {
8784             *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
8785             if (j==7)
8786             {
8787                 *(cp++) = ' ';
8788                 *(cp++) = '-';
8789                 *(cp++) = ' ';
8790             }
8791         }
8792
8793         *cp = 0;
8794
8795         osi_Log0( smb_logp, osi_LogSaveString(smb_logp, buf));
8796     }
8797
8798     osi_Log0(smb_logp, "*** End SMB packet dump ***");
8799 }
8800 #endif /* LOG_PACKET */
8801
8802
8803 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
8804 {
8805     int zilch;
8806     char output[1024];
8807   
8808     smb_vc_t *vcp;
8809   
8810     if (lock)
8811         lock_ObtainRead(&smb_rctLock);
8812   
8813     sprintf(output, "begin dumping smb_vc_t\n");
8814     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8815
8816     for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) 
8817     {
8818         smb_fid_t *fidp;
8819       
8820         sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
8821                  cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
8822         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8823       
8824         sprintf(output, "begin dumping smb_fid_t\n");
8825         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8826
8827         for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8828         {
8829             sprintf(output, "%s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, ioctlp=0x%p, NTopen_pathp=%s, NTopen_wholepathp=%s\n", 
8830                      cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp, 
8831                      fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL", 
8832                      fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
8833             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8834         }
8835       
8836         sprintf(output, "done dumping smb_fid_t\n");
8837         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8838     }
8839
8840     sprintf(output, "done dumping smb_vc_t\n");
8841     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8842   
8843     if (lock)
8844         lock_ReleaseRead(&smb_rctLock);
8845     return 0;
8846 }