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