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