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