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