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