no-more-ini-files-20040713
[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 #define NOMOREFILESFIX 1
13
14 #include <afs/param.h>
15 #include <afs/stds.h>
16
17 #ifndef DJGPP
18 #include <windows.h>
19 #else
20 #include <sys/timeb.h>
21 #include <tzfile.h>
22 #endif /* !DJGPP */
23 #include <stddef.h>
24 #include <stdlib.h>
25 #include <malloc.h>
26 #include <string.h>
27 #include <stdio.h>
28 #include <time.h>
29
30 #include <osi.h>
31 #include <ntstatus.h>
32
33 #include "afsd.h"
34
35 #include "smb.h"
36 #include "lanahelper.h"
37
38 /* These characters are illegal in Windows filenames */
39 static char *illegalChars = "\\/:*?\"<>|";
40 BOOL isWindows2000 = FALSE;
41
42 smb_vc_t *dead_vcp = NULL;
43 smb_vc_t *active_vcp = NULL;
44
45 /* TODO; logout mechanism needs to be thread-safe */
46 char *loggedOutName = NULL;
47 smb_user_t *loggedOutUserp = NULL;
48 unsigned long loggedOutTime;
49 int loggedOut = 0;
50 int smbShutdownFlag = 0;
51
52 int smb_LogoffTokenTransfer;
53 unsigned long smb_LogoffTransferTimeout;
54
55 DWORD last_msg_time = 0;
56
57 long ongoingOps = 0;
58
59 unsigned int sessionGen = 0;
60
61 extern void afsi_log(char *pattern, ...);
62 extern HANDLE afsi_file;
63
64 osi_hyper_t hzero = {0, 0};
65 osi_hyper_t hones = {0xFFFFFFFF, -1};
66
67 osi_log_t *  smb_logp;
68 osi_rwlock_t smb_globalLock;
69 osi_rwlock_t smb_rctLock;
70 osi_mutex_t  smb_ListenerLock;
71  
72 char smb_LANadapter;
73 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
74
75 /* for debugging */
76 long smb_maxObsConcurrentCalls=0;
77 long smb_concurrentCalls=0;
78
79 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
80
81 smb_packet_t *smb_packetFreeListp;
82 smb_ncb_t *smb_ncbFreeListp;
83
84 int smb_NumServerThreads;
85
86 int numNCBs, numSessions, numVCs;
87
88 int smb_maxVCPerServer;
89 int smb_maxMpxRequests;
90
91 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
92 HANDLE smb_lsaHandle;
93 ULONG smb_lsaSecPackage;
94 LSA_STRING smb_lsaLogonOrigin;
95
96 #define NCBmax MAXIMUM_WAIT_OBJECTS
97 EVENT_HANDLE NCBavails[NCBmax], NCBevents[NCBmax];
98 EVENT_HANDLE **NCBreturns;
99 DWORD NCBsessions[NCBmax];
100 NCB *NCBs[NCBmax];
101 struct smb_packet *bufs[NCBmax];
102
103 #define Sessionmax MAXIMUM_WAIT_OBJECTS
104 EVENT_HANDLE SessionEvents[Sessionmax];
105 unsigned short LSNs[Sessionmax];
106 int lanas[Sessionmax];
107 BOOL dead_sessions[Sessionmax];
108 LANA_ENUM lana_list;
109
110 /* for raw I/O */
111 osi_mutex_t smb_RawBufLock;
112 #ifdef DJGPP
113 #define SMB_RAW_BUFS 4
114 dos_ptr smb_RawBufs;
115 int smb_RawBufSel[SMB_RAW_BUFS];
116 #else
117 char *smb_RawBufs;
118 #endif /* DJGPP */
119
120 #define SMB_MASKFLAG_TILDE 1
121 #define SMB_MASKFLAG_CASEFOLD 2
122
123 #define RAWTIMEOUT INFINITE
124
125 /* for raw write */
126 typedef struct raw_write_cont {
127         long code;
128         osi_hyper_t offset;
129         long count;
130 #ifndef DJGPP
131         char *buf;
132 #else
133         dos_ptr buf;
134 #endif /* DJGPP */
135         int writeMode;
136         long alreadyWritten;
137 } raw_write_cont_t;
138
139 /* dir search stuff */
140 long smb_dirSearchCounter = 1;
141 smb_dirSearch_t *smb_firstDirSearchp;
142 smb_dirSearch_t *smb_lastDirSearchp;
143
144 /* hide dot files? */
145 int smb_hideDotFiles;
146
147 /* global state about V3 protocols */
148 int smb_useV3;          /* try to negotiate V3 */
149
150 #ifndef DJGPP
151 static showErrors = 1;
152 /* MessageBox or something like it */
153 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
154 extern HANDLE WaitToTerminate;
155 #endif /* DJGPP */
156
157 /* GMT time info:
158  * Time in Unix format of midnight, 1/1/1970 local time.
159  * When added to dosUTime, gives Unix (AFS) time.
160  */
161 long smb_localZero;
162
163 /* Time difference for converting to kludge-GMT */
164 int smb_NowTZ;
165
166 char *smb_localNamep = NULL;
167
168 smb_vc_t *smb_allVCsp;
169
170 smb_username_t *usernamesp = NULL;
171
172 smb_waitingLock_t *smb_allWaitingLocks;
173
174 /* forward decl */
175 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
176                                                 NCB *ncbp, raw_write_cont_t *rwcp);
177 void smb_NetbiosInit();
178 #ifdef DJGPP
179 #ifndef AFS_WIN95_ENV
180 DWORD smb_ServerExceptionFilter(void);
181 #endif
182
183 extern char cm_HostName[];
184 extern char cm_confDir[];
185 #endif
186
187 #ifdef DJGPP
188 #define LPTSTR char *
189 #define GetComputerName(str, sizep) \
190        strcpy((str), cm_HostName); \
191        *(sizep) = strlen(cm_HostName)
192 #endif /* DJGPP */
193
194 extern char AFSConfigKeyName[];
195
196 char smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = ""; /* domain name */
197 int smb_ServerDomainNameLength = 0;
198 char smb_ServerOS[] = "Windows 5.0"; /* Faux OS String */
199 int smb_ServerOSLength = sizeof(smb_ServerOS);
200 char smb_ServerLanManager[] = "Windows 2000 LAN Manager"; /* Faux LAN Manager string */
201 int smb_ServerLanManagerLength = sizeof(smb_ServerLanManager);
202
203 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
204
205 /*
206  * Demo expiration
207  *
208  * To build an expiring version, comment out the definition of NOEXPIRE,
209  * and set the definition of EXPIREDATE to the desired value.
210  */
211 #define NOEXPIRE 1
212 #define EXPIREDATE 834000000            /* Wed Jun 5 1996 */
213
214
215 char * myCrt_Dispatch(int i)
216 {
217         switch (i)
218         {
219         default:
220                 return "unknown SMB op";
221         case 0x00:
222                 return "(00)ReceiveCoreMakeDir";
223         case 0x01:
224                 return "(01)ReceiveCoreRemoveDir";
225         case 0x02:
226                 return "(02)ReceiveCoreOpen";
227         case 0x03:
228                 return "(03)ReceiveCoreCreate";
229         case 0x04:
230                 return "(04)ReceiveCoreClose";
231         case 0x05:
232                 return "(05)ReceiveCoreFlush";
233         case 0x06:
234                 return "(06)ReceiveCoreUnlink";
235         case 0x07:
236                 return "(07)ReceiveCoreRename";
237         case 0x08:
238                 return "(08)ReceiveCoreGetFileAttributes";
239         case 0x09:
240                 return "(09)ReceiveCoreSetFileAttributes";
241         case 0x0a:
242                 return "(0a)ReceiveCoreRead";
243         case 0x0b:
244                 return "(0b)ReceiveCoreWrite";
245         case 0x0c:
246                 return "(0c)ReceiveCoreLockRecord";
247         case 0x0d:
248                 return "(0d)ReceiveCoreUnlockRecord";
249         case 0x0e:
250                 return "(0e)SendCoreBadOp";
251         case 0x0f:
252                 return "(0f)ReceiveCoreCreate";
253         case 0x10:
254                 return "(10)ReceiveCoreCheckPath";
255         case 0x11:
256                 return "(11)SendCoreBadOp";
257         case 0x12:
258                 return "(12)ReceiveCoreSeek";
259         case 0x1a:
260                 return "(1a)ReceiveCoreReadRaw";
261         case 0x1d:
262                 return "(1d)ReceiveCoreWriteRawDummy";
263         case 0x22:
264                 return "(22)ReceiveV3SetAttributes";
265         case 0x23:
266                 return "(23)ReceiveV3GetAttributes";
267         case 0x24:
268                 return "(24)ReceiveV3LockingX";
269         case 0x29:
270                 return "(29)SendCoreBadOp";
271         case 0x2b:
272                 return "(2b)ReceiveCoreEcho";
273         case 0x2d:
274                 return "(2d)ReceiveV3OpenX";
275         case 0x2e:
276                 return "(2e)ReceiveV3ReadX";
277         case 0x32:
278                 return "(32)ReceiveV3Tran2A";
279         case 0x33:
280                 return "(33)ReceiveV3Tran2A";
281         case 0x34:
282                 return "(34)ReceiveV3FindClose";
283         case 0x35:
284                 return "(35)ReceiveV3FindNotifyClose";
285         case 0x70:
286                 return "(70)ReceiveCoreTreeConnect";
287         case 0x71:
288                 return "(71)ReceiveCoreTreeDisconnect";
289         case 0x72:
290                 return "(72)ReceiveNegotiate";
291         case 0x73:
292                 return "(73)ReceiveV3SessionSetupX";
293         case 0x74:
294                 return "(74)ReceiveV3UserLogoffX";
295         case 0x75:
296                 return "(75)ReceiveV3TreeConnectX";
297         case 0x80:
298                 return "(80)ReceiveCoreGetDiskAttributes";
299         case 0x81:
300                 return "(81)ReceiveCoreSearchDir";
301         case 0xA0:
302                 return "(A0)ReceiveNTTransact";
303         case 0xA2:
304                 return "(A2)ReceiveNTCreateX";
305         case 0xA4:
306                 return "(A4)ReceiveNTCancel";
307         case 0xc0:
308                 return "(c0)SendCoreBadOp";
309         case 0xc1:
310                 return "(c1)SendCoreBadOp";
311         case 0xc2:
312                 return "(c2)SendCoreBadOp";
313         case 0xc3:
314                 return "(c3)SendCoreBadOp";
315         }
316 }
317
318 char * myCrt_2Dispatch(int i)
319 {
320         switch (i)
321         {
322         default:
323                 return "unknown SMB op-2";
324         case 0:
325                 return "S(00)CreateFile";
326         case 1:
327                 return "S(01)FindFirst";
328         case 2:
329                 return "S(02)FindNext"; /* FindNext */
330         case 3:
331                 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
332         case 4:
333                 return "S(04)??";
334         case 5:
335                 return "S(05)QueryFileInfo_ReceiveTran2QPathInfo";
336         case 6:
337                 return "S(06)SetFileInfo_ReceiveTran2SetPathInfo";
338         case 7:
339                 return "S(07)SetInfoHandle_ReceiveTran2QFileInfo";
340         case 8:
341                 return "S(08)??_ReceiveTran2SetFileInfo";
342         case 9:
343                 return "S(09)??_ReceiveTran2FSCTL";
344         case 10:
345                 return "S(0a)_ReceiveTran2IOCTL";
346         case 11:
347                 return "S(0b)_ReceiveTran2FindNotifyFirst";
348         case 12:
349                 return "S(0c)_ReceiveTran2FindNotifyNext";
350         case 13:
351                 return "S(0d)CreateDirectory_ReceiveTran2MKDir";
352         }
353 }
354
355 /* scache must be locked */
356 unsigned int smb_Attributes(cm_scache_t *scp)
357 {
358         unsigned int attrs;
359
360         if (scp->fileType == CM_SCACHETYPE_DIRECTORY
361                 || scp->fileType == CM_SCACHETYPE_MOUNTPOINT)
362                 attrs = SMB_ATTR_DIRECTORY;
363         else
364                 attrs = 0;
365
366         /*
367          * We used to mark a file RO if it was in an RO volume, but that
368          * turns out to be impolitic in NT.  See defect 10007.
369          */
370 #ifdef notdef
371         if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
372 #endif
373         if ((scp->unixModeBits & 0222) == 0)
374                 attrs |= SMB_ATTR_READONLY;     /* turn on read-only flag */
375
376         return attrs;
377 }
378
379 /* Check if the named file/dir is a dotfile/dotdir */
380 /* String pointed to by lastComp can have leading slashes, but otherwise should have
381    no other patch components */
382 unsigned int smb_IsDotFile(char *lastComp) {
383         char *s;
384         if(lastComp) {
385                 /* skip over slashes */
386         for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
387         }
388         else
389                 return 0;
390
391     /* nulls, curdir and parent dir doesn't count */
392         if(!*s) return 0;
393         if(*s == '.') {
394                 if(!*(s + 1)) return 0;
395                 if(*(s+1) == '.' && !*(s + 2)) return 0;
396                 return 1;
397         }
398         return 0;
399 }
400
401 static int ExtractBits(WORD bits, short start, short len)
402 {
403         int end;
404         WORD num;
405
406         end = start + len;
407         
408         num = bits << (16 - end);
409         num = num >> ((16 - end) + start);
410
411         return (int)num;
412 }
413
414 #ifndef DJGPP
415 void ShowUnixTime(char *FuncName, long unixTime)
416 {
417         FILETIME ft;
418         WORD wDate, wTime;
419
420         smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
421                 
422         if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
423                 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
424         else {
425                 int day, month, year, sec, min, hour;
426                 char msg[256];
427
428                 day = ExtractBits(wDate, 0, 5);
429                 month = ExtractBits(wDate, 5, 4);
430                 year = ExtractBits(wDate, 9, 7) + 1980;
431
432                 sec = ExtractBits(wTime, 0, 5);
433                 min = ExtractBits(wTime, 5, 6);
434                 hour = ExtractBits(wTime, 11, 5);
435
436                 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
437                 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
438         }
439 }
440 #endif /* DJGPP */
441
442 #ifndef DJGPP
443 /* Determine if we are observing daylight savings time */
444 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
445 {
446         TIME_ZONE_INFORMATION timeZoneInformation;
447         SYSTEMTIME utc, local, localDST;
448
449         /* Get the time zone info. NT uses this to calc if we are in DST. */
450         GetTimeZoneInformation(&timeZoneInformation);
451  
452         /* Return the daylight bias */
453         *pDstBias = timeZoneInformation.DaylightBias;
454
455         /* Return the bias */
456         *pBias = timeZoneInformation.Bias;
457
458         /* Now determine if DST is being observed */
459
460         /* Get the UTC (GMT) time */
461         GetSystemTime(&utc);
462
463         /* Convert UTC time to local time using the time zone info.  If we are
464            observing DST, the calculated local time will include this. 
465         */
466         SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
467
468         /* Set the daylight bias to 0.  The daylight bias is the amount of change
469            in time that we use for daylight savings time.  By setting this to 0
470            we cause there to be no change in time during daylight savings time. 
471         */
472         timeZoneInformation.DaylightBias = 0;
473
474         /* Convert the utc time to local time again, but this time without any
475            adjustment for daylight savings time. 
476         */
477         SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
478
479         /* If the two times are different, then it means that the localDST that
480            we calculated includes the daylight bias, and therefore we are
481            observing daylight savings time.
482         */
483         *pDST = localDST.wHour != local.wHour;
484 }
485 #else
486 /* Determine if we are observing daylight savings time */
487 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
488 {
489         struct timeb t;
490
491         ftime(&t);
492         *pDST = t.dstflag;
493         *pDstBias = -60;    /* where can this be different? */
494         *pBias = t.timezone;
495 }
496 #endif /* DJGPP */
497  
498
499 void CompensateForSmbClientLastWriteTimeBugs(long *pLastWriteTime)
500 {
501         BOOL dst;       /* Will be TRUE if observing DST */
502         LONG dstBias;   /* Offset from local time if observing DST */
503         LONG bias;      /* Offset from GMT for local time */
504
505         /*
506          * This function will adjust the last write time to compensate
507          * for two bugs in the smb client:
508          *
509          *    1) During Daylight Savings Time, the LastWriteTime is ahead
510          *       in time by the DaylightBias (ignoring the sign - the
511          *       DaylightBias is always stored as a negative number).  If
512          *       the DaylightBias is -60, then the LastWriteTime will be
513          *       ahead by 60 minutes.
514          *
515          *    2) If the local time zone is a positive offset from GMT, then
516          *       the LastWriteTime will be the correct local time plus the
517          *       Bias (ignoring the sign - a positive offset from GMT is
518          *       always stored as a negative Bias).  If the Bias is -120,
519          *       then the LastWriteTime will be ahead by 120 minutes.
520          *
521          *    These bugs can occur at the same time.
522          */
523
524         GetTimeZoneInfo(&dst, &dstBias, &bias);
525
526         /* First adjust for DST */
527         if (dst)
528                 *pLastWriteTime -= (-dstBias * 60);     /* Convert dstBias to seconds */
529
530         /* Now adjust for a positive offset from GMT (a negative bias). */
531         if (bias < 0)
532                 *pLastWriteTime -= (-bias * 60);        /* Convert bias to seconds */
533 }               
534
535 /*
536  * Calculate the difference (in seconds) between local time and GMT.
537  * This enables us to convert file times to kludge-GMT.
538  */
539 static void
540 smb_CalculateNowTZ()
541 {
542         time_t t;
543         struct tm gmt_tm, local_tm;
544         int days, hours, minutes, seconds;
545
546         t = time(NULL);
547         gmt_tm = *(gmtime(&t));
548         local_tm = *(localtime(&t));
549
550         days = local_tm.tm_yday - gmt_tm.tm_yday;
551         hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour
552 #ifdef COMMENT
553         /* There is a problem with DST immediately after the time change
554          * which may continue to exist until the machine is rebooted
555          */
556         - (local_tm.tm_isdst ? 1 : 0)
557 #endif /* COMMENT */
558         ;
559         minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
560         seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
561
562         smb_NowTZ = seconds;
563 }
564
565 #ifndef DJGPP
566 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, long unixTime)
567 {
568         struct tm *ltp;
569         SYSTEMTIME stm;
570         struct tm localJunk;
571         long ersatz_unixTime;
572
573         /*
574          * Must use kludge-GMT instead of real GMT.
575          * kludge-GMT is computed by adding time zone difference to localtime.
576          *
577          * real GMT would be:
578          * ltp = gmtime(&unixTime);
579          */
580         ersatz_unixTime = unixTime - smb_NowTZ;
581         ltp = localtime(&ersatz_unixTime);
582
583         /* if we fail, make up something */
584         if (!ltp) {
585                 ltp = &localJunk;
586                 localJunk.tm_year = 89 - 20;
587                 localJunk.tm_mon = 4;
588                 localJunk.tm_mday = 12;
589                 localJunk.tm_hour = 0;
590                 localJunk.tm_min = 0;
591                 localJunk.tm_sec = 0;
592         }
593
594         stm.wYear = ltp->tm_year + 1900;
595         stm.wMonth = ltp->tm_mon + 1;
596         stm.wDayOfWeek = ltp->tm_wday;
597         stm.wDay = ltp->tm_mday;
598         stm.wHour = ltp->tm_hour;
599         stm.wMinute = ltp->tm_min;
600         stm.wSecond = ltp->tm_sec;
601         stm.wMilliseconds = 0;
602
603         SystemTimeToFileTime(&stm, largeTimep);
604 }
605 #else /* DJGPP */
606 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, long unixTime)
607 {
608         /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
609         /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 ??? */
610         LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
611         LARGE_INTEGER ut;
612         int leap_years = 89;   /* leap years betw 1/1/1601 and 1/1/1970 */
613
614         /* set ft to number of 100ns intervals betw 1/1/1601 and 1/1/1970 GMT */
615         *ft = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years)
616                                    * 24 * 60);
617         *ft = LargeIntegerMultiplyByLong(*ft, 60);
618         *ft = LargeIntegerMultiplyByLong(*ft, 10000000);
619
620         /* add unix time */
621         ut = ConvertLongToLargeInteger(unixTime);
622         ut = LargeIntegerMultiplyByLong(ut, 10000000);
623         *ft = LargeIntegerAdd(*ft, ut);
624 }
625 #endif /* !DJGPP */
626
627 #ifndef DJGPP
628 void smb_UnixTimeFromLargeSearchTime(long *unixTimep, FILETIME *largeTimep)
629 {
630         SYSTEMTIME stm;
631         struct tm lt;
632         long save_timezone;
633
634         FileTimeToSystemTime(largeTimep, &stm);
635
636         lt.tm_year = stm.wYear - 1900;
637         lt.tm_mon = stm.wMonth - 1;
638         lt.tm_wday = stm.wDayOfWeek;
639         lt.tm_mday = stm.wDay;
640         lt.tm_hour = stm.wHour;
641         lt.tm_min = stm.wMinute;
642         lt.tm_sec = stm.wSecond;
643         lt.tm_isdst = -1;
644
645         save_timezone = _timezone;
646         _timezone += smb_NowTZ;
647         *unixTimep = mktime(&lt);
648         _timezone = save_timezone;
649 }
650 #else /* DJGPP */
651 void smb_UnixTimeFromLargeSearchTime(long *unixTimep, FILETIME *largeTimep)
652 {
653         /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
654         /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 GMT? */
655         LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
656         LARGE_INTEGER a;
657         int leap_years = 89;
658
659         /* set to number of 100ns intervals betw 1/1/1601 and 1/1/1970 */
660         a = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years) * 24 * 60);
661         a = LargeIntegerMultiplyByLong(a, 60);
662         a = LargeIntegerMultiplyByLong(a, 10000000);
663
664         /* subtract it from ft */
665         a = LargeIntegerSubtract(*ft, a);
666
667         /* divide down to seconds */
668         *unixTimep = LargeIntegerDivideByLong(a, 10000000);
669 }
670 #endif /* !DJGPP */
671
672 void smb_SearchTimeFromUnixTime(long *dosTimep, long unixTime)
673 {
674         struct tm *ltp;
675         int dosDate;
676         int dosTime;
677         struct tm localJunk;
678
679         ltp = localtime((time_t*) &unixTime);
680
681         /* if we fail, make up something */
682         if (!ltp) {
683                 ltp = &localJunk;
684                 localJunk.tm_year = 89 - 20;
685                 localJunk.tm_mon = 4;
686                 localJunk.tm_mday = 12;
687                 localJunk.tm_hour = 0;
688                 localJunk.tm_min = 0;
689                 localJunk.tm_sec = 0;
690         }       
691
692         dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
693         dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
694         *dosTimep = (dosDate<<16) | dosTime;
695 }       
696
697 void smb_UnixTimeFromSearchTime(long *unixTimep, long searchTime)
698 {
699         unsigned short dosDate;
700         unsigned short dosTime;
701         struct tm localTm;
702         
703         dosDate = searchTime & 0xffff;
704         dosTime = (searchTime >> 16) & 0xffff;
705         
706         localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
707         localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1;    /* January is 0 in localTm */
708         localTm.tm_mday = (dosDate) & 0x1f;
709         localTm.tm_hour = (dosTime>>11) & 0x1f;
710         localTm.tm_min = (dosTime >> 5) & 0x3f;
711         localTm.tm_sec = (dosTime & 0x1f) * 2;
712         localTm.tm_isdst = -1;                          /* compute whether DST in effect */
713
714         *unixTimep = mktime(&localTm);
715 }
716
717 void smb_DosUTimeFromUnixTime(long *dosUTimep, long unixTime)
718 {
719         *dosUTimep = unixTime - smb_localZero;
720 }
721
722 void smb_UnixTimeFromDosUTime(long *unixTimep, long dosTime)
723 {
724 #ifndef DJGPP
725         *unixTimep = dosTime + smb_localZero;
726 #else /* DJGPP */
727         /* dosTime seems to be already adjusted for GMT */
728         *unixTimep = dosTime;
729 #endif /* !DJGPP */
730 }
731
732 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
733 {
734         smb_vc_t *vcp;
735
736         lock_ObtainWrite(&smb_rctLock);
737         for(vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
738                 if (lsn == vcp->lsn && lana == vcp->lana) {
739                         vcp->refCount++;
740                         break;
741                 }
742         }
743         if (!vcp && (flags & SMB_FLAG_CREATE)) {
744                 vcp = malloc(sizeof(*vcp));
745                 memset(vcp, 0, sizeof(*vcp));
746         vcp->vcID = numVCs++;
747                 vcp->refCount = 1;
748                 vcp->tidCounter = 1;
749                 vcp->fidCounter = 1;
750                 vcp->uidCounter = 1;  /* UID 0 is reserved for blank user */
751                 vcp->nextp = smb_allVCsp;
752                 smb_allVCsp = vcp;
753                 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
754                 vcp->lsn = lsn;
755                 vcp->lana = lana;
756         vcp->secCtx = NULL;
757
758                 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
759             /* We must obtain a challenge for extended auth 
760              * in case the client negotiates smb v3 
761              */
762             NTSTATUS nts,ntsEx;
763                         MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
764                         PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp;
765                         ULONG lsaRespSize;
766
767                         lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
768
769                         nts = LsaCallAuthenticationPackage( smb_lsaHandle,
770                                                 smb_lsaSecPackage,
771                                                 &lsaReq,
772                                                 sizeof(lsaReq),
773                                                 &lsaResp,
774                                                 &lsaRespSize,
775                                                 &ntsEx);
776                         osi_assert(nts == STATUS_SUCCESS); /* this had better work! */
777
778                         memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
779             LsaFreeReturnBuffer(lsaResp);
780                 }
781                 else
782                         memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
783         }
784         lock_ReleaseWrite(&smb_rctLock);
785         return vcp;
786 }
787
788 int smb_IsStarMask(char *maskp)
789 {
790         int i;
791         char tc;
792         
793         for(i=0; i<11; i++) {
794                 tc = *maskp++;
795                 if (tc == '?' || tc == '*' || tc == '>') return 1;        
796         }       
797         return 0;
798 }
799
800 void smb_ReleaseVC(smb_vc_t *vcp)
801 {
802         lock_ObtainWrite(&smb_rctLock);
803         osi_assert(vcp->refCount-- > 0);
804         lock_ReleaseWrite(&smb_rctLock);
805 }
806
807 void smb_HoldVC(smb_vc_t *vcp)
808 {
809         lock_ObtainWrite(&smb_rctLock);
810         vcp->refCount++;
811         lock_ReleaseWrite(&smb_rctLock);
812 }
813
814 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
815 {
816         smb_tid_t *tidp;
817
818         lock_ObtainWrite(&smb_rctLock);
819         for(tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
820                 if (tid == tidp->tid) {
821                         tidp->refCount++;
822                         break;
823                 }       
824         }
825         if (!tidp && (flags & SMB_FLAG_CREATE)) {
826                 tidp = malloc(sizeof(*tidp));
827                 memset(tidp, 0, sizeof(*tidp));
828                 tidp->nextp = vcp->tidsp;
829                 tidp->refCount = 1;
830                 tidp->vcp = vcp;
831         vcp->refCount++;
832                 vcp->tidsp = tidp;
833                 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
834                 tidp->tid = tid;
835         }
836         lock_ReleaseWrite(&smb_rctLock);
837         return tidp;
838 }       
839
840 void smb_ReleaseTID(smb_tid_t *tidp)
841 {
842         smb_tid_t *tp;
843         smb_tid_t **ltpp;
844         cm_user_t *userp;
845     smb_vc_t  *vcp;
846
847         userp = NULL;
848     vcp = NULL;
849         lock_ObtainWrite(&smb_rctLock);
850         osi_assert(tidp->refCount-- > 0);
851         if (tidp->refCount == 0 && (tidp->flags & SMB_TIDFLAG_DELETE)) {
852                 ltpp = &tidp->vcp->tidsp;
853                 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
854                         if (tp == tidp) break;
855                 }
856                 osi_assert(tp != NULL);
857                 *ltpp = tp->nextp;
858                 lock_FinalizeMutex(&tidp->mx);
859                 userp = tidp->userp;    /* remember to drop ref later */
860         vcp = tidp->vcp;
861         }
862         lock_ReleaseWrite(&smb_rctLock);
863         if (userp) {
864                 cm_ReleaseUser(userp);
865         }       
866     if (vcp) {
867         smb_ReleaseVC(vcp);
868     }
869 }       
870
871 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
872 {
873         smb_user_t *uidp = NULL;
874
875         lock_ObtainWrite(&smb_rctLock);
876         for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
877                 if (uid == uidp->userID) {
878                         uidp->refCount++;
879                         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 : "");
880                 break;
881                 }
882         }
883         if (!uidp && (flags & SMB_FLAG_CREATE)) {
884                 uidp = malloc(sizeof(*uidp));
885                 memset(uidp, 0, sizeof(*uidp));
886                 uidp->nextp = vcp->usersp;
887                 uidp->refCount = 1;
888                 uidp->vcp = vcp;
889         vcp->refCount++;
890                 vcp->usersp = uidp;
891                 lock_InitializeMutex(&uidp->mx, "user_t mutex");
892                 uidp->userID = uid;
893                 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 : ""));
894         }
895         lock_ReleaseWrite(&smb_rctLock);
896         return uidp;
897 }       
898
899 smb_username_t *smb_FindUserByName(char *usern, char *machine, int flags)
900 {
901         smb_username_t *unp= NULL;
902
903         lock_ObtainWrite(&smb_rctLock);
904         for(unp = usernamesp; unp; unp = unp->nextp) {
905                 if (stricmp(unp->name, usern) == 0 &&
906                         stricmp(unp->machine, machine) == 0) {
907                         unp->refCount++;
908                         break;
909                 }
910         }
911         if (!unp && (flags & SMB_FLAG_CREATE)) {
912                 unp = malloc(sizeof(*unp));
913                 memset(unp, 0, sizeof(*unp));
914                 unp->refCount = 1;
915                 unp->nextp = usernamesp;
916                 unp->name = strdup(usern);
917                 unp->machine = strdup(machine);
918                 usernamesp = unp;
919                 lock_InitializeMutex(&unp->mx, "username_t mutex");
920         }
921         lock_ReleaseWrite(&smb_rctLock);
922         return unp;
923 }       
924
925 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
926 {
927         smb_user_t *uidp= NULL;
928
929         lock_ObtainWrite(&smb_rctLock);
930         for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
931                 if (!uidp->unp) 
932             continue;
933                 if (stricmp(uidp->unp->name, usern) == 0) {
934             uidp->refCount++;
935                         osi_LogEvent("AFS smb_FindUserByNameThisSession",NULL,"VCP[%x] uid[%d] match-name[%s]",(int)vcp,uidp->userID,usern);
936             break;
937                 } else
938             continue;
939         }       
940         lock_ReleaseWrite(&smb_rctLock);
941         return uidp;
942 }
943 void smb_ReleaseUID(smb_user_t *uidp)
944 {
945         smb_user_t *up;
946         smb_user_t **lupp;
947         cm_user_t *userp;
948     smb_vc_t  *vcp;
949
950         userp = NULL;
951     vcp = NULL;
952         lock_ObtainWrite(&smb_rctLock);
953         osi_assert(uidp->refCount-- > 0);
954         if (uidp->refCount == 0 && (uidp->flags & SMB_USERFLAG_DELETE)) {
955                 lupp = &uidp->vcp->usersp;
956                 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
957                         if (up == uidp) break;
958                 }
959                 osi_assert(up != NULL);
960                 *lupp = up->nextp;
961                 lock_FinalizeMutex(&uidp->mx);
962                 if (uidp->unp) {
963                         userp = uidp->unp->userp;       /* remember to drop ref later */
964             uidp->unp->userp = NULL;
965         }
966         vcp = uidp->vcp;
967         uidp->vcp = NULL;
968         }               
969         lock_ReleaseWrite(&smb_rctLock);
970         if (userp) {
971                 cm_ReleaseUserVCRef(userp);
972                 cm_ReleaseUser(userp);
973         }       
974     if (vcp) {
975         smb_ReleaseVC(vcp);
976     }
977 }       
978
979 /* retrieve a held reference to a user structure corresponding to an incoming
980  * request.
981  * corresponding release function is cm_ReleaseUser.
982  */
983 cm_user_t *smb_GetUser(smb_vc_t *vcp, smb_packet_t *inp)
984 {
985         smb_user_t *uidp;
986         cm_user_t *up;
987         smb_t *smbp;
988
989         smbp = (smb_t *) inp;
990         uidp = smb_FindUID(vcp, smbp->uid, 0);
991         if ((!uidp) ||  (!uidp->unp))
992                 return NULL;
993         
994         lock_ObtainMutex(&uidp->mx);
995         up = uidp->unp->userp;
996         cm_HoldUser(up);
997         lock_ReleaseMutex(&uidp->mx);
998
999         smb_ReleaseUID(uidp);
1000         
1001         return up;
1002 }
1003
1004 /*
1005  * Return a pointer to a pathname extracted from a TID structure.  The
1006  * TID structure is not held; assume it won't go away.
1007  */
1008 char *smb_GetTIDPath(smb_vc_t *vcp, unsigned short tid)
1009 {
1010         smb_tid_t *tidp;
1011         char *tpath;
1012
1013         tidp = smb_FindTID(vcp, tid, 0);
1014     if (!tidp) 
1015         return NULL;
1016         tpath = tidp->pathname;
1017         smb_ReleaseTID(tidp);
1018         return tpath;
1019 }
1020
1021 /* check to see if we have a chained fid, that is, a fid that comes from an
1022  * OpenAndX message that ran earlier in this packet.  In this case, the fid
1023  * field in a read, for example, request, isn't set, since the value is
1024  * supposed to be inherited from the openAndX call.
1025  */
1026 int smb_ChainFID(int fid, smb_packet_t *inp)
1027 {
1028         if (inp->fid == 0 || inp->inCount == 0) 
1029                 return fid;
1030         else 
1031                 return inp->fid;
1032 }
1033
1034 /* are we a priv'd user?  What does this mean on NT? */
1035 int smb_SUser(cm_user_t *userp)
1036 {
1037         return 1;
1038 }
1039
1040 /* find a file ID.  If we pass in 0 we select an used File ID.
1041  * If the SMB_FLAG_CREATE flag is set, we allocate a new  
1042  * smb_fid_t data structure if desired File ID cannot be found.
1043  */
1044 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1045 {
1046         smb_fid_t *fidp;
1047         int newFid = 0;
1048         
1049     if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1050         return NULL;
1051
1052         lock_ObtainWrite(&smb_rctLock);
1053         /* figure out if we need to allocate a new file ID */
1054         if (fid == 0) {
1055                 newFid = 1;
1056                 fid = vcp->fidCounter;
1057         }
1058
1059 retry:
1060         for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1061                 if (fid == fidp->fid) {
1062                         if (newFid) {
1063                                 fid++;
1064                 if (fid == 0) 
1065                                         fid = 1;
1066                 goto retry;
1067             }
1068                         fidp->refCount++;
1069             break;
1070                 }
1071     }
1072     if (!fidp && (flags & SMB_FLAG_CREATE)) {
1073         char eventName[MAX_PATH];
1074         EVENT_HANDLE event;
1075         sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1076         event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1077         if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1078             afsi_log("Event Object Already Exists: %s", eventName);
1079             thrd_CloseHandle(event);
1080             fid++;
1081             if (fid == 0)
1082                 fid = 1;
1083             goto retry;
1084         }
1085
1086                 fidp = malloc(sizeof(*fidp));
1087         memset(fidp, 0, sizeof(*fidp));
1088                 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1089         fidp->refCount = 1;
1090         fidp->vcp = vcp;
1091         vcp->refCount++;
1092         lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1093         fidp->fid = fid;
1094                 fidp->curr_chunk = fidp->prev_chunk = -2;
1095                 fidp->raw_write_event = event;
1096         if (newFid) {
1097             vcp->fidCounter = fid+1;
1098             if (vcp->fidCounter == 0) 
1099                 vcp->fidCounter = 1;
1100         }
1101     }
1102     lock_ReleaseWrite(&smb_rctLock);
1103     return fidp;
1104 }
1105
1106 void smb_ReleaseFID(smb_fid_t *fidp)
1107 {
1108         cm_scache_t *scp;
1109     smb_vc_t *vcp = NULL;
1110     smb_ioctl_t *ioctlp;
1111
1112     if (!fidp)
1113         return;
1114
1115         scp = NULL;
1116         lock_ObtainWrite(&smb_rctLock);
1117         osi_assert(fidp->refCount-- > 0);
1118     if (fidp->refCount == 0 && (fidp->flags & SMB_FID_DELETE)) {
1119                 vcp = fidp->vcp;
1120                 if (!(fidp->flags & SMB_FID_IOCTL))
1121                         scp = fidp->scp;
1122                 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1123                 thrd_CloseHandle(fidp->raw_write_event);
1124
1125                 /* and see if there is ioctl stuff to free */
1126         ioctlp = fidp->ioctlp;
1127         if (ioctlp) {
1128                         if (ioctlp->prefix) cm_FreeSpace(ioctlp->prefix);
1129                         if (ioctlp->inAllocp) free(ioctlp->inAllocp);
1130                         if (ioctlp->outAllocp) free(ioctlp->outAllocp);
1131                         free(ioctlp);
1132         }
1133
1134         free(fidp);
1135
1136         /* do not call smb_ReleaseVC() because we already have the lock */
1137         vcp->refCount--;
1138     }
1139         lock_ReleaseWrite(&smb_rctLock);
1140
1141         /* now release the scache structure */
1142         if (scp) 
1143                 cm_ReleaseSCache(scp);
1144 }
1145
1146 /*
1147  * Case-insensitive search for one string in another;
1148  * used to find variable names in submount pathnames.
1149  */
1150 static char *smb_stristr(char *str1, char *str2)
1151 {
1152         char *cursor;
1153
1154         for (cursor = str1; *cursor; cursor++)
1155                 if (stricmp(cursor, str2) == 0)
1156                         return cursor;
1157
1158         return NULL;
1159 }
1160
1161 /*
1162  * Substitute a variable value for its name in a submount pathname.  Variable
1163  * name has been identified by smb_stristr() and is in substr.  Variable name
1164  * length (plus one) is in substr_size.  Variable value is in newstr.
1165  */
1166 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1167         char *newstr)
1168 {
1169         char temp[1024];
1170
1171         strcpy(temp, substr + substr_size - 1);
1172         strcpy(substr, newstr);
1173         strcat(str1, temp);
1174 }
1175
1176 char VNUserName[] = "%USERNAME%";
1177 char VNLCUserName[] = "%LCUSERNAME%";
1178 char VNComputerName[] = "%COMPUTERNAME%";
1179 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1180
1181 /* List available shares */
1182 int smb_ListShares()
1183 {
1184         char sbmtpath[256];
1185         char pathName[256];
1186         char shareBuf[4096];
1187         int num_shares=0;
1188         char *this_share;
1189         int len;
1190         char *p;
1191         int print_afs = 0;
1192         int code;
1193
1194         /*strcpy(shareNameList[num_shares], "all");
1195          strcpy(pathNameList[num_shares++], "/afs");*/
1196         fprintf(stderr, "The following shares are available:\n");
1197         fprintf(stderr, "Share Name (AFS Path)\n");
1198         fprintf(stderr, "---------------------\n");
1199         fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
1200
1201 #ifndef DJGPP
1202         code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1203         if (code == 0 || code > sizeof(sbmtpath)) return -1;
1204 #else
1205         strcpy(sbmtpath, cm_confDir);
1206 #endif /* !DJGPP */
1207         strcat(sbmtpath, "/afsdsbmt.ini");
1208         len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1209                                                                    shareBuf, sizeof(shareBuf),
1210                                                                    sbmtpath);
1211         if (len == 0) {
1212                 return num_shares;
1213         }
1214
1215         this_share = shareBuf;
1216         do
1217         {
1218                 print_afs = 0;
1219                 /*strcpy(shareNameList[num_shares], this_share);*/
1220                 len = GetPrivateProfileString("AFS Submounts", this_share,
1221                                                                            NULL,
1222                                                                            pathName, 256,
1223                                                                            sbmtpath);
1224                 if (!len) 
1225                         return num_shares;
1226                 p = pathName;
1227                 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) != 0)
1228             print_afs = 1;
1229                 while (*p) {
1230             if (*p == '\\') *p = '/';    /* change to / */
1231             p++;
1232                 }
1233
1234                 fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1235                                  smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
1236                                  pathName);
1237                 num_shares++;
1238                 while (*this_share != 0) this_share++;  /* find next NUL */
1239                 this_share++;   /* skip past the NUL */
1240         } while (*this_share != 0);  /* stop at final NUL */
1241
1242         return num_shares;
1243 }
1244
1245 /* find a shareName in the table of submounts */
1246 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1247         char **pathNamep)
1248 {
1249         DWORD len;
1250         char pathName[1024];
1251         char *var;
1252         char temp[1024];
1253         DWORD sizeTemp;
1254     char sbmtpath[MAX_PATH];
1255     char *p, *q;
1256         HKEY parmKey;
1257         DWORD code;
1258     DWORD allSubmount = 1;
1259
1260         if (strcmp(shareName, "IPC$") == 0) {
1261                 *pathNamep = NULL;
1262                 return 0;
1263         }
1264
1265     /* if allSubmounts == 0, only return the //mountRoot/all share 
1266      * if in fact it has been been created in the subMounts table.  
1267      * This is to allow sites that want to restrict access to the 
1268      * world to do so.
1269      */
1270         code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName,
1271                                                 0, KEY_QUERY_VALUE, &parmKey);
1272         if (code == ERROR_SUCCESS) {
1273         len = sizeof(allSubmount);
1274         code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1275                                 (BYTE *) &allSubmount, &len);
1276         if (code != ERROR_SUCCESS) {
1277             allSubmount = 1;
1278         }
1279         RegCloseKey (parmKey);
1280         }
1281
1282         if (allSubmount && _stricmp(shareName, "all") == 0) {
1283                 *pathNamep = NULL;
1284                 return 1;
1285         }
1286
1287     /* In case, the all share is disabled we need to still be able
1288      * to handle ioctl requests 
1289      */
1290         if (_stricmp(shareName, "ioctl$") == 0) {
1291                 *pathNamep = strdup("/.__ioctl__");
1292                 return 1;
1293         }
1294
1295 #ifndef DJGPP
1296     strcpy(sbmtpath, "afsdsbmt.ini");
1297 #else /* DJGPP */
1298     strcpy(sbmtpath, cm_confDir);
1299     strcat(sbmtpath, "/afsdsbmt.ini");
1300 #endif /* !DJGPP */
1301         len = GetPrivateProfileString("AFS Submounts", shareName, "",
1302                                   pathName, sizeof(pathName), sbmtpath);
1303         if (len != 0 && len != sizeof(pathName) - 1) {
1304         /* We can accept either unix or PC style AFS pathnames.  Convert
1305          * Unix-style to PC style here for internal use. 
1306          */
1307         p = pathName;
1308         if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1309             p += strlen(cm_mountRoot);  /* skip mount path */
1310         q = p;
1311         while (*q) {
1312             if (*q == '/') *q = '\\';    /* change to \ */
1313             q++;
1314         }
1315
1316         while (1)
1317         {
1318             if (var = smb_stristr(p, VNUserName)) {
1319                 if (uidp && uidp->unp)
1320                     smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1321                 else
1322                     smb_subst(p, var, sizeof(VNUserName)," ");
1323             }
1324             else if (var = smb_stristr(p, VNLCUserName)) 
1325             {
1326                 if (uidp && uidp->unp)
1327                     strcpy(temp, uidp->unp->name);
1328                 else 
1329                     strcpy(temp, " ");
1330                 _strlwr(temp);
1331                 smb_subst(p, var, sizeof(VNLCUserName), temp);
1332             }
1333             else if (var = smb_stristr(p, VNComputerName)) 
1334             {
1335                 sizeTemp = sizeof(temp);
1336                 GetComputerName((LPTSTR)temp, &sizeTemp);
1337                 smb_subst(p, var, sizeof(VNComputerName), temp);
1338             }
1339             else if (var = smb_stristr(p, VNLCComputerName)) 
1340             {
1341                 sizeTemp = sizeof(temp);
1342                 GetComputerName((LPTSTR)temp, &sizeTemp);
1343                 _strlwr(temp);
1344                 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1345             }
1346             else     
1347                 break;
1348         }
1349         *pathNamep = strdup(p);
1350         return 1;
1351     } 
1352     else /* create  \\<netbiosName>\<cellname>  */
1353     {
1354         char * p = shareName; 
1355         int rw = 0;
1356
1357         if ( *p == '.' ) {
1358             p++;
1359             rw = 1;
1360         }
1361         /* Get the full name for this cell */
1362         code = cm_SearchCellFile(p, temp, 0, 0);
1363 #ifdef AFS_AFSDB_ENV
1364                 if (code && cm_dnsEnabled) {
1365             int ttl;
1366             code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1367         }
1368 #endif
1369         /* construct the path */
1370         if (code == 0) {     
1371             sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1372             *pathNamep = strdup(strlwr(pathName));
1373             return 1;
1374         }
1375         }
1376     /* failure */
1377     *pathNamep = NULL;
1378     return 0;
1379 }
1380
1381 /* Client-side offline caching policy types */
1382 #define CSC_POLICY_MANUAL 0
1383 #define CSC_POLICY_DOCUMENTS 1
1384 #define CSC_POLICY_PROGRAMS 2
1385 #define CSC_POLICY_DISABLE 3
1386
1387 int smb_FindShareCSCPolicy(char *shareName)
1388 {
1389         DWORD len;
1390         char policy[1024];
1391     DWORD dwType;
1392     HKEY hkCSCPolicy;
1393     int  retval = CSC_POLICY_MANUAL;
1394
1395     RegCreateKeyEx( HKEY_LOCAL_MACHINE, 
1396                     "SOFTWARE\\OpenAFS\\Client\\CSCPolicy",
1397                     0, 
1398                     "AFS", 
1399                     REG_OPTION_NON_VOLATILE,
1400                     KEY_READ,
1401                     NULL, 
1402                     &hkCSCPolicy,
1403                     NULL );
1404
1405     len = sizeof(policy);
1406     if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1407          len == 0) {
1408                 retval = CSC_POLICY_MANUAL;
1409     }
1410         else if (stricmp(policy, "documents") == 0)
1411         {
1412                 retval = CSC_POLICY_DOCUMENTS;
1413         }
1414         else if (stricmp(policy, "programs") == 0)
1415         {
1416                 retval = CSC_POLICY_PROGRAMS;
1417         }
1418         else if (stricmp(policy, "disable") == 0)
1419         {
1420                 retval = CSC_POLICY_DISABLE;
1421         }
1422         
1423     RegCloseKey(hkCSCPolicy);
1424         return retval;
1425 }
1426
1427 /* find a dir search structure by cookie value, and return it held.
1428  * Must be called with smb_globalLock held.
1429  */
1430 smb_dirSearch_t *smb_FindDirSearchNL(long cookie)
1431 {
1432         smb_dirSearch_t *dsp;
1433         
1434         for(dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1435                 if (dsp->cookie == cookie) {
1436                         if (dsp != smb_firstDirSearchp) {
1437                                 /* move to head of LRU queue, too, if we're not already there */
1438                                 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1439                                         smb_lastDirSearchp = (smb_dirSearch_t *)
1440                                                 osi_QPrev(&dsp->q);
1441                                 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1442                                 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1443                                 if (!smb_lastDirSearchp)
1444                                         smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1445                         }
1446                         dsp->refCount++;
1447                         break;
1448                 }
1449         }
1450         return dsp;
1451 }
1452
1453 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1454 {
1455         lock_ObtainWrite(&smb_globalLock);
1456         dsp->flags |= SMB_DIRSEARCH_DELETE;
1457         lock_ReleaseWrite(&smb_globalLock);
1458         lock_ObtainMutex(&dsp->mx);
1459         if(dsp->scp != NULL) {
1460                 lock_ObtainMutex(&dsp->scp->mx);
1461                 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1462                         dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1463                     dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1464                     dsp->scp->bulkStatProgress = hones;
1465                 }       
1466                 lock_ReleaseMutex(&dsp->scp->mx);
1467         }       
1468         lock_ReleaseMutex(&dsp->mx);
1469 }
1470
1471 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1472 {
1473         cm_scache_t *scp;
1474         
1475         scp = NULL;
1476
1477         lock_ObtainWrite(&smb_globalLock);
1478         osi_assert(dsp->refCount-- > 0);
1479         if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1480                 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1481                         smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1482                 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1483                 lock_FinalizeMutex(&dsp->mx);
1484                 scp = dsp->scp;
1485                 free(dsp);
1486         }
1487         lock_ReleaseWrite(&smb_globalLock);
1488
1489         /* do this now to avoid spurious locking hierarchy creation */
1490         if (scp) cm_ReleaseSCache(scp);
1491 }
1492
1493 /* find a dir search structure by cookie value, and return it held */
1494 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1495 {
1496         smb_dirSearch_t *dsp;
1497
1498         lock_ObtainWrite(&smb_globalLock);
1499         dsp = smb_FindDirSearchNL(cookie);
1500         lock_ReleaseWrite(&smb_globalLock);
1501         return dsp;
1502 }
1503
1504 /* GC some dir search entries, in the address space expected by the specific protocol.
1505  * Must be called with smb_globalLock held; release the lock temporarily.
1506  */
1507 #define SMB_DIRSEARCH_GCMAX     10      /* how many at once */
1508 void smb_GCDirSearches(int isV3)
1509 {
1510         smb_dirSearch_t *prevp;
1511         smb_dirSearch_t *tp;
1512         smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1513         int victimCount;
1514         int i;
1515         
1516         victimCount = 0;        /* how many have we got so far */
1517         for(tp = smb_lastDirSearchp; tp; tp=prevp) {
1518                 /* we'll move tp from queue, so
1519                  * do this early.
1520                  */
1521                 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);  
1522                 /* if no one is using this guy, and we're either in the new protocol,
1523                  * or we're in the old one and this is a small enough ID to be useful
1524                  * to the old protocol, GC this guy.
1525                  */
1526                 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1527                         /* hold and delete */
1528                         tp->flags |= SMB_DIRSEARCH_DELETE;
1529                         victimsp[victimCount++] = tp;
1530                         tp->refCount++;
1531                 }
1532
1533                 /* don't do more than this */
1534                 if (victimCount >= SMB_DIRSEARCH_GCMAX) break;
1535         }
1536         
1537         /* now release them */
1538         lock_ReleaseWrite(&smb_globalLock);
1539         for(i = 0; i < victimCount; i++) {
1540                 smb_ReleaseDirSearch(victimsp[i]);
1541         }
1542         lock_ObtainWrite(&smb_globalLock);
1543 }
1544
1545 /* function for allocating a dir search entry.  We need these to remember enough context
1546  * since we don't get passed the path from call to call during a directory search.
1547  *
1548  * Returns a held dir search structure, and bumps the reference count on the vnode,
1549  * since it saves a pointer to the vnode.
1550  */
1551 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1552 {
1553         smb_dirSearch_t *dsp;
1554         int counter;
1555         int maxAllowed;
1556
1557         lock_ObtainWrite(&smb_globalLock);
1558         counter = 0;
1559
1560         /* what's the biggest ID allowed in this version of the protocol */
1561         if (isV3) maxAllowed = 65535;
1562         else maxAllowed = 255;
1563
1564         while(1) {
1565                 /* twice so we have enough tries to find guys we GC after one pass;
1566                  * 10 extra is just in case I mis-counted.
1567                  */
1568                 if (++counter > 2*maxAllowed+10) osi_panic("afsd: dir search cookie leak",
1569                                                                                                         __FILE__, __LINE__);
1570                 if (smb_dirSearchCounter > maxAllowed) {        
1571                         smb_dirSearchCounter = 1;
1572                         smb_GCDirSearches(isV3);        /* GC some (drops global lock) */
1573                 }       
1574                 dsp = smb_FindDirSearchNL(smb_dirSearchCounter);
1575                 if (dsp) {
1576                         /* don't need to watch for refcount zero and deleted, since
1577                          * we haven't dropped the global lock.
1578                          */
1579                         dsp->refCount--;
1580                         ++smb_dirSearchCounter;
1581                         continue;
1582                 }       
1583                 
1584                 dsp = malloc(sizeof(*dsp));
1585                 memset(dsp, 0, sizeof(*dsp));
1586                 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1587                 if (!smb_lastDirSearchp) smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1588                 dsp->cookie = smb_dirSearchCounter;
1589                 ++smb_dirSearchCounter;
1590                 dsp->refCount = 1;
1591                 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
1592                 dsp->lastTime = osi_Time();
1593                 break;
1594         }       
1595         lock_ReleaseWrite(&smb_globalLock);
1596         return dsp;
1597 }
1598
1599 static smb_packet_t *GetPacket(void)
1600 {
1601         smb_packet_t *tbp;
1602 #ifdef DJGPP
1603         unsigned int npar, seg, tb_sel;
1604 #endif
1605
1606         lock_ObtainWrite(&smb_globalLock);
1607         tbp = smb_packetFreeListp;
1608     if (tbp) 
1609         smb_packetFreeListp = tbp->nextp;
1610         lock_ReleaseWrite(&smb_globalLock);
1611     if (!tbp) {
1612 #ifndef DJGPP
1613         tbp = calloc(65540,1);
1614 #else /* DJGPP */
1615         tbp = malloc(sizeof(smb_packet_t));
1616 #endif /* !DJGPP */
1617         tbp->magic = SMB_PACKETMAGIC;
1618                 tbp->ncbp = NULL;
1619                 tbp->vcp = NULL;
1620                 tbp->resumeCode = 0;
1621                 tbp->inCount = 0;
1622                 tbp->fid = 0;
1623                 tbp->wctp = NULL;
1624                 tbp->inCom = 0;
1625                 tbp->oddByte = 0;
1626                 tbp->ncb_length = 0;
1627                 tbp->flags = 0;
1628         tbp->spacep = NULL;
1629         
1630 #ifdef DJGPP
1631         npar = SMB_PACKETSIZE >> 4;  /* number of paragraphs */
1632         {
1633             signed int retval =
1634                 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1635             if (retval == -1) {
1636                 afsi_log("Cannot allocate %d paragraphs of DOS memory",
1637                           npar);
1638                 osi_panic("",__FILE__,__LINE__);
1639             }
1640             else {
1641                 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
1642                           npar, retval);
1643                 seg = retval;
1644             }
1645         }
1646         tbp->dos_pkt = (seg * 16) + 0;  /* DOS physical address */
1647         tbp->dos_pkt_sel = tb_sel;
1648 #endif /* DJGPP */
1649         }
1650     osi_assert(tbp->magic == SMB_PACKETMAGIC);
1651
1652     return tbp;
1653 }
1654
1655 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
1656 {
1657         smb_packet_t *tbp;
1658         tbp = GetPacket();
1659         memcpy(tbp, pkt, sizeof(smb_packet_t));
1660         tbp->wctp = tbp->data + ((unsigned int)pkt->wctp - (unsigned int)pkt->data);
1661         return tbp;
1662 }
1663
1664 static NCB *GetNCB(void)
1665 {
1666         smb_ncb_t *tbp;
1667     NCB *ncbp;
1668 #ifdef DJGPP
1669     unsigned int npar, seg, tb_sel;
1670 #endif /* DJGPP */
1671
1672         lock_ObtainWrite(&smb_globalLock);
1673         tbp = smb_ncbFreeListp;
1674     if (tbp) 
1675         smb_ncbFreeListp = tbp->nextp;
1676         lock_ReleaseWrite(&smb_globalLock);
1677     if (!tbp) {
1678 #ifndef DJGPP
1679         tbp = calloc(sizeof(*tbp),1);
1680 #else /* DJGPP */
1681         tbp = malloc(sizeof(*tbp));
1682         npar = (sizeof(NCB)+15) >> 4;  /* number of paragraphs */
1683         {
1684             signed int retval =
1685                 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1686             if (retval == -1) {
1687                 afsi_log("Cannot allocate %d paragraphs of DOS mem in GetNCB",
1688                           npar);
1689                 osi_panic("",__FILE__,__LINE__);
1690             } else {
1691                 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
1692                           npar, retval);
1693                 seg = retval;
1694             }
1695         }
1696         tbp->dos_ncb = (seg * 16) + 0;  /* DOS physical address */
1697         tbp->dos_ncb_sel = tb_sel;
1698 #endif /* !DJGPP */
1699         tbp->magic = SMB_NCBMAGIC;
1700         }
1701         
1702     osi_assert(tbp->magic == SMB_NCBMAGIC);
1703
1704         memset(&tbp->ncb, 0, sizeof(NCB));
1705     ncbp = &tbp->ncb;
1706 #ifdef DJGPP
1707     dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
1708 #endif /* DJGPP */
1709     return ncbp;
1710 }
1711
1712 void smb_FreePacket(smb_packet_t *tbp)
1713 {
1714     osi_assert(tbp->magic == SMB_PACKETMAGIC);
1715         
1716     lock_ObtainWrite(&smb_globalLock);
1717         tbp->nextp = smb_packetFreeListp;
1718         smb_packetFreeListp = tbp;
1719         tbp->magic = SMB_PACKETMAGIC;
1720         tbp->ncbp = NULL;
1721         tbp->vcp = NULL;
1722         tbp->resumeCode = 0;
1723         tbp->inCount = 0;
1724         tbp->fid = 0;
1725         tbp->wctp = NULL;
1726         tbp->inCom = 0;
1727         tbp->oddByte = 0;
1728         tbp->ncb_length = 0;
1729         tbp->flags = 0;
1730     lock_ReleaseWrite(&smb_globalLock);
1731 }
1732
1733 static void FreeNCB(NCB *bufferp)
1734 {
1735         smb_ncb_t *tbp;
1736         
1737     tbp = (smb_ncb_t *) bufferp;
1738     osi_assert(tbp->magic == SMB_NCBMAGIC);
1739         
1740     lock_ObtainWrite(&smb_globalLock);
1741         tbp->nextp = smb_ncbFreeListp;
1742         smb_ncbFreeListp = tbp;
1743     lock_ReleaseWrite(&smb_globalLock);
1744 }
1745
1746 /* get a ptr to the data part of a packet, and its count */
1747 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
1748 {
1749     int parmBytes;
1750     int dataBytes;
1751     unsigned char *afterParmsp;
1752
1753     parmBytes = *smbp->wctp << 1;
1754         afterParmsp = smbp->wctp + parmBytes + 1;
1755         
1756     dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
1757     if (nbytesp) *nbytesp = dataBytes;
1758         
1759         /* don't forget to skip the data byte count, since it follows
1760      * the parameters; that's where the "2" comes from below.
1761      */
1762     return (unsigned char *) (afterParmsp + 2);
1763 }
1764
1765 /* must set all the returned parameters before playing around with the
1766  * data region, since the data region is located past the end of the
1767  * variable number of parameters.
1768  */
1769 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
1770 {
1771         unsigned char *afterParmsp;
1772
1773         afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
1774         
1775         *afterParmsp++ = dsize & 0xff;
1776         *afterParmsp = (dsize>>8) & 0xff;
1777 }
1778
1779 /* return the parm'th parameter in the smbp packet */
1780 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
1781 {
1782         int parmCount;
1783         unsigned char *parmDatap;
1784
1785         parmCount = *smbp->wctp;
1786
1787         if (parm >= parmCount) {
1788 #ifndef DJGPP
1789         HANDLE h;
1790                 char *ptbuf[1];
1791                 char s[100];
1792                 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1793                 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
1794                                 parm, parmCount, smbp->ncb_length);
1795                 ptbuf[0] = s;
1796                 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1797                                         1, smbp->ncb_length, ptbuf, smbp);
1798                 DeregisterEventSource(h);
1799 #else /* DJGPP */
1800                 char s[100];
1801
1802                 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
1803                                 parm, parmCount, smbp->ncb_length);
1804                 osi_Log0(smb_logp, s);
1805 #endif /* !DJGPP */
1806                 osi_panic(s, __FILE__, __LINE__);
1807         }
1808         parmDatap = smbp->wctp + (2*parm) + 1;
1809         
1810         return parmDatap[0] + (parmDatap[1] << 8);
1811 }
1812
1813 /* return the parm'th parameter in the smbp packet */
1814 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
1815 {
1816         int parmCount;
1817         unsigned char *parmDatap;
1818
1819         parmCount = *smbp->wctp;
1820
1821         if (parm * 2 + offset >= parmCount * 2) {
1822 #ifndef DJGPP
1823                 HANDLE h;
1824                 char *ptbuf[1];
1825                 char s[100];
1826                 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1827                 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
1828                                 parm, offset, parmCount, smbp->ncb_length);
1829                 ptbuf[0] = s;
1830                 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1831                                         1, smbp->ncb_length, ptbuf, smbp);
1832                 DeregisterEventSource(h);
1833 #else /* DJGPP */
1834                 char s[100];
1835                 
1836                 sprintf(s, "Bad SMB param %d offset %d out of %d, "
1837                                 "ncb len %d",
1838                                  parm, offset, parmCount, smbp->ncb_length);
1839                 osi_Log0(smb_logp, s);
1840 #endif /* !DJGPP */
1841
1842                 osi_panic(s, __FILE__, __LINE__);
1843         }
1844         parmDatap = smbp->wctp + (2*parm) + 1 + offset;
1845         
1846         return parmDatap[0] + (parmDatap[1] << 8);
1847 }
1848
1849 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
1850 {
1851         char *parmDatap;
1852
1853         /* make sure we have enough slots */
1854         if (*smbp->wctp <= slot) *smbp->wctp = slot+1;
1855         
1856         parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1857         *parmDatap++ = parmValue & 0xff;
1858         *parmDatap = (parmValue>>8) & 0xff;
1859 }
1860
1861 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
1862 {
1863         char *parmDatap;
1864
1865         /* make sure we have enough slots */
1866         if (*smbp->wctp <= slot) *smbp->wctp = slot+2;
1867
1868         parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1869         *parmDatap++ = parmValue & 0xff;
1870         *parmDatap++ = (parmValue>>8) & 0xff;
1871         *parmDatap++ = (parmValue>>16) & 0xff;
1872         *parmDatap++ = (parmValue>>24) & 0xff;
1873 }
1874
1875 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
1876 {
1877         char *parmDatap;
1878         int i;
1879
1880         /* make sure we have enough slots */
1881         if (*smbp->wctp <= slot) *smbp->wctp = slot+4;
1882
1883         parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1884         for (i=0; i<8; i++)
1885                 *parmDatap++ = *parmValuep++;
1886 }
1887
1888 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
1889 {
1890         char *parmDatap;
1891
1892         /* make sure we have enough slots */
1893         if (*smbp->wctp <= slot) {
1894                 if (smbp->oddByte) {
1895                         smbp->oddByte = 0;
1896                         *smbp->wctp = slot+1;
1897                 } else
1898                         smbp->oddByte = 1;
1899         }
1900
1901         parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
1902         *parmDatap++ = parmValue & 0xff;
1903 }
1904
1905 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
1906 {
1907         char *lastSlashp;
1908         
1909         lastSlashp = strrchr(inPathp, '\\');
1910         if (lastComponentp)
1911                 *lastComponentp = lastSlashp;
1912         if (lastSlashp) {
1913                 while (1) {
1914                         if (inPathp == lastSlashp) 
1915                                 break;
1916                         *outPathp++ = *inPathp++;
1917                 }
1918                 *outPathp++ = 0;
1919         }
1920         else {
1921                 *outPathp++ = 0;
1922         }
1923 }
1924
1925 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
1926 {
1927         if (*inp++ != 0x4) 
1928                 return NULL;
1929         if (chainpp) {
1930                 *chainpp = inp + strlen(inp) + 1;       /* skip over null-terminated string */
1931         }
1932         return inp;
1933 }
1934
1935 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
1936 {
1937         int tlen;
1938
1939         if (*inp++ != 0x5) 
1940                 return NULL;
1941         tlen = inp[0] + (inp[1]<<8);
1942         inp += 2;               /* skip length field */
1943         
1944         if (chainpp) {
1945                 *chainpp = inp + tlen;
1946         }
1947         
1948         if (lengthp) 
1949                 *lengthp = tlen;
1950         
1951         return inp;
1952 }       
1953
1954 /* format a packet as a response */
1955 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
1956 {
1957         smb_t *outp;
1958         smb_t *inSmbp;
1959
1960         outp = (smb_t *) op;
1961         
1962         /* zero the basic structure through the smb_wct field, and zero the data
1963          * size field, assuming that wct stays zero; otherwise, you have to 
1964          * explicitly set the data size field, too.
1965          */
1966         inSmbp = (smb_t *) inp;
1967         memset(outp, 0, sizeof(smb_t)+2);
1968         outp->id[0] = 0xff;
1969         outp->id[1] = 'S';
1970         outp->id[2] = 'M';
1971         outp->id[3] = 'B';
1972         if (inp) {
1973                 outp->com = inSmbp->com;
1974                 outp->tid = inSmbp->tid;
1975                 outp->pid = inSmbp->pid;
1976                 outp->uid = inSmbp->uid;
1977                 outp->mid = inSmbp->mid;
1978                 outp->res[0] = inSmbp->res[0];
1979                 outp->res[1] = inSmbp->res[1];
1980                 op->inCom = inSmbp->com;
1981         }
1982         outp->reb = 0x80;       /* SERVER_RESP */
1983         outp->flg2 = 0x1;       /* KNOWS_LONG_NAMES */
1984
1985         /* copy fields in generic packet area */
1986         op->wctp = &outp->wct;
1987 }
1988
1989 /* send a (probably response) packet; vcp tells us to whom to send it.
1990  * we compute the length by looking at wct and bcc fields.
1991  */
1992 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
1993 {
1994         NCB *ncbp;
1995         int extra;
1996         long code = 0;
1997         unsigned char *tp;
1998         int localNCB = 0;
1999 #ifdef DJGPP
2000         dos_ptr dos_ncb;
2001 #endif /* DJGPP */
2002         
2003         ncbp = inp->ncbp;
2004         if (ncbp == NULL) {
2005                 ncbp = GetNCB();
2006                 localNCB = 1;
2007         }
2008 #ifdef DJGPP
2009         dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2010 #endif /* DJGPP */
2011  
2012         memset((char *)ncbp, 0, sizeof(NCB));
2013
2014         extra = 2 * (*inp->wctp);       /* space used by parms, in bytes */
2015         tp = inp->wctp + 1+ extra;      /* points to count of data bytes */
2016         extra += tp[0] + (tp[1]<<8);
2017         extra += ((unsigned int)inp->wctp - (unsigned int)inp->data);   /* distance to last wct field */
2018         extra += 3;                     /* wct and length fields */
2019         
2020         ncbp->ncb_length = extra;       /* bytes to send */
2021         ncbp->ncb_lsn = (unsigned char) vcp->lsn;       /* vc to use */
2022         ncbp->ncb_lana_num = vcp->lana;
2023         ncbp->ncb_command = NCBSEND;    /* op means send data */
2024 #ifndef DJGPP
2025         ncbp->ncb_buffer = (char *) inp;/* packet */
2026         code = Netbios(ncbp);
2027 #else /* DJGPP */
2028         ncbp->ncb_buffer = inp->dos_pkt;/* packet */
2029         ((smb_ncb_t*)ncbp)->orig_pkt = inp;
2030
2031         /* copy header information from virtual to DOS address space */
2032         dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
2033         code = Netbios(ncbp, dos_ncb);
2034 #endif /* !DJGPP */
2035         
2036         if (code != 0)
2037                 osi_Log1(smb_logp, "SendPacket failure code %d", code);
2038
2039         if (localNCB)
2040                 FreeNCB(ncbp);
2041 }
2042
2043 void smb_MapNTError(long code, unsigned long *NTStatusp)
2044 {
2045         unsigned long NTStatus;
2046
2047         /* map CM_ERROR_* errors to NT 32-bit status codes */
2048     /* NT Status codes are listed in ntstatus.h not winerror.h */
2049         if (code == CM_ERROR_NOSUCHCELL) {
2050                 NTStatus = 0xC000000FL; /* No such file */
2051         }
2052         else if (code == CM_ERROR_NOSUCHVOLUME) {
2053                 NTStatus = 0xC000000FL; /* No such file */
2054         }
2055         else if (code == CM_ERROR_TIMEDOUT) {
2056                 NTStatus = 0xC00000CFL; /* Sharing Paused */
2057         }
2058         else if (code == CM_ERROR_RETRY) {
2059                 NTStatus = 0xC000022DL; /* Retry */
2060         }
2061         else if (code == CM_ERROR_NOACCESS) {
2062                 NTStatus = 0xC0000022L; /* Access denied */
2063         }
2064         else if (code == CM_ERROR_READONLY) {
2065                 NTStatus = 0xC00000A2L; /* Write protected */
2066         }       
2067         else if (code == CM_ERROR_NOSUCHFILE) {
2068                 NTStatus = 0xC000000FL; /* No such file */
2069         }
2070         else if (code == CM_ERROR_NOSUCHPATH) {
2071                 NTStatus = 0xC000003AL; /* Object path not found */
2072         }               
2073         else if (code == CM_ERROR_TOOBIG) {
2074                 NTStatus = 0xC000007BL; /* Invalid image format */
2075         }
2076         else if (code == CM_ERROR_INVAL) {
2077                 NTStatus = 0xC000000DL; /* Invalid parameter */
2078         }
2079         else if (code == CM_ERROR_BADFD) {
2080                 NTStatus = 0xC0000008L; /* Invalid handle */
2081         }
2082         else if (code == CM_ERROR_BADFDOP) {
2083                 NTStatus = 0xC0000022L; /* Access denied */
2084         }
2085         else if (code == CM_ERROR_EXISTS) {
2086                 NTStatus = 0xC0000035L; /* Object name collision */
2087         }
2088         else if (code == CM_ERROR_NOTEMPTY) {
2089                 NTStatus = 0xC0000101L; /* Directory not empty */
2090         }       
2091         else if (code == CM_ERROR_CROSSDEVLINK) {
2092                 NTStatus = 0xC00000D4L; /* Not same device */
2093         }
2094         else if (code == CM_ERROR_NOTDIR) {
2095                 NTStatus = 0xC0000103L; /* Not a directory */
2096         }
2097         else if (code == CM_ERROR_ISDIR) {
2098                 NTStatus = 0xC00000BAL; /* File is a directory */
2099         }
2100         else if (code == CM_ERROR_BADOP) {
2101                 NTStatus = 0xC09820FFL; /* SMB no support */
2102         }
2103         else if (code == CM_ERROR_BADSHARENAME) {
2104                 NTStatus = 0xC00000CCL; /* Bad network name */
2105         }
2106         else if (code == CM_ERROR_NOIPC) {
2107 #ifdef COMMENT
2108                 NTStatus = 0xC0000022L; /* Access Denied */
2109 #else
2110         NTStatus = 0xC000013DL; /* Remote Resources */
2111 #endif
2112         }
2113         else if (code == CM_ERROR_CLOCKSKEW) {
2114                 NTStatus = 0xC0000133L; /* Time difference at DC */
2115         }
2116         else if (code == CM_ERROR_BADTID) {
2117                 NTStatus = 0xC0982005L; /* SMB bad TID */
2118         }
2119         else if (code == CM_ERROR_USESTD) {
2120                 NTStatus = 0xC09820FBL; /* SMB use standard */
2121         }
2122         else if (code == CM_ERROR_QUOTA) {
2123                 NTStatus = 0xC0000044L; /* Quota exceeded */
2124         }
2125         else if (code == CM_ERROR_SPACE) {
2126                 NTStatus = 0xC000007FL; /* Disk full */
2127         }
2128         else if (code == CM_ERROR_ATSYS) {
2129                 NTStatus = 0xC0000033L; /* Object name invalid */
2130         }
2131         else if (code == CM_ERROR_BADNTFILENAME) {
2132                 NTStatus = 0xC0000033L; /* Object name invalid */
2133         }
2134         else if (code == CM_ERROR_WOULDBLOCK) {
2135                 NTStatus = 0xC0000055L; /* Lock not granted */
2136         }
2137         else if (code == CM_ERROR_PARTIALWRITE) {
2138                 NTStatus = 0xC000007FL; /* Disk full */
2139         }
2140         else if (code == CM_ERROR_BUFFERTOOSMALL) {
2141                 NTStatus = 0xC0000023L; /* Buffer too small */
2142         }
2143     else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2144                 NTStatus = 0xC0000035L; /* Object name collision */
2145     }
2146         else if (code == CM_ERROR_BADPASSWORD) {
2147                 NTStatus = 0xC000006DL; /* unknown username or bad password */
2148         }
2149         else if (code == CM_ERROR_BADLOGONTYPE) {
2150                 NTStatus = 0xC000015BL; /* logon type not granted */
2151         }
2152         else if (code == CM_ERROR_GSSCONTINUE) {
2153                 NTStatus = 0xC0000016L; /* more processing required */
2154         }
2155         else {
2156                 NTStatus = 0xC0982001L; /* SMB non-specific error */
2157         }
2158
2159         *NTStatusp = NTStatus;
2160         osi_Log2(smb_logp, "SMB SEND code %x as NT %x", code, NTStatus);
2161 }
2162
2163 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2164         unsigned char *classp)
2165 {
2166         unsigned char class;
2167         unsigned short error;
2168
2169         /* map CM_ERROR_* errors to SMB errors */
2170         if (code == CM_ERROR_NOSUCHCELL) {
2171                 class = 1;
2172                 error = 3;      /* bad path */
2173         }
2174         else if (code == CM_ERROR_NOSUCHVOLUME) {
2175                 class = 1;
2176                 error = 3;      /* bad path */
2177         }
2178         else if (code == CM_ERROR_TIMEDOUT) {
2179                 class = 2;
2180                 error = 81;     /* server is paused */
2181         }
2182         else if (code == CM_ERROR_RETRY) {
2183                 class = 2;      /* shouldn't happen */
2184                 error = 1;
2185         }
2186         else if (code == CM_ERROR_NOACCESS) {
2187                 class = 2;
2188                 error = 4;      /* bad access */
2189         }
2190         else if (code == CM_ERROR_READONLY) {
2191                 class = 3;
2192                 error = 19;     /* read only */
2193         }
2194         else if (code == CM_ERROR_NOSUCHFILE) {
2195                 class = 1;
2196                 error = 2;      /* ENOENT! */
2197         }
2198         else if (code == CM_ERROR_NOSUCHPATH) {
2199                 class = 1;
2200                 error = 3;      /* Bad path */
2201         }
2202         else if (code == CM_ERROR_TOOBIG) {
2203                 class = 1;
2204                 error = 11;     /* bad format */
2205         }
2206         else if (code == CM_ERROR_INVAL) {
2207                 class = 2;      /* server non-specific error code */
2208                 error = 1;
2209         }
2210         else if (code == CM_ERROR_BADFD) {
2211                 class = 1;
2212                 error = 6;      /* invalid file handle */
2213         }
2214         else if (code == CM_ERROR_BADFDOP) {
2215                 class = 1;      /* invalid op on FD */
2216                 error = 5;
2217         }
2218         else if (code == CM_ERROR_EXISTS) {
2219                 class = 1;
2220                 error = 80;     /* file already exists */
2221         }
2222         else if (code == CM_ERROR_NOTEMPTY) {
2223                 class = 1;
2224                 error = 5;      /* delete directory not empty */
2225         }
2226         else if (code == CM_ERROR_CROSSDEVLINK) {
2227                 class = 1;
2228                 error = 17;     /* EXDEV */
2229         }
2230         else if (code == CM_ERROR_NOTDIR) {
2231                 class = 1;      /* bad path */
2232                 error = 3;
2233         }
2234         else if (code == CM_ERROR_ISDIR) {
2235                 class = 1;      /* access denied; DOS doesn't have a good match */
2236                 error = 5;
2237         }
2238         else if (code == CM_ERROR_BADOP) {
2239                 class = 2;
2240                 error = 65535;
2241         }
2242         else if (code == CM_ERROR_BADSHARENAME) {
2243                 class = 2;
2244                 error = 6;
2245         }
2246         else if (code == CM_ERROR_NOIPC) {
2247                 class = 2;
2248                 error = 4; /* bad access */
2249         }
2250         else if (code == CM_ERROR_CLOCKSKEW) {
2251                 class = 1;      /* invalid function */
2252                 error = 1;
2253         }
2254         else if (code == CM_ERROR_BADTID) {
2255                 class = 2;
2256                 error = 5;
2257         }
2258         else if (code == CM_ERROR_USESTD) {
2259                 class = 2;
2260                 error = 251;
2261         }
2262         else if (code == CM_ERROR_REMOTECONN) {
2263                 class = 2;
2264                 error = 82;
2265         }
2266         else if (code == CM_ERROR_QUOTA) {
2267                 if (vcp->flags & SMB_VCFLAG_USEV3) {
2268                         class = 3;
2269                         error = 39;     /* disk full */
2270                 }
2271                 else {
2272                         class = 1;
2273                         error = 5;      /* access denied */
2274                 }
2275         }
2276         else if (code == CM_ERROR_SPACE) {
2277                 if (vcp->flags & SMB_VCFLAG_USEV3) {
2278                         class = 3;
2279                         error = 39;     /* disk full */
2280                 }
2281                 else {
2282                         class = 1;
2283                         error = 5;      /* access denied */
2284                 }
2285         }
2286         else if (code == CM_ERROR_PARTIALWRITE) {
2287                 class = 3;
2288                 error = 39;     /* disk full */
2289         }
2290         else if (code == CM_ERROR_ATSYS) {
2291                 class = 1;
2292                 error = 2;      /* ENOENT */
2293         }
2294         else if (code == CM_ERROR_WOULDBLOCK) {
2295                 class = 1;
2296                 error = 33;     /* lock conflict */
2297         }
2298         else if (code == CM_ERROR_NOFILES) {
2299                 class = 1;
2300                 error = 18;     /* no files in search */
2301         }
2302         else if (code == CM_ERROR_RENAME_IDENTICAL) {
2303                 class = 1;
2304                 error = 183;     /* Samba uses this */
2305         }
2306         else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2307                 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2308                 class = 2;
2309                 error = 2; /* bad password */
2310         }
2311         else {
2312                 class = 2;
2313                 error = 1;
2314         }
2315
2316         *scodep = error;
2317         *classp = class;
2318         osi_Log3(smb_logp, "SMB SEND code %x as SMB %d: %d", code, class, error);
2319 }
2320
2321 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2322 {
2323         return CM_ERROR_BADOP;
2324 }
2325
2326 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2327 {
2328         unsigned short EchoCount, i;
2329         char *data, *outdata;
2330         int dataSize;
2331
2332         EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2333
2334         for (i=1; i<=EchoCount; i++) {
2335             data = smb_GetSMBData(inp, &dataSize);
2336             smb_SetSMBParm(outp, 0, i);
2337             smb_SetSMBDataLength(outp, dataSize);
2338             outdata = smb_GetSMBData(outp, NULL);
2339             memcpy(outdata, data, dataSize);
2340             smb_SendPacket(vcp, outp);
2341         }
2342
2343         return 0;
2344 }
2345
2346 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2347 {
2348         osi_hyper_t offset;
2349         long count, minCount, finalCount;
2350         unsigned short fd;
2351         smb_fid_t *fidp;
2352         long code = 0;
2353         cm_user_t *userp = NULL;
2354     NCB *ncbp;
2355     int rc;
2356 #ifndef DJGPP
2357     char *rawBuf = NULL;
2358 #else
2359     dos_ptr rawBuf = NULL;
2360     dos_ptr dos_ncb;
2361 #endif /* DJGPP */
2362
2363         rawBuf = NULL;
2364         finalCount = 0;
2365
2366         fd = smb_GetSMBParm(inp, 0);
2367         count = smb_GetSMBParm(inp, 3);
2368         minCount = smb_GetSMBParm(inp, 4);
2369         offset.HighPart = 0;    /* too bad */
2370         offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2371
2372         osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2373              fd, offset.LowPart, count);
2374
2375         fidp = smb_FindFID(vcp, fd, 0);
2376         if (!fidp)
2377                 goto send1;
2378
2379         lock_ObtainMutex(&smb_RawBufLock);
2380         if (smb_RawBufs) {
2381                 /* Get a raw buf, from head of list */
2382                 rawBuf = smb_RawBufs;
2383 #ifndef DJGPP
2384                 smb_RawBufs = *(char **)smb_RawBufs;
2385 #else /* DJGPP */
2386         smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2387 #endif /* !DJGPP */
2388         }
2389         lock_ReleaseMutex(&smb_RawBufLock);
2390         if (!rawBuf)
2391                 goto send1a;
2392
2393     if (fidp->flags & SMB_FID_IOCTL)
2394     {
2395 #ifndef DJGPP
2396         rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2397 #else
2398         rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2399 #endif
2400         if (rawBuf) {
2401             /* Give back raw buffer */
2402             lock_ObtainMutex(&smb_RawBufLock);
2403 #ifndef DJGPP
2404             *((char **) rawBuf) = smb_RawBufs;
2405 #else /* DJGPP */
2406             _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2407 #endif /* !DJGPP */
2408             
2409             smb_RawBufs = rawBuf;
2410             lock_ReleaseMutex(&smb_RawBufLock);
2411         }
2412
2413         smb_ReleaseFID(fidp);
2414         return rc;
2415     }
2416         
2417     userp = smb_GetUser(vcp, inp);
2418
2419 #ifndef DJGPP
2420         code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2421 #else /* DJGPP */
2422     /* have to give ReadData flag so it will treat buffer as DOS mem. */
2423     code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2424                         userp, &finalCount, TRUE /* rawFlag */);
2425 #endif /* !DJGPP */
2426
2427         if (code != 0)
2428                 goto send;
2429
2430   send:
2431     cm_ReleaseUser(userp);
2432
2433   send1a:
2434         smb_ReleaseFID(fidp);
2435
2436   send1:
2437         ncbp = outp->ncbp;
2438 #ifdef DJGPP
2439     dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2440 #endif /* DJGPP */
2441         memset((char *)ncbp, 0, sizeof(NCB));
2442
2443         ncbp->ncb_length = (unsigned short) finalCount;
2444         ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2445         ncbp->ncb_lana_num = vcp->lana;
2446         ncbp->ncb_command = NCBSEND;
2447         ncbp->ncb_buffer = rawBuf;
2448
2449 #ifndef DJGPP
2450         code = Netbios(ncbp);
2451 #else /* DJGPP */
2452         code = Netbios(ncbp, dos_ncb);
2453 #endif /* !DJGPP */
2454         if (code != 0)
2455                 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2456
2457         if (rawBuf) {
2458                 /* Give back raw buffer */
2459                 lock_ObtainMutex(&smb_RawBufLock);
2460 #ifndef DJGPP
2461                 *((char **) rawBuf) = smb_RawBufs;
2462 #else /* DJGPP */
2463         _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2464 #endif /* !DJGPP */
2465
2466                 smb_RawBufs = rawBuf;
2467                 lock_ReleaseMutex(&smb_RawBufLock);
2468         }
2469
2470         return 0;
2471 }
2472
2473 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2474 {
2475         return 0;
2476 }
2477
2478 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2479 {
2480         return 0;
2481 }
2482
2483 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2484 {
2485         char *namep;
2486     char *datap;
2487         int coreProtoIndex;
2488         int v3ProtoIndex;
2489         int NTProtoIndex;
2490         int protoIndex;                         /* index we're using */
2491         int namex;
2492         int dbytes;
2493         int entryLength;
2494         int tcounter;
2495         char protocol_array[10][1024];  /* protocol signature of the client */
2496     int caps;                       /* capabilities */
2497     time_t unixTime;
2498         long dosTime;
2499         TIME_ZONE_INFORMATION tzi;
2500
2501     osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2502                          ongoingOps - 1);
2503         if (!isGateway) {
2504                 if (active_vcp) {
2505                         DWORD now = GetCurrentTime();
2506                         if (now - last_msg_time >= 30000
2507                                 && now - last_msg_time <= 90000) {
2508                                 osi_Log1(smb_logp,
2509                                                  "Setting dead_vcp %x", active_vcp);
2510                 if (dead_vcp) {
2511                     smb_ReleaseVC(dead_vcp);
2512                     osi_Log1(smb_logp,
2513                               "Previous dead_vcp %x", dead_vcp);
2514                 }
2515                 smb_HoldVC(active_vcp);
2516                                 dead_vcp = active_vcp;
2517                                 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2518                         }
2519                 }
2520         }
2521
2522         inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
2523
2524         namep = smb_GetSMBData(inp, &dbytes);
2525         namex = 0;
2526         tcounter = 0;
2527         coreProtoIndex = -1;            /* not found */
2528         v3ProtoIndex = -1;
2529         NTProtoIndex = -1;
2530         while(namex < dbytes) {
2531                 osi_Log1(smb_logp, "Protocol %s",
2532                                  osi_LogSaveString(smb_logp, namep+1));
2533                 strcpy(protocol_array[tcounter], namep+1);
2534
2535                 /* namep points at the first protocol, or really, a 0x02
2536                  * byte preceding the null-terminated ASCII name.
2537                  */
2538                 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2539                         coreProtoIndex = tcounter;
2540                 }       
2541                 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2542                         v3ProtoIndex = tcounter;
2543                 }
2544                 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
2545                         NTProtoIndex = tcounter;
2546                 }
2547
2548                 /* compute size of protocol entry */
2549                 entryLength = strlen(namep+1);
2550         entryLength += 2;       /* 0x02 bytes and null termination */
2551                 
2552         /* advance over this protocol entry */
2553                 namex += entryLength;
2554         namep += entryLength;
2555         tcounter++;             /* which proto entry we're looking at */
2556         }
2557 #ifndef NOMOREFILESFIX
2558         /* 
2559          * NOTE: We can determine what OS (NT4.0, W2K, W9X, etc)
2560          * the client is running by reading the protocol signature.
2561          * ie. the order in which it sends us the protocol list.
2562          *
2563          * Special handling for Windows 2000 clients (defect 11765 )
2564      * <asanka:11Jun03> Proto signature is the same for Win XP. </>
2565          */
2566         if (tcounter == 6) {
2567                 int i = 0;
2568                 smb_t *ip = (smb_t *) inp;
2569                 smb_t *op = (smb_t *) outp;
2570
2571                 if ((strcmp("PC NETWORK PROGRAM 1.0", protocol_array[0]) == 0) &&
2572                          (strcmp("LANMAN1.0", protocol_array[1]) == 0) &&
2573                          (strcmp("Windows for Workgroups 3.1a", protocol_array[2]) == 0) &&
2574                          (strcmp("LM1.2X002", protocol_array[3]) == 0) &&
2575                          (strcmp("LANMAN2.1", protocol_array[4]) == 0) &&
2576                          (strcmp("NT LM 0.12", protocol_array[5]) == 0)) {
2577                         isWindows2000 = TRUE;
2578                         osi_Log0(smb_logp, "Looks like a Windows 2000 client");
2579                         /* 
2580                          * HACK: for now - just negotiate a lower protocol till we 
2581                          * figure out which flag/flag2 or some other field 
2582                          * (capabilities maybe?) to set in order for this to work
2583                          * correctly with Windows 2000 clients (defect 11765)
2584                          */
2585                         NTProtoIndex = -1;
2586                         /* Things to try (after looking at tcpdump output could be
2587                          * setting flags and flags2 to 0x98 and 0xc853 like this
2588                          * op->reb = 0x98; op->flg2 = 0xc853;
2589                          * osi_Log2(smb_logp, "Flags:0x%x Flags2:0x%x", ip->reb, ip->flg2);
2590                          */
2591                 }       
2592         }       
2593 #endif /* NOMOREFILESFIX */
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         cm_InitReq(&req);
4920
4921         bufferp = NULL;
4922         doWriteBack = 0;
4923         offset = *offsetp;
4924
4925         lock_ObtainMutex(&fidp->mx);
4926         scp = fidp->scp;
4927         lock_ObtainMutex(&scp->mx);
4928
4929         /* start by looking up the file's end */
4930         code = cm_SyncOp(scp, NULL, userp, &req, 0,
4931                                          CM_SCACHESYNC_NEEDCALLBACK
4932                                          | CM_SCACHESYNC_SETSTATUS
4933                                          | CM_SCACHESYNC_GETSTATUS);
4934         if (code) 
4935                 goto done;
4936         
4937         /* make sure we have a writable FD */
4938         if (!(fidp->flags & SMB_FID_OPENWRITE)) {
4939                 code = CM_ERROR_BADFDOP;
4940                 goto done;
4941         }
4942         
4943         /* now we have the entry locked, look up the length */
4944         fileLength = scp->length;
4945         minLength = fileLength;
4946         if (LargeIntegerGreaterThan(minLength, scp->serverLength))
4947                 minLength = scp->serverLength;
4948
4949         /* adjust file length if we extend past EOF */
4950         thyper.LowPart = count;
4951         thyper.HighPart = 0;
4952         thyper = LargeIntegerAdd(offset, thyper);       /* where write should end */
4953         if (LargeIntegerGreaterThan(thyper, fileLength)) {
4954                 /* we'd write past EOF, so extend the file */
4955                 scp->mask |= CM_SCACHEMASK_LENGTH;
4956                 scp->length = thyper;
4957                 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
4958         } else
4959                 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
4960         
4961         /* now, if the new position (thyper) and the old (offset) are in
4962          * different storeback windows, remember to store back the previous
4963          * storeback window when we're done with the write.
4964          */
4965         if ((thyper.LowPart & (-cm_chunkSize)) !=
4966                  (offset.LowPart & (-cm_chunkSize))) {
4967                 /* they're different */
4968                 doWriteBack = 1;
4969                 writeBackOffset.HighPart = offset.HighPart;
4970                 writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
4971         }
4972         
4973         *writtenp = count;
4974
4975         /* now, copy the data one buffer at a time, until we've filled the
4976          * request packet */
4977         while (1) {
4978                 /* if we've copied all the data requested, we're done */
4979                 if (count <= 0) break;
4980
4981                 /* handle over quota or out of space */
4982                 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
4983                         *writtenp = written;
4984                         break;
4985                 }
4986                 
4987                 /* otherwise, load up a buffer of data */
4988                 thyper.HighPart = offset.HighPart;
4989                 thyper.LowPart = offset.LowPart & ~(buf_bufferSize-1);
4990                 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4991                         /* wrong buffer */
4992                         if (bufferp) {
4993                                 lock_ReleaseMutex(&bufferp->mx);
4994                                 buf_Release(bufferp);
4995                                 bufferp = NULL;
4996                         }       
4997                         lock_ReleaseMutex(&scp->mx);
4998
4999                         lock_ObtainRead(&scp->bufCreateLock);
5000                         code = buf_Get(scp, &thyper, &bufferp);
5001                         lock_ReleaseRead(&scp->bufCreateLock);
5002
5003                         lock_ObtainMutex(&bufferp->mx);
5004                         lock_ObtainMutex(&scp->mx);
5005                         if (code) goto done;
5006
5007                         bufferOffset = thyper;
5008
5009                         /* now get the data in the cache */
5010                         while (1) {
5011                                 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
5012                                                                  CM_SCACHESYNC_NEEDCALLBACK
5013                                                                  | CM_SCACHESYNC_WRITE
5014                                                                  | CM_SCACHESYNC_BUFLOCKED);
5015                                 if (code) 
5016                                         goto done;
5017                                 
5018                                 /* If we're overwriting the entire buffer, or
5019                                  * if we're writing at or past EOF, mark the
5020                                  * buffer as current so we don't call
5021                                  * cm_GetBuffer.  This skips the fetch from the
5022                                  * server in those cases where we're going to 
5023                                  * obliterate all the data in the buffer anyway,
5024                                  * or in those cases where there is no useful
5025                                  * data at the server to start with.
5026                                  *
5027                                  * Use minLength instead of scp->length, since
5028                                  * the latter has already been updated by this
5029                                  * call.
5030                                  */
5031                                 if (LargeIntegerGreaterThanOrEqualTo(
5032                                         bufferp->offset, minLength)
5033                                     || LargeIntegerEqualTo(offset, bufferp->offset)
5034                                        && (count >= buf_bufferSize
5035                                            || LargeIntegerGreaterThanOrEqualTo(
5036                                                LargeIntegerAdd(offset,
5037                                                    ConvertLongToLargeInteger(count)),
5038                                                minLength))) {
5039                                         if (count < buf_bufferSize
5040                                             && bufferp->dataVersion == -1)
5041                                             memset(bufferp->datap, 0,
5042                                                    buf_bufferSize);
5043                                         bufferp->dataVersion = scp->dataVersion;
5044                                 }
5045
5046                                 if (cm_HaveBuffer(scp, bufferp, 1)) break;
5047
5048                                 /* otherwise, load the buffer and try again */
5049                                 lock_ReleaseMutex(&bufferp->mx);
5050                                 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5051                                                                         &req);
5052                                 lock_ReleaseMutex(&scp->mx);
5053                                 lock_ObtainMutex(&bufferp->mx);
5054                                 lock_ObtainMutex(&scp->mx);
5055                                 if (code) break;
5056                         }
5057                         if (code) {
5058                                 lock_ReleaseMutex(&bufferp->mx);
5059                                 buf_Release(bufferp);
5060                                 bufferp = NULL;
5061                                 goto done;
5062                         }
5063                 }       /* if (wrong buffer) ... */
5064                 
5065                 /* now we have the right buffer loaded.  Copy out the
5066                  * data from here to the user's buffer.
5067                  */
5068                 bufIndex = offset.LowPart & (buf_bufferSize - 1);
5069
5070                 /* and figure out how many bytes we want from this buffer */
5071                 nbytes = buf_bufferSize - bufIndex;     /* what remains in buffer */
5072                 if (nbytes > count) 
5073                         nbytes = count; /* don't go past end of request */
5074                 
5075                 /* now copy the data */
5076 #ifdef DJGPP
5077                 if (dosflag)
5078                         dosmemget((dos_ptr)op, nbytes, bufferp->datap + bufIndex);
5079                 else
5080 #endif /* DJGPP */
5081                         memcpy(bufferp->datap + bufIndex, op, nbytes);
5082                 buf_SetDirty(bufferp);
5083
5084                 /* and record the last writer */
5085                 if (bufferp->userp != userp) {
5086                         cm_HoldUser(userp);
5087                         if (bufferp->userp) 
5088                 cm_ReleaseUser(bufferp->userp);
5089                         bufferp->userp = userp;
5090                 }
5091                 
5092                 /* adjust counters, pointers, etc. */
5093                 op += nbytes;
5094                 count -= nbytes;
5095                 written += nbytes;
5096                 thyper.LowPart = nbytes;
5097                 thyper.HighPart = 0;
5098                 offset = LargeIntegerAdd(thyper, offset);
5099         } /* while 1 */
5100
5101   done:
5102         lock_ReleaseMutex(&scp->mx);
5103         lock_ReleaseMutex(&fidp->mx);
5104         if (bufferp) {
5105                 lock_ReleaseMutex(&bufferp->mx);
5106                 buf_Release(bufferp);
5107         }
5108
5109         if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
5110             && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
5111                 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
5112                                                  fidp->NTopen_dscp, fidp->NTopen_pathp,
5113                                                  NULL, TRUE);
5114         }
5115
5116         if (code == 0 && doWriteBack) {
5117                 lock_ObtainMutex(&scp->mx);
5118                 cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
5119                 lock_ReleaseMutex(&scp->mx);
5120                 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
5121                                                    writeBackOffset.HighPart, cm_chunkSize, 0, userp);
5122         }
5123
5124         return code;
5125 }
5126
5127 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5128 {
5129         osi_hyper_t offset;
5130     long count, written = 0;
5131     unsigned short fd;
5132     smb_fid_t *fidp;
5133     long code = 0;
5134     cm_user_t *userp;
5135     cm_attr_t truncAttr;        /* attribute struct used for truncating file */
5136     char *op;
5137     int inDataBlockCount;
5138
5139     fd = smb_GetSMBParm(inp, 0);
5140     count = smb_GetSMBParm(inp, 1);
5141     offset.HighPart = 0;        /* too bad */
5142     offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
5143
5144     op = smb_GetSMBData(inp, NULL);
5145         op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
5146
5147     osi_Log3(smb_logp, "smb_ReceiveCoreWrite fd %d, off 0x%x, size 0x%x",
5148              fd, offset.LowPart, count);
5149         
5150         fd = smb_ChainFID(fd, inp);
5151     fidp = smb_FindFID(vcp, fd, 0);
5152     if (!fidp) {
5153                 return CM_ERROR_BADFD;
5154     }
5155         
5156     if (fidp->flags & SMB_FID_IOCTL)
5157         return smb_IoctlWrite(fidp, vcp, inp, outp);
5158         
5159         userp = smb_GetUser(vcp, inp);
5160
5161         /* special case: 0 bytes transferred means truncate to this position */
5162     if (count == 0) {
5163                 cm_req_t req;
5164
5165                 cm_InitReq(&req);
5166
5167                 truncAttr.mask = CM_ATTRMASK_LENGTH;
5168         truncAttr.length.LowPart = offset.LowPart;
5169         truncAttr.length.HighPart = 0;
5170                 lock_ObtainMutex(&fidp->mx);
5171         code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
5172                 lock_ReleaseMutex(&fidp->mx);
5173                 smb_SetSMBParm(outp, 0, /* count */ 0);
5174         smb_SetSMBDataLength(outp, 0);
5175                 fidp->flags |= SMB_FID_LENGTHSETDONE;
5176         goto done;
5177     }
5178
5179         /*
5180          * Work around bug in NT client
5181          *
5182          * When copying a file, the NT client should first copy the data,
5183          * then copy the last write time.  But sometimes the NT client does
5184          * these in the wrong order, so the data copies would inadvertently
5185          * cause the last write time to be overwritten.  We try to detect this,
5186          * and don't set client mod time if we think that would go against the
5187          * intention.
5188          */
5189         if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
5190                 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5191                 fidp->scp->clientModTime = time(NULL);
5192         }
5193
5194 #ifndef DJGPP
5195         code = smb_WriteData(fidp, &offset, count, op, userp, &written);
5196 #else /* DJGPP */
5197         code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
5198 #endif /* !DJGPP */
5199         if (code == 0 && written < count)
5200                 code = CM_ERROR_PARTIALWRITE;
5201
5202         /* set the packet data length to 3 bytes for the data block header,
5203      * plus the size of the data.
5204      */
5205         smb_SetSMBParm(outp, 0, written);
5206     smb_SetSMBDataLength(outp, 0);
5207
5208   done:
5209     smb_ReleaseFID(fidp);
5210     cm_ReleaseUser(userp);
5211
5212         return code;
5213 }
5214
5215 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
5216         NCB *ncbp, raw_write_cont_t *rwcp)
5217 {
5218         unsigned short fd;
5219         smb_fid_t *fidp;
5220         cm_user_t *userp;
5221 #ifndef DJGPP
5222         char *rawBuf;
5223 #else /* DJGPP */
5224         dos_ptr rawBuf;
5225 #endif /* !DJGPP */
5226         long written = 0;
5227         long code = 0;
5228
5229         fd = smb_GetSMBParm(inp, 0);
5230         fidp = smb_FindFID(vcp, fd, 0);
5231
5232         osi_Log2(smb_logp, "Completing Raw Write offset %x count %x",
5233                  rwcp->offset.LowPart, rwcp->count);
5234
5235         userp = smb_GetUser(vcp, inp);
5236
5237 #ifndef DJGPP
5238         rawBuf = rwcp->buf;
5239         code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
5240                                                  &written);
5241 #else /* DJGPP */
5242         rawBuf = (dos_ptr) rwcp->buf;
5243         code = smb_WriteData(fidp, &rwcp->offset, rwcp->count,
5244                          (unsigned char *) rawBuf, userp,
5245                          &written, TRUE);
5246 #endif /* !DJGPP */
5247
5248         if (rwcp->writeMode & 0x1) {    /* synchronous */
5249                 smb_t *op;
5250
5251                 smb_FormatResponsePacket(vcp, inp, outp);
5252                 op = (smb_t *) outp;
5253                 op->com = 0x20;         /* SMB_COM_WRITE_COMPLETE */
5254                 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
5255                 smb_SetSMBDataLength(outp,  0);
5256                 smb_SendPacket(vcp, outp);
5257                 smb_FreePacket(outp);
5258         }
5259         else {                          /* asynchronous */
5260                 lock_ObtainMutex(&fidp->mx);
5261                 fidp->raw_writers--;
5262                 if (fidp->raw_writers == 0)
5263                         thrd_SetEvent(fidp->raw_write_event);
5264                 lock_ReleaseMutex(&fidp->mx);
5265         }
5266
5267         /* Give back raw buffer */
5268         lock_ObtainMutex(&smb_RawBufLock);
5269 #ifndef DJGPP
5270         *((char **)rawBuf) = smb_RawBufs;
5271 #else /* DJGPP */
5272     _farpokel(_dos_ds, rawBuf, smb_RawBufs);
5273 #endif /* !DJGPP */
5274         smb_RawBufs = rawBuf;
5275         lock_ReleaseMutex(&smb_RawBufLock);
5276
5277         smb_ReleaseFID(fidp);
5278         cm_ReleaseUser(userp);
5279 }
5280
5281 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5282 {
5283         return 0;
5284 }
5285
5286 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
5287 {
5288         osi_hyper_t offset;
5289     long count, written = 0;
5290         long totalCount;
5291     unsigned short fd;
5292     smb_fid_t *fidp;
5293     long code = 0;
5294     cm_user_t *userp;
5295     char *op;
5296         unsigned short writeMode;
5297 #ifndef DJGPP
5298         char *rawBuf;
5299 #else /* DJGPP */
5300     dos_ptr rawBuf;
5301 #endif /* !DJGPP */
5302
5303     fd = smb_GetSMBParm(inp, 0);
5304         totalCount = smb_GetSMBParm(inp, 1);
5305     count = smb_GetSMBParm(inp, 10);
5306     offset.HighPart = 0;        /* too bad */
5307     offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
5308         writeMode = smb_GetSMBParm(inp, 7);
5309
5310         op = (char *) inp->data;
5311         op += smb_GetSMBParm(inp, 11);
5312
5313     osi_Log4(smb_logp,
5314              "smb_ReceiveCoreWriteRaw fd %d, off 0x%x, size 0x%x, WriteMode 0x%x",
5315              fd, offset.LowPart, count, writeMode);
5316         
5317         fd = smb_ChainFID(fd, inp);
5318     fidp = smb_FindFID(vcp, fd, 0);
5319     if (!fidp) {
5320                 return CM_ERROR_BADFD;
5321     }
5322         
5323         userp = smb_GetUser(vcp, inp);
5324
5325         /*
5326          * Work around bug in NT client
5327          *
5328          * When copying a file, the NT client should first copy the data,
5329          * then copy the last write time.  But sometimes the NT client does
5330          * these in the wrong order, so the data copies would inadvertently
5331          * cause the last write time to be overwritten.  We try to detect this,
5332          * and don't set client mod time if we think that would go against the
5333          * intention.
5334          */
5335         if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
5336                 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5337                 fidp->scp->clientModTime = time(NULL);
5338         }
5339
5340 #ifndef DJGPP
5341         code = smb_WriteData(fidp, &offset, count, op, userp, &written);
5342 #else /* DJGPP */
5343         code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
5344 #endif /* !DJGPP */
5345         if (code == 0 && written < count)
5346                 code = CM_ERROR_PARTIALWRITE;
5347
5348         /* Get a raw buffer */
5349         if (code == 0) {
5350                 rawBuf = NULL;
5351                 lock_ObtainMutex(&smb_RawBufLock);
5352                 if (smb_RawBufs) {
5353                         /* Get a raw buf, from head of list */
5354                         rawBuf = smb_RawBufs;
5355 #ifndef DJGPP
5356                         smb_RawBufs = *(char **)smb_RawBufs;
5357 #else /* DJGPP */
5358             smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
5359 #endif /* !DJGPP */
5360                 }
5361                 else
5362                         code = CM_ERROR_USESTD;
5363                 
5364         lock_ReleaseMutex(&smb_RawBufLock);
5365         }
5366
5367         /* Don't allow a premature Close */
5368         if (code == 0 && (writeMode & 1) == 0) {
5369                 lock_ObtainMutex(&fidp->mx);
5370                 fidp->raw_writers++;
5371                 thrd_ResetEvent(fidp->raw_write_event);
5372                 lock_ReleaseMutex(&fidp->mx);
5373         }
5374
5375         smb_ReleaseFID(fidp);
5376         cm_ReleaseUser(userp);
5377
5378         if (code) {
5379                 smb_SetSMBParm(outp, 0, written);
5380                 smb_SetSMBDataLength(outp, 0);
5381                 ((smb_t *)outp)->com = 0x20;    /* SMB_COM_WRITE_COMPLETE */
5382                 rwcp->code = code;
5383                 return code;
5384         }
5385
5386         rwcp->code = 0;
5387         rwcp->buf = rawBuf;
5388         rwcp->offset.HighPart = 0;
5389         rwcp->offset.LowPart = offset.LowPart + count;
5390         rwcp->count = totalCount - count;
5391         rwcp->writeMode = writeMode;
5392         rwcp->alreadyWritten = written;
5393
5394         /* set the packet data length to 3 bytes for the data block header,
5395      * plus the size of the data.
5396      */
5397         smb_SetSMBParm(outp, 0, 0xffff);
5398     smb_SetSMBDataLength(outp, 0);
5399
5400         return 0;
5401 }
5402
5403 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5404 {
5405         osi_hyper_t offset;
5406     long count, finalCount;
5407     unsigned short fd;
5408     smb_fid_t *fidp;
5409     long code = 0;
5410     cm_user_t *userp;
5411     char *op;
5412         
5413     fd = smb_GetSMBParm(inp, 0);
5414     count = smb_GetSMBParm(inp, 1);
5415     offset.HighPart = 0;        /* too bad */
5416     offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
5417         
5418     osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
5419              fd, offset.LowPart, count);
5420         
5421         fd = smb_ChainFID(fd, inp);
5422     fidp = smb_FindFID(vcp, fd, 0);
5423     if (!fidp) {
5424                 return CM_ERROR_BADFD;
5425     }
5426         
5427     if (fidp->flags & SMB_FID_IOCTL) {
5428                 return smb_IoctlRead(fidp, vcp, inp, outp);
5429     }
5430         
5431         userp = smb_GetUser(vcp, inp);
5432
5433         /* remember this for final results */
5434     smb_SetSMBParm(outp, 0, count);
5435     smb_SetSMBParm(outp, 1, 0);
5436     smb_SetSMBParm(outp, 2, 0);
5437     smb_SetSMBParm(outp, 3, 0);
5438     smb_SetSMBParm(outp, 4, 0);
5439
5440         /* set the packet data length to 3 bytes for the data block header,
5441      * plus the size of the data.
5442      */
5443     smb_SetSMBDataLength(outp, count+3);
5444         
5445         /* get op ptr after putting in the parms, since otherwise we don't
5446      * know where the data really is.
5447      */
5448     op = smb_GetSMBData(outp, NULL);
5449
5450         /* now emit the data block header: 1 byte of type and 2 bytes of length */
5451     *op++ = 1;  /* data block marker */
5452     *op++ = (unsigned char) (count & 0xff);
5453     *op++ = (unsigned char) ((count >> 8) & 0xff);
5454                 
5455 #ifndef DJGPP
5456         code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
5457 #else /* DJGPP */
5458     code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
5459 #endif /* !DJGPP */
5460
5461         /* fix some things up */
5462         smb_SetSMBParm(outp, 0, finalCount);
5463         smb_SetSMBDataLength(outp, finalCount+3);
5464
5465     smb_ReleaseFID(fidp);
5466         
5467     cm_ReleaseUser(userp);
5468     return code;
5469 }
5470
5471 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5472 {
5473         char *pathp;
5474     long code = 0;
5475         cm_space_t *spacep;
5476     char *tp;
5477     cm_user_t *userp;
5478     cm_scache_t *dscp;                  /* dir we're dealing with */
5479     cm_scache_t *scp;                   /* file we're creating */
5480     cm_attr_t setAttr;
5481     int initialModeBits;
5482     char *lastNamep;
5483     int caseFold;
5484         char *tidPathp;
5485         cm_req_t req;
5486
5487         cm_InitReq(&req);
5488
5489     scp = NULL;
5490         
5491         /* compute initial mode bits based on read-only flag in attributes */
5492     initialModeBits = 0777;
5493         
5494         tp = smb_GetSMBData(inp, NULL);
5495     pathp = smb_ParseASCIIBlock(tp, &tp);
5496
5497         if (strcmp(pathp, "\\") == 0)
5498                 return CM_ERROR_EXISTS;
5499
5500         spacep = inp->spacep;
5501     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5502
5503         userp = smb_GetUser(vcp, inp);
5504
5505     caseFold = CM_FLAG_CASEFOLD;
5506
5507         tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
5508
5509         code = cm_NameI(cm_rootSCachep, spacep->data,
5510                     caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
5511                     userp, tidPathp, &req, &dscp);
5512
5513     if (code) {
5514         cm_ReleaseUser(userp);
5515         return code;
5516     }
5517         
5518     /* otherwise, scp points to the parent directory.  Do a lookup, and
5519          * fail if we find it.  Otherwise, we do the create.
5520      */
5521     if (!lastNamep) 
5522         lastNamep = pathp;
5523     else 
5524         lastNamep++;
5525     code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
5526     if (scp) cm_ReleaseSCache(scp);
5527     if (code != CM_ERROR_NOSUCHFILE) {
5528         if (code == 0) code = CM_ERROR_EXISTS;
5529                 cm_ReleaseSCache(dscp);
5530         cm_ReleaseUser(userp);
5531         return code;
5532     }
5533         
5534         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5535         setAttr.clientModTime = time(NULL);
5536         code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
5537         if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5538                 smb_NotifyChange(FILE_ACTION_ADDED,
5539                          FILE_NOTIFY_CHANGE_DIR_NAME,
5540                          dscp, lastNamep, NULL, TRUE);
5541         
5542         /* we don't need this any longer */
5543         cm_ReleaseSCache(dscp);
5544
5545     if (code) {
5546                 /* something went wrong creating or truncating the file */
5547         cm_ReleaseUser(userp);
5548         return code;
5549     }
5550         
5551         /* otherwise we succeeded */
5552     smb_SetSMBDataLength(outp, 0);
5553     cm_ReleaseUser(userp);
5554
5555     return 0;
5556 }
5557
5558 BOOL smb_IsLegalFilename(char *filename)
5559 {
5560     /* 
5561      *  Find the longest substring of filename that does not contain
5562      *  any of the chars in illegalChars.  If that substring is less
5563      *  than the length of the whole string, then one or more of the
5564      *  illegal chars is in filename. 
5565      */
5566     if (strcspn(filename, illegalChars) < strlen(filename))
5567         return FALSE;
5568
5569     return TRUE;
5570 }        
5571
5572 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5573 {
5574         char *pathp;
5575     long code = 0;
5576         cm_space_t *spacep;
5577     char *tp;
5578     int excl;
5579     cm_user_t *userp;
5580     cm_scache_t *dscp;                  /* dir we're dealing with */
5581     cm_scache_t *scp;                   /* file we're creating */
5582     cm_attr_t setAttr;
5583     int initialModeBits;
5584     smb_fid_t *fidp;
5585     int attributes;
5586     char *lastNamep;
5587     int caseFold;
5588     long dosTime;
5589         char *tidPathp;
5590         cm_req_t req;
5591
5592         cm_InitReq(&req);
5593
5594     scp = NULL;
5595     excl = (inp->inCom == 0x03)? 0 : 1;
5596         
5597     attributes = smb_GetSMBParm(inp, 0);
5598     dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5599         
5600         /* compute initial mode bits based on read-only flag in attributes */
5601     initialModeBits = 0666;
5602     if (attributes & 1) initialModeBits &= ~0222;
5603         
5604         tp = smb_GetSMBData(inp, NULL);
5605     pathp = smb_ParseASCIIBlock(tp, &tp);
5606
5607         spacep = inp->spacep;
5608     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5609
5610         userp = smb_GetUser(vcp, inp);
5611
5612     caseFold = CM_FLAG_CASEFOLD;
5613
5614         tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
5615         code = cm_NameI(cm_rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5616                     userp, tidPathp, &req, &dscp);
5617
5618     if (code) {
5619         cm_ReleaseUser(userp);
5620         return code;
5621     }
5622         
5623     /* otherwise, scp points to the parent directory.  Do a lookup, and
5624          * truncate the file if we find it, otherwise we create the file.
5625      */
5626     if (!lastNamep) lastNamep = pathp;
5627     else lastNamep++;
5628
5629     if (!smb_IsLegalFilename(lastNamep))
5630         return CM_ERROR_BADNTFILENAME;
5631
5632     osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
5633 #ifdef DEBUG_VERBOSE
5634     {
5635         char *hexp;
5636         hexp = osi_HexifyString( lastNamep );
5637         DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
5638         free(hexp);
5639     }
5640 #endif    
5641
5642     code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
5643     if (code && code != CM_ERROR_NOSUCHFILE) {
5644                 cm_ReleaseSCache(dscp);
5645         cm_ReleaseUser(userp);
5646         return code;
5647     }
5648         
5649     /* if we get here, if code is 0, the file exists and is represented by
5650      * scp.  Otherwise, we have to create it.
5651      */
5652         if (code == 0) {
5653                 if (excl) {
5654                         /* oops, file shouldn't be there */
5655             cm_ReleaseSCache(dscp);
5656             cm_ReleaseSCache(scp);
5657             cm_ReleaseUser(userp);
5658             return CM_ERROR_EXISTS;
5659         }
5660
5661                 setAttr.mask = CM_ATTRMASK_LENGTH;
5662         setAttr.length.LowPart = 0;
5663         setAttr.length.HighPart = 0;
5664                 code = cm_SetAttr(scp, &setAttr, userp, &req);
5665     }
5666     else {
5667                 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5668                 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
5669         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5670                          &req);
5671                 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5672                         smb_NotifyChange(FILE_ACTION_ADDED,
5673                              FILE_NOTIFY_CHANGE_FILE_NAME,
5674                              dscp, lastNamep, NULL, TRUE);
5675         if (!excl && code == CM_ERROR_EXISTS) {
5676                         /* not an exclusive create, and someone else tried
5677                          * creating it already, then we open it anyway.  We
5678                          * don't bother retrying after this, since if this next
5679                          * fails, that means that the file was deleted after
5680                          * we started this call.
5681              */
5682             code = cm_Lookup(dscp, lastNamep, caseFold, userp,
5683                              &req, &scp);
5684             if (code == 0) {
5685                                 setAttr.mask = CM_ATTRMASK_LENGTH;
5686                 setAttr.length.LowPart = 0;
5687                 setAttr.length.HighPart = 0;
5688                 code = cm_SetAttr(scp, &setAttr, userp, &req);
5689             }
5690         }
5691     }
5692         
5693         /* we don't need this any longer */
5694         cm_ReleaseSCache(dscp);
5695
5696     if (code) {
5697                 /* something went wrong creating or truncating the file */
5698         if (scp) cm_ReleaseSCache(scp);
5699         cm_ReleaseUser(userp);
5700         return code;
5701     }
5702
5703         /* make sure we only open files */
5704         if (scp->fileType != CM_SCACHETYPE_FILE) {
5705                 cm_ReleaseSCache(scp);
5706         cm_ReleaseUser(userp);
5707         return CM_ERROR_ISDIR;
5708         }
5709
5710     /* now all we have to do is open the file itself */
5711     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5712     osi_assert(fidp);
5713         
5714         /* save a pointer to the vnode */
5715     fidp->scp = scp;
5716         
5717         /* always create it open for read/write */
5718         fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
5719
5720         smb_ReleaseFID(fidp);
5721         
5722         smb_SetSMBParm(outp, 0, fidp->fid);
5723     smb_SetSMBDataLength(outp, 0);
5724
5725         cm_Open(scp, 0, userp);
5726
5727     cm_ReleaseUser(userp);
5728     /* leave scp held since we put it in fidp->scp */
5729     return 0;
5730 }
5731
5732 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5733 {
5734     long code = 0;
5735     long offset;
5736     int whence;
5737     unsigned short fd;
5738     smb_fid_t *fidp;
5739     cm_scache_t *scp;
5740     cm_user_t *userp;
5741         cm_req_t req;
5742
5743         cm_InitReq(&req);
5744         
5745     fd = smb_GetSMBParm(inp, 0);
5746         whence = smb_GetSMBParm(inp, 1);
5747     offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
5748         
5749         /* try to find the file descriptor */
5750         fd = smb_ChainFID(fd, inp);
5751     fidp = smb_FindFID(vcp, fd, 0);
5752     if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
5753                 return CM_ERROR_BADFD;
5754     }
5755         
5756         userp = smb_GetUser(vcp, inp);
5757
5758     lock_ObtainMutex(&fidp->mx);
5759     scp = fidp->scp;
5760         lock_ObtainMutex(&scp->mx);
5761         code = cm_SyncOp(scp, NULL, userp, &req, 0,
5762                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5763         if (code == 0) {
5764                 if (whence == 1) {
5765             /* offset from current offset */
5766             offset += fidp->offset;
5767                 }
5768                 else if (whence == 2) {
5769             /* offset from current EOF */
5770             offset += scp->length.LowPart;
5771                 }
5772         fidp->offset = offset;
5773         smb_SetSMBParm(outp, 0, offset & 0xffff);
5774         smb_SetSMBParm(outp, 1, (offset>>16) & 0xffff);
5775         smb_SetSMBDataLength(outp, 0);
5776     }
5777         lock_ReleaseMutex(&scp->mx);
5778     lock_ReleaseMutex(&fidp->mx);
5779     smb_ReleaseFID(fidp);
5780     cm_ReleaseUser(userp);
5781     return code;
5782 }
5783
5784 /* dispatch all of the requests received in a packet.  Due to chaining, this may
5785  * be more than one request.
5786  */
5787 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
5788         NCB *ncbp, raw_write_cont_t *rwcp)
5789 {
5790     smb_dispatch_t *dp;
5791     smb_t *smbp;
5792     unsigned long code = 0;
5793     unsigned char *outWctp;
5794     int nparms;                 /* # of bytes of parameters */
5795     char tbuffer[200];
5796     int nbytes;                 /* bytes of data, excluding count */
5797     int temp;
5798     unsigned char *tp;
5799     unsigned short errCode;
5800         unsigned long NTStatus;
5801     int noSend;
5802     unsigned char errClass;
5803         unsigned int oldGen;
5804         DWORD oldTime, newTime;
5805
5806         /* get easy pointer to the data */
5807         smbp = (smb_t *) inp->data;
5808
5809         if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
5810         /* setup the basic parms for the initial request in the packet */
5811                 inp->inCom = smbp->com;
5812         inp->wctp = &smbp->wct;
5813         inp->inCount = 0;
5814                 inp->ncb_length = ncbp->ncb_length;
5815         }
5816     noSend = 0;
5817
5818         /* Sanity check */
5819         if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
5820                 /* log it and discard it */
5821 #ifndef DJGPP
5822                 HANDLE h;
5823                 char *ptbuf[1];
5824                 char s[100];
5825                 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
5826                 sprintf(s, "SMB message too short, len %d", ncbp->ncb_length);
5827                 ptbuf[0] = s;
5828                 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1007, NULL,
5829                         1, ncbp->ncb_length, ptbuf, inp);
5830                 DeregisterEventSource(h);
5831 #else /* DJGPP */
5832         osi_Log1(smb_logp, "SMB message too short, len %d",
5833                  ncbp->ncb_length);
5834 #endif /* !DJGPP */
5835
5836                 return;
5837         }
5838
5839         /* We are an ongoing op */
5840         thrd_Increment(&ongoingOps);
5841
5842     /* set up response packet for receiving output */
5843         if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
5844         smb_FormatResponsePacket(vcp, inp, outp);
5845     outWctp = outp->wctp;
5846
5847         /* Remember session generation number and time */
5848         oldGen = sessionGen;
5849         oldTime = GetCurrentTime();
5850
5851         while(inp->inCom != 0xff) {
5852         dp = &smb_dispatchTable[inp->inCom];
5853
5854                 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
5855                         outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
5856                         code = outp->resumeCode;
5857                         goto resume;
5858                 }
5859
5860         /* process each request in the packet; inCom, wctp and inCount
5861          * are already set up.
5862          */
5863                 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
5864                  ncbp->ncb_lsn);
5865
5866                 /* now do the dispatch */
5867                 /* start by formatting the response record a little, as a default */
5868         if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
5869                         outWctp[0] = 2;
5870             outWctp[1] = 0xff;  /* no operation */
5871             outWctp[2] = 0;             /* padding */
5872             outWctp[3] = 0;
5873             outWctp[4] = 0;
5874         }
5875                 else {
5876                         /* not a chained request, this is a more reasonable default */
5877             outWctp[0] = 0;     /* wct of zero */
5878             outWctp[1] = 0;     /* and bcc (word) of zero */
5879             outWctp[2] = 0;
5880                 }   
5881
5882                 /* once set, stays set.  Doesn't matter, since we never chain
5883          * "no response" calls.
5884          */
5885                 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
5886             noSend = 1;
5887
5888         if (dp->procp) {
5889                         /* we have a recognized operation */
5890
5891                         if (inp->inCom == 0x1d)
5892                                 /* Raw Write */
5893                                 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp,
5894                                                 rwcp);
5895                         else {
5896                                         osi_LogEvent("AFS Dispatch %s",(myCrt_Dispatch(inp->inCom)),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
5897                                         osi_Log4(smb_logp,"Dispatch %s vcp[%x] lana[%d] lsn[%d]",(myCrt_Dispatch(inp->inCom)),vcp,vcp->lana,vcp->lsn);
5898                                         code = (*(dp->procp)) (vcp, inp, outp);
5899                                         osi_LogEvent("AFS Dispatch return",NULL,"Code[%d]",(code==0)?0:code-CM_ERROR_BASE);
5900                                         osi_Log1(smb_logp,"Dispatch return  code[%d]",(code==0)?0:code-CM_ERROR_BASE);
5901             }
5902
5903                         if (oldGen != sessionGen) {
5904 #ifndef DJGPP
5905                                 HANDLE h;
5906                                 char *ptbuf[1];
5907                                 char s[100];
5908                                 newTime = GetCurrentTime();
5909                                 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
5910                                 sprintf(s, "Pkt straddled session startup, took %d ms, ncb length %d",
5911                         newTime - oldTime, ncbp->ncb_length);
5912                                 ptbuf[0] = s;
5913                                 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
5914                             1005, NULL, 1, ncbp->ncb_length, ptbuf, smbp);
5915                                 DeregisterEventSource(h);
5916 #else /* DJGPP */
5917                                 osi_Log1(smb_logp, "Pkt straddled session startup, "
5918                          "ncb length %d", ncbp->ncb_length);
5919 #endif /* !DJGPP */
5920                         }
5921         }
5922         else {
5923                         /* bad opcode, fail the request, after displaying it */
5924 #ifdef NOTSERVICE
5925             smb_LogPacket(inp);
5926 #endif  /* NOTSERVICE */
5927
5928 #ifndef DJGPP
5929                         if (showErrors) {
5930                                 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
5931                 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
5932                                      MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
5933                 if (code == IDCANCEL) showErrors = 0;
5934                         }
5935 #endif /* DJGPP */
5936             code = CM_ERROR_BADOP;
5937         }
5938
5939                 /* catastrophic failure:  log as much as possible */
5940                 if (code == CM_ERROR_BADSMB) {
5941 #ifndef DJGPP
5942                         HANDLE h;
5943                         char *ptbuf[1];
5944                         char s[100];
5945
5946                         osi_Log1(smb_logp,
5947                       "Invalid SMB, ncb_length %d",
5948                       ncbp->ncb_length);
5949
5950                         h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
5951                         sprintf(s, "Invalid SMB message, length %d",
5952                      ncbp->ncb_length);
5953                         ptbuf[0] = s;
5954                         ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1002, NULL,
5955                          1, ncbp->ncb_length, ptbuf, smbp);
5956                         DeregisterEventSource(h);
5957 #ifdef NOTSERVICE
5958             smb_LogPacket(inp);
5959 #endif /* NOTSERVICE */
5960 #else /* DJGPP */
5961             osi_Log1(smb_logp, "Invalid SMB message, length %d",
5962                      ncbp->ncb_length);
5963 #endif /* !DJGPP */
5964
5965                         code = CM_ERROR_INVAL;
5966                 }
5967
5968                 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
5969                         thrd_Decrement(&ongoingOps);
5970                         return;
5971                 }
5972
5973       resume:
5974                 /* now, if we failed, turn the current response into an empty
5975          * one, and fill in the response packet's error code.
5976          */
5977                 if (code) {
5978                         if (vcp->flags & SMB_VCFLAG_STATUS32) {
5979                                 smb_MapNTError(code, &NTStatus);
5980                                 outWctp = outp->wctp;
5981                                 smbp = (smb_t *) &outp->data;
5982                                 if (code != CM_ERROR_PARTIALWRITE
5983                                     && code != CM_ERROR_BUFFERTOOSMALL 
5984                     && code != CM_ERROR_GSSCONTINUE) {
5985                                         /* nuke wct and bcc.  For a partial
5986                                          * write or an in-process authentication handshake, 
5987                      * assume they're OK.
5988                                          */
5989                                         *outWctp++ = 0;
5990                                         *outWctp++ = 0;
5991                                         *outWctp++ = 0;
5992                                 }
5993                                 smbp->rcls = (unsigned char) (NTStatus & 0xff);
5994                                 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
5995                                 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
5996                                 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
5997                                 smbp->flg2 |= 0x4000;
5998                                 break;
5999                         }
6000                         else {
6001                 smb_MapCoreError(code, vcp, &errCode, &errClass);
6002                                 outWctp = outp->wctp;
6003                                 smbp = (smb_t *) &outp->data;
6004                                 if (code != CM_ERROR_PARTIALWRITE) {
6005                                         /* nuke wct and bcc.  For a partial
6006                                          * write, assume they're OK.
6007                                          */
6008                                         *outWctp++ = 0;
6009                                         *outWctp++ = 0;
6010                                         *outWctp++ = 0;
6011                                 }
6012                                 smbp->errLow = (unsigned char) (errCode & 0xff);
6013                                 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
6014                 smbp->rcls = errClass;
6015                                 break;
6016                         }
6017                 }       /* error occurred */
6018                 
6019         /* if we're here, we've finished one request.  Look to see if
6020                  * this is a chained opcode.  If it is, setup things to process
6021                  * the chained request, and setup the output buffer to hold the
6022                  * chained response.  Start by finding the next input record.
6023          */
6024         if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
6025             break;              /* not a chained req */
6026         tp = inp->wctp;         /* points to start of last request */
6027         /* in a chained request, the first two
6028          * parm fields are required, and are
6029          * AndXCommand/AndXReserved and
6030          * AndXOffset. */
6031         if (tp[0] < 2) break;   
6032         if (tp[1] == 0xff) break;       /* no more chained opcodes */
6033         inp->inCom = tp[1];
6034         inp->wctp = inp->data + tp[3] + (tp[4] << 8);
6035         inp->inCount++;
6036
6037         /* and now append the next output request to the end of this
6038          * last request.  Begin by finding out where the last response
6039                  * ends, since that's where we'll put our new response.
6040          */
6041         outWctp = outp->wctp;           /* ptr to out parameters */
6042         osi_assert (outWctp[0] >= 2);   /* need this for all chained requests */
6043         nparms = outWctp[0] << 1;
6044         tp = outWctp + nparms + 1;      /* now points to bcc field */
6045         nbytes = tp[0] + (tp[1] << 8);  /* # of data bytes */
6046         tp += 2 /* for the count itself */ + nbytes;
6047                 /* tp now points to the new output record; go back and patch the
6048          * second parameter (off2) to point to the new record.
6049          */
6050                 temp = (unsigned int)tp - ((unsigned int) outp->data);
6051         outWctp[3] = (unsigned char) (temp & 0xff);
6052         outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
6053         outWctp[2] = 0; /* padding */
6054         outWctp[1] = inp->inCom;        /* next opcode */
6055
6056                 /* finally, setup for the next iteration */
6057         outp->wctp = tp;
6058                 outWctp = tp;
6059         }       /* while loop over all requests in the packet */
6060
6061         /* done logging out, turn off logging-out flag */
6062         if (!(inp->flags & SMB_PACKETFLAG_PROFILE_UPDATE_OK)) {
6063                 vcp->justLoggedOut = NULL;
6064                 if (loggedOut) {
6065                         loggedOut = 0;
6066                         free(loggedOutName);
6067                         loggedOutName = NULL;
6068                         smb_ReleaseUID(loggedOutUserp);
6069                         loggedOutUserp = NULL;
6070                 }
6071         }
6072  
6073     /* now send the output packet, and return */
6074     if (!noSend)
6075                 smb_SendPacket(vcp, outp);
6076         thrd_Decrement(&ongoingOps);
6077
6078         if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
6079         if (active_vcp) {
6080             smb_ReleaseVC(active_vcp);
6081             osi_Log2(smb_logp,
6082                       "Replacing active_vcp %x with %x", active_vcp, vcp);
6083         }
6084         smb_HoldVC(vcp);
6085                 active_vcp = vcp;
6086                 last_msg_time = GetCurrentTime();
6087         }
6088         else if (active_vcp == vcp) {
6089         smb_ReleaseVC(active_vcp);
6090                 active_vcp = NULL;
6091     }
6092
6093     return;
6094 }
6095
6096 #ifndef DJGPP
6097 /* Wait for Netbios() calls to return, and make the results available to server
6098  * threads.  Note that server threads can't wait on the NCBevents array
6099  * themselves, because NCB events are manual-reset, and the servers would race
6100  * each other to reset them.
6101  */
6102 void smb_ClientWaiter(void *parmp)
6103 {
6104         DWORD code;
6105     int   idx;
6106
6107         while (1) {
6108                 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
6109                                               FALSE, INFINITE);
6110                 if (code == WAIT_OBJECT_0)
6111                         continue;
6112
6113         /* error checking */
6114         if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6115         {
6116             int abandonIdx = code - WAIT_ABANDONED_0;
6117             afsi_log("Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6118         }
6119
6120         if (code == WAIT_IO_COMPLETION)
6121         {
6122             afsi_log("Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
6123             continue;
6124         }
6125         
6126         if (code == WAIT_TIMEOUT)
6127         {
6128             afsi_log("Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
6129         }
6130
6131         if (code == WAIT_FAILED)
6132         {
6133             afsi_log("Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
6134         }
6135
6136         idx = code - WAIT_OBJECT_0;
6137  
6138         /* check idx range! */
6139         if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
6140         {
6141             /* this is fatal - log as much as possible */
6142             afsi_log("Fatal: NCBevents idx [ %d ] out of range.\n", idx);
6143             osi_assert(0);
6144         }
6145         
6146                 thrd_ResetEvent(NCBevents[idx]);
6147                 thrd_SetEvent(NCBreturns[0][idx]);
6148         }
6149 }
6150 #endif /* !DJGPP */
6151
6152 /*
6153  * Try to have one NCBRECV request waiting for every live session.  Not more
6154  * than one, because if there is more than one, it's hard to handle Write Raw.
6155  */
6156 void smb_ServerWaiter(void *parmp)
6157 {
6158         DWORD code;
6159     int idx_session, idx_NCB;
6160         NCB *ncbp;
6161 #ifdef DJGPP
6162     dos_ptr dos_ncb;
6163 #endif /* DJGPP */
6164
6165         while (1) {
6166                 /* Get a session */
6167                 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
6168                                                    FALSE, INFINITE);
6169                 if (code == WAIT_OBJECT_0)
6170                         continue;
6171
6172         if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
6173         {
6174             int abandonIdx = code - WAIT_ABANDONED_0;
6175             afsi_log("Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6176         }
6177         
6178         if (code == WAIT_IO_COMPLETION)
6179         {
6180             afsi_log("Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
6181             continue;
6182         }
6183         
6184         if (code == WAIT_TIMEOUT)
6185         {
6186             afsi_log("Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
6187         }
6188         
6189         if (code == WAIT_FAILED)
6190         {
6191             afsi_log("Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
6192         }
6193         
6194         idx_session = code - WAIT_OBJECT_0;
6195
6196         /* check idx range! */
6197         if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
6198         {
6199             /* this is fatal - log as much as possible */
6200             afsi_log("Fatal: session idx [ %d ] out of range.\n", idx_session);
6201             osi_assert(0);
6202         }
6203
6204                 /* Get an NCB */
6205       NCBretry:
6206                 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
6207                                                    FALSE, INFINITE);
6208                 if (code == WAIT_OBJECT_0)
6209                         goto NCBretry;
6210
6211         /* error checking */
6212         if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6213         {
6214             int abandonIdx = code - WAIT_ABANDONED_0;
6215             afsi_log("Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6216         }
6217         
6218         if (code == WAIT_IO_COMPLETION)
6219         {
6220             afsi_log("Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
6221             continue;
6222         }
6223         
6224         if (code == WAIT_TIMEOUT)
6225         {
6226             afsi_log("Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
6227         }
6228         
6229         if (code == WAIT_FAILED)
6230         {
6231             afsi_log("Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
6232         }
6233                 
6234         idx_NCB = code - WAIT_OBJECT_0;
6235
6236         /* check idx range! */
6237         if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
6238         {
6239             /* this is fatal - log as much as possible */
6240             afsi_log("Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
6241             osi_assert(0);
6242         }
6243
6244                 /* Link them together */
6245                 NCBsessions[idx_NCB] = idx_session;
6246
6247                 /* Fire it up */
6248                 ncbp = NCBs[idx_NCB];
6249 #ifdef DJGPP
6250         dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6251 #endif /* DJGPP */
6252                 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
6253                 ncbp->ncb_command = NCBRECV | ASYNCH;
6254                 ncbp->ncb_lana_num = lanas[idx_session];
6255 #ifndef DJGPP
6256                 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
6257                 ncbp->ncb_event = NCBevents[idx_NCB];
6258                 ncbp->ncb_length = SMB_PACKETSIZE;
6259                 Netbios(ncbp);
6260 #else /* DJGPP */
6261                 ncbp->ncb_buffer = bufs[idx_NCB]->dos_pkt;
6262                 ((smb_ncb_t*)ncbp)->orig_pkt = bufs[idx_NCB];
6263                 ncbp->ncb_event = NCBreturns[0][idx_NCB];
6264                 ncbp->ncb_length = SMB_PACKETSIZE;
6265                 Netbios(ncbp, dos_ncb);
6266 #endif /* !DJGPP */
6267         }
6268 }
6269
6270 /*
6271  * The top level loop for handling SMB request messages.  Each server thread
6272  * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
6273  * NCB and buffer for the incoming request are loaned to us.
6274  *
6275  * Write Raw trickery starts here.  When we get a Write Raw, we are supposed
6276  * to immediately send a request for the rest of the data.  This must come
6277  * before any other traffic for that session, so we delay setting the session
6278  * event until that data has come in.
6279  */
6280 void smb_Server(VOID *parmp)
6281 {
6282         int myIdx = (int) parmp;
6283         NCB *ncbp;
6284         NCB *outncbp;
6285     smb_packet_t *bufp;
6286         smb_packet_t *outbufp;
6287     DWORD code, rcode;
6288     int idx_NCB, idx_session;
6289         UCHAR rc;
6290         smb_vc_t *vcp = NULL;
6291         smb_t *smbp;
6292 #ifdef DJGPP
6293     dos_ptr dos_ncb;
6294 #endif /* DJGPP */
6295
6296         outncbp = GetNCB();
6297         outbufp = GetPacket();
6298         outbufp->ncbp = outncbp;
6299
6300         while (1) {
6301 #ifndef NOEXPIRE
6302                 /* check for demo expiration */
6303                 {
6304                         unsigned long tod = time((void *) 0);
6305                         if (tod > EXPIREDATE) {
6306                                 (*smb_MBfunc)(NULL, "AFS demo expiration",
6307                                            "afsd dispatcher",
6308                                            MB_OK|MB_ICONSTOP|MB_SETFOREGROUND|MB_SERVICE_NOTIFICATION);
6309                                 trhd_Exit(1);
6310                         }
6311                 }
6312 #endif /* !NOEXPIRE */
6313
6314                 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
6315                                                    FALSE, INFINITE);
6316                 if (code == WAIT_OBJECT_0) {
6317                         continue;
6318         }
6319
6320         /* error checking */
6321         if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6322         {
6323             int abandonIdx = code - WAIT_ABANDONED_0;
6324             afsi_log("Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
6325         }
6326         
6327         if (code == WAIT_IO_COMPLETION)
6328         {
6329             afsi_log("Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
6330             continue;
6331         }
6332         
6333         if (code == WAIT_TIMEOUT)
6334         {
6335             afsi_log("Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
6336         }
6337         
6338         if (code == WAIT_FAILED)
6339         {
6340             afsi_log("Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
6341         }
6342
6343         idx_NCB = code - WAIT_OBJECT_0;
6344         
6345         /* check idx range! */
6346         if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
6347         {
6348             /* this is fatal - log as much as possible */
6349             afsi_log("Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
6350             osi_assert(0);
6351         }
6352
6353                 ncbp = NCBs[idx_NCB];
6354 #ifdef DJGPP
6355                 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6356 #endif /* DJGPP */
6357                 idx_session = NCBsessions[idx_NCB];
6358                 rc = ncbp->ncb_retcode;
6359
6360                 if (rc != NRC_PENDING && rc != NRC_GOODRET)
6361                         osi_Log1(smb_logp, "NCBRECV failure code %d", rc);
6362
6363                 switch (rc) {
6364                         case NRC_GOODRET: break;
6365
6366                         case NRC_PENDING:
6367                                 /* Can this happen? Or is it just my
6368                                  * UNIX paranoia? 
6369                  */
6370                                 continue;
6371
6372                         case NRC_SCLOSED:
6373                         case NRC_SNUMOUT:
6374                                 /* Client closed session */
6375                 if (reportSessionStartups) 
6376                 {
6377                     afsi_log("session [ %d ] closed", idx_session);
6378                 }
6379                                 dead_sessions[idx_session] = TRUE;
6380                 if (vcp)
6381                     smb_ReleaseVC(vcp);
6382                                 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
6383                                 /* Should also release vcp.  [done] 2004-05-11 jaltman
6384                  * Also, should do
6385                                  * sanity check that all TID's are gone. 
6386                  *
6387                  * TODO: check if we could use LSNs[idx_session] instead, 
6388                  * also cleanup after dead vcp 
6389                  */
6390                 if (vcp) {
6391                     if (dead_vcp)
6392                         osi_Log1(smb_logp,
6393                                   "dead_vcp already set, %x",
6394                                   dead_vcp);
6395                     if (!dead_vcp && !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
6396                         osi_Log2(smb_logp,
6397                                   "setting dead_vcp %x, user struct %x",
6398                                   vcp, vcp->usersp);
6399                         smb_HoldVC(vcp);
6400                         dead_vcp = vcp;
6401                         vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
6402                     }
6403                     if (vcp->justLoggedOut) {
6404                         loggedOut = 1;
6405                         loggedOutTime = vcp->logoffTime;
6406                         loggedOutName =
6407                             strdup(vcp->justLoggedOut->unp->name);
6408                         loggedOutUserp = vcp->justLoggedOut;
6409                         lock_ObtainWrite(&smb_rctLock);
6410                         loggedOutUserp->refCount++;
6411                         lock_ReleaseWrite(&smb_rctLock);
6412                     }
6413                 }
6414                                 goto doneWithNCB;
6415
6416                         case NRC_INCOMP:
6417                                 /* Treat as transient error */
6418                                 {
6419 #ifndef DJGPP
6420                                         EVENT_HANDLE h;
6421                                         char *ptbuf[1];
6422                                         char s[100];
6423
6424                                         osi_Log1(smb_logp, "dispatch smb recv failed, message incomplete, ncb_length %d",
6425                              ncbp->ncb_length);
6426                                         h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6427                                         sprintf(s, "SMB message incomplete, length %d",
6428                             ncbp->ncb_length);
6429                                         ptbuf[0] = s;
6430                                         ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
6431                                 1001, NULL, 1,
6432                                 ncbp->ncb_length, ptbuf,
6433                                 bufp);
6434                                         DeregisterEventSource(h);
6435 #else /* DJGPP */
6436                                         osi_Log1(smb_logp,
6437                               "dispatch smb recv failed, message incomplete, ncb_length %d",
6438                               ncbp->ncb_length);
6439                     osi_Log1(smb_logp,
6440                               "SMB message incomplete, "
6441                               "length %d", ncbp->ncb_length);
6442 #endif /* !DJGPP */
6443
6444                                         /*
6445                                          * We used to discard the packet.
6446                                          * Instead, try handling it normally.
6447                                          *
6448                      continue;
6449                                          */
6450                                         break;
6451                                 }
6452
6453                         default:
6454                                 /* A weird error code.  Log it, sleep, and
6455                                  * continue. */
6456                                 if (vcp && vcp->errorCount++ > 3) {
6457                     afsi_log("session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
6458                                         dead_sessions[idx_session] = TRUE;
6459                 }
6460                                 else {
6461                                         thrd_Sleep(1000);
6462                                         thrd_SetEvent(SessionEvents[idx_session]);
6463                                 }
6464                                 continue;
6465                 }
6466
6467                 /* Success, so now dispatch on all the data in the packet */
6468
6469                 smb_concurrentCalls++;
6470                 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
6471                         smb_maxObsConcurrentCalls = smb_concurrentCalls;
6472
6473         if (vcp)
6474             smb_ReleaseVC(vcp);
6475                 vcp = smb_FindVC(ncbp->ncb_lsn, 0, ncbp->ncb_lana_num);
6476         /*
6477                 * If at this point vcp is NULL (implies that packet was invalid)
6478                 * then we are in big trouble. This means either :
6479                 *   a) we have the wrong NCB.
6480                 *   b) Netbios screwed up the call.
6481                 * Obviously this implies that 
6482                 *   ( LSNs[idx_session] != ncbp->ncb_lsn ||
6483                 *   lanas[idx_session] != ncbp->ncb_lana_num )
6484                 * Either way, we can't do anything with this packet.
6485                 * Log, sleep and resume.
6486                 */
6487                 if(!vcp) {
6488                         HANDLE h;
6489                         char buf[1000];
6490                         char *ptbuf[1];
6491
6492                         sprintf(buf,
6493                                 "Bad vcp!! : "
6494                                 "LSNs[idx_session]=[%d],"
6495                                 "lanas[idx_session]=[%d],"
6496                                 "ncbp->ncb_lsn=[%d],"
6497                                 "ncbp->ncb_lana_num=[%d]",
6498                                 LSNs[idx_session],
6499                                 lanas[idx_session],
6500                                 ncbp->ncb_lsn,
6501                                 ncbp->ncb_lana_num);
6502
6503                         ptbuf[0] = buf;
6504
6505                         h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
6506                         if(h) {
6507                                 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,sizeof(*ncbp),ptbuf,(void*)ncbp);
6508                                 DeregisterEventSource(h);
6509                         }
6510
6511                         /* Also log in the trace log. */
6512                         osi_Log4(smb_logp, "Server: BAD VCP!"
6513                                 "LSNs[idx_session]=[%d],"
6514                                 "lanas[idx_session]=[%d],"
6515                                 "ncbp->ncb_lsn=[%d],"
6516                                 "ncbp->ncb_lana_num=[%d]",
6517                                 LSNs[idx_session],
6518                                 lanas[idx_session],
6519                                 ncbp->ncb_lsn,
6520                                 ncbp->ncb_lana_num);
6521
6522                         /* thrd_Sleep(1000); Don't bother sleeping */
6523                         thrd_SetEvent(SessionEvents[idx_session]);
6524                         smb_concurrentCalls--;
6525                         continue;
6526                 }
6527
6528
6529                 vcp->errorCount = 0;
6530                 bufp = (struct smb_packet *) ncbp->ncb_buffer;
6531 #ifdef DJGPP
6532                 bufp = ((smb_ncb_t *) ncbp)->orig_pkt;
6533         /* copy whole packet to virtual memory */
6534         /*fprintf(stderr, "smb_Server: copying dos packet at 0x%x, "
6535         "bufp=0x%x\n",
6536         bufp->dos_pkt / 16, bufp);*/
6537         fflush(stderr);
6538         dosmemget(bufp->dos_pkt, ncbp->ncb_length, bufp->data);
6539 #endif /* DJGPP */
6540                 smbp = (smb_t *)bufp->data;
6541                 outbufp->flags = 0;
6542
6543 #if !defined(DJGPP) && !defined(AFS_WIN32_ENV)
6544         __try
6545         {
6546 #endif
6547                 if (smbp->com == 0x1d) {
6548                         /* Special handling for Write Raw */
6549                         raw_write_cont_t rwc;
6550                         EVENT_HANDLE rwevent;
6551             char eventName[MAX_PATH];
6552             
6553             smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
6554                         if (rwc.code == 0) {
6555                                 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
6556                 if ( GetLastError() == ERROR_ALREADY_EXISTS )
6557                     afsi_log("Event Object Already Exists: %s", eventName);
6558                                 ncbp->ncb_command = NCBRECV | ASYNCH;
6559                                 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
6560                                 ncbp->ncb_lana_num = vcp->lana;
6561                                 ncbp->ncb_buffer = rwc.buf;
6562                                 ncbp->ncb_length = 65535;
6563                                 ncbp->ncb_event = rwevent;
6564 #ifndef DJGPP
6565                                 Netbios(ncbp);
6566 #else
6567                                 Netbios(ncbp, dos_ncb);
6568 #endif /* !DJGPP */
6569                                 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
6570                                 thrd_CloseHandle(rwevent);
6571                         }
6572                         thrd_SetEvent(SessionEvents[idx_session]);
6573                         if (rwc.code == 0)
6574                                 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
6575                 } else if (smbp->com == 0xa0) { 
6576             /* 
6577              * Serialize the handling for NT Transact 
6578              * (defect 11626)
6579              */
6580             smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
6581                         thrd_SetEvent(SessionEvents[idx_session]);
6582         } else {
6583                         thrd_SetEvent(SessionEvents[idx_session]);
6584             /* TODO: what else needs to be serialized? */
6585                         smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
6586                 }
6587 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
6588         }
6589         __except( smb_ServerExceptionFilter() ) {
6590         }
6591 #endif
6592
6593                 smb_concurrentCalls--;
6594
6595 doneWithNCB:
6596                 thrd_SetEvent(NCBavails[idx_NCB]);
6597         }
6598     if (vcp)
6599         smb_ReleaseVC(vcp);
6600 }
6601
6602 /*
6603  * Exception filter for the server threads.  If an exception occurs in the
6604  * dispatch routines, which is where exceptions are most common, then do a
6605  * force trace and give control to upstream exception handlers. Useful for
6606  * debugging.
6607  */
6608 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
6609 DWORD smb_ServerExceptionFilter(void) {
6610         /* While this is not the best time to do a trace, if it succeeds, then
6611          * we have a trace (assuming tracing was enabled). Otherwise, this should
6612          * throw a second exception.
6613          */
6614         HANDLE h;
6615         char *ptbuf[1];
6616
6617         ptbuf[0] = "Unhandled exception forcing trace";
6618
6619         h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
6620         if(h) {
6621                 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,0,ptbuf,NULL);
6622                 DeregisterEventSource(h);
6623         }
6624
6625         afsd_ForceTrace(TRUE);
6626         return EXCEPTION_CONTINUE_SEARCH;
6627 }
6628 #endif
6629
6630 /*
6631  * Create a new NCB and associated events, packet buffer, and "space" buffer.
6632  * If the number of server threads is M, and the number of live sessions is
6633  * N, then the number of NCB's in use at any time either waiting for, or
6634  * holding, received messages is M + N, so that is how many NCB's get created.
6635  */
6636 void InitNCBslot(int idx)
6637 {
6638         struct smb_packet *bufp;
6639         EVENT_HANDLE retHandle;
6640         int i;
6641     char eventName[MAX_PATH];
6642
6643     osi_assert( idx < (sizeof(NCBs) / sizeof(NCBs[0])) );
6644
6645         NCBs[idx] = GetNCB();
6646     sprintf(eventName,"NCBavails[%d]", idx);
6647         NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
6648     if ( GetLastError() == ERROR_ALREADY_EXISTS )
6649         afsi_log("Event Object Already Exists: %s", eventName);
6650 #ifndef DJGPP
6651     sprintf(eventName,"NCBevents[%d]", idx);
6652         NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
6653     if ( GetLastError() == ERROR_ALREADY_EXISTS )
6654         afsi_log("Event Object Already Exists: %s", eventName);
6655 #endif /* !DJGPP */
6656     sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
6657         retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
6658     if ( GetLastError() == ERROR_ALREADY_EXISTS )
6659         afsi_log("Event Object Already Exists: %s", eventName);
6660         for (i=0; i<smb_NumServerThreads; i++)
6661                 NCBreturns[i][idx] = retHandle;
6662         bufp = GetPacket();
6663         bufp->spacep = cm_GetSpace();
6664         bufs[idx] = bufp;
6665 }
6666
6667 /* listen for new connections */
6668 void smb_Listener(void *parmp)
6669 {
6670         NCB *ncbp;
6671     long code = 0;
6672     long len;
6673         long i, j;
6674     smb_vc_t *vcp;
6675         int flags = 0;
6676         char rname[NCBNAMSZ+1];
6677         char cname[MAX_COMPUTERNAME_LENGTH+1];
6678         int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
6679 #ifdef DJGPP
6680     dos_ptr dos_ncb;
6681     time_t now;
6682 #endif /* DJGPP */
6683         int lana = (int) parmp;
6684
6685         ncbp = GetNCB();
6686 #ifdef DJGPP
6687     dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6688 #endif /* DJGPP */
6689
6690     /* retrieve computer name */
6691     GetComputerName(cname, &cnamelen);
6692     _strupr(cname);
6693
6694         while (1) {
6695                 memset(ncbp, 0, sizeof(NCB));
6696                 flags = 0;
6697
6698 #ifndef NOEXPIRE
6699                 /* check for demo expiration */
6700                 {
6701                         unsigned long tod = time((void *) 0);
6702                         if (tod > EXPIREDATE) {
6703                                 (*smb_MBfunc)(NULL, "AFS demo expiration",
6704                                "afsd listener",
6705                                MB_OK|MB_ICONSTOP|MB_SETFOREGROUND|MB_SERVICE_NOTIFICATION);
6706 #ifndef DJGPP
6707                 ExitThread(1);
6708 #else
6709                 thrd_Exit(1);
6710 #endif
6711                         }
6712                 }
6713 #endif /* !NOEXPIRE */
6714
6715         ncbp->ncb_command = NCBLISTEN;
6716         ncbp->ncb_rto = 0;      /* No receive timeout */
6717         ncbp->ncb_sto = 0;      /* No send timeout */
6718
6719                 /* pad out with spaces instead of null termination */
6720                 len = strlen(smb_localNamep);
6721         strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
6722         for(i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
6723         
6724         strcpy(ncbp->ncb_callname, "*");
6725         for(i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
6726         
6727                 ncbp->ncb_lana_num = lana;
6728
6729 #ifndef DJGPP
6730         code = Netbios(ncbp);
6731 #else /* DJGPP */
6732         code = Netbios(ncbp, dos_ncb);
6733 #endif
6734
6735         if (code != 0)
6736         {
6737 #ifndef DJGPP
6738             char tbuffer[256];
6739 #endif
6740
6741             /* terminate silently if shutdown flag is set */
6742                 if (smbShutdownFlag == 1) {
6743 #ifndef DJGPP
6744                             ExitThread(1);
6745 #else
6746                                 thrd_Exit(1);
6747 #endif
6748                         }
6749
6750             osi_Log2(smb_logp, 
6751                      "NCBLISTEN lana=%d failed with code %d",
6752                      ncbp->ncb_lana_num, code);
6753             osi_Log0(smb_logp, 
6754                      "Client exiting due to network failure. Please restart client.\n");
6755
6756 #ifndef DJGPP
6757             sprintf(tbuffer, 
6758                      "Client exiting due to network failure.  Please restart client.\n"
6759                      "NCBLISTEN lana=%d failed with code %d",
6760                      ncbp->ncb_lana_num, code);
6761                         if (showErrors)
6762                 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
6763                                      MB_OK|MB_SERVICE_NOTIFICATION);
6764             osi_assert(tbuffer);
6765             ExitThread(1);
6766 #else
6767             fprintf(stderr, "NCBLISTEN lana=%d failed with code %d\n",
6768                      ncbp->ncb_lana_num, code);
6769             fprintf(stderr, "\nClient exiting due to network failure "
6770                      "(possibly due to power-saving mode)\n");
6771             fprintf(stderr, "Please restart client.\n");
6772                         afs_exit(AFS_EXITCODE_NETWORK_FAILURE);
6773 #endif /* !DJGPP */
6774         }
6775
6776                 /* check for remote conns */
6777                 /* first get remote name and insert null terminator */
6778                 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
6779                 for (i=NCBNAMSZ; i>0; i--) {
6780                         if (rname[i-1] != ' ' && rname[i-1] != 0) {
6781                                 rname[i] = 0;
6782                                 break;
6783                         }
6784                 }
6785
6786         /* compare with local name */
6787                 if (!isGateway)
6788                         if (strncmp(rname, cname, NCBNAMSZ) != 0)
6789                                 flags |= SMB_VCFLAG_REMOTECONN;
6790
6791                 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
6792                 /* lock */
6793                 lock_ObtainMutex(&smb_ListenerLock);
6794
6795                 /* New generation */
6796                 sessionGen++;
6797
6798                 /* Log session startup */
6799 #ifdef NOTSERVICE
6800         fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host "
6801                                 "%s\n",
6802                 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
6803 #endif
6804         afsi_log("New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
6805                   ncbp->ncb_lsn,ncbp->ncb_lana_num, rname, ongoingOps);
6806
6807         if (reportSessionStartups) {
6808 #ifndef DJGPP
6809                         HANDLE h;
6810                         char *ptbuf[1];
6811                         char s[100];
6812
6813                         h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6814                         sprintf(s, "SMB session startup, %d ongoing ops", ongoingOps);
6815                         ptbuf[0] = s;
6816                         ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1004, NULL,
6817                         1, 0, ptbuf, NULL);
6818                         DeregisterEventSource(h);
6819 #else /* DJGPP */
6820             afsi_log("NCBLISTEN completed, call from %s",rname);
6821             osi_Log1(smb_logp, "SMB session startup, %d ongoing ops",
6822                      ongoingOps);
6823             time(&now);
6824             fprintf(stderr, "%s: New session %d starting from host %s\n",
6825                     asctime(localtime(&now)), ncbp->ncb_lsn, rname);
6826             fflush(stderr);
6827 #endif /* !DJGPP */
6828                 }
6829
6830         /* now ncbp->ncb_lsn is the connection ID */
6831         vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
6832                 vcp->flags |= flags;
6833         strcpy(vcp->rname, rname);
6834
6835                 /* Allocate slot in session arrays */
6836                 /* Re-use dead session if possible, otherwise add one more */
6837         /* But don't look at session[0], it is reserved */
6838                 for (i = 1; i < numSessions; i++) {
6839                         if (dead_sessions[i]) {
6840                 afsi_log("connecting to dead session [ %d ]", i);
6841                                 dead_sessions[i] = FALSE;
6842                                 break;
6843                         }
6844                 }
6845
6846         /* assert that we do not exceed the maximum number of sessions or NCBs.
6847          * we should probably want to wait for a session to be freed in case
6848          * we run out.
6849          */
6850
6851         osi_assert(i < Sessionmax - 1);
6852         osi_assert(numNCBs < NCBmax - 1);   /* if we pass this test we can allocate one more */
6853
6854                 LSNs[i] = ncbp->ncb_lsn;
6855                 lanas[i] = ncbp->ncb_lana_num;
6856                 
6857                 if (i == numSessions) {
6858                         /* Add new NCB for new session */
6859             char eventName[MAX_PATH];
6860
6861             osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
6862
6863                         InitNCBslot(numNCBs);
6864                         numNCBs++;
6865                         thrd_SetEvent(NCBavails[0]);
6866                         thrd_SetEvent(NCBevents[0]);
6867                         for (j = 0; j < smb_NumServerThreads; j++)
6868                                 thrd_SetEvent(NCBreturns[j][0]);
6869                         /* Also add new session event */
6870             sprintf(eventName, "SessionEvents[%d]", i);
6871             SessionEvents[i] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
6872             if ( GetLastError() == ERROR_ALREADY_EXISTS )
6873                 afsi_log("Event Object Already Exists: %s", eventName);
6874                         numSessions++;
6875             afsi_log("increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
6876                         thrd_SetEvent(SessionEvents[0]);
6877                 } else {
6878                         thrd_SetEvent(SessionEvents[i]);
6879                 }
6880                 /* unlock */
6881                 lock_ReleaseMutex(&smb_ListenerLock);
6882
6883     }   /* dispatch while loop */
6884 }
6885
6886 /* initialize Netbios */
6887 void smb_NetbiosInit()
6888 {
6889     NCB *ncbp;
6890 #ifdef DJGPP
6891     dos_ptr dos_ncb;
6892 #endif /* DJGPP */
6893     int i, lana, code, l;
6894     char s[100];
6895     int delname_tried=0;
6896     int len;
6897     int lana_found = 0;
6898     OSVERSIONINFO Version;
6899
6900     /* AFAIK, this is the default for the ms loopback adapter.*/
6901     unsigned char kWLA_MAC[6] = { 0x02, 0x00, 0x4c, 0x4f, 0x4f, 0x50 };
6902     /*******************************************************************/
6903
6904     /* Get the version of Windows */
6905     memset(&Version, 0x00, sizeof(Version));
6906     Version.dwOSVersionInfoSize = sizeof(Version);
6907     GetVersionEx(&Version);
6908
6909     /* setup the NCB system */
6910     ncbp = GetNCB();
6911 #ifdef DJGPP
6912     dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6913 #endif /* DJGPP */
6914
6915 #ifndef DJGPP
6916     if (smb_LANadapter == -1) {
6917         ncbp->ncb_command = NCBENUM;
6918         ncbp->ncb_buffer = (PUCHAR)&lana_list;
6919         ncbp->ncb_length = sizeof(lana_list);
6920         code = Netbios(ncbp);
6921         if (code != 0) {
6922             sprintf(s, "Netbios NCBENUM error code %d", code);
6923             afsi_log(s);
6924             osi_panic(s, __FILE__, __LINE__);
6925         }
6926     }
6927     else {
6928         lana_list.length = 1;
6929         lana_list.lana[0] = smb_LANadapter;
6930     }
6931           
6932     for (i = 0; i < lana_list.length; i++) {
6933         /* reset the adaptor: in Win32, this is required for every process, and
6934          * acts as an init call, not as a real hardware reset.
6935          */
6936         ncbp->ncb_command = NCBRESET;
6937         ncbp->ncb_callname[0] = 100;
6938         ncbp->ncb_callname[2] = 100;
6939         ncbp->ncb_lana_num = lana_list.lana[i];
6940         code = Netbios(ncbp);
6941         if (code == 0) 
6942             code = ncbp->ncb_retcode;
6943         if (code != 0) {
6944             sprintf(s, "Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
6945             afsi_log(s);
6946             lana_list.lana[i] = 255;  /* invalid lana */
6947         } else {
6948             sprintf(s, "Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
6949             afsi_log(s);
6950         }
6951     }
6952 #else
6953     /* for DJGPP, there is no NCBENUM and NCBRESET is a real reset.  so
6954        we will just fake the LANA list */
6955     if (smb_LANadapter == -1) {
6956         for (i = 0; i < 8; i++)
6957             lana_list.lana[i] = i;
6958         lana_list.length = 8;
6959     }
6960     else {
6961         lana_list.length = 1;
6962         lana_list.lana[0] = smb_LANadapter;
6963     }
6964 #endif /* !DJGPP */
6965
6966     /* and declare our name so we can receive connections */
6967     memset(ncbp, 0, sizeof(*ncbp));
6968     len=lstrlen(smb_localNamep);
6969     memset(smb_sharename,' ',NCBNAMSZ);
6970     memcpy(smb_sharename,smb_localNamep,len);
6971     sprintf(s, "lana_list.length %d", lana_list.length);
6972     afsi_log(s);
6973
6974     /* Keep the name so we can unregister it later */
6975     for (l = 0; l < lana_list.length; l++) {
6976         lana = lana_list.lana[l];
6977
6978         ncbp->ncb_command = NCBADDNAME;
6979         ncbp->ncb_lana_num = lana;
6980         memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
6981 #ifndef DJGPP
6982         code = Netbios(ncbp);
6983 #else /* DJGPP */
6984         code = Netbios(ncbp, dos_ncb);
6985 #endif /* !DJGPP */
6986           
6987         afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
6988                  lana, code, ncbp->ncb_retcode,ncbp->ncb_cmd_cplt);
6989         {
6990             char name[NCBNAMSZ+1];
6991             name[NCBNAMSZ]=0;
6992             memcpy(name,ncbp->ncb_name,NCBNAMSZ);
6993             afsi_log("Netbios NCBADDNAME added new name >%s<",name);
6994         }
6995
6996         if (code == 0) code = ncbp->ncb_retcode;
6997         if (code == 0) {
6998             afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
6999 #ifdef DJGPP
7000             /* we only use one LANA with djgpp */
7001             lana_list.lana[0] = lana;
7002             lana_list.length = 1;
7003 #endif    
7004         }
7005         else {
7006             sprintf(s, "Netbios NCBADDNAME lana %d error code %d", lana, code);
7007             afsi_log(s);
7008             if (code == NRC_BRIDGE) {    /* invalid LANA num */
7009                 lana_list.lana[l] = 255;
7010                 continue;
7011             }
7012             else if (code == NRC_DUPNAME) {
7013                 afsi_log("Name already exists; try to delete it");
7014                 memset(ncbp, 0, sizeof(*ncbp));
7015                 ncbp->ncb_command = NCBDELNAME;
7016                 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7017                 ncbp->ncb_lana_num = lana;
7018 #ifndef DJGPP
7019                 code = Netbios(ncbp);
7020 #else
7021                 code = Netbios(ncbp, dos_ncb);
7022 #endif /* DJGPP */
7023                 if (code == 0) code = ncbp->ncb_retcode;
7024                 else {
7025                     sprintf(s, "Netbios NCBDELNAME lana %d error code %d\n", lana, code);
7026                     afsi_log(s);
7027                 }
7028                 if (code != 0 || delname_tried) {
7029                     lana_list.lana[l] = 255;
7030                 }
7031                 else if (code == 0) {
7032                     if (!delname_tried) {
7033                         lana--;
7034                         delname_tried = 1;
7035                         continue;
7036                     }
7037                 }
7038             }
7039             else {
7040                 sprintf(s, "Netbios NCBADDNAME lana %d error code %d", lana, code);
7041                 afsi_log(s);
7042                 lana_list.lana[l] = 255;  /* invalid lana */
7043                 osi_panic(s, __FILE__, __LINE__);
7044             }
7045         }
7046         if (code == 0) {
7047             lana_found = 1;   /* at least one worked */
7048 #ifdef DJGPP
7049             break;
7050 #endif
7051         }
7052     }
7053
7054     osi_assert(lana_list.length >= 0);
7055     if (!lana_found) {
7056         sprintf(s, "No valid LANA numbers found!");
7057         osi_panic(s, __FILE__, __LINE__);
7058     }
7059         
7060     /* we're done with the NCB now */
7061     FreeNCB(ncbp);
7062 }
7063
7064 void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
7065               int nThreads
7066 #ifndef DJGPP
7067               , void *aMBfunc
7068 #endif
7069   )
7070
7071 {
7072         thread_t phandle;
7073     int lpid;
7074     int i;
7075     int len;
7076         struct tm myTime;
7077 #ifdef DJGPP
7078     int npar, seg, sel;
7079     dos_ptr rawBuf;
7080 #endif /* DJGPP */
7081     EVENT_HANDLE retHandle;
7082     char eventName[MAX_PATH];
7083
7084 #ifndef DJGPP
7085         smb_MBfunc = aMBfunc;
7086 #endif /* DJGPP */
7087
7088 #ifndef NOEXPIRE
7089         /* check for demo expiration */
7090         {
7091                 unsigned long tod = time((void *) 0);
7092                 if (tod > EXPIREDATE) {
7093 #ifndef DJGPP
7094                         (*smb_MBfunc)(NULL, "AFS demo expiration", "afsd",
7095                           MB_OK|MB_ICONSTOP|MB_SETFOREGROUND|MB_SERVICE_NOTIFICATION);
7096                         exit(1);
7097 #else /* DJGPP */
7098             fprintf(stderr, "AFS demo expiration\n");
7099             afs_exit(0);
7100 #endif /* !DJGPP */
7101                 }
7102         }
7103 #endif /* !NOEXPIRE */
7104
7105         smb_useV3 = useV3;
7106         smb_LANadapter = LANadapt;
7107
7108         /* Initialize smb_localZero */
7109         myTime.tm_isdst = -1;           /* compute whether on DST or not */
7110         myTime.tm_year = 70;
7111         myTime.tm_mon = 0;
7112         myTime.tm_mday = 1;
7113         myTime.tm_hour = 0;
7114         myTime.tm_min = 0;
7115         myTime.tm_sec = 0;
7116         smb_localZero = mktime(&myTime);
7117
7118         /* Initialize kludge-GMT */
7119         smb_CalculateNowTZ();
7120
7121         /* initialize the remote debugging log */
7122         smb_logp = logp;
7123         
7124     /* remember the name */
7125         len = strlen(snamep);
7126     smb_localNamep = malloc(len+1);
7127     strcpy(smb_localNamep, snamep);
7128     afsi_log("smb_localNamep is >%s<", smb_localNamep);
7129
7130         /* and the global lock */
7131     lock_InitializeRWLock(&smb_globalLock, "smb global lock");
7132     lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
7133
7134         /* Raw I/O data structures */
7135         lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
7136
7137         lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
7138         
7139         /* 4 Raw I/O buffers */
7140 #ifndef DJGPP
7141         smb_RawBufs = calloc(65536,1);
7142         *((char **)smb_RawBufs) = NULL;
7143         for (i=0; i<3; i++) {
7144                 char *rawBuf = calloc(65536,1);
7145                 *((char **)rawBuf) = smb_RawBufs;
7146                 smb_RawBufs = rawBuf;
7147         }
7148 #else /* DJGPP */
7149     npar = 65536 >> 4;  /* number of paragraphs */
7150     seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[0]);
7151     if (seg == -1) {
7152         afsi_log("Cannot allocate %d paragraphs of DOS memory",
7153                   npar);
7154         osi_panic("",__FILE__,__LINE__);
7155     }
7156     else {
7157         afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
7158                   npar, seg);
7159     }
7160     smb_RawBufs = (seg * 16) + 0;  /* DOS physical address */
7161         
7162     _farpokel(_dos_ds, smb_RawBufs, NULL);
7163     for (i=0; i<SMB_RAW_BUFS-1; i++) {
7164         npar = 65536 >> 4;  /* number of paragraphs */
7165         seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[i+1]);
7166         if (seg == -1) {
7167             afsi_log("Cannot allocate %d paragraphs of DOS memory",
7168                       npar);
7169             osi_panic("",__FILE__,__LINE__);
7170         }
7171         else {
7172             afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
7173                       npar, seg);
7174         }
7175         rawBuf = (seg * 16) + 0;  /* DOS physical address */
7176         /*_farpokel(_dos_ds, smb_RawBufs, smb_RawBufs);*/
7177         _farpokel(_dos_ds, rawBuf, smb_RawBufs);
7178         smb_RawBufs = rawBuf;
7179     }
7180 #endif /* !DJGPP */
7181
7182         /* global free lists */
7183         smb_ncbFreeListp = NULL;
7184     smb_packetFreeListp = NULL;
7185
7186     smb_NetbiosInit();
7187
7188         /* Initialize listener and server structures */
7189     numVCs = 0;
7190         memset(dead_sessions, 0, sizeof(dead_sessions));
7191     sprintf(eventName, "SessionEvents[0]");
7192         SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7193     if ( GetLastError() == ERROR_ALREADY_EXISTS )
7194         afsi_log("Event Object Already Exists: %s", eventName);
7195         numSessions = 1;
7196         smb_NumServerThreads = nThreads;
7197     sprintf(eventName, "NCBavails[0]");
7198         NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7199     if ( GetLastError() == ERROR_ALREADY_EXISTS )
7200         afsi_log("Event Object Already Exists: %s", eventName);
7201     sprintf(eventName, "NCBevents[0]");
7202         NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7203     if ( GetLastError() == ERROR_ALREADY_EXISTS )
7204         afsi_log("Event Object Already Exists: %s", eventName);
7205         NCBreturns = malloc(nThreads * sizeof(EVENT_HANDLE *));
7206     sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
7207     retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7208     if ( GetLastError() == ERROR_ALREADY_EXISTS )
7209         afsi_log("Event Object Already Exists: %s", eventName);
7210         for (i = 0; i < smb_NumServerThreads; i++) {
7211                 NCBreturns[i] = malloc(NCBmax * sizeof(EVENT_HANDLE));
7212                 NCBreturns[i][0] = retHandle;
7213         }
7214         for (i = 1; i <= nThreads; i++)
7215                 InitNCBslot(i);
7216         numNCBs = nThreads + 1;
7217
7218         /* Initialize dispatch table */
7219         memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
7220         smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
7221         smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
7222         smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
7223         smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
7224         smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
7225         smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
7226         smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
7227         smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
7228         smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
7229         smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
7230         smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
7231         smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
7232         smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
7233         smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
7234         smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
7235         smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
7236         smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
7237         smb_dispatchTable[0x11].procp = smb_SendCoreBadOp;      /* process exit */
7238         smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
7239         smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
7240         /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
7241         smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7242         smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
7243         smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
7244         smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
7245         smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
7246         smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
7247         smb_dispatchTable[0x29].procp = smb_SendCoreBadOp;      /* copy file */
7248         smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
7249         /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
7250         smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7251     smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
7252     smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
7253     smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
7254     smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
7255         smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A;    /* both are same */
7256     smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7257     smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
7258     smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7259     smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
7260     smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
7261         smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
7262         smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
7263         smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
7264         smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
7265     smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
7266     smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
7267     smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
7268     smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
7269     smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
7270         smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
7271         smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
7272         smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
7273         smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
7274         smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
7275         smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
7276         smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7277         smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp;
7278         smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp;
7279         smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp;
7280         smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp;
7281         for(i=0xd0; i<= 0xd7; i++) {
7282                 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
7283     }
7284
7285         /* setup tran 2 dispatch table */
7286         smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
7287         smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir;    /* FindFirst */
7288         smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir;    /* FindNext */
7289         smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
7290         smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
7291         smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
7292         smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
7293         smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
7294         smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
7295         smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
7296         smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
7297         smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
7298         smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
7299         smb_tran2DispatchTable[13].procp = smb_ReceiveTran2MKDir;
7300
7301         smb3_Init();
7302
7303         /* if we are doing SMB authentication we have register outselves as a logon process */
7304         if (smb_authType != SMB_AUTH_NONE) {
7305         NTSTATUS nts;
7306                 LSA_STRING afsProcessName;
7307                 LSA_OPERATIONAL_MODE dummy; /*junk*/
7308                 DWORD bufsize;
7309
7310                 afsProcessName.Buffer = "OpenAFSClientDaemon";
7311                 afsProcessName.Length = strlen(afsProcessName.Buffer);
7312                 afsProcessName.MaximumLength = afsProcessName.Length + 1;
7313
7314                 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
7315
7316                 if (nts == STATUS_SUCCESS) {
7317                         LSA_STRING packageName;
7318                         /* we are registered. Find out the security package id */
7319                         packageName.Buffer = MSV1_0_PACKAGE_NAME;
7320                         packageName.Length = strlen(packageName.Buffer);
7321                         packageName.MaximumLength = packageName.Length + 1;
7322                         nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
7323                         if (nts == STATUS_SUCCESS) {
7324                                 /* Now get ourselves a domain name. */
7325                                 /* For now we are using the local computer name as the domain name.
7326                                  * It is actually the domain for local logins, and we are acting as
7327                                  * a local SMB server. 
7328                  */
7329                                 bufsize = sizeof(smb_ServerDomainName) - 1;
7330                                 GetComputerName(smb_ServerDomainName, &bufsize);
7331                                 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
7332                                 afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
7333
7334                                 smb_lsaLogonOrigin.Buffer = "OpenAFS";
7335                                 smb_lsaLogonOrigin.Length = strlen(smb_lsaLogonOrigin.Buffer);
7336                                 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
7337                         } else {
7338                                 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%l]",nts);
7339                         }
7340                 } else {
7341                         afsi_log("Can't register logon process!! NTSTATUS=[%l]",nts);
7342                 }
7343
7344                 if (nts != STATUS_SUCCESS) {
7345                         /* something went wrong. We report the error and revert back to no authentication
7346                            because we can't perform any auth requests without a successful lsa handle
7347                            or sec package id. */
7348                         afsi_log("Reverting to NO SMB AUTH");
7349                         smb_authType = SMB_AUTH_NONE;
7350                 } else if ( smb_authType == SMB_AUTH_EXTENDED) {
7351             /* Test to see if there is anything to negotiate.  If SPNEGO is not going to be used 
7352             * then the only option is NTLMSSP anyway; so just fallback. 
7353             */
7354             void * secBlob;
7355             int secBlobLength;
7356
7357             smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
7358             if (secBlobLength == 0) {
7359                 smb_authType = SMB_AUTH_NTLM;
7360                 afsi_log("Reverting to SMB AUTH NTLM");
7361             } else
7362                 free(secBlob);
7363         }
7364         }
7365
7366         /* Start listeners, waiters, servers, and daemons */
7367
7368         for (i = 0; i < lana_list.length; i++) {
7369                 if (lana_list.lana[i] == 255) continue;
7370                 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
7371                         (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
7372                 osi_assert(phandle != NULL);
7373                 thrd_CloseHandle(phandle);
7374         }
7375
7376 #ifndef DJGPP
7377     phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
7378                           NULL, 0, &lpid, "smb_ClientWaiter");
7379         osi_assert(phandle != NULL);
7380         thrd_CloseHandle(phandle);
7381 #endif /* !DJGPP */
7382
7383     phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
7384                           NULL, 0, &lpid, "smb_ServerWaiter");
7385         osi_assert(phandle != NULL);
7386         thrd_CloseHandle(phandle);
7387
7388         for (i=0; i<nThreads; i++) {
7389                 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
7390                               (void *) i, 0, &lpid, "smb_Server");
7391                 osi_assert(phandle != NULL);
7392                 thrd_CloseHandle(phandle);
7393         }
7394
7395     phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
7396                           NULL, 0, &lpid, "smb_Daemon");
7397         osi_assert(phandle != NULL);
7398         thrd_CloseHandle(phandle);
7399
7400         phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
7401                           NULL, 0, &lpid, "smb_WaitingLocksDaemon");
7402         osi_assert(phandle != NULL);
7403         thrd_CloseHandle(phandle);
7404
7405 #ifdef DJGPP
7406         smb_ListShares();
7407 #endif
7408
7409         return;
7410 }
7411
7412 void smb_Shutdown(void)
7413 {
7414     NCB *ncbp;
7415 #ifdef DJGPP
7416     dos_ptr dos_ncb;
7417 #endif
7418     long code = 0;
7419     int i;
7420
7421     /*fprintf(stderr, "Entering smb_Shutdown\n");*/
7422         
7423     /* setup the NCB system */
7424     ncbp = GetNCB();
7425 #ifdef DJGPP
7426     dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7427 #endif
7428
7429     /* Block new sessions by setting shutdown flag */
7430     smbShutdownFlag = 1;
7431
7432     /* Hang up all sessions */
7433     memset((char *)ncbp, 0, sizeof(NCB));
7434     for (i = 1; i < numSessions; i++)
7435     {
7436         if (dead_sessions[i])
7437             continue;
7438       
7439         /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
7440         ncbp->ncb_command = NCBHANGUP;
7441         ncbp->ncb_lana_num = lanas[i];  /*smb_LANadapter;*/
7442         ncbp->ncb_lsn = LSNs[i];
7443 #ifndef DJGPP
7444         code = Netbios(ncbp);
7445 #else
7446                 code = Netbios(ncbp, dos_ncb);
7447 #endif
7448         /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
7449         if (code == 0) code = ncbp->ncb_retcode;
7450         if (code != 0) {
7451             osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
7452             fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
7453         }
7454     }
7455
7456     /* Delete Netbios name */
7457     memset((char *)ncbp, 0, sizeof(NCB));
7458         for (i = 0; i < lana_list.length; i++) {
7459                 if (lana_list.lana[i] == 255) continue;
7460                 ncbp->ncb_command = NCBDELNAME;
7461                 ncbp->ncb_lana_num = lana_list.lana[i];
7462                 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7463 #ifndef DJGPP
7464         code = Netbios(ncbp);
7465 #else
7466                 code = Netbios(ncbp, dos_ncb);
7467 #endif
7468                 if (code == 0) code = ncbp->ncb_retcode;
7469                 if (code != 0) {
7470                         fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
7471                         ncbp->ncb_lana_num, code);
7472                 }
7473                 fflush(stderr);
7474         }
7475 }
7476
7477 /* Get the UNC \\<servername>\<sharename> prefix. */
7478 char *smb_GetSharename()
7479 {
7480     char *name;
7481
7482         /* Make sure we have been properly initialized. */
7483         if (smb_localNamep == NULL)
7484                 return NULL;
7485
7486     /* Allocate space for \\<servername>\<sharename>, plus the
7487      * terminator.
7488      */
7489     name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
7490     sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
7491     return name;
7492 }   
7493
7494 #ifdef NOTSERVICE
7495
7496 void smb_LogPacket(smb_packet_t *packet)
7497 {
7498         BYTE *vp, *cp;
7499         unsigned length, paramlen, datalen, i, j;
7500         char buf[81];
7501         char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
7502
7503         if(!packet) return;
7504
7505         osi_Log0(smb_logp, "*** SMB packet dump ***");
7506
7507         vp = (BYTE *) packet->data;
7508
7509         datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
7510         length = paramlen + 2 + datalen;
7511
7512
7513         for(i=0;i < length; i+=16)
7514         {
7515                 memset( buf, ' ', 80 );
7516                 buf[80] = 0;
7517
7518                 itoa( i, buf, 16 );
7519
7520                 buf[strlen(buf)] = ' ';
7521
7522                 cp = (BYTE*) buf + 7;
7523
7524                 for(j=0;j < 16 && (i+j)<length; j++)
7525                 {
7526                         *(cp++) = hex[vp[i+j] >> 4];
7527                         *(cp++) = hex[vp[i+j] & 0xf];
7528                         *(cp++) = ' ';
7529
7530                         if(j==7)
7531                         {
7532                                 *(cp++) = '-';
7533                                 *(cp++) = ' ';
7534                         }
7535                 }
7536
7537                 for(j=0;j < 16 && (i+j)<length;j++)
7538                 {
7539                         *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
7540                         if(j==7)
7541                         {
7542                                 *(cp++) = ' ';
7543                                 *(cp++) = '-';
7544                                 *(cp++) = ' ';
7545                         }
7546                 }
7547
7548                 *cp = 0;
7549
7550                 osi_Log0( smb_logp, buf );
7551         }
7552
7553         osi_Log0(smb_logp, "*** End SMB packet dump ***");
7554
7555 }
7556
7557 #endif /* NOTSERVICE */
7558
7559 int smb_DumpVCP(FILE *outputFile, char *cookie)
7560 {
7561     int zilch;
7562     char output[1024];
7563   
7564     smb_vc_t *vcp;
7565   
7566     lock_ObtainRead(&smb_rctLock);
7567   
7568     sprintf(output, "begin dumping vcpsp\n");
7569     WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7570
7571     for(vcp = smb_allVCsp; vcp; vcp=vcp->nextp) 
7572     {
7573         smb_fid_t *fidp;
7574       
7575         sprintf(output, "%s vcp=0x%08X, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
7576                  cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
7577         WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7578       
7579         sprintf(output, "begin dumping fidsp\n");
7580         WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7581
7582         for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
7583         {
7584             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", 
7585                      cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp, 
7586                      fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL", 
7587                      fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
7588             WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7589         }
7590       
7591         sprintf(output, "done dumping fidsp\n");
7592         WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7593     }
7594
7595     sprintf(output, "done dumping vcpsp\n");
7596     WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7597   
7598     lock_ReleaseRead(&smb_rctLock);
7599     return 0;
7600 }