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