winnt-win2000-win98-afs-client-updates-20010623
[openafs.git] / src / WINNT / afsd / smb.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 //#define NOSERVICE 1
11
12 #include <afs/param.h>
13 #include <afs/stds.h>
14
15 #ifndef DJGPP
16 #include <windows.h>
17 #else
18 #include <sys/timeb.h>
19 #include <tzfile.h>
20 #endif /* !DJGPP */
21 #include <stddef.h>
22 #include <stdlib.h>
23 #include <malloc.h>
24 #include <string.h>
25 #include <stdio.h>
26 #include <time.h>
27
28 #include <osi.h>
29
30 #include "afsd.h"
31
32 #include "smb.h"
33
34 /* These characters are illegal in Windows filenames */
35 static char *illegalChars = "\\/:*?\"<>|";
36 BOOL isWindows2000 = FALSE;
37
38 smb_vc_t *dead_vcp = NULL;
39 smb_vc_t *active_vcp = NULL;
40
41 char *loggedOutName = NULL;
42 smb_user_t *loggedOutUserp = NULL;
43 unsigned long loggedOutTime;
44 int loggedOut = 0;
45 #ifdef DJGPP
46 int smbShutdownFlag = 0;
47 #endif /* DJGPP */
48
49 int smb_LogoffTokenTransfer;
50 unsigned long smb_LogoffTransferTimeout;
51
52 DWORD last_msg_time = 0;
53
54 long ongoingOps = 0;
55
56 unsigned int sessionGen = 0;
57
58 void afsi_log();
59
60 osi_hyper_t hzero = {0, 0};
61 osi_hyper_t hones = {0xFFFFFFFF, -1};
62
63 osi_log_t *smb_logp;
64 osi_rwlock_t smb_globalLock;
65 osi_rwlock_t smb_rctLock;
66 osi_rwlock_t smb_ListenerLock;
67  
68 char smb_LANadapter;
69 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
70
71 /* for debugging */
72 long smb_maxObsConcurrentCalls=0;
73 long smb_concurrentCalls=0;
74
75 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
76
77 smb_packet_t *smb_packetFreeListp;
78 smb_ncb_t *smb_ncbFreeListp;
79
80 int smb_NumServerThreads;
81
82 int numNCBs, numSessions;
83
84 #define NCBmax 100
85 EVENT_HANDLE NCBavails[NCBmax], NCBevents[NCBmax];
86 EVENT_HANDLE **NCBreturns;
87 DWORD NCBsessions[NCBmax];
88 NCB *NCBs[NCBmax];
89 struct smb_packet *bufs[NCBmax];
90
91 #define Sessionmax 100
92 EVENT_HANDLE SessionEvents[Sessionmax];
93 unsigned short LSNs[Sessionmax];
94 int lanas[Sessionmax];
95 BOOL dead_sessions[Sessionmax];
96 LANA_ENUM lana_list;
97
98 /* for raw I/O */
99 osi_mutex_t smb_RawBufLock;
100 #ifdef DJGPP
101 #define SMB_RAW_BUFS 4
102 dos_ptr smb_RawBufs;
103 int smb_RawBufSel[SMB_RAW_BUFS];
104 #else
105 char *smb_RawBufs;
106 #endif /* DJGPP */
107
108 #define RAWTIMEOUT INFINITE
109
110 /* for raw write */
111 typedef struct raw_write_cont {
112         long code;
113         osi_hyper_t offset;
114         long count;
115 #ifndef DJGPP
116         char *buf;
117 #else
118         dos_ptr buf;
119 #endif /* DJGPP */
120         int writeMode;
121         long alreadyWritten;
122 } raw_write_cont_t;
123
124 /* dir search stuff */
125 long smb_dirSearchCounter = 1;
126 smb_dirSearch_t *smb_firstDirSearchp;
127 smb_dirSearch_t *smb_lastDirSearchp;
128
129 /* global state about V3 protocols */
130 int smb_useV3;          /* try to negotiate V3 */
131
132 #ifndef DJGPP
133 /* MessageBox or something like it */
134 int (WINAPI *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
135 #endif /* DJGPP */
136
137 /* GMT time info:
138  * Time in Unix format of midnight, 1/1/1970 local time.
139  * When added to dosUTime, gives Unix (AFS) time.
140  */
141 long smb_localZero;
142
143 /* Time difference for converting to kludge-GMT */
144 int smb_NowTZ;
145
146 char *smb_localNamep;
147
148 smb_vc_t *smb_allVCsp;
149
150 smb_username_t *usernamesp = NULL;
151
152 smb_waitingLock_t *smb_allWaitingLocks;
153
154 /* forward decl */
155 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
156         NCB *ncbp, raw_write_cont_t *rwcp);
157 void smb_NetbiosInit();
158 extern char cm_HostName[];
159 #ifdef DJGPP
160 extern char cm_confDir[];
161 #endif
162
163 #ifdef DJGPP
164 #define LPTSTR char *
165 #define GetComputerName(str, sizep) \
166        strcpy((str), cm_HostName); \
167        *(sizep) = strlen(cm_HostName)
168 #endif /* DJGPP */
169
170 /*
171  * Demo expiration
172  *
173  * To build an expiring version, comment out the definition of NOEXPIRE,
174  * and set the definition of EXPIREDATE to the desired value.
175  */
176 #define NOEXPIRE 1
177 #define EXPIREDATE 834000000            /* Wed Jun 5 1996 */
178
179
180 char * myCrt_Dispatch(int i)
181 {
182         switch (i)
183         {
184         default:
185                 return "unknown SMB op";
186         case 0x00:
187                 return "(00)ReceiveCoreMakeDir";
188         case 0x01:
189                 return "(01)ReceiveCoreRemoveDir";
190         case 0x02:
191                 return "(02)ReceiveCoreOpen";
192         case 0x03:
193                 return "(03)ReceiveCoreCreate";
194         case 0x04:
195                 return "(04)ReceiveCoreClose";
196         case 0x05:
197                 return "(05)ReceiveCoreFlush";
198         case 0x06:
199                 return "(06)ReceiveCoreUnlink";
200         case 0x07:
201                 return "(07)ReceiveCoreRename";
202         case 0x08:
203                 return "(08)ReceiveCoreGetFileAttributes";
204         case 0x09:
205                 return "(09)ReceiveCoreSetFileAttributes";
206         case 0x0a:
207                 return "(0a)ReceiveCoreRead";
208         case 0x0b:
209                 return "(0b)ReceiveCoreWrite";
210         case 0x0c:
211                 return "(0c)ReceiveCoreLockRecord";
212         case 0x0d:
213                 return "(0d)ReceiveCoreUnlockRecord";
214         case 0x0e:
215                 return "(0e)SendCoreBadOp";
216         case 0x0f:
217                 return "(0f)ReceiveCoreCreate";
218         case 0x10:
219                 return "(10)ReceiveCoreCheckPath";
220         case 0x11:
221                 return "(11)SendCoreBadOp";
222         case 0x12:
223                 return "(12)ReceiveCoreSeek";
224         case 0x1a:
225                 return "(1a)ReceiveCoreReadRaw";
226         case 0x1d:
227                 return "(1d)ReceiveCoreWriteRawDummy";
228         case 0x22:
229                 return "(22)ReceiveV3SetAttributes";
230         case 0x23:
231                 return "(23)ReceiveV3GetAttributes";
232         case 0x24:
233                 return "(24)ReceiveV3LockingX";
234         case 0x29:
235                 return "(29)SendCoreBadOp";
236         case 0x2b:
237                 return "(2b)ReceiveCoreEcho";
238         case 0x2d:
239                 return "(2d)ReceiveV3OpenX";
240         case 0x2e:
241                 return "(2e)ReceiveV3ReadX";
242         case 0x32:
243                 return "(32)ReceiveV3Tran2A";
244         case 0x33:
245                 return "(33)ReceiveV3Tran2A";
246         case 0x34:
247                 return "(34)ReceiveV3FindClose";
248         case 0x35:
249                 return "(35)ReceiveV3FindNotifyClose";
250         case 0x70:
251                 return "(70)ReceiveCoreTreeConnect";
252         case 0x71:
253                 return "(71)ReceiveCoreTreeDisconnect";
254         case 0x72:
255                 return "(72)ReceiveNegotiate";
256         case 0x73:
257                 return "(73)ReceiveV3SessionSetupX";
258         case 0x74:
259                 return "(74)ReceiveV3UserLogoffX";
260         case 0x75:
261                 return "(75)ReceiveV3TreeConnectX";
262         case 0x80:
263                 return "(80)ReceiveCoreGetDiskAttributes";
264         case 0x81:
265                 return "(81)ReceiveCoreSearchDir";
266         case 0xA0:
267                 return "(A0)ReceiveNTTransact";
268         case 0xA2:
269                 return "(A2)ReceiveNTCreateX";
270         case 0xA4:
271                 return "(A4)ReceiveNTCancel";
272         case 0xc0:
273                 return "(c0)SendCoreBadOp";
274         case 0xc1:
275                 return "(c1)SendCoreBadOp";
276         case 0xc2:
277                 return "(c2)SendCoreBadOp";
278         case 0xc3:
279                 return "(c3)SendCoreBadOp";
280         }
281 }
282
283 char * myCrt_2Dispatch(int i)
284 {
285         switch (i)
286         {
287         default:
288                 return "unknown SMB op-2";
289         case 0:
290                 return "S(00)CreateFile";
291         case 1:
292                 return "S(01)FindFirst";
293         case 2:
294                 return "S(02)FindNext"; /* FindNext */
295         case 3:
296                 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
297         case 4:
298                 return "S(04)??";
299         case 5:
300                 return "S(05)QueryFileInfo_ReceiveTran2QPathInfo";
301         case 6:
302                 return "S(06)SetFileInfo_ReceiveTran2SetPathInfo";
303         case 7:
304                 return "S(07)SetInfoHandle_ReceiveTran2QFileInfo";
305         case 8:
306                 return "S(08)??_ReceiveTran2SetFileInfo";
307         case 9:
308                 return "S(09)??_ReceiveTran2FSCTL";
309         case 10:
310                 return "S(0a)_ReceiveTran2IOCTL";
311         case 11:
312                 return "S(0b)_ReceiveTran2FindNotifyFirst";
313         case 12:
314                 return "S(0c)_ReceiveTran2FindNotifyNext";
315         case 13:
316                 return "S(0d)CreateDirectory_ReceiveTran2MKDir";
317         }
318 }
319
320 /* scache must be locked */
321 unsigned int smb_Attributes(cm_scache_t *scp)
322 {
323         unsigned int attrs;
324
325         if (scp->fileType == CM_SCACHETYPE_DIRECTORY
326                 || scp->fileType == CM_SCACHETYPE_MOUNTPOINT)
327                         attrs = 0x10;
328         else
329                 attrs = 0;
330
331         /*
332          * We used to mark a file RO if it was in an RO volume, but that
333          * turns out to be impolitic in NT.  See defect 10007.
334          */
335 #ifdef notdef
336         if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
337 #endif
338         if ((scp->unixModeBits & 0222) == 0)
339                 attrs |= 1;     /* turn on read-only flag */
340
341         return attrs;
342 }
343
344 static int ExtractBits(WORD bits, short start, short len)
345 {
346         int end;
347         WORD num;
348
349         end = start + len;
350         
351         num = bits << (16 - end);
352         num = num >> ((16 - end) + start);
353         
354         return (int)num;
355 }
356
357 #ifndef DJGPP
358 void ShowUnixTime(char *FuncName, long unixTime)
359 {
360         FILETIME ft;
361         WORD wDate, wTime;
362
363         smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
364                 
365         if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
366                 osi_Log1(afsd_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
367         else {
368                 int day, month, year, sec, min, hour;
369                 char msg[256];
370                 
371                 day = ExtractBits(wDate, 0, 5);
372                 month = ExtractBits(wDate, 5, 4);
373                 year = ExtractBits(wDate, 9, 7) + 1980;
374                 
375                 sec = ExtractBits(wTime, 0, 5);
376                 min = ExtractBits(wTime, 5, 6);
377                 hour = ExtractBits(wTime, 11, 5);
378                 
379                 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
380                 osi_Log1(afsd_logp, "%s", osi_LogSaveString(afsd_logp, msg));
381         }
382 }
383 #endif /* DJGPP */
384
385 #ifndef DJGPP
386 /* Determine if we are observing daylight savings time */
387 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
388 {
389         TIME_ZONE_INFORMATION timeZoneInformation;
390         SYSTEMTIME utc, local, localDST;
391
392         /* Get the time zone info. NT uses this to calc if we are in DST. */
393         GetTimeZoneInformation(&timeZoneInformation);
394  
395         /* Return the daylight bias */
396         *pDstBias = timeZoneInformation.DaylightBias;
397
398         /* Return the bias */
399         *pBias = timeZoneInformation.Bias;
400
401         /* Now determine if DST is being observed */
402
403         /* Get the UTC (GMT) time */
404         GetSystemTime(&utc);
405
406         /* Convert UTC time to local time using the time zone info.  If we are
407            observing DST, the calculated local time will include this. 
408         */
409         SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
410
411         /* Set the daylight bias to 0.  The daylight bias is the amount of change
412            in time that we use for daylight savings time.  By setting this to 0
413            we cause there to be no change in time during daylight savings time. 
414         */
415         timeZoneInformation.DaylightBias = 0;
416
417         /* Convert the utc time to local time again, but this time without any
418            adjustment for daylight savings time. 
419         */
420         SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
421
422         /* If the two times are different, then it means that the localDST that
423            we calculated includes the daylight bias, and therefore we are
424            observing daylight savings time.
425         */
426         *pDST = localDST.wHour != local.wHour;
427 }
428 #else
429 /* Determine if we are observing daylight savings time */
430 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
431 {
432   struct timeb t;
433
434   ftime(&t);
435   *pDST = t.dstflag;
436   *pDstBias = -60;    /* where can this be different? */
437   *pBias = t.timezone;
438 }
439 #endif /* DJGPP */
440  
441
442 void CompensateForSmbClientLastWriteTimeBugs(long *pLastWriteTime)
443 {
444         BOOL dst;       /* Will be TRUE if observing DST */
445         LONG dstBias;   /* Offset from local time if observing DST */
446         LONG bias;      /* Offset from GMT for local time */
447         
448         /*
449          * This function will adjust the last write time to compensate
450          * for two bugs in the smb client:
451          *
452          *    1) During Daylight Savings Time, the LastWriteTime is ahead
453          *       in time by the DaylightBias (ignoring the sign - the
454          *       DaylightBias is always stored as a negative number).  If
455          *       the DaylightBias is -60, then the LastWriteTime will be
456          *       ahead by 60 minutes.
457          *
458          *    2) If the local time zone is a positive offset from GMT, then
459          *       the LastWriteTime will be the correct local time plus the
460          *       Bias (ignoring the sign - a positive offset from GMT is
461          *       always stored as a negative Bias).  If the Bias is -120,
462          *       then the LastWriteTime will be ahead by 120 minutes.
463          *
464          *    These bugs can occur at the same time.
465          */
466
467         GetTimeZoneInfo(&dst, &dstBias, &bias);
468          
469          /* First adjust for DST */
470         if (dst)
471                 *pLastWriteTime -= (-dstBias * 60);     /* Convert dstBias to seconds */
472                 
473         /* Now adjust for a positive offset from GMT (a negative bias). */
474         if (bias < 0)
475                 *pLastWriteTime -= (-bias * 60);        /* Convert bias to seconds */
476 }
477
478 /*
479  * Calculate the difference (in seconds) between local time and GMT.
480  * This enables us to convert file times to kludge-GMT.
481  */
482 static void
483 smb_CalculateNowTZ()
484 {
485         time_t t;
486         struct tm gmt_tm, local_tm;
487         int days, hours, minutes, seconds;
488
489         t = time(NULL);
490         gmt_tm = *(gmtime(&t));
491         local_tm = *(localtime(&t));
492
493         days = local_tm.tm_yday - gmt_tm.tm_yday;
494         hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour;
495         minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
496         seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
497
498         smb_NowTZ = seconds;
499 }
500
501 #ifndef DJGPP
502 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, long unixTime)
503 {
504         struct tm *ltp;
505         SYSTEMTIME stm;
506         struct tm localJunk;
507         long ersatz_unixTime;
508
509         /*
510          * Must use kludge-GMT instead of real GMT.
511          * kludge-GMT is computed by adding time zone difference to localtime.
512          *
513          * real GMT would be:
514          * ltp = gmtime(&unixTime);
515          */
516         ersatz_unixTime = unixTime - smb_NowTZ;
517         ltp = localtime(&ersatz_unixTime);
518
519         /* if we fail, make up something */
520         if (!ltp) {
521                 ltp = &localJunk;
522                 localJunk.tm_year = 89 - 20;
523                 localJunk.tm_mon = 4;
524                 localJunk.tm_mday = 12;
525                 localJunk.tm_hour = 0;
526                 localJunk.tm_min = 0;
527                 localJunk.tm_sec = 0;
528         }
529
530         stm.wYear = ltp->tm_year + 1900;
531         stm.wMonth = ltp->tm_mon + 1;
532         stm.wDayOfWeek = ltp->tm_wday;
533         stm.wDay = ltp->tm_mday;
534         stm.wHour = ltp->tm_hour;
535         stm.wMinute = ltp->tm_min;
536         stm.wSecond = ltp->tm_sec;
537         stm.wMilliseconds = 0;
538
539         SystemTimeToFileTime(&stm, largeTimep);
540 }
541 #else /* DJGPP */
542 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, long unixTime)
543 {
544   /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
545   /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 ??? */
546   LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
547   LARGE_INTEGER ut;
548   int leap_years = 89;   /* leap years betw 1/1/1601 and 1/1/1970 */
549
550   /* set ft to number of 100ns intervals betw 1/1/1601 and 1/1/1970 GMT */
551   *ft = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years)
552                                    * 24 * 60);
553   *ft = LargeIntegerMultiplyByLong(*ft, 60);
554   *ft = LargeIntegerMultiplyByLong(*ft, 10000000);
555
556   /* add unix time */
557   ut = ConvertLongToLargeInteger(unixTime);
558   ut = LargeIntegerMultiplyByLong(ut, 10000000);
559   *ft = LargeIntegerAdd(*ft, ut);
560 }
561 #endif /* !DJGPP */
562
563 #ifndef DJGPP
564 void smb_UnixTimeFromLargeSearchTime(long *unixTimep, FILETIME *largeTimep)
565 {
566         SYSTEMTIME stm;
567         struct tm lt;
568         long save_timezone;
569
570         FileTimeToSystemTime(largeTimep, &stm);
571
572         lt.tm_year = stm.wYear - 1900;
573         lt.tm_mon = stm.wMonth - 1;
574         lt.tm_wday = stm.wDayOfWeek;
575         lt.tm_mday = stm.wDay;
576         lt.tm_hour = stm.wHour;
577         lt.tm_min = stm.wMinute;
578         lt.tm_sec = stm.wSecond;
579         lt.tm_isdst = -1;
580
581         save_timezone = _timezone;
582         _timezone += smb_NowTZ;
583         *unixTimep = mktime(&lt);
584         _timezone = save_timezone;
585 }
586 #else /* DJGPP */
587 void smb_UnixTimeFromLargeSearchTime(long *unixTimep, FILETIME *largeTimep)
588 {
589   /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
590   /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 GMT? */
591   LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
592   LARGE_INTEGER a;
593   int leap_years = 89;
594
595   /* set to number of 100ns intervals betw 1/1/1601 and 1/1/1970 */
596   a = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years) * 24 * 60
597 );
598   a = LargeIntegerMultiplyByLong(a, 60);
599   a = LargeIntegerMultiplyByLong(a, 10000000);
600
601   /* subtract it from ft */
602   a = LargeIntegerSubtract(*ft, a);
603
604   /* divide down to seconds */
605   *unixTimep = LargeIntegerDivideByLong(a, 10000000);
606 }
607 #endif /* !DJGPP */
608
609 void smb_SearchTimeFromUnixTime(long *dosTimep, long unixTime)
610 {
611         struct tm *ltp;
612         int dosDate;
613         int dosTime;
614         struct tm localJunk;
615
616         ltp = localtime((time_t*) &unixTime);
617
618         /* if we fail, make up something */
619         if (!ltp) {
620                 ltp = &localJunk;
621                 localJunk.tm_year = 89 - 20;
622                 localJunk.tm_mon = 4;
623                 localJunk.tm_mday = 12;
624                 localJunk.tm_hour = 0;
625                 localJunk.tm_min = 0;
626                 localJunk.tm_sec = 0;
627         }
628
629         dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
630         dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
631         *dosTimep = (dosDate<<16) | dosTime;
632 }
633
634 void smb_UnixTimeFromSearchTime(long *unixTimep, long searchTime)
635 {
636         unsigned short dosDate;
637         unsigned short dosTime;
638         struct tm localTm;
639         
640         dosDate = searchTime & 0xffff;
641         dosTime = (searchTime >> 16) & 0xffff;
642         
643         localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
644         localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1;    /* January is 0 in localTm */
645         localTm.tm_mday = (dosDate) & 0x1f;
646         localTm.tm_hour = (dosTime>>11) & 0x1f;
647         localTm.tm_min = (dosTime >> 5) & 0x3f;
648         localTm.tm_sec = (dosTime & 0x1f) * 2;
649         localTm.tm_isdst = -1;                          /* compute whether DST in effect */
650         
651         *unixTimep = mktime(&localTm);
652 }
653
654 void smb_DosUTimeFromUnixTime(long *dosUTimep, long unixTime)
655 {
656         *dosUTimep = unixTime - smb_localZero;
657 }
658
659 void smb_UnixTimeFromDosUTime(long *unixTimep, long dosTime)
660 {
661 #ifndef DJGPP
662         *unixTimep = dosTime + smb_localZero;
663 #else /* DJGPP */
664         /* dosTime seems to be already adjusted for GMT */
665         *unixTimep = dosTime;
666 #endif /* !DJGPP */
667 }
668
669 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
670 {
671         smb_vc_t *vcp;
672
673         lock_ObtainWrite(&smb_rctLock);
674         for(vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
675                 if (lsn == vcp->lsn && lana == vcp->lana) {
676                         vcp->refCount++;
677                         break;
678                 }
679         }
680         if (!vcp && (flags & SMB_FLAG_CREATE)) {
681                 vcp = malloc(sizeof(*vcp));
682                 memset(vcp, 0, sizeof(*vcp));
683                 vcp->refCount = 1;
684                 vcp->tidCounter = 1;
685                 vcp->fidCounter = 1;
686                 vcp->uidCounter = 1;  /* UID 0 is reserved for blank user */
687                 vcp->nextp = smb_allVCsp;
688                 smb_allVCsp = vcp;
689                 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
690                 vcp->lsn = lsn;
691                 vcp->lana = lana;
692         }
693         lock_ReleaseWrite(&smb_rctLock);
694         return vcp;
695 }
696
697 int smb_IsStarMask(char *maskp)
698 {
699         int i;
700         char tc;
701         
702         for(i=0; i<11; i++) {
703                 tc = *maskp++;
704                 if (tc == '?' || tc == '*' || tc == '>') return 1;        
705         }
706         return 0;
707 }
708
709 void smb_ReleaseVC(smb_vc_t *vcp)
710 {
711         lock_ObtainWrite(&smb_rctLock);
712         osi_assert(vcp->refCount-- > 0);
713         lock_ReleaseWrite(&smb_rctLock);
714 }
715
716 void smb_HoldVC(smb_vc_t *vcp)
717 {
718         lock_ObtainWrite(&smb_rctLock);
719         vcp->refCount++;
720         lock_ReleaseWrite(&smb_rctLock);
721 }
722
723 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
724 {
725         smb_tid_t *tidp;
726
727         lock_ObtainWrite(&smb_rctLock);
728         for(tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
729                 if (tid == tidp->tid) {
730                         tidp->refCount++;
731                         break;
732                 }
733         }
734         if (!tidp && (flags & SMB_FLAG_CREATE)) {
735                 tidp = malloc(sizeof(*tidp));
736                 memset(tidp, 0, sizeof(*tidp));
737                 tidp->nextp = vcp->tidsp;
738                 tidp->refCount = 1;
739                 tidp->vcp = vcp;
740                 vcp->tidsp = tidp;
741                 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
742                 tidp->tid = tid;
743         }
744         lock_ReleaseWrite(&smb_rctLock);
745         return tidp;
746 }
747
748 void smb_ReleaseTID(smb_tid_t *tidp)
749 {
750         smb_tid_t *tp;
751         smb_tid_t **ltpp;
752         cm_user_t *userp;
753
754         userp = NULL;
755         lock_ObtainWrite(&smb_rctLock);
756         osi_assert(tidp->refCount-- > 0);
757         if (tidp->refCount == 0 && (tidp->flags & SMB_TIDFLAG_DELETE)) {
758                 ltpp = &tidp->vcp->tidsp;
759                 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
760                         if (tp == tidp) break;
761                 }
762                 osi_assert(tp != NULL);
763                 *ltpp = tp->nextp;
764                 lock_FinalizeMutex(&tidp->mx);
765                 userp = tidp->userp;    /* remember to drop ref later */
766         }
767         lock_ReleaseWrite(&smb_rctLock);
768         if (userp) {
769                 cm_ReleaseUser(userp);
770         }
771 }
772
773 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
774 {
775         smb_user_t *uidp = NULL;
776
777         lock_ObtainWrite(&smb_rctLock);
778         for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
779                 if (uid == uidp->userID) {
780                         uidp->refCount++;
781 #ifdef DEBUG_VERBOSE 
782                 {
783         HANDLE h; char *ptbuf[1],buf[132];
784         h = RegisterEventSource(NULL, "AFS Service - smb_FindUID (Find by UID)");
785         sprintf(buf, "VCP[%x] found-uid[%d] name[%s]",vcp,uidp->userID,(uidp->unp ? uidp->unp->name : ""));
786         ptbuf[0] = buf;
787         ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, ptbuf, NULL);
788         DeregisterEventSource(h);
789                 }
790 #endif
791                 break;
792                 }
793         }
794         if (!uidp && (flags & SMB_FLAG_CREATE)) {
795                 uidp = malloc(sizeof(*uidp));
796                 memset(uidp, 0, sizeof(*uidp));
797                 uidp->nextp = vcp->usersp;
798                 uidp->refCount = 1;
799                 uidp->vcp = vcp;
800                 vcp->usersp = uidp;
801                 lock_InitializeMutex(&uidp->mx, "uid_t mutex");
802                 uidp->userID = uid;
803 #ifdef DEBUG_VERBOSE 
804                 {
805         HANDLE h; char *ptbuf[1],buf[132];
806         h = RegisterEventSource(NULL, "AFS Service - smb_FindUID (Find by UID)");
807         sprintf(buf, "VCP[%x] new-uid[%d] name[%s]",vcp,uidp->userID,(uidp->unp ? uidp->unp->name : ""));
808         ptbuf[0] = buf;
809         ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, ptbuf, NULL);
810         DeregisterEventSource(h);
811                 }
812 #endif
813         }
814         lock_ReleaseWrite(&smb_rctLock);
815         return uidp;
816 }
817
818 smb_username_t *smb_FindUserByName(char *usern, char *machine, int flags)
819 {
820         smb_username_t *unp= NULL;
821
822         lock_ObtainWrite(&smb_rctLock);
823         for(unp = usernamesp; unp; unp = unp->nextp) {
824                 if (stricmp(unp->name, usern) == 0 &&
825                     stricmp(unp->machine, machine) == 0) {
826                         unp->refCount++;
827                         break;
828                 }
829         }
830         if (!unp && (flags & SMB_FLAG_CREATE)) {
831           unp = malloc(sizeof(*unp));
832           memset(unp, 0, sizeof(*unp));
833           unp->nextp = usernamesp;
834           unp->name = strdup(usern);
835           unp->machine = strdup(machine);
836           usernamesp = unp;
837           lock_InitializeMutex(&unp->mx, "username_t mutex");
838         }
839         lock_ReleaseWrite(&smb_rctLock);
840         return unp;
841 }
842
843 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
844 {
845         smb_user_t *uidp= NULL;
846
847         lock_ObtainWrite(&smb_rctLock);
848         for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
849           if (!uidp->unp) 
850             continue;
851           if (stricmp(uidp->unp->name, usern) == 0) {
852             uidp->refCount++;
853 #ifdef DEBUG_VERBOSE 
854             {
855               HANDLE h; char *ptbuf[1],buf[132];
856               h = RegisterEventSource(NULL, "AFS Service - smb_FindUserByNameThisSession");
857               sprintf(buf, "VCP[%x] uid[%d] match-name[%s]",vcp,uidp->userID,usern);
858               ptbuf[0] = buf;
859               ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, ptbuf, NULL);
860               DeregisterEventSource(h);
861             }
862 #endif
863             break;
864           } else
865             continue;
866         }
867         lock_ReleaseWrite(&smb_rctLock);
868         return uidp;
869 }
870 void smb_ReleaseUID(smb_user_t *uidp)
871 {
872         smb_user_t *up;
873         smb_user_t **lupp;
874         cm_user_t *userp;
875
876         userp = NULL;
877         lock_ObtainWrite(&smb_rctLock);
878         osi_assert(uidp->refCount-- > 0);
879         if (uidp->refCount == 0 && (uidp->flags & SMB_USERFLAG_DELETE)) {
880                 lupp = &uidp->vcp->usersp;
881                 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
882                         if (up == uidp) break;
883                 }
884                 osi_assert(up != NULL);
885                 *lupp = up->nextp;
886                 lock_FinalizeMutex(&uidp->mx);
887                 if (uidp->unp)
888                   userp = uidp->unp->userp;     /* remember to drop ref later */
889         }
890         lock_ReleaseWrite(&smb_rctLock);
891         if (userp) {
892                 cm_ReleaseUserVCRef(userp);
893                 cm_ReleaseUser(userp);
894         }
895 }
896
897 /* retrieve a held reference to a user structure corresponding to an incoming
898  * request.
899  * corresponding release function is cm_ReleaseUser.
900  */
901 cm_user_t *smb_GetUser(smb_vc_t *vcp, smb_packet_t *inp)
902 {
903         smb_user_t *uidp;
904         cm_user_t *up;
905         smb_t *smbp;
906         
907         smbp = (smb_t *) inp;
908         uidp = smb_FindUID(vcp, smbp->uid, 0);
909         if ((!uidp) ||  (!uidp->unp))
910                  return NULL;
911         
912         lock_ObtainMutex(&uidp->mx);
913         up = uidp->unp->userp;
914         cm_HoldUser(up);
915         lock_ReleaseMutex(&uidp->mx);
916
917         smb_ReleaseUID(uidp);
918         
919         return up;
920 }
921
922 /*
923  * Return a pointer to a pathname extracted from a TID structure.  The
924  * TID structure is not held; assume it won't go away.
925  */
926 char *smb_GetTIDPath(smb_vc_t *vcp, unsigned short tid)
927 {
928         smb_tid_t *tidp;
929         char *tpath;
930
931         tidp = smb_FindTID(vcp, tid, 0);
932         tpath = tidp->pathname;
933         smb_ReleaseTID(tidp);
934         return tpath;
935 }
936
937 /* check to see if we have a chained fid, that is, a fid that comes from an
938  * OpenAndX message that ran earlier in this packet.  In this case, the fid
939  * field in a read, for example, request, isn't set, since the value is
940  * supposed to be inherited from the openAndX call.
941  */
942 int smb_ChainFID(int fid, smb_packet_t *inp)
943 {
944         if (inp->fid == 0 || inp->inCount == 0) return fid;
945         else return inp->fid;
946 }
947
948 /* are we a priv'd user?  What does this mean on NT? */
949 int smb_SUser(cm_user_t *userp)
950 {
951         return 1;
952 }
953
954 /* find a file ID.  If pass in 0, we'll allocate on on a create operation. */
955 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
956 {
957         smb_fid_t *fidp;
958         int newFid;
959         
960         /* figure out if we need to allocate a new file ID */
961         if (fid == 0) {
962                 newFid = 1;
963                 fid = vcp->fidCounter;
964         }
965         else newFid = 0;
966
967         lock_ObtainWrite(&smb_rctLock);
968 retry:
969         for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
970                 if (fid == fidp->fid) {
971                         if (newFid) {
972                                 fid++;
973                                 if (fid == 0) fid = 1;
974                                 goto retry;
975                         }
976                         fidp->refCount++;
977                         break;
978                 }
979         }
980         if (!fidp && (flags & SMB_FLAG_CREATE)) {
981                 fidp = malloc(sizeof(*fidp));
982                 memset(fidp, 0, sizeof(*fidp));
983                 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
984                 fidp->refCount = 1;
985                 fidp->vcp = vcp;
986                 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
987                 fidp->fid = fid;
988                 fidp->curr_chunk = fidp->prev_chunk = -2;
989                 fidp->raw_write_event = thrd_CreateEvent(NULL, FALSE, TRUE, NULL);
990                 if (newFid) {
991                         vcp->fidCounter = fid+1;
992                         if (vcp->fidCounter == 0) vcp->fidCounter = 1;
993                 }
994         }
995         lock_ReleaseWrite(&smb_rctLock);
996         return fidp;
997 }
998
999 void smb_ReleaseFID(smb_fid_t *fidp)
1000 {
1001         cm_scache_t *scp;
1002         smb_vc_t *vcp;
1003         smb_ioctl_t *ioctlp;
1004
1005         scp = NULL;
1006         lock_ObtainWrite(&smb_rctLock);
1007         osi_assert(fidp->refCount-- > 0);
1008         if (fidp->refCount == 0 && (fidp->flags & SMB_FID_DELETE)) {
1009                 vcp = fidp->vcp;
1010                 if (!(fidp->flags & SMB_FID_IOCTL))
1011                         scp = fidp->scp;
1012                 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1013                 thrd_CloseHandle(fidp->raw_write_event);
1014
1015                 /* and see if there is ioctl stuff to free */
1016                 ioctlp = fidp->ioctlp;
1017                 if (ioctlp) {
1018                         if (ioctlp->prefix) cm_FreeSpace(ioctlp->prefix);
1019                         if (ioctlp->inAllocp) free(ioctlp->inAllocp);
1020                         if (ioctlp->outAllocp) free(ioctlp->outAllocp);
1021                         free(ioctlp);
1022                 }
1023
1024                 free(fidp);
1025         }
1026         lock_ReleaseWrite(&smb_rctLock);
1027
1028         /* now release the scache structure */
1029         if (scp) cm_ReleaseSCache(scp);
1030 }
1031
1032 /*
1033  * Case-insensitive search for one string in another;
1034  * used to find variable names in submount pathnames.
1035  */
1036 static char *smb_stristr(char *str1, char *str2)
1037 {
1038         char *cursor;
1039
1040         for (cursor = str1; *cursor; cursor++)
1041                 if (stricmp(cursor, str2) == 0)
1042                         return cursor;
1043
1044         return NULL;
1045 }
1046
1047 /*
1048  * Substitute a variable value for its name in a submount pathname.  Variable
1049  * name has been identified by smb_stristr() and is in substr.  Variable name
1050  * length (plus one) is in substr_size.  Variable value is in newstr.
1051  */
1052 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1053         char *newstr)
1054 {
1055         char temp[1024];
1056
1057         strcpy(temp, substr + substr_size - 1);
1058         strcpy(substr, newstr);
1059         strcat(str1, temp);
1060 }
1061
1062 char VNUserName[] = "%USERNAME%";
1063 char VNLCUserName[] = "%LCUSERNAME%";
1064 char VNComputerName[] = "%COMPUTERNAME%";
1065 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1066
1067 /* List available shares */
1068 int smb_ListShares()
1069 {
1070         char sbmtpath[256];
1071         char pathName[256];
1072         char shareBuf[4096];
1073         int num_shares=0;
1074         char *this_share;
1075         int len;
1076         char *p;
1077         int print_afs = 0;
1078         int code;
1079
1080         /*strcpy(shareNameList[num_shares], "all");
1081           strcpy(pathNameList[num_shares++], "/afs");*/
1082         fprintf(stderr, "The following shares are available:\n");
1083         fprintf(stderr, "Share Name (AFS Path)\n");
1084         fprintf(stderr, "---------------------\n");
1085         fprintf(stderr, "\\\\%s\\%-16s (/afs)\n", smb_localNamep, "ALL");
1086
1087 #ifndef DJGPP
1088         code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1089         if (code == 0 || code > sizeof(sbmtpath)) return -1;
1090 #else
1091         strcpy(sbmtpath, cm_confDir);
1092 #endif /* !DJGPP */
1093         strcat(sbmtpath, "/afsdsbmt.ini");
1094         len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1095                                       shareBuf, sizeof(shareBuf),
1096                                       sbmtpath);
1097         if (len == 0) {
1098           return num_shares;
1099         }
1100
1101         this_share = shareBuf;
1102         do
1103         {
1104           print_afs = 0;
1105           /*strcpy(shareNameList[num_shares], this_share);*/
1106           len = GetPrivateProfileString("AFS Submounts", this_share,
1107                                         NULL,
1108                                         pathName, 256,
1109                                         sbmtpath);
1110           if (!len) return num_shares;
1111           p = pathName;
1112           if (strncmp(p, "/afs", 4) != 0)
1113             print_afs = 1;
1114           while (*p) {
1115             if (*p == '\\') *p = '/';    /* change to / */
1116             p++;
1117           }
1118
1119           fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1120                   smb_localNamep, this_share, (print_afs ? "/afs" : "\0"),
1121                   pathName);
1122           num_shares++;
1123           while (*this_share != NULL) this_share++;  /* find next NULL */
1124           this_share++;   /* skip past the NULL */
1125         } while (*this_share != NULL);  /* stop at final NULL */
1126
1127         return num_shares;
1128 }
1129
1130 /* find a shareName in the table of submounts */
1131 int smb_FindShare(smb_vc_t *vcp, smb_packet_t *inp, char *shareName,
1132         char **pathNamep)
1133 {
1134         DWORD len;
1135         char pathName[1024];
1136         char *var;
1137         smb_user_t *uidp;
1138         char temp[1024];
1139         DWORD sizeTemp;
1140         char sbmtpath[256];
1141         char *p, *q;
1142
1143         if (strcmp(shareName, "IPC$") == 0) {
1144                 *pathNamep = NULL;
1145                 return 0;
1146         }
1147
1148         if (_stricmp(shareName, "all") == 0) {
1149                 *pathNamep = NULL;
1150                 return 1;
1151         }
1152
1153 #ifndef DJGPP
1154         strcpy(sbmtpath, "afsdsbmt.ini");
1155 #else /* DJGPP */
1156         strcpy(sbmtpath, cm_confDir);
1157         strcat(sbmtpath, "/afsdsbmt.ini");
1158 #endif /* !DJGPP */
1159         len = GetPrivateProfileString("AFS Submounts", shareName, "",
1160                                       pathName, sizeof(pathName), sbmtpath);
1161         if (len == 0 || len == sizeof(pathName) - 1) {
1162                 *pathNamep = NULL;
1163                 return 0;
1164         }
1165         
1166         /* We can accept either unix or PC style AFS pathnames.  Convert
1167            Unix-style to PC style here for internal use. */
1168         p = pathName;
1169         if (strncmp(p, "/afs", 4) == 0)
1170           p += 4;  /* skip /afs */
1171         q = p;
1172         while (*q) {
1173           if (*q == '/') *q = '\\';    /* change to \ */
1174           q++;
1175         }
1176
1177         while (1)
1178         {
1179                 if (var = smb_stristr(p, VNUserName)) {
1180                         uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1181                         if (uidp && uidp->unp)
1182                           smb_subst(p, var, sizeof(VNUserName),
1183                                        uidp->unp->name);
1184                         else
1185                           smb_subst(p, var, sizeof(VNUserName),
1186                                        " ");
1187                         smb_ReleaseUID(uidp);
1188                 }
1189                 else if (var = smb_stristr(p, VNLCUserName)) {
1190                         uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1191                         if (uidp && uidp->unp)
1192                           strcpy(temp, uidp->unp->name);
1193                         else strcpy(temp, " ");
1194                         _strlwr(temp);
1195                         smb_subst(p, var, sizeof(VNLCUserName), temp);
1196                         smb_ReleaseUID(uidp);
1197                 }
1198                 else if (var = smb_stristr(p, VNComputerName)) {
1199                         sizeTemp = sizeof(temp);
1200                         GetComputerName((LPTSTR)temp, &sizeTemp);
1201                         smb_subst(p, var, sizeof(VNComputerName),
1202                                   temp);
1203                 }
1204                 else if (var = smb_stristr(p, VNLCComputerName)) {
1205                         sizeTemp = sizeof(temp);
1206                         GetComputerName((LPTSTR)temp, &sizeTemp);
1207                         _strlwr(temp);
1208                         smb_subst(p, var, sizeof(VNLCComputerName),
1209                                   temp);
1210                 }
1211                 else break;
1212         }
1213
1214         *pathNamep = strdup(p);
1215         return 1;
1216 }
1217
1218 /* find a dir search structure by cookie value, and return it held.
1219  * Must be called with smb_globalLock held.
1220  */
1221 smb_dirSearch_t *smb_FindDirSearchNL(long cookie)
1222 {
1223         smb_dirSearch_t *dsp;
1224         
1225         for(dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1226                 if (dsp->cookie == cookie) {
1227                         if (dsp != smb_firstDirSearchp) {
1228                                 /* move to head of LRU queue, too, if we're not already there */
1229                                 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1230                                         smb_lastDirSearchp = (smb_dirSearch_t *)
1231                                                 osi_QPrev(&dsp->q);
1232                                 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1233                                 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1234                                 if (!smb_lastDirSearchp)
1235                                         smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1236                         }
1237                         dsp->refCount++;
1238                         break;
1239                 }
1240         }
1241         return dsp;
1242 }
1243
1244 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1245 {
1246         lock_ObtainWrite(&smb_globalLock);
1247         dsp->flags |= SMB_DIRSEARCH_DELETE;
1248         lock_ReleaseWrite(&smb_globalLock);
1249         lock_ObtainMutex(&dsp->mx);
1250         if(dsp->scp != NULL) {
1251               lock_ObtainMutex(&dsp->scp->mx);
1252               if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1253                     dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1254                     dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1255                     dsp->scp->bulkStatProgress = hones;
1256               }
1257               lock_ReleaseMutex(&dsp->scp->mx);
1258         }
1259         lock_ReleaseMutex(&dsp->mx);
1260 }
1261
1262 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1263 {
1264         cm_scache_t *scp;
1265         
1266         scp = NULL;
1267
1268         lock_ObtainWrite(&smb_globalLock);
1269         osi_assert(dsp->refCount-- > 0);
1270         if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1271                 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1272                         smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1273                 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1274                 lock_FinalizeMutex(&dsp->mx);
1275                 scp = dsp->scp;
1276                 free(dsp);
1277         }
1278         lock_ReleaseWrite(&smb_globalLock);
1279         
1280         /* do this now to avoid spurious locking hierarchy creation */
1281         if (scp) cm_ReleaseSCache(scp);
1282 }
1283
1284 /* find a dir search structure by cookie value, and return it held */
1285 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1286 {
1287         smb_dirSearch_t *dsp;
1288
1289         lock_ObtainWrite(&smb_globalLock);
1290         dsp = smb_FindDirSearchNL(cookie);
1291         lock_ReleaseWrite(&smb_globalLock);
1292         return dsp;
1293 }
1294
1295 /* GC some dir search entries, in the address space expected by the specific protocol.
1296  * Must be called with smb_globalLock held; release the lock temporarily.
1297  */
1298 #define SMB_DIRSEARCH_GCMAX     10      /* how many at once */
1299 void smb_GCDirSearches(int isV3)
1300 {
1301         smb_dirSearch_t *prevp;
1302         smb_dirSearch_t *tp;
1303         smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1304         int victimCount;
1305         int i;
1306         
1307         victimCount = 0;        /* how many have we got so far */
1308         for(tp = smb_lastDirSearchp; tp; tp=prevp) {
1309                 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);  /* we'll move tp from queue, so
1310                                                                  * do this early.
1311                                                                  */
1312                 /* if no one is using this guy, and we're either in the new protocol,
1313                  * or we're in the old one and this is a small enough ID to be useful
1314                  * to the old protocol, GC this guy.
1315                  */
1316                 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1317                         /* hold and delete */
1318                         tp->flags |= SMB_DIRSEARCH_DELETE;
1319                         victimsp[victimCount++] = tp;
1320                         tp->refCount++;
1321                 }
1322
1323                 /* don't do more than this */
1324                 if (victimCount >= SMB_DIRSEARCH_GCMAX) break;
1325         }
1326         
1327         /* now release them */
1328         lock_ReleaseWrite(&smb_globalLock);
1329         for(i = 0; i < victimCount; i++) {
1330                 smb_ReleaseDirSearch(victimsp[i]);
1331         }
1332         lock_ObtainWrite(&smb_globalLock);
1333 }
1334
1335 /* function for allocating a dir search entry.  We need these to remember enough context
1336  * since we don't get passed the path from call to call during a directory search.
1337  *
1338  * Returns a held dir search structure, and bumps the reference count on the vnode,
1339  * since it saves a pointer to the vnode.
1340  */
1341 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1342 {
1343         smb_dirSearch_t *dsp;
1344         int counter;
1345         int maxAllowed;
1346
1347         lock_ObtainWrite(&smb_globalLock);
1348         counter = 0;
1349
1350         /* what's the biggest ID allowed in this version of the protocol */
1351         if (isV3) maxAllowed = 65535;
1352         else maxAllowed = 255;
1353
1354         while(1) {
1355                 /* twice so we have enough tries to find guys we GC after one pass;
1356                  * 10 extra is just in case I mis-counted.
1357                  */
1358                 if (++counter > 2*maxAllowed+10) osi_panic("afsd: dir search cookie leak",
1359                         __FILE__, __LINE__);
1360                 if (smb_dirSearchCounter > maxAllowed) {
1361                         smb_dirSearchCounter = 1;
1362                         smb_GCDirSearches(isV3);        /* GC some (drops global lock) */
1363                 }
1364                 dsp = smb_FindDirSearchNL(smb_dirSearchCounter);
1365                 if (dsp) {
1366                         /* don't need to watch for refcount zero and deleted, since
1367                          * we haven't dropped the global lock.
1368                          */
1369                         dsp->refCount--;
1370                         ++smb_dirSearchCounter;
1371                         continue;
1372                 }
1373                 
1374                 dsp = malloc(sizeof(*dsp));
1375                 memset(dsp, 0, sizeof(*dsp));
1376                 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1377                 if (!smb_lastDirSearchp) smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1378                 dsp->cookie = smb_dirSearchCounter;
1379                 ++smb_dirSearchCounter;
1380                 dsp->refCount = 1;
1381                 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
1382                 dsp->lastTime = osi_Time();
1383                 break;
1384         }
1385         lock_ReleaseWrite(&smb_globalLock);
1386         return dsp;
1387 }
1388
1389 static smb_packet_t *GetPacket(void)
1390 {
1391         smb_packet_t *tbp;
1392 #ifdef DJGPP
1393         unsigned int npar, seg, tb_sel;
1394 #endif
1395
1396         lock_ObtainWrite(&smb_globalLock);
1397         tbp = smb_packetFreeListp;
1398         if (tbp) smb_packetFreeListp = tbp->nextp;
1399         lock_ReleaseWrite(&smb_globalLock);
1400         if (!tbp) {
1401 #ifndef DJGPP
1402                 tbp = GlobalAlloc(GMEM_FIXED, 65540);
1403 #else /* DJGPP */
1404                 tbp = malloc(sizeof(smb_packet_t));
1405 #endif /* !DJGPP */
1406                 tbp->magic = SMB_PACKETMAGIC;
1407                 tbp->ncbp = NULL;
1408                 tbp->vcp = NULL;
1409                 tbp->resumeCode = 0;
1410                 tbp->inCount = 0;
1411                 tbp->fid = 0;
1412                 tbp->wctp = NULL;
1413                 tbp->inCom = 0;
1414                 tbp->oddByte = 0;
1415                 tbp->ncb_length = 0;
1416                 tbp->flags = 0;
1417         
1418 #ifdef DJGPP
1419                 npar = SMB_PACKETSIZE >> 4;  /* number of paragraphs */
1420                 {
1421                   signed int retval =
1422                     __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1423                   if (retval == -1) {
1424                     afsi_log("Cannot allocate %d paragraphs of DOS memory",
1425                              npar);
1426                     osi_panic("",__FILE__,__LINE__);
1427                   }
1428                   else {
1429                     afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
1430                              npar, retval);
1431                     seg = retval;
1432                   }
1433                 }
1434                 tbp->dos_pkt = (seg * 16) + 0;  /* DOS physical address */
1435                 tbp->dos_pkt_sel = tb_sel;
1436 #endif /* DJGPP */
1437         }
1438         osi_assert(tbp->magic == SMB_PACKETMAGIC);
1439
1440         return tbp;
1441 }
1442
1443 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
1444 {
1445         smb_packet_t *tbp;
1446         tbp = GetPacket();
1447         memcpy(tbp, pkt, sizeof(smb_packet_t));
1448         tbp->wctp = tbp->data + ((unsigned int)pkt->wctp -
1449                                  (unsigned int)pkt->data);
1450         return tbp;
1451 }
1452
1453 static NCB *GetNCB(void)
1454 {
1455         smb_ncb_t *tbp;
1456         NCB *ncbp;
1457 #ifdef DJGPP
1458         unsigned int npar, seg, tb_sel;
1459 #endif /* DJGPP */
1460
1461         lock_ObtainWrite(&smb_globalLock);
1462         tbp = smb_ncbFreeListp;
1463         if (tbp) smb_ncbFreeListp = tbp->nextp;
1464         lock_ReleaseWrite(&smb_globalLock);
1465         if (!tbp) {
1466 #ifndef DJGPP
1467                 tbp = GlobalAlloc(GMEM_FIXED, sizeof(*tbp));
1468 #else /* DJGPP */
1469                 tbp = malloc(sizeof(*tbp));
1470                 npar = (sizeof(NCB)+15) >> 4;  /* number of paragraphs */
1471                 {
1472                   signed int retval =
1473                     __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1474                   if (retval == -1) {
1475                     afsi_log("Cannot allocate %d paragraphs of DOS mem in GetNCB",
1476                              npar);
1477                     osi_panic("",__FILE__,__LINE__);
1478                   } else {
1479                     afsi_log("Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
1480                              npar, retval);
1481                     seg = retval;
1482                   }
1483                 }
1484                 tbp->dos_ncb = (seg * 16) + 0;  /* DOS physical address */
1485                 tbp->dos_ncb_sel = tb_sel;
1486 #endif /* !DJGPP */
1487                 tbp->magic = SMB_NCBMAGIC;
1488         }
1489         
1490         osi_assert(tbp->magic == SMB_NCBMAGIC);
1491
1492         memset(&tbp->ncb, 0, sizeof(NCB));
1493         ncbp = &tbp->ncb;
1494 #ifdef DJGPP
1495         dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
1496 #endif /* DJGPP */
1497         return ncbp;
1498 }
1499
1500 void smb_FreePacket(smb_packet_t *tbp)
1501 {
1502         osi_assert(tbp->magic == SMB_PACKETMAGIC);
1503         
1504         lock_ObtainWrite(&smb_globalLock);
1505         tbp->nextp = smb_packetFreeListp;
1506         smb_packetFreeListp = tbp;
1507         tbp->magic = SMB_PACKETMAGIC;
1508         tbp->ncbp = NULL;
1509         tbp->vcp = NULL;
1510         tbp->resumeCode = 0;
1511         tbp->inCount = 0;
1512         tbp->fid = 0;
1513         tbp->wctp = NULL;
1514         tbp->inCom = 0;
1515         tbp->oddByte = 0;
1516         tbp->ncb_length = 0;
1517         tbp->flags = 0;
1518         lock_ReleaseWrite(&smb_globalLock);
1519 }
1520
1521 static void FreeNCB(NCB *bufferp)
1522 {
1523         smb_ncb_t *tbp;
1524         
1525         tbp = (smb_ncb_t *) bufferp;
1526         osi_assert(tbp->magic == SMB_NCBMAGIC);
1527         
1528         lock_ObtainWrite(&smb_globalLock);
1529         tbp->nextp = smb_ncbFreeListp;
1530         smb_ncbFreeListp = tbp;
1531         lock_ReleaseWrite(&smb_globalLock);
1532 }
1533
1534 /* get a ptr to the data part of a packet, and its count */
1535 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
1536 {
1537         int parmBytes;
1538         int dataBytes;
1539         unsigned char *afterParmsp;
1540
1541         parmBytes = *smbp->wctp << 1;
1542         afterParmsp = smbp->wctp + parmBytes + 1;
1543         
1544         dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
1545         if (nbytesp) *nbytesp = dataBytes;
1546         
1547         /* don't forget to skip the data byte count, since it follows
1548          * the parameters; that's where the "2" comes from below.
1549          */
1550         return (unsigned char *) (afterParmsp + 2);
1551 }
1552
1553 /* must set all the returned parameters before playing around with the
1554  * data region, since the data region is located past the end of the
1555  * variable number of parameters.
1556  */
1557 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
1558 {
1559         unsigned char *afterParmsp;
1560
1561         afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
1562         
1563         *afterParmsp++ = dsize & 0xff;
1564         *afterParmsp = (dsize>>8) & 0xff;
1565 }
1566
1567 /* return the parm'th parameter in the smbp packet */
1568 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
1569 {
1570         int parmCount;
1571         unsigned char *parmDatap;
1572
1573         parmCount = *smbp->wctp;
1574
1575         if (parm >= parmCount) {
1576 #ifndef DJGPP
1577                 HANDLE h;
1578                 char *ptbuf[1];
1579                 char s[100];
1580                 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1581                 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
1582                         parm, parmCount, smbp->ncb_length);
1583                 ptbuf[0] = s;
1584                 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1585                             1, smbp->ncb_length, ptbuf, smbp);
1586                 DeregisterEventSource(h);
1587 #else /* DJGPP */
1588                 char s[100];
1589
1590                 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
1591                         parm, parmCount, smbp->ncb_length);
1592                 osi_Log0(afsd_logp, s);
1593 #endif /* !DJGPP */
1594                 osi_panic(s, __FILE__, __LINE__);
1595         }
1596         parmDatap = smbp->wctp + (2*parm) + 1;
1597         
1598         return parmDatap[0] + (parmDatap[1] << 8);
1599 }
1600
1601 /* return the parm'th parameter in the smbp packet */
1602 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
1603 {
1604         int parmCount;
1605         unsigned char *parmDatap;
1606
1607         parmCount = *smbp->wctp;
1608
1609         if (parm * 2 + offset >= parmCount * 2) {
1610 #ifndef DJGPP
1611                 HANDLE h;
1612                 char *ptbuf[1];
1613                 char s[100];
1614                 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1615                 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
1616                         parm, offset, parmCount, smbp->ncb_length);
1617                 ptbuf[0] = s;
1618                 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1619                             1, smbp->ncb_length, ptbuf, smbp);
1620                 DeregisterEventSource(h);
1621 #else /* DJGPP */
1622                 char s[100];
1623                 
1624                 sprintf(s, "Bad SMB param %d offset %d out of %d, "
1625                         "ncb len %d",
1626                         parm, offset, parmCount, smbp->ncb_length);
1627                 osi_Log0(afsd_logp, s);
1628 #endif /* !DJGPP */
1629
1630                 osi_panic(s, __FILE__, __LINE__);
1631         }
1632         parmDatap = smbp->wctp + (2*parm) + 1 + offset;
1633         
1634         return parmDatap[0] + (parmDatap[1] << 8);
1635 }
1636
1637 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
1638 {
1639         char *parmDatap;
1640
1641         /* make sure we have enough slots */
1642         if (*smbp->wctp <= slot) *smbp->wctp = slot+1;
1643         
1644         parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1645         *parmDatap++ = parmValue & 0xff;
1646         *parmDatap = (parmValue>>8) & 0xff;
1647 }
1648
1649 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
1650 {
1651         char *parmDatap;
1652
1653         /* make sure we have enough slots */
1654         if (*smbp->wctp <= slot) *smbp->wctp = slot+2;
1655
1656         parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1657         *parmDatap++ = parmValue & 0xff;
1658         *parmDatap++ = (parmValue>>8) & 0xff;
1659         *parmDatap++ = (parmValue>>16) & 0xff;
1660         *parmDatap++ = (parmValue>>24) & 0xff;
1661 }
1662
1663 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
1664 {
1665         char *parmDatap;
1666         int i;
1667
1668         /* make sure we have enough slots */
1669         if (*smbp->wctp <= slot) *smbp->wctp = slot+4;
1670
1671         parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1672         for (i=0; i<8; i++)
1673                 *parmDatap++ = *parmValuep++;
1674 }
1675
1676 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
1677 {
1678         char *parmDatap;
1679
1680         /* make sure we have enough slots */
1681         if (*smbp->wctp <= slot) {
1682                 if (smbp->oddByte) {
1683                         smbp->oddByte = 0;
1684                         *smbp->wctp = slot+1;
1685                 } else
1686                         smbp->oddByte = 1;
1687         }
1688
1689         parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
1690         *parmDatap++ = parmValue & 0xff;
1691 }
1692
1693 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
1694 {
1695         char *lastSlashp;
1696         
1697         lastSlashp = strrchr(inPathp, '\\');
1698         if (lastComponentp)
1699                 *lastComponentp = lastSlashp;
1700         if (lastSlashp) {
1701                 while (1) {
1702                         if (inPathp == lastSlashp) break;
1703                         *outPathp++ = *inPathp++;
1704                 }
1705                 *outPathp++ = 0;
1706         }
1707         else {
1708                 *outPathp++ = 0;
1709         }
1710 }
1711
1712 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
1713 {
1714         if (*inp++ != 0x4) return NULL;
1715         if (chainpp) {
1716                 *chainpp = inp + strlen(inp) + 1;       /* skip over null-terminated string */
1717         }
1718         return inp;
1719 }
1720
1721 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
1722 {
1723         int tlen;
1724
1725         if (*inp++ != 0x5) return NULL;
1726         tlen = inp[0] + (inp[1]<<8);
1727         inp += 2;               /* skip length field */
1728         
1729         if (chainpp) {
1730                 *chainpp = inp + tlen;
1731         }
1732         
1733         if (lengthp) *lengthp = tlen;
1734         
1735         return inp;
1736 }
1737
1738 /* format a packet as a response */
1739 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
1740 {
1741         smb_t *outp;
1742         smb_t *inSmbp;
1743
1744         outp = (smb_t *) op;
1745         
1746         /* zero the basic structure through the smb_wct field, and zero the data
1747          * size field, assuming that wct stays zero; otherwise, you have to 
1748          * explicitly set the data size field, too.
1749          */
1750         inSmbp = (smb_t *) inp;
1751         memset(outp, 0, sizeof(smb_t)+2);
1752         outp->id[0] = 0xff;
1753         outp->id[1] = 'S';
1754         outp->id[2] = 'M';
1755         outp->id[3] = 'B';
1756         if (inp) {
1757                 outp->com = inSmbp->com;
1758                 outp->tid = inSmbp->tid;
1759                 outp->pid = inSmbp->pid;
1760                 outp->uid = inSmbp->uid;
1761                 outp->mid = inSmbp->mid;
1762                 outp->res[0] = inSmbp->res[0];
1763                 outp->res[1] = inSmbp->res[1];
1764                 op->inCom = inSmbp->com;
1765         }
1766         outp->reb = 0x80;       /* SERVER_RESP */
1767         outp->flg2 = 0x1;       /* KNOWS_LONG_NAMES */
1768
1769         /* copy fields in generic packet area */
1770         op->wctp = &outp->wct;
1771 }
1772
1773 /* send a (probably response) packet; vcp tells us to whom to send it.
1774  * we compute the length by looking at wct and bcc fields.
1775  */
1776 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
1777 {
1778         NCB *ncbp;
1779         int extra;
1780         long code;
1781         unsigned char *tp;
1782         int localNCB = 0;
1783 #ifdef DJGPP
1784         dos_ptr dos_ncb;
1785 #endif /* DJGPP */
1786         
1787         ncbp = inp->ncbp;
1788         if (ncbp == NULL) {
1789                 ncbp = GetNCB();
1790                 localNCB = 1;
1791         }
1792 #ifdef DJGPP
1793         dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
1794 #endif /* DJGPP */
1795  
1796         memset((char *)ncbp, 0, sizeof(NCB));
1797
1798         extra = 2 * (*inp->wctp);       /* space used by parms, in bytes */
1799         tp = inp->wctp + 1+ extra;      /* points to count of data bytes */
1800         extra += tp[0] + (tp[1]<<8);
1801         extra += ((unsigned int)inp->wctp - (unsigned int)inp->data);   /* distance to last wct field */
1802         extra += 3;                     /* wct and length fields */
1803         
1804         ncbp->ncb_length = extra;       /* bytes to send */
1805         ncbp->ncb_lsn = (unsigned char) vcp->lsn;       /* vc to use */
1806         ncbp->ncb_lana_num = vcp->lana;
1807         ncbp->ncb_command = NCBSEND;    /* op means send data */
1808 #ifndef DJGPP
1809         ncbp->ncb_buffer = (char *) inp;/* packet */
1810         code = Netbios(ncbp);
1811 #else /* DJGPP */
1812         ncbp->ncb_buffer = inp->dos_pkt;/* packet */
1813         ((smb_ncb_t*)ncbp)->orig_pkt = inp;
1814
1815         /* copy header information from virtual to DOS address space */
1816         dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
1817         code = Netbios(ncbp, dos_ncb);
1818 #endif /* !DJGPP */
1819         
1820         if (code != 0)
1821                 osi_Log1(afsd_logp, "SendPacket failure code %d", code);
1822
1823         if (localNCB)
1824                 FreeNCB(ncbp);
1825 }
1826
1827 void smb_MapNTError(long code, unsigned long *NTStatusp)
1828 {
1829         unsigned long NTStatus;
1830
1831         /* map CM_ERROR_* errors to NT 32-bit status codes */
1832         if (code == CM_ERROR_NOSUCHCELL) {
1833                 NTStatus = 0xC000000FL; /* No such file */
1834         }
1835         else if (code == CM_ERROR_NOSUCHVOLUME) {
1836                 NTStatus = 0xC000000FL; /* No such file */
1837         }
1838         else if (code == CM_ERROR_TIMEDOUT) {
1839                 NTStatus = 0xC00000CFL; /* Paused */
1840         }
1841         else if (code == CM_ERROR_RETRY) {
1842                 NTStatus = 0xC000022DL; /* Retry */
1843         }
1844         else if (code == CM_ERROR_NOACCESS) {
1845                 NTStatus = 0xC0000022L; /* Access denied */
1846         }
1847         else if (code == CM_ERROR_READONLY) {
1848                 NTStatus = 0xC00000A2L; /* Write protected */
1849         }
1850         else if (code == CM_ERROR_NOSUCHFILE) {
1851                 NTStatus = 0xC000000FL; /* No such file */
1852         }
1853         else if (code == CM_ERROR_NOSUCHPATH) {
1854                 NTStatus = 0xC000003AL; /* Object path not found */
1855         }
1856         else if (code == CM_ERROR_TOOBIG) {
1857                 NTStatus = 0xC000007BL; /* Invalid image format */
1858         }
1859         else if (code == CM_ERROR_INVAL) {
1860                 NTStatus = 0xC000000DL; /* Invalid parameter */
1861         }
1862         else if (code == CM_ERROR_BADFD) {
1863                 NTStatus = 0xC0000008L; /* Invalid handle */
1864         }
1865         else if (code == CM_ERROR_BADFDOP) {
1866                 NTStatus = 0xC0000022L; /* Access denied */
1867         }
1868         else if (code == CM_ERROR_EXISTS) {
1869                 NTStatus = 0xC0000035L; /* Object name collision */
1870         }
1871         else if (code == CM_ERROR_NOTEMPTY) {
1872                 NTStatus = 0xC0000101L; /* Directory not empty */
1873         }
1874         else if (code == CM_ERROR_CROSSDEVLINK) {
1875                 NTStatus = 0xC00000D4L; /* Not same device */
1876         }
1877         else if (code == CM_ERROR_NOTDIR) {
1878                 NTStatus = 0xC0000103L; /* Not a directory */
1879         }
1880         else if (code == CM_ERROR_ISDIR) {
1881                 NTStatus = 0xC00000BAL; /* File is a directory */
1882         }
1883         else if (code == CM_ERROR_BADOP) {
1884                 NTStatus = 0xC09820FFL; /* SMB no support */
1885         }
1886         else if (code == CM_ERROR_BADSHARENAME) {
1887                 NTStatus = 0xC00000CCL; /* Bad network name */
1888         }
1889         else if (code == CM_ERROR_NOIPC) {
1890                 NTStatus = 0xC00000CCL; /* Bad network name */
1891         }
1892         else if (code == CM_ERROR_CLOCKSKEW) {
1893                 NTStatus = 0xC0000133L; /* Time difference at DC */
1894         }
1895         else if (code == CM_ERROR_BADTID) {
1896                 NTStatus = 0xC0982005L; /* SMB bad TID */
1897         }
1898         else if (code == CM_ERROR_USESTD) {
1899                 NTStatus = 0xC09820FBL; /* SMB use standard */
1900         }
1901         else if (code == CM_ERROR_QUOTA) {
1902                 NTStatus = 0xC0000044L; /* Quota exceeded */
1903         }
1904         else if (code == CM_ERROR_SPACE) {
1905                 NTStatus = 0xC000007FL; /* Disk full */
1906         }
1907         else if (code == CM_ERROR_ATSYS) {
1908                 NTStatus = 0xC0000033L; /* Object name invalid */
1909         }
1910         else if (code == CM_ERROR_BADNTFILENAME) {
1911                 NTStatus = 0xC0000033L; /* Object name invalid */
1912         }
1913         else if (code == CM_ERROR_WOULDBLOCK) {
1914                 NTStatus = 0xC0000055L; /* Lock not granted */
1915         }
1916         else if (code == CM_ERROR_PARTIALWRITE) {
1917                 NTStatus = 0xC000007FL; /* Disk full */
1918         }
1919         else if (code == CM_ERROR_BUFFERTOOSMALL) {
1920                 NTStatus = 0xC0000023L; /* Buffer too small */
1921         }
1922         else {
1923                 NTStatus = 0xC0982001L; /* SMB non-specific error */
1924         }
1925
1926         *NTStatusp = NTStatus;
1927         osi_Log2(afsd_logp, "SMB SEND code %x as NT %x", code, NTStatus);
1928 }
1929
1930 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
1931         unsigned char *classp)
1932 {
1933         unsigned char class;
1934         unsigned short error;
1935
1936         /* map CM_ERROR_* errors to SMB errors */
1937         if (code == CM_ERROR_NOSUCHCELL) {
1938                 class = 1;
1939                 error = 3;      /* bad path */
1940         }
1941         else if (code == CM_ERROR_NOSUCHVOLUME) {
1942                 class = 1;
1943                 error = 3;      /* bad path */
1944         }
1945         else if (code == CM_ERROR_TIMEDOUT) {
1946                 class = 2;
1947                 error = 81;     /* server is paused */
1948         }
1949         else if (code == CM_ERROR_RETRY) {
1950                 class = 2;      /* shouldn't happen */
1951                 error = 1;
1952         }
1953         else if (code == CM_ERROR_NOACCESS) {
1954                 class = 2;
1955                 error = 4;      /* bad access */
1956         }
1957         else if (code == CM_ERROR_READONLY) {
1958                 class = 3;
1959                 error = 19;     /* read only */
1960         }
1961         else if (code == CM_ERROR_NOSUCHFILE) {
1962                 class = 1;
1963                 error = 2;      /* ENOENT! */
1964         }
1965         else if (code == CM_ERROR_NOSUCHPATH) {
1966                 class = 1;
1967                 error = 3;      /* Bad path */
1968         }
1969         else if (code == CM_ERROR_TOOBIG) {
1970                 class = 1;
1971                 error = 11;     /* bad format */
1972         }
1973         else if (code == CM_ERROR_INVAL) {
1974                 class = 2;      /* server non-specific error code */
1975                 error = 1;
1976         }
1977         else if (code == CM_ERROR_BADFD) {
1978                 class = 1;
1979                 error = 6;      /* invalid file handle */
1980         }
1981         else if (code == CM_ERROR_BADFDOP) {
1982                 class = 1;      /* invalid op on FD */
1983                 error = 5;
1984         }
1985         else if (code == CM_ERROR_EXISTS) {
1986                 class = 1;
1987                 error = 80;     /* file already exists */
1988         }
1989         else if (code == CM_ERROR_NOTEMPTY) {
1990                 class = 1;
1991                 error = 5;      /* delete directory not empty */
1992         }
1993         else if (code == CM_ERROR_CROSSDEVLINK) {
1994                 class = 1;
1995                 error = 17;     /* EXDEV */
1996         }
1997         else if (code == CM_ERROR_NOTDIR) {
1998                 class = 1;      /* bad path */
1999                 error = 3;
2000         }
2001         else if (code == CM_ERROR_ISDIR) {
2002                 class = 1;      /* access denied; DOS doesn't have a good match */
2003                 error = 5;
2004         }
2005         else if (code == CM_ERROR_BADOP) {
2006                 class = 2;
2007                 error = 65535;
2008         }
2009         else if (code == CM_ERROR_BADSHARENAME) {
2010                 class = 2;
2011                 error = 6;
2012         }
2013         else if (code == CM_ERROR_NOIPC) {
2014                 class = 1;
2015                 error = 66;
2016         }
2017         else if (code == CM_ERROR_CLOCKSKEW) {
2018                 class = 1;      /* invalid function */
2019                 error = 1;
2020         }
2021         else if (code == CM_ERROR_BADTID) {
2022                 class = 2;
2023                 error = 5;
2024         }
2025         else if (code == CM_ERROR_USESTD) {
2026                 class = 2;
2027                 error = 251;
2028         }
2029         else if (code == CM_ERROR_REMOTECONN) {
2030                 class = 2;
2031                 error = 82;
2032         }
2033         else if (code == CM_ERROR_QUOTA) {
2034                 if (vcp->flags & SMB_VCFLAG_USEV3) {
2035                         class = 3;
2036                         error = 39;     /* disk full */
2037                 }
2038                 else {
2039                         class = 1;
2040                         error = 5;      /* access denied */
2041                 }
2042         }
2043         else if (code == CM_ERROR_SPACE) {
2044                 if (vcp->flags & SMB_VCFLAG_USEV3) {
2045                         class = 3;
2046                         error = 39;     /* disk full */
2047                 }
2048                 else {
2049                         class = 1;
2050                         error = 5;      /* access denied */
2051                 }
2052         }
2053         else if (code == CM_ERROR_PARTIALWRITE) {
2054                 class = 3;
2055                 error = 39;     /* disk full */
2056         }
2057         else if (code == CM_ERROR_ATSYS) {
2058                 class = 1;
2059                 error = 2;      /* ENOENT */
2060         }
2061         else if (code == CM_ERROR_WOULDBLOCK) {
2062                 class = 1;
2063                 error = 33;     /* lock conflict */
2064         }
2065         else if (code == CM_ERROR_NOFILES) {
2066                 class = 1;
2067                 error = 18;     /* no files in search */
2068         }
2069         else if (code == CM_ERROR_RENAME_IDENTICAL) {
2070                 class = 1;
2071                 error = 183;     /* Samba uses this */
2072         }
2073         else {
2074                 class = 2;
2075                 error = 1;
2076         }
2077
2078         *scodep = error;
2079         *classp = class;
2080         osi_Log3(afsd_logp, "SMB SEND code %x as SMB %d: %d", code, class, error);
2081 }
2082
2083 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2084 {
2085         return CM_ERROR_BADOP;
2086 }
2087
2088 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2089 {
2090         unsigned short EchoCount, i;
2091         char *data, *outdata;
2092         int dataSize;
2093
2094         EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2095
2096         for (i=1; i<=EchoCount; i++) {
2097             data = smb_GetSMBData(inp, &dataSize);
2098             smb_SetSMBParm(outp, 0, i);
2099             smb_SetSMBDataLength(outp, dataSize);
2100             outdata = smb_GetSMBData(outp, NULL);
2101             memcpy(outdata, data, dataSize);
2102             smb_SendPacket(vcp, outp);
2103         }
2104
2105         return 0;
2106 }
2107
2108 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2109 {
2110         osi_hyper_t offset;
2111         long count, minCount, finalCount;
2112         unsigned short fd;
2113         smb_fid_t *fidp;
2114         long code;
2115         cm_user_t *userp = NULL;
2116         NCB *ncbp;
2117         int rc;
2118 #ifndef DJGPP
2119         char *rawBuf = NULL;
2120 #else
2121         dos_ptr rawBuf = NULL;
2122         dos_ptr dos_ncb;
2123 #endif /* DJGPP */
2124
2125         rawBuf = NULL;
2126         finalCount = 0;
2127
2128         fd = smb_GetSMBParm(inp, 0);
2129         count = smb_GetSMBParm(inp, 3);
2130         minCount = smb_GetSMBParm(inp, 4);
2131         offset.HighPart = 0;    /* too bad */
2132         offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2133
2134         osi_Log3(afsd_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2135                  fd, offset.LowPart, count);
2136
2137         fidp = smb_FindFID(vcp, fd, 0);
2138         if (!fidp)
2139                 goto send1;
2140
2141         lock_ObtainMutex(&smb_RawBufLock);
2142         if (smb_RawBufs) {
2143                 /* Get a raw buf, from head of list */
2144                 rawBuf = smb_RawBufs;
2145 #ifndef DJGPP
2146                 smb_RawBufs = *(char **)smb_RawBufs;
2147 #else /* DJGPP */
2148                 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2149 #endif /* !DJGPP */
2150         }
2151         lock_ReleaseMutex(&smb_RawBufLock);
2152         if (!rawBuf)
2153                 goto send1a;
2154
2155         if (fidp->flags & SMB_FID_IOCTL)
2156         {
2157 #ifndef DJGPP
2158           rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2159 #else
2160           rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2161 #endif
2162           if (rawBuf) {
2163             /* Give back raw buffer */
2164             lock_ObtainMutex(&smb_RawBufLock);
2165 #ifndef DJGPP
2166             *((char **) rawBuf) = smb_RawBufs;
2167 #else /* DJGPP */
2168             _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2169 #endif /* !DJGPP */
2170             
2171             smb_RawBufs = rawBuf;
2172             lock_ReleaseMutex(&smb_RawBufLock);
2173           }
2174           return rc;
2175         }
2176         
2177         userp = smb_GetUser(vcp, inp);
2178
2179 #ifndef DJGPP
2180         code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2181 #else /* DJGPP */
2182         /* have to give ReadData flag so it will treat buffer as DOS mem. */
2183         code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2184                             userp, &finalCount, TRUE /* rawFlag */);
2185 #endif /* !DJGPP */
2186
2187         if (code != 0)
2188                 goto send;
2189
2190 send:
2191         cm_ReleaseUser(userp);
2192 send1a:
2193         smb_ReleaseFID(fidp);
2194
2195 send1:
2196         ncbp = outp->ncbp;
2197 #ifdef DJGPP
2198         dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2199 #endif /* DJGPP */
2200         memset((char *)ncbp, 0, sizeof(NCB));
2201
2202         ncbp->ncb_length = (unsigned short) finalCount;
2203         ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2204         ncbp->ncb_lana_num = vcp->lana;
2205         ncbp->ncb_command = NCBSEND;
2206         ncbp->ncb_buffer = rawBuf;
2207
2208 #ifndef DJGPP
2209         code = Netbios(ncbp);
2210 #else /* DJGPP */
2211         code = Netbios(ncbp, dos_ncb);
2212 #endif /* !DJGPP */
2213         if (code != 0)
2214                 osi_Log1(afsd_logp, "ReadRaw send failure code %d", code);
2215
2216         if (rawBuf) {
2217                 /* Give back raw buffer */
2218                 lock_ObtainMutex(&smb_RawBufLock);
2219 #ifndef DJGPP
2220                 *((char **) rawBuf) = smb_RawBufs;
2221 #else /* DJGPP */
2222                 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2223 #endif /* !DJGPP */
2224
2225                 smb_RawBufs = rawBuf;
2226                 lock_ReleaseMutex(&smb_RawBufLock);
2227         }
2228
2229         return 0;
2230 }
2231
2232 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2233 {
2234         return 0;
2235 }
2236
2237 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2238 {
2239         return 0;
2240 }
2241
2242 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2243 {
2244         char *namep;
2245         int coreProtoIndex;
2246         int v3ProtoIndex;
2247         int NTProtoIndex;
2248         int protoIndex;                 /* index we're using */
2249         int namex;
2250         int dbytes;
2251         int entryLength;
2252         int tcounter;
2253         char protocol_array[10][1024]; /* protocol signature of the client */
2254
2255         
2256         osi_Log1(afsd_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2257                  ongoingOps - 1);
2258         if (!isGateway) {
2259                 if (active_vcp) {
2260                         DWORD now = GetCurrentTime();
2261                         if (now - last_msg_time >= 30000
2262                               && now - last_msg_time <= 90000) {
2263                                 osi_Log1(afsd_logp,
2264                                          "Setting dead_vcp %x", active_vcp);
2265                                 dead_vcp = active_vcp;
2266                                 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2267                         }
2268                 }
2269         }
2270
2271         inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
2272
2273         namep = smb_GetSMBData(inp, &dbytes);
2274         namex = 0;
2275         tcounter = 0;
2276         coreProtoIndex = -1;            /* not found */
2277         v3ProtoIndex = -1;
2278         NTProtoIndex = -1;
2279         while(namex < dbytes) {
2280                 osi_Log1(afsd_logp, "Protocol %s",
2281                          osi_LogSaveString(afsd_logp, namep+1));
2282                 strcpy(protocol_array[tcounter], namep+1);
2283
2284                 /* namep points at the first protocol, or really, a 0x02
2285                  * byte preceding the null-terminated ASCII name.
2286                  */
2287                 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2288                         coreProtoIndex = tcounter;
2289                 }
2290                 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2291                         v3ProtoIndex = tcounter;
2292                 }
2293                 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
2294                         NTProtoIndex = tcounter;
2295                 }
2296
2297                 /* compute size of protocol entry */
2298                 entryLength = strlen(namep+1);
2299                 entryLength += 2;       /* 0x02 bytes and null termination */
2300                 
2301                 /* advance over this protocol entry */
2302                 namex += entryLength;
2303                 namep += entryLength;
2304                 tcounter++;             /* which proto entry we're looking at */
2305         }
2306         /* 
2307          * NOTE: We can determine what OS (NT4.0, W2K, W9X, etc)
2308          * the client is running by reading the protocol signature.
2309          * ie. the order in which it sends us the protocol list.
2310          *
2311          * Special handling for Windows 2000 clients (defect 11765 )
2312          */
2313         if (tcounter == 6) {
2314                int i = 0;
2315                smb_t *ip = (smb_t *) inp;
2316                smb_t *op = (smb_t *) outp;
2317
2318                if ((strcmp("PC NETWORK PROGRAM 1.0", protocol_array[0]) == 0) &&
2319                    (strcmp("LANMAN1.0", protocol_array[1]) == 0) &&
2320                    (strcmp("Windows for Workgroups 3.1a", protocol_array[2]) == 0) &&
2321                    (strcmp("LM1.2X002", protocol_array[3]) == 0) &&
2322                    (strcmp("LANMAN2.1", protocol_array[4]) == 0) &&
2323                    (strcmp("NT LM 0.12", protocol_array[5]) == 0)) {
2324                       isWindows2000 = TRUE;
2325                       osi_Log0(afsd_logp, "Looks like a Windows 2000 client");
2326                       /* 
2327                        * HACK: for now - just negotiate a lower protocol till we 
2328                        * figure out which flag/flag2 or some other field 
2329                        * (capabilities maybe?) to set in order for this to work
2330                        * correctly with Windows 2000 clients (defect 11765)
2331                        */
2332                       NTProtoIndex = -1;
2333                       /* Things to try (after looking at tcpdump output could be
2334                        * setting flags and flags2 to 0x98 and 0xc853 like this
2335                        * op->reb = 0x98; op->flg2 = 0xc853;
2336                        * osi_Log2(afsd_logp, "Flags:0x%x Flags2:0x%x", ip->reb, ip->flg2);
2337                        */
2338                }
2339         }
2340
2341         if (NTProtoIndex != -1) {
2342                 protoIndex = NTProtoIndex;
2343                 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2344         }
2345         else if (v3ProtoIndex != -1) {
2346                 protoIndex = v3ProtoIndex;
2347                 vcp->flags |= SMB_VCFLAG_USEV3;
2348         }
2349         else if (coreProtoIndex != -1) {
2350                 protoIndex = coreProtoIndex;
2351                 vcp->flags |= SMB_VCFLAG_USECORE;
2352         }
2353         else protoIndex = -1;
2354
2355         if (protoIndex == -1)
2356                 return CM_ERROR_INVAL;
2357         else if (NTProtoIndex != -1) {
2358                 smb_SetSMBParm(outp, 0, protoIndex);
2359                 smb_SetSMBParmByte(outp, 1, 0); /* share level security, no passwd encrypt */
2360                 smb_SetSMBParm(outp, 1, 8);     /* max multiplexed requests */
2361                 smb_SetSMBParm(outp, 2, 100);   /* max VCs per consumer/server connection */
2362                 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
2363                 smb_SetSMBParmLong(outp, 5, 65536);     /* raw buffer size */
2364                 smb_SetSMBParm(outp, 7, 1);     /* next 2: session key */
2365                 smb_SetSMBParm(outp, 8, 1);
2366                 /* 
2367                  * Tried changing the capabilities to support for W2K - defect 117695
2368                  * Maybe something else needs to be changed here?
2369                  */
2370                 /*
2371                   if (isWindows2000) 
2372                   smb_SetSMBParmLong(outp, 9, 0x43fd);
2373                   else 
2374                   smb_SetSMBParmLong(outp, 9, 0x251);
2375                   */
2376                 smb_SetSMBParmLong(outp, 9, 0x251);     /* Capabilities: *
2377                                                  * 32-bit error codes *
2378                                                  * and NT Find *
2379                                                  * and NT SMB's *
2380                                                  * and raw mode */
2381                 smb_SetSMBParmLong(outp, 11, 0);/* XXX server time: do we need? */
2382                 smb_SetSMBParmLong(outp, 13, 0);/* XXX server date: do we need? */
2383                 smb_SetSMBParm(outp, 15, 0);    /* XXX server tzone: do we need? */
2384                 smb_SetSMBParmByte(outp, 16, 0);/* Encryption key length */
2385                 smb_SetSMBDataLength(outp, 0);  /* perhaps should specify 8 bytes anyway */
2386         }
2387         else if (v3ProtoIndex != -1) {
2388                 smb_SetSMBParm(outp, 0, protoIndex);
2389                 smb_SetSMBParm(outp, 1, 0);     /* share level security, no passwd encrypt */
2390                 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
2391                 smb_SetSMBParm(outp, 3, 8);     /* max multiplexed requests */
2392                 smb_SetSMBParm(outp, 4, 100);   /* max VCs per consumer/server connection */
2393                 smb_SetSMBParm(outp, 5, 0);     /* no support of block mode for read or write */
2394                 smb_SetSMBParm(outp, 6, 1);     /* next 2: session key */
2395                 smb_SetSMBParm(outp, 7, 1);
2396                 smb_SetSMBParm(outp, 8, 0);     /* XXX server time: do we need? */
2397                 smb_SetSMBParm(outp, 9, 0);     /* XXX server date: do we need? */
2398                 smb_SetSMBParm(outp, 10, 0);    /* XXX server tzone: do we need? */
2399                 smb_SetSMBParm(outp, 11, 0);    /* resvd */
2400                 smb_SetSMBParm(outp, 12, 0);    /* resvd */
2401                 smb_SetSMBDataLength(outp, 0);  /* perhaps should specify 8 bytes anyway */
2402         }
2403         else if (coreProtoIndex != -1) {
2404                 smb_SetSMBParm(outp, 0, protoIndex);
2405                 smb_SetSMBDataLength(outp, 0);
2406         }
2407         return 0;
2408 }
2409
2410 void smb_Daemon(void *parmp)
2411 {
2412         int count = 0;
2413
2414         while(1) {
2415                 count++;
2416                 thrd_Sleep(10000);
2417                 if ((count % 360) == 0)         /* every hour */
2418                         smb_CalculateNowTZ();
2419                 /* XXX GC dir search entries */
2420         }
2421 }
2422
2423 void smb_WaitingLocksDaemon()
2424 {
2425         smb_waitingLock_t *wL, *nwL;
2426         int first;
2427         smb_vc_t *vcp;
2428         smb_packet_t *inp, *outp;
2429         NCB *ncbp;
2430         long code;
2431
2432         while(1) {
2433                 lock_ObtainWrite(&smb_globalLock);
2434                 nwL = smb_allWaitingLocks;
2435                 if (nwL == NULL) {
2436                         osi_SleepW((long)&smb_allWaitingLocks, &smb_globalLock);
2437                         thrd_Sleep(1000);
2438                         continue;
2439                 }
2440                 else first = 1;
2441                 do {
2442                         if (first)
2443                                 first = 0;
2444                         else
2445                                 lock_ObtainWrite(&smb_globalLock);
2446                         wL = nwL;
2447                         nwL = (smb_waitingLock_t *) osi_QNext(&wL->q);
2448                         lock_ReleaseWrite(&smb_globalLock);
2449                         code = cm_RetryLock((cm_file_lock_t *) wL->lockp,
2450                                 wL->vcp->flags & SMB_VCFLAG_ALREADYDEAD);
2451                         if (code == CM_ERROR_WOULDBLOCK) {
2452                                 /* no progress */
2453                                 if (wL->timeRemaining != 0xffffffff
2454                                     && (wL->timeRemaining -= 1000) < 0)
2455                                         goto endWait;
2456                                 continue;
2457                         }
2458 endWait:
2459                         vcp = wL->vcp;
2460                         inp = wL->inp;
2461                         outp = wL->outp;
2462                         ncbp = GetNCB();
2463                         ncbp->ncb_length = inp->ncb_length;
2464                         inp->spacep = cm_GetSpace();
2465
2466                         /* Remove waitingLock from list */
2467                         lock_ObtainWrite(&smb_globalLock);
2468                         osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
2469                                     &wL->q);
2470                         lock_ReleaseWrite(&smb_globalLock);
2471
2472                         /* Resume packet processing */
2473                         if (code == 0)
2474                                 smb_SetSMBDataLength(outp, 0);
2475                         outp->flags |= SMB_PACKETFLAG_SUSPENDED;
2476                         outp->resumeCode = code;
2477                         outp->ncbp = ncbp;
2478                         smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
2479
2480                         /* Clean up */
2481                         cm_FreeSpace(inp->spacep);
2482                         smb_FreePacket(inp);
2483                         smb_FreePacket(outp);
2484                         FreeNCB(ncbp);
2485                         free(wL);
2486                 } while (nwL);
2487                 thrd_Sleep(1000);
2488         }
2489 }
2490
2491 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2492 {
2493         osi_Log0(afsd_logp, "SMB receive get disk attributes");
2494
2495         smb_SetSMBParm(outp, 0, 32000);
2496         smb_SetSMBParm(outp, 1, 64);
2497         smb_SetSMBParm(outp, 2, 1024);
2498         smb_SetSMBParm(outp, 3, 30000);
2499         smb_SetSMBParm(outp, 4, 0);
2500         smb_SetSMBDataLength(outp, 0);
2501         return 0;
2502 }
2503
2504 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
2505 {
2506         smb_tid_t *tidp;
2507         unsigned short newTid;
2508         char shareName[256];
2509         char *sharePath;
2510         int shareFound;
2511         char *tp;
2512         char *pathp;
2513         char *passwordp;
2514         cm_user_t *userp;
2515         
2516         osi_Log0(afsd_logp, "SMB receive tree connect");
2517
2518         /* parse input parameters */
2519         tp = smb_GetSMBData(inp, NULL);
2520         pathp = smb_ParseASCIIBlock(tp, &tp);
2521         passwordp = smb_ParseASCIIBlock(tp, &tp);
2522         tp = strrchr(pathp, '\\');
2523         if (!tp)
2524                 return CM_ERROR_BADSMB;
2525         strcpy(shareName, tp+1);
2526
2527         userp = smb_GetUser(vcp, inp);
2528
2529         lock_ObtainMutex(&vcp->mx);
2530         newTid = vcp->tidCounter++;
2531         lock_ReleaseMutex(&vcp->mx);
2532         
2533         tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
2534         shareFound = smb_FindShare(vcp, inp, shareName, &sharePath);
2535         if (!shareFound) {
2536                 smb_ReleaseTID(tidp);
2537                 return CM_ERROR_BADSHARENAME;
2538         }
2539         lock_ObtainMutex(&tidp->mx);
2540         tidp->userp = userp;
2541         tidp->pathname = sharePath;
2542         lock_ReleaseMutex(&tidp->mx);
2543         smb_ReleaseTID(tidp);
2544
2545         smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
2546         smb_SetSMBParm(rsp, 1, newTid);
2547         smb_SetSMBDataLength(rsp, 0);
2548         
2549         osi_Log1(afsd_logp, "SMB tree connect created ID %d", newTid);
2550         return 0;
2551 }
2552
2553 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2554 {
2555         int tlen;
2556
2557         if (*inp++ != 0x1) return NULL;
2558         tlen = inp[0] + (inp[1]<<8);
2559         inp += 2;               /* skip length field */
2560         
2561         if (chainpp) {
2562                 *chainpp = inp + tlen;
2563         }
2564         
2565         if (lengthp) *lengthp = tlen;
2566         
2567         return inp;
2568 }
2569
2570 /* set maskp to the mask part of the incoming path.
2571  * Mask is 11 bytes long (8.3 with the dot elided).
2572  * Returns true if succeeds with a valid name, otherwise it does
2573  * its best, but returns false.
2574  */
2575 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
2576 {
2577         char *tp;
2578         char *up;
2579         int i;
2580         int tc;
2581         int valid8Dot3;
2582
2583         /* starts off valid */
2584         valid8Dot3 = 1;
2585
2586         /* mask starts out all blanks */
2587         memset(maskp, ' ', 11);
2588
2589         /* find last backslash, or use whole thing if there is none */
2590         tp = strrchr(pathp, '\\');
2591         if (!tp) tp = pathp;
2592         else tp++;      /* skip slash */
2593         
2594         up = maskp;
2595
2596         /* names starting with a dot are illegal */
2597         if (*tp == '.') valid8Dot3 = 0;
2598
2599         for(i=0;; i++) {
2600                 tc = *tp++;
2601                 if (tc == 0) return valid8Dot3;
2602                 if (tc == '.' || tc == '"') break;
2603                 if (i < 8) *up++ = tc;
2604                 else valid8Dot3 = 0;
2605         }
2606         
2607         /* if we get here, tp point after the dot */
2608         up = maskp+8;   /* ext goes here */
2609         for(i=0;;i++) {
2610                 tc = *tp++;
2611                 if (tc == 0) return valid8Dot3;
2612                 
2613                 /* too many dots */
2614                 if (tc == '.' || tc == '"') valid8Dot3 = 0;
2615
2616                 /* copy extension if not too long */
2617                 if (i < 3) *up++ = tc;
2618                 else valid8Dot3 = 0;
2619         }
2620 }
2621
2622 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
2623 {
2624         char umask[11];
2625         int valid;
2626         int i;
2627         char tc1;
2628         char tc2;
2629         char *tp1;
2630         char *tp2;
2631         
2632         /* XXX redo this, calling smb_V3MatchMask with a converted mask */
2633
2634         valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
2635         if (!valid) return 0;
2636  
2637         /* otherwise, we have a valid 8.3 name; see if we have a match,
2638          * treating '?' as a wildcard in maskp (but not in the file name).
2639          */
2640         tp1 = umask;    /* real name, in mask format */
2641         tp2 = maskp;    /* mask, in mask format */
2642         for(i=0; i<11; i++) {
2643                 tc1 = *tp1++;   /* char from real name */
2644                 tc2 = *tp2++;   /* char from mask */
2645                 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
2646                 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
2647                 if (tc1 == tc2) continue;
2648                 if (tc2 == '?' && tc1 != ' ') continue;
2649                 if (tc2 == '>') continue;
2650                 return 0;
2651         }
2652
2653         /* we got a match */
2654         return 1;
2655 }
2656
2657 char *smb_FindMask(char *pathp)
2658 {
2659         char *tp;
2660         
2661         tp = strrchr(pathp, '\\');      /* find last slash */
2662
2663         if (tp) return tp+1;    /* skip the slash */
2664         else return pathp;      /* no slash, return the entire path */
2665 }
2666
2667 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2668 {
2669         unsigned char *pathp;
2670         unsigned char *tp;
2671         unsigned char mask[11];
2672         unsigned char *statBlockp;
2673         unsigned char initStatBlock[21];
2674         int statLen;
2675         
2676         osi_Log0(afsd_logp, "SMB receive search volume");
2677
2678         /* pull pathname and stat block out of request */
2679         tp = smb_GetSMBData(inp, NULL);
2680         pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
2681         osi_assert(pathp != NULL);
2682         statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
2683         osi_assert(statBlockp != NULL);
2684         if (statLen == 0) {
2685                 statBlockp = initStatBlock;
2686                 statBlockp[0] = 8;
2687         }
2688         
2689         /* for returning to caller */
2690         smb_Get8Dot3MaskFromPath(mask, pathp);
2691         
2692         smb_SetSMBParm(outp, 0, 1);             /* we're returning one entry */
2693         tp = smb_GetSMBData(outp, NULL);
2694         *tp++ = 5;
2695         *tp++ = 43;     /* bytes in a dir entry */
2696         *tp++ = 0;      /* high byte in counter */
2697         
2698         /* now marshall the dir entry, starting with the search status */
2699         *tp++ = statBlockp[0];          /* Reserved */
2700         memcpy(tp, mask, 11); tp += 11; /* FileName */
2701
2702         /* now pass back server use info, with 1st byte non-zero */
2703         *tp++ = 1;
2704         memset(tp, 0, 4); tp += 4;      /* reserved for server use */
2705         
2706         memcpy(tp, statBlockp+17, 4); tp += 4;  /* reserved for consumer */
2707         
2708         *tp++ = 0x8;            /* attribute: volume */
2709
2710         /* copy out time */
2711         *tp++ = 0;
2712         *tp++ = 0;
2713         
2714         /* copy out date */
2715         *tp++ = 18;
2716         *tp++ = 178;
2717         
2718         /* 4 byte file size */
2719         *tp++ = 0;
2720         *tp++ = 0;
2721         *tp++ = 0;
2722         *tp++ = 0;
2723
2724         /* finally, null-terminated 8.3 pathname, which we set to AFS */
2725         memset(tp, ' ', 13);
2726         strcpy(tp, "AFS");
2727         
2728         /* set the length of the data part of the packet to 43 + 3, for the dir
2729          * entry plus the 5 and the length fields.
2730          */
2731         smb_SetSMBDataLength(outp, 46);
2732         return 0;
2733 }
2734
2735 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
2736         cm_user_t *userp, cm_req_t *reqp)
2737 {
2738         long code;
2739         cm_scache_t *scp;
2740         char *dptr;
2741         long dosTime;
2742         u_short shortTemp;
2743         char attr;
2744         smb_dirListPatch_t *patchp;
2745         smb_dirListPatch_t *npatchp;
2746         
2747         for(patchp = *dirPatchespp; patchp; patchp =
2748                 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
2749                 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
2750                 if (code) continue;
2751                 lock_ObtainMutex(&scp->mx);
2752                 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
2753                         CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2754                 if (code) {
2755                         lock_ReleaseMutex(&scp->mx);
2756                         cm_ReleaseSCache(scp);
2757                         continue;
2758                 }
2759                 dptr = patchp->dptr;
2760
2761                 attr = smb_Attributes(scp);
2762                 *dptr++ = attr;
2763
2764                 /* get dos time */
2765                 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2766                 
2767                 /* copy out time */
2768                 shortTemp = dosTime & 0xffff;
2769                 *((u_short *)dptr) = shortTemp;
2770                 dptr += 2;
2771
2772                 /* and copy out date */
2773                 shortTemp = (dosTime>>16) & 0xffff;
2774                 *((u_short *)dptr) = shortTemp;
2775                 dptr += 2;
2776                 
2777                 /* copy out file length */
2778                 *((u_long *)dptr) = scp->length.LowPart;
2779                 dptr += 4;
2780                 lock_ReleaseMutex(&scp->mx);
2781                 cm_ReleaseSCache(scp);
2782         }
2783         
2784         /* now free the patches */
2785         for(patchp = *dirPatchespp; patchp; patchp = npatchp) {
2786                 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
2787                 free(patchp);
2788         }
2789         
2790         /* and mark the list as empty */
2791         *dirPatchespp = NULL;
2792
2793         return code;
2794 }
2795
2796 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2797 {
2798         int attribute;
2799         long nextCookie;
2800         char *tp;
2801         long code;
2802         char *pathp;
2803         cm_dirEntry_t *dep;
2804         int maxCount;
2805         smb_dirListPatch_t *dirListPatchesp;
2806         smb_dirListPatch_t *curPatchp;
2807         int dataLength;
2808         cm_buf_t *bufferp;
2809         long temp;
2810         osi_hyper_t dirLength;
2811         osi_hyper_t bufferOffset;
2812         osi_hyper_t curOffset;
2813         osi_hyper_t thyper;
2814         unsigned char *inCookiep;
2815         smb_dirSearch_t *dsp;
2816         cm_scache_t *scp;
2817         long entryInDir;
2818         long entryInBuffer;
2819         unsigned long clientCookie;
2820         cm_pageHeader_t *pageHeaderp;
2821         cm_user_t *userp = NULL;
2822         int slotInPage;
2823         char shortName[13];
2824         char *actualName;
2825         char *shortNameEnd;
2826         char mask[11];
2827         int returnedNames;
2828         long nextEntryCookie;
2829         int numDirChunks;               /* # of 32 byte dir chunks in this entry */
2830         char resByte;                   /* reserved byte from the cookie */
2831         char *op;                       /* output data ptr */
2832         char *origOp;                   /* original value of op */
2833         cm_space_t *spacep;             /* for pathname buffer */
2834         int starPattern;
2835         int rootPath = 0;
2836         int caseFold;
2837         char *tidPathp;
2838         cm_req_t req;
2839         cm_fid_t fid;
2840         int fileType;
2841
2842         cm_InitReq(&req);
2843
2844         maxCount = smb_GetSMBParm(inp, 0);
2845
2846         dirListPatchesp = NULL;
2847         
2848         caseFold = CM_FLAG_CASEFOLD;
2849
2850         tp = smb_GetSMBData(inp, NULL);
2851         pathp = smb_ParseASCIIBlock(tp, &tp);
2852         inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
2853         
2854         /* bail out if request looks bad */
2855         if (!tp || !pathp) {
2856                 return CM_ERROR_BADSMB;
2857         }
2858
2859         /* We can handle long names */
2860         if (vcp->flags & SMB_VCFLAG_USENT)
2861                 ((smb_t *)outp)->flg2 |= 0x40;  /* IS_LONG_NAME */
2862         
2863         /* make sure we got a whole search status */
2864         if (dataLength < 21) {
2865                 nextCookie = 0;         /* start at the beginning of the dir */
2866                 resByte = 0;
2867                 clientCookie = 0;
2868                 attribute = smb_GetSMBParm(inp, 1);
2869
2870                 /* handle volume info in another function */
2871                 if (attribute & 0x8)
2872                         return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
2873
2874                 osi_Log2(afsd_logp, "SMB receive search dir count %d |%s|",
2875                          maxCount, osi_LogSaveString(afsd_logp, pathp));
2876
2877                 if (*pathp == 0) {      /* null pathp, treat as root dir */
2878                         if (!(attribute & 0x10))        /* exclude dirs */
2879                                 return CM_ERROR_NOFILES;
2880                         rootPath = 1;
2881                 }
2882
2883                 dsp = smb_NewDirSearch(0);
2884                 dsp->attribute = attribute;
2885                 smb_Get8Dot3MaskFromPath(mask, pathp);
2886                 memcpy(dsp->mask, mask, 11);
2887
2888                 /* track if this is likely to match a lot of entries */
2889                 if (smb_IsStarMask(mask)) starPattern = 1;
2890                 else starPattern = 0;
2891         }
2892         else {
2893                 /* pull the next cookie value out of the search status block */
2894                 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
2895                         + (inCookiep[16]<<24);
2896                 dsp = smb_FindDirSearch(inCookiep[12]);
2897                 if (!dsp) {
2898                         /* can't find dir search status; fatal error */
2899                         return CM_ERROR_BADFD;
2900                 }
2901                 attribute = dsp->attribute;
2902                 resByte = inCookiep[0];
2903
2904                 /* copy out client cookie, in host byte order.  Don't bother
2905                  * interpreting it, since we're just passing it through, anyway.
2906                  */
2907                 memcpy(&clientCookie, &inCookiep[17], 4);
2908
2909                 memcpy(mask, dsp->mask, 11);
2910
2911                 /* assume we're doing a star match if it has continued for more
2912                  * than one call.
2913                  */
2914                 starPattern = 1;
2915         }
2916
2917         osi_Log3(afsd_logp, "SMB dir search cookie 0x%x, connection %d, attr 0x%x",
2918                 nextCookie, dsp->cookie, attribute);
2919
2920         userp = smb_GetUser(vcp, inp);
2921
2922         /* try to get the vnode for the path name next */
2923         lock_ObtainMutex(&dsp->mx);
2924         if (dsp->scp) {
2925                 scp = dsp->scp;
2926                 cm_HoldSCache(scp);
2927                 code = 0;
2928         }
2929         else {
2930                 spacep = inp->spacep;
2931                 smb_StripLastComponent(spacep->data, NULL, pathp);
2932                 lock_ReleaseMutex(&dsp->mx);
2933                 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
2934                 code = cm_NameI(cm_rootSCachep, spacep->data,
2935                         caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
2936                 lock_ObtainMutex(&dsp->mx);
2937                 if (code == 0) {
2938                         if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
2939                         dsp->scp = scp;
2940                         /* we need one hold for the entry we just stored into,
2941                          * and one for our own processing.  When we're done with this
2942                          * function, we'll drop the one for our own processing.
2943                          * We held it once from the namei call, and so we do another hold
2944                          * now.
2945                          */
2946                         cm_HoldSCache(scp);
2947                         lock_ObtainMutex(&scp->mx);
2948                         if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
2949                             && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
2950                                 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
2951                                 dsp->flags |= SMB_DIRSEARCH_BULKST;
2952                         }
2953                         lock_ReleaseMutex(&scp->mx);
2954                 }
2955         }
2956         lock_ReleaseMutex(&dsp->mx);
2957         if (code) {
2958                 cm_ReleaseUser(userp);
2959                 smb_DeleteDirSearch(dsp);
2960                 smb_ReleaseDirSearch(dsp);
2961                 return code;
2962         }
2963
2964         /* reserves space for parameter; we'll adjust it again later to the
2965          * real count of the # of entries we returned once we've actually
2966          * assembled the directory listing.
2967          */
2968         smb_SetSMBParm(outp, 0, 0);
2969         
2970         /* get the directory size */
2971         lock_ObtainMutex(&scp->mx);
2972         code = cm_SyncOp(scp, NULL, userp, &req, 0,
2973                 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2974         if (code) {
2975                 lock_ReleaseMutex(&scp->mx);
2976                 cm_ReleaseSCache(scp);
2977                 cm_ReleaseUser(userp);
2978                 smb_DeleteDirSearch(dsp);
2979                 smb_ReleaseDirSearch(dsp);
2980                 return code;
2981         }
2982         
2983         dirLength = scp->length;
2984         bufferp = NULL;
2985         bufferOffset.LowPart = bufferOffset.HighPart = 0;
2986         curOffset.HighPart = 0;
2987         curOffset.LowPart = nextCookie;
2988         origOp = op = smb_GetSMBData(outp, NULL);
2989         /* and write out the basic header */
2990         *op++ = 5;              /* variable block */
2991         op += 2;                /* skip vbl block length; we'll fill it in later */
2992         code = 0;
2993         returnedNames = 0;
2994         while (1) {
2995                 /* make sure that curOffset.LowPart doesn't point to the first
2996                  * 32 bytes in the 2nd through last dir page, and that it doesn't
2997                  * point at the first 13 32-byte chunks in the first dir page,
2998                  * since those are dir and page headers, and don't contain useful
2999                  * information.
3000                  */
3001                 temp = curOffset.LowPart & (2048-1);
3002                 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3003                         /* we're in the first page */
3004                         if (temp < 13*32) temp = 13*32;
3005                 }
3006                 else {
3007                         /* we're in a later dir page */
3008                         if (temp < 32) temp = 32;
3009                 }
3010                 
3011                 /* make sure the low order 5 bits are zero */
3012                 temp &= ~(32-1);
3013                 
3014                 /* now put temp bits back ito curOffset.LowPart */
3015                 curOffset.LowPart &= ~(2048-1);
3016                 curOffset.LowPart |= temp;
3017
3018                 /* check if we've returned all the names that will fit in the
3019                  * response packet.
3020                  */
3021                 if (returnedNames >= maxCount) break;
3022                 
3023                 /* check if we've passed the dir's EOF */
3024                 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
3025                 
3026                 /* see if we can use the bufferp we have now; compute in which page
3027                  * the current offset would be, and check whether that's the offset
3028                  * of the buffer we have.  If not, get the buffer.
3029                  */
3030                 thyper.HighPart = curOffset.HighPart;
3031                 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
3032                 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3033                         /* wrong buffer */
3034                         if (bufferp) {
3035                                 buf_Release(bufferp);
3036                                 bufferp = NULL;
3037                         }
3038                         lock_ReleaseMutex(&scp->mx);
3039                         lock_ObtainRead(&scp->bufCreateLock);
3040                         code = buf_Get(scp, &thyper, &bufferp);
3041                         lock_ReleaseRead(&scp->bufCreateLock);
3042
3043                         /* now, if we're doing a star match, do bulk fetching of all of 
3044                          * the status info for files in the dir.
3045                          */
3046                         if (starPattern) {
3047                                 smb_ApplyDirListPatches(&dirListPatchesp, userp,
3048                                                         &req);
3049                                 if ((dsp->flags & SMB_DIRSEARCH_BULKST)
3050                                     && LargeIntegerGreaterThanOrEqualTo(thyper, 
3051                                                                         scp->bulkStatProgress)) {
3052                                   /* Don't bulk stat if risking timeout */
3053                                   int now = GetCurrentTime();
3054                                   if (now - req.startTime > 5000) {
3055                                     scp->bulkStatProgress = thyper;
3056                                     scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3057                                     dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3058                                   } else
3059                                     cm_TryBulkStat(scp, &thyper,
3060                                                    userp, &req);
3061                                 }
3062                         }
3063
3064                         lock_ObtainMutex(&scp->mx);
3065                         if (code) break;
3066                         bufferOffset = thyper;
3067
3068                         /* now get the data in the cache */
3069                         while (1) {
3070                                 code = cm_SyncOp(scp, bufferp, userp, &req,
3071                                         PRSFS_LOOKUP,
3072                                         CM_SCACHESYNC_NEEDCALLBACK
3073                                         | CM_SCACHESYNC_READ);
3074                                 if (code) break;
3075                                 
3076                                 if (cm_HaveBuffer(scp, bufferp, 0)) break;
3077                                 
3078                                 /* otherwise, load the buffer and try again */
3079                                 code = cm_GetBuffer(scp, bufferp, NULL, userp,
3080                                                     &req);
3081                                 if (code) break;
3082                         }
3083                         if (code) {
3084                                 buf_Release(bufferp);
3085                                 bufferp = NULL;
3086                                 break;
3087                         }
3088                 }       /* if (wrong buffer) ... */
3089                 
3090                 /* now we have the buffer containing the entry we're interested in; copy
3091                  * it out if it represents a non-deleted entry.
3092                  */
3093                 entryInDir = curOffset.LowPart & (2048-1);
3094                 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
3095
3096                 /* page header will help tell us which entries are free.  Page header
3097                  * can change more often than once per buffer, since AFS 3 dir page size
3098                  * may be less than (but not more than a buffer package buffer.
3099                  */
3100                 temp = curOffset.LowPart & (buf_bufferSize - 1);  /* only look intra-buffer */
3101                 temp &= ~(2048 - 1);    /* turn off intra-page bits */
3102                 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3103
3104                 /* now determine which entry we're looking at in the page.  If it is
3105                  * free (there's a free bitmap at the start of the dir), we should
3106                  * skip these 32 bytes.
3107                  */
3108                 slotInPage = (entryInDir & 0x7e0) >> 5;
3109                 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
3110                         /* this entry is free */
3111                         numDirChunks = 1;               /* only skip this guy */
3112                         goto nextEntry;
3113                 }
3114
3115                 tp = bufferp->datap + entryInBuffer;
3116                 dep = (cm_dirEntry_t *) tp;             /* now points to AFS3 dir entry */
3117
3118                 /* while we're here, compute the next entry's location, too,
3119                  * since we'll need it when writing out the cookie into the dir
3120                  * listing stream.
3121                  *
3122                  * XXXX Probably should do more sanity checking.
3123                  */
3124                 numDirChunks = cm_NameEntries(dep->name, NULL);
3125                 
3126                 /* compute the offset of the cookie representing the next entry */
3127                 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3128
3129                 /* Compute 8.3 name if necessary */
3130                 actualName = dep->name;
3131                 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
3132                         cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3133                         actualName = shortName;
3134                 }
3135
3136                 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
3137                         /* this is one of the entries to use: it is not deleted
3138                          * and it matches the star pattern we're looking for.
3139                          */
3140
3141                         /* Eliminate entries that don't match requested
3142                            attributes */
3143                         if (!(dsp->attribute & 0x10))  /* no directories */
3144                         {
3145                            /* We have already done the cm_TryBulkStat above */
3146                            fid.cell = scp->fid.cell;
3147                            fid.volume = scp->fid.volume;
3148                            fid.vnode = ntohl(dep->fid.vnode);
3149                            fid.unique = ntohl(dep->fid.unique);
3150                            fileType = cm_FindFileType(&fid);
3151                            osi_Log2(afsd_logp, "smb_ReceiveCoreSearchDir: file %s "
3152                                     "has filetype %d", dep->name,
3153                                     fileType);
3154                            if (fileType == CM_SCACHETYPE_DIRECTORY)
3155                               goto nextEntry;
3156                         }
3157
3158                         *op++ = resByte;
3159                         memcpy(op, mask, 11); op += 11;
3160                         *op++ = (char) dsp->cookie;     /* they say it must be non-zero */
3161                         *op++ = nextEntryCookie & 0xff;
3162                         *op++ = (nextEntryCookie>>8) & 0xff;
3163                         *op++ = (nextEntryCookie>>16) & 0xff;
3164                         *op++ = (nextEntryCookie>>24) & 0xff;
3165                         memcpy(op, &clientCookie, 4); op += 4;
3166                         
3167                         /* now we emit the attribute.  This is sort of tricky,
3168                          * since we need to really stat the file to find out
3169                          * what type of entry we've got.  Right now, we're
3170                          * copying out data from a buffer, while holding the
3171                          * scp locked, so it isn't really convenient to stat
3172                          * something now.  We'll put in a place holder now,
3173                          * and make a second pass before returning this to get
3174                          * the real attributes.  So, we just skip the data for
3175                          * now, and adjust it later.  We allocate a patch
3176                          * record to make it easy to find this point later.
3177                          * The replay will happen at a time when it is safe to
3178                          * unlock the directory.
3179                          */
3180                         curPatchp = malloc(sizeof(*curPatchp));
3181                         osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
3182                         curPatchp->dptr = op;
3183                         curPatchp->fid.cell = scp->fid.cell;
3184                         curPatchp->fid.volume = scp->fid.volume;
3185                         curPatchp->fid.vnode = ntohl(dep->fid.vnode);
3186                         curPatchp->fid.unique = ntohl(dep->fid.unique);
3187                         op += 9;        /* skip attr, time, date and size */
3188                         
3189                         /* zero out name area.  The spec says to pad with
3190                          * spaces, but Samba doesn't, and neither do we.
3191                          */
3192                         memset(op, 0, 13);
3193
3194                         /* finally, we get to copy out the name; we know that
3195                          * it fits in 8.3 or the pattern wouldn't match, but it
3196                          * never hurts to be sure.
3197                          */
3198                         strncpy(op, actualName, 13);
3199
3200                         /* Uppercase if requested by client */
3201                         if ((((smb_t *)inp)->flg2 & 1) == 0)
3202                                 _strupr(op);
3203
3204                         op += 13;
3205
3206                         /* now, adjust the # of entries copied */
3207                         returnedNames++;
3208                 }       /* if we're including this name */
3209                 
3210 nextEntry:
3211                 /* and adjust curOffset to be where the new cookie is */
3212                 thyper.HighPart = 0;
3213                 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
3214                 curOffset = LargeIntegerAdd(thyper, curOffset);
3215         }               /* while copying data for dir listing */
3216
3217         /* release the mutex */
3218         lock_ReleaseMutex(&scp->mx);
3219         if (bufferp) buf_Release(bufferp);
3220
3221         /* apply and free last set of patches; if not doing a star match, this
3222          * will be empty, but better safe (and freeing everything) than sorry.
3223          */
3224         smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3225
3226         /* special return code for unsuccessful search */
3227         if (code == 0 && dataLength < 21 && returnedNames == 0)
3228                 code = CM_ERROR_NOFILES;
3229
3230         osi_Log2(afsd_logp, "SMB search dir done, %d names, code %d",
3231                  returnedNames, code);
3232
3233         if (code != 0) {
3234                 smb_DeleteDirSearch(dsp);
3235                 smb_ReleaseDirSearch(dsp);
3236                 cm_ReleaseSCache(scp);
3237                 cm_ReleaseUser(userp);
3238                 return code;
3239         }
3240
3241         /* finalize the output buffer */
3242         smb_SetSMBParm(outp, 0, returnedNames);
3243         temp = (long) (op - origOp);
3244         smb_SetSMBDataLength(outp, temp);
3245
3246         /* the data area is a variable block, which has a 5 (already there)
3247          * followed by the length of the # of data bytes.  We now know this to
3248          * be "temp," although that includes the 3 bytes of vbl block header.
3249          * Deduct for them and fill in the length field.
3250          */
3251         temp -= 3;              /* deduct vbl block info */
3252         osi_assert(temp == (43 * returnedNames));
3253         origOp[1] = temp & 0xff;
3254         origOp[2] = (temp>>8) & 0xff;
3255         if (returnedNames == 0) smb_DeleteDirSearch(dsp);
3256         smb_ReleaseDirSearch(dsp);
3257         cm_ReleaseSCache(scp);
3258         cm_ReleaseUser(userp);
3259         return code;
3260 }
3261
3262 /* verify that this is a valid path to a directory.  I don't know why they
3263  * don't use the get file attributes call.
3264  */
3265 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3266 {
3267         char *pathp;
3268         long code;
3269         cm_scache_t *rootScp;
3270         cm_scache_t *newScp;
3271         cm_user_t *userp;
3272         unsigned int attrs;
3273         int caseFold;
3274         char *tidPathp;
3275         cm_req_t req;
3276
3277         cm_InitReq(&req);
3278
3279         pathp = smb_GetSMBData(inp, NULL);
3280         pathp = smb_ParseASCIIBlock(pathp, NULL);
3281         osi_Log1(afsd_logp, "SMB receive check path %s",
3282                         osi_LogSaveString(afsd_logp, pathp));
3283         
3284         if (!pathp) {
3285                 return CM_ERROR_BADFD;
3286         }
3287         
3288         rootScp = cm_rootSCachep;
3289         
3290         userp = smb_GetUser(vcp, inp);
3291
3292         caseFold = CM_FLAG_CASEFOLD;
3293
3294         tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3295         code = cm_NameI(rootScp, pathp,
3296                         caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
3297                         userp, tidPathp, &req, &newScp);
3298
3299         if (code) {
3300                 cm_ReleaseUser(userp);
3301                 return code;
3302         }
3303         
3304         /* now lock the vnode with a callback; returns with newScp locked */
3305         lock_ObtainMutex(&newScp->mx);
3306         code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
3307                 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3308         if (code && code != CM_ERROR_NOACCESS) {
3309                 lock_ReleaseMutex(&newScp->mx);
3310                 cm_ReleaseSCache(newScp);
3311                 cm_ReleaseUser(userp);
3312                 return code;
3313         }
3314
3315         attrs = smb_Attributes(newScp);
3316
3317         if (!(attrs & 0x10))
3318                 code = CM_ERROR_NOTDIR;
3319
3320         lock_ReleaseMutex(&newScp->mx);
3321         
3322         cm_ReleaseSCache(newScp);
3323         cm_ReleaseUser(userp);
3324         return code;
3325 }
3326
3327 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3328 {
3329         char *pathp;
3330         long code;
3331         cm_scache_t *rootScp;
3332         unsigned short attribute;
3333         cm_attr_t attr;
3334         cm_scache_t *newScp;
3335         long dosTime;
3336         cm_user_t *userp;
3337         int caseFold;
3338         char *tidPathp;
3339         cm_req_t req;
3340
3341         cm_InitReq(&req);
3342
3343         /* decode basic attributes we're passed */
3344         attribute = smb_GetSMBParm(inp, 0);
3345         dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3346
3347         pathp = smb_GetSMBData(inp, NULL);
3348         pathp = smb_ParseASCIIBlock(pathp, NULL);
3349         
3350         if (!pathp) {
3351                 return CM_ERROR_BADSMB;
3352         }
3353         
3354         osi_Log2(afsd_logp, "SMB receive setfile attributes time %d, attr 0x%x",
3355                 dosTime, attribute);
3356
3357         rootScp = cm_rootSCachep;
3358         
3359         userp = smb_GetUser(vcp, inp);
3360
3361         caseFold = CM_FLAG_CASEFOLD;
3362
3363         tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3364         code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
3365                         tidPathp, &req, &newScp);
3366
3367         if (code) {
3368                 cm_ReleaseUser(userp);
3369                 return code;
3370         }
3371         
3372         /* now lock the vnode with a callback; returns with newScp locked; we
3373          * need the current status to determine what the new status is, in some
3374          * cases.
3375          */
3376         lock_ObtainMutex(&newScp->mx);
3377         code = cm_SyncOp(newScp, NULL, userp, &req, 0,
3378                 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3379         if (code) {
3380                 lock_ReleaseMutex(&newScp->mx);
3381                 cm_ReleaseSCache(newScp);
3382                 cm_ReleaseUser(userp);
3383                 return code;
3384         }
3385
3386         /* Check for RO volume */
3387         if (newScp->flags & CM_SCACHEFLAG_RO) {
3388                 lock_ReleaseMutex(&newScp->mx);
3389                 cm_ReleaseSCache(newScp);
3390                 cm_ReleaseUser(userp);
3391                 return CM_ERROR_READONLY;
3392         }
3393
3394         /* prepare for setattr call */
3395         attr.mask = 0;
3396         if (dosTime != 0) {
3397                 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3398                 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
3399         }
3400         if ((newScp->unixModeBits & 0222) && (attribute & 1) != 0) {
3401                 /* we're told to make a writable file read-only */
3402                 attr.unixModeBits = newScp->unixModeBits & ~0222;
3403                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3404         }
3405         else if ((newScp->unixModeBits & 0222) == 0 && (attribute & 1) == 0) {
3406                 /* we're told to make a read-only file writable */
3407                 attr.unixModeBits = newScp->unixModeBits | 0222;
3408                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3409         }
3410         lock_ReleaseMutex(&newScp->mx);
3411
3412         /* now call setattr */
3413         if (attr.mask)
3414                 code = cm_SetAttr(newScp, &attr, userp, &req);
3415         else
3416                 code = 0;
3417         
3418         cm_ReleaseSCache(newScp);