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