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