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