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