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