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