windows-smb-and-symlinks-20041213
[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 = SMB_FLAGS2_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          * and DFS */
2769         caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
2770 #ifdef DFS_SUPPORT
2771                NTNEGOTIATE_CAPABILITY_DFS |
2772 #endif
2773                NTNEGOTIATE_CAPABILITY_NTFIND |
2774                NTNEGOTIATE_CAPABILITY_RAWMODE |
2775                NTNEGOTIATE_CAPABILITY_NTSMB;
2776
2777         if ( smb_authType == SMB_AUTH_EXTENDED )
2778             caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
2779
2780         smb_SetSMBParmLong(outp, 9, caps);
2781         time(&unixTime);
2782         smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2783         smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
2784         smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
2785
2786         GetTimeZoneInformation(&tzi);
2787         smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias);    /* server tzone */
2788
2789         if (smb_authType == SMB_AUTH_NTLM) {
2790             smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
2791             smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
2792             /* paste in encryption key */
2793             datap = smb_GetSMBData(outp, NULL);
2794             memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
2795             /* and the faux domain name */
2796             strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
2797         } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
2798             void * secBlob;
2799             int secBlobLength;
2800
2801             smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2802
2803             smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
2804
2805             smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
2806                         
2807             datap = smb_GetSMBData(outp, NULL);
2808             memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
2809
2810             if (secBlob) {
2811                 datap += sizeof(smb_ServerGUID);
2812                 memcpy(datap, secBlob, secBlobLength);
2813                 free(secBlob);
2814             }
2815         } else {
2816             smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2817             smb_SetSMBDataLength(outp, 0);   /* Perhaps we should specify 8 bytes anyway */
2818         }
2819     }
2820     else if (v3ProtoIndex != -1) {
2821         smb_SetSMBParm(outp, 0, protoIndex);
2822
2823         /* NOTE: Extended authentication cannot be negotiated with v3
2824          * therefore we fail over to NTLM 
2825          */
2826         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2827             smb_SetSMBParm(outp, 1,
2828                            NEGOTIATE_SECURITY_USER_LEVEL |
2829                            NEGOTIATE_SECURITY_CHALLENGE_RESPONSE);      /* user level security, challenge response */
2830         } else {
2831             smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
2832         }
2833         smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
2834         smb_SetSMBParm(outp, 3, smb_maxMpxRequests);    /* max multiplexed requests */
2835         smb_SetSMBParm(outp, 4, smb_maxVCPerServer);    /* max VCs per consumer/server connection */
2836         smb_SetSMBParm(outp, 5, 0);     /* no support of block mode for read or write */
2837         smb_SetSMBParm(outp, 6, 1);     /* next 2: session key */
2838         smb_SetSMBParm(outp, 7, 1);
2839         time(&unixTime);
2840         smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2841         smb_SetSMBParm(outp, 8, LOWORD(dosTime));       /* server time */
2842         smb_SetSMBParm(outp, 9, HIWORD(dosTime));       /* server date */
2843
2844         GetTimeZoneInformation(&tzi);
2845         smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias);    /* server tzone */
2846
2847         /* NOTE: Extended authentication cannot be negotiated with v3
2848          * therefore we fail over to NTLM 
2849          */
2850         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2851             smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH);  /* encryption key length */
2852             smb_SetSMBParm(outp, 12, 0);        /* resvd */
2853             smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);   /* perhaps should specify 8 bytes anyway */
2854             datap = smb_GetSMBData(outp, NULL);
2855             /* paste in a new encryption key */
2856             memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
2857             /* and the faux domain name */
2858             strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
2859         } else {
2860             smb_SetSMBParm(outp, 11, 0); /* encryption key length */
2861             smb_SetSMBParm(outp, 12, 0); /* resvd */
2862             smb_SetSMBDataLength(outp, 0);
2863         }
2864     }
2865     else if (coreProtoIndex != -1) {     /* not really supported anymore */
2866         smb_SetSMBParm(outp, 0, protoIndex);
2867         smb_SetSMBDataLength(outp, 0);
2868     }
2869     return 0;
2870 }
2871
2872 void smb_Daemon(void *parmp)
2873 {
2874     afs_uint32 count = 0;
2875
2876     while(smbShutdownFlag == 0) {
2877         count++;
2878         thrd_Sleep(10000);
2879
2880         if (smbShutdownFlag == 1)
2881             break;
2882         
2883         if ((count % 72) == 0)  {       /* every five minutes */
2884             struct tm myTime;
2885             time_t old_localZero = smb_localZero;
2886                  
2887             /* Initialize smb_localZero */
2888             myTime.tm_isdst = -1;               /* compute whether on DST or not */
2889             myTime.tm_year = 70;
2890             myTime.tm_mon = 0;
2891             myTime.tm_mday = 1;
2892             myTime.tm_hour = 0;
2893             myTime.tm_min = 0;
2894             myTime.tm_sec = 0;
2895             smb_localZero = mktime(&myTime);
2896
2897             smb_CalculateNowTZ();
2898
2899 #ifdef AFS_FREELANCE
2900             if ( smb_localZero != old_localZero )
2901                 cm_noteLocalMountPointChange();
2902 #endif
2903         }
2904         /* XXX GC dir search entries */
2905     }
2906 }
2907
2908 void smb_WaitingLocksDaemon()
2909 {
2910     smb_waitingLock_t *wL, *nwL;
2911     int first;
2912     smb_vc_t *vcp;
2913     smb_packet_t *inp, *outp;
2914     NCB *ncbp;
2915     long code = 0;
2916
2917     while (1) {
2918         lock_ObtainWrite(&smb_globalLock);
2919         nwL = smb_allWaitingLocks;
2920         if (nwL == NULL) {
2921             osi_SleepW((long)&smb_allWaitingLocks, &smb_globalLock);
2922             thrd_Sleep(1000);
2923             continue;
2924         }
2925         else first = 1;
2926         do {
2927             if (first)
2928                 first = 0;
2929             else
2930                 lock_ObtainWrite(&smb_globalLock);
2931             wL = nwL;
2932             nwL = (smb_waitingLock_t *) osi_QNext(&wL->q);
2933             lock_ReleaseWrite(&smb_globalLock);
2934             code = cm_RetryLock((cm_file_lock_t *) wL->lockp,
2935                                  wL->vcp->flags & SMB_VCFLAG_ALREADYDEAD);
2936             if (code == CM_ERROR_WOULDBLOCK) {
2937                 /* no progress */
2938                 if (wL->timeRemaining != 0xffffffff
2939                      && (wL->timeRemaining -= 1000) < 0)
2940                     goto endWait;
2941                 continue;
2942             }
2943           endWait:
2944             vcp = wL->vcp;
2945             inp = wL->inp;
2946             outp = wL->outp;
2947             ncbp = GetNCB();
2948             ncbp->ncb_length = inp->ncb_length;
2949             inp->spacep = cm_GetSpace();
2950
2951             /* Remove waitingLock from list */
2952             lock_ObtainWrite(&smb_globalLock);
2953             osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
2954                          &wL->q);
2955             lock_ReleaseWrite(&smb_globalLock);
2956
2957             /* Resume packet processing */
2958             if (code == 0)
2959                 smb_SetSMBDataLength(outp, 0);
2960             outp->flags |= SMB_PACKETFLAG_SUSPENDED;
2961             outp->resumeCode = code;
2962             outp->ncbp = ncbp;
2963             smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
2964
2965             /* Clean up */
2966             cm_FreeSpace(inp->spacep);
2967             smb_FreePacket(inp);
2968             smb_FreePacket(outp);
2969             FreeNCB(ncbp);
2970             free(wL);
2971         } while (nwL);
2972         thrd_Sleep(1000);
2973     }
2974 }
2975
2976 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2977 {
2978     osi_Log0(smb_logp, "SMB receive get disk attributes");
2979
2980     smb_SetSMBParm(outp, 0, 32000);
2981     smb_SetSMBParm(outp, 1, 64);
2982     smb_SetSMBParm(outp, 2, 1024);
2983     smb_SetSMBParm(outp, 3, 30000);
2984     smb_SetSMBParm(outp, 4, 0);
2985     smb_SetSMBDataLength(outp, 0);
2986     return 0;
2987 }
2988
2989 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
2990 {
2991     smb_tid_t *tidp;
2992     smb_user_t *uidp;
2993     unsigned short newTid;
2994     char shareName[256];
2995     char *sharePath;
2996     int shareFound;
2997     char *tp;
2998     char *pathp;
2999     char *passwordp;
3000     cm_user_t *userp;
3001
3002     osi_Log0(smb_logp, "SMB receive tree connect");
3003
3004     /* parse input parameters */
3005     tp = smb_GetSMBData(inp, NULL);
3006     pathp = smb_ParseASCIIBlock(tp, &tp);
3007     if (smb_StoreAnsiFilenames)
3008         OemToChar(pathp,pathp);
3009     passwordp = smb_ParseASCIIBlock(tp, &tp);
3010     tp = strrchr(pathp, '\\');
3011     if (!tp)
3012         return CM_ERROR_BADSMB;
3013     strcpy(shareName, tp+1);
3014
3015     userp = smb_GetUser(vcp, inp);
3016
3017     lock_ObtainMutex(&vcp->mx);
3018     newTid = vcp->tidCounter++;
3019     lock_ReleaseMutex(&vcp->mx);
3020
3021     tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3022     uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3023     shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3024     if (uidp)
3025         smb_ReleaseUID(uidp);
3026     if (!shareFound) {
3027         smb_ReleaseTID(tidp);
3028         return CM_ERROR_BADSHARENAME;
3029     }
3030     lock_ObtainMutex(&tidp->mx);
3031     tidp->userp = userp;
3032     tidp->pathname = sharePath;
3033     lock_ReleaseMutex(&tidp->mx);
3034     smb_ReleaseTID(tidp);
3035
3036     smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3037     smb_SetSMBParm(rsp, 1, newTid);
3038     smb_SetSMBDataLength(rsp, 0);
3039
3040     osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3041     return 0;
3042 }
3043
3044 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3045 {
3046     int tlen;
3047
3048     if (*inp++ != 0x1) return NULL;
3049     tlen = inp[0] + (inp[1]<<8);
3050     inp += 2;           /* skip length field */
3051         
3052     if (chainpp) {
3053         *chainpp = inp + tlen;
3054     }   
3055
3056     if (lengthp) *lengthp = tlen;
3057         
3058     return inp;
3059 }
3060
3061 /* set maskp to the mask part of the incoming path.
3062  * Mask is 11 bytes long (8.3 with the dot elided).
3063  * Returns true if succeeds with a valid name, otherwise it does
3064  * its best, but returns false.
3065  */
3066 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3067 {
3068     char *tp;
3069     char *up;
3070     int i;
3071     int tc;
3072     int valid8Dot3;
3073
3074     /* starts off valid */
3075     valid8Dot3 = 1;
3076
3077     /* mask starts out all blanks */
3078     memset(maskp, ' ', 11);
3079
3080     /* find last backslash, or use whole thing if there is none */
3081     tp = strrchr(pathp, '\\');
3082     if (!tp) tp = pathp;
3083     else tp++;  /* skip slash */
3084         
3085     up = maskp;
3086
3087     /* names starting with a dot are illegal */
3088     if (*tp == '.') valid8Dot3 = 0;
3089
3090     for(i=0;; i++) {
3091         tc = *tp++;
3092         if (tc == 0) return valid8Dot3;
3093         if (tc == '.' || tc == '"') break;
3094         if (i < 8) *up++ = tc;
3095         else valid8Dot3 = 0;
3096     }
3097         
3098     /* if we get here, tp point after the dot */
3099     up = maskp+8;       /* ext goes here */
3100     for(i=0;;i++) {
3101         tc = *tp++;
3102         if (tc == 0) 
3103             return valid8Dot3;
3104
3105         /* too many dots */
3106         if (tc == '.' || tc == '"') 
3107             valid8Dot3 = 0;
3108
3109         /* copy extension if not too long */
3110         if (i < 3) 
3111             *up++ = tc;
3112         else 
3113             valid8Dot3 = 0;
3114     }   
3115
3116     /* unreachable */
3117 }
3118
3119 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3120 {
3121     char umask[11];
3122     int valid;
3123     int i;
3124     char tc1;
3125     char tc2;
3126     char *tp1;
3127     char *tp2;
3128
3129     /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3130
3131     valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3132     if (!valid) 
3133         return 0;
3134  
3135     /* otherwise, we have a valid 8.3 name; see if we have a match,
3136      * treating '?' as a wildcard in maskp (but not in the file name).
3137      */
3138     tp1 = umask;        /* real name, in mask format */
3139     tp2 = maskp;        /* mask, in mask format */
3140     for(i=0; i<11; i++) {
3141         tc1 = *tp1++;   /* char from real name */
3142         tc2 = *tp2++;   /* char from mask */
3143         tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3144         tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3145         if (tc1 == tc2) 
3146             continue;
3147         if (tc2 == '?' && tc1 != ' ') 
3148             continue;
3149         if (tc2 == '>') 
3150             continue;
3151         return 0;
3152     }
3153
3154     /* we got a match */
3155     return 1;
3156 }
3157
3158 char *smb_FindMask(char *pathp)
3159 {
3160     char *tp;
3161         
3162     tp = strrchr(pathp, '\\');  /* find last slash */
3163
3164     if (tp) 
3165         return tp+1;    /* skip the slash */
3166     else 
3167         return pathp;   /* no slash, return the entire path */
3168 }       
3169
3170 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3171 {
3172     unsigned char *pathp;
3173     unsigned char *tp;
3174     unsigned char mask[11];
3175     unsigned char *statBlockp;
3176     unsigned char initStatBlock[21];
3177     int statLen;
3178         
3179     osi_Log0(smb_logp, "SMB receive search volume");
3180
3181     /* pull pathname and stat block out of request */
3182     tp = smb_GetSMBData(inp, NULL);
3183     pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3184     osi_assert(pathp != NULL);
3185     if (smb_StoreAnsiFilenames)
3186         OemToChar(pathp,pathp);
3187     statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3188     osi_assert(statBlockp != NULL);
3189     if (statLen == 0) {
3190         statBlockp = initStatBlock;
3191         statBlockp[0] = 8;
3192     }
3193         
3194     /* for returning to caller */
3195     smb_Get8Dot3MaskFromPath(mask, pathp);
3196
3197     smb_SetSMBParm(outp, 0, 1);         /* we're returning one entry */
3198     tp = smb_GetSMBData(outp, NULL);
3199     *tp++ = 5;
3200     *tp++ = 43; /* bytes in a dir entry */
3201     *tp++ = 0;  /* high byte in counter */
3202
3203     /* now marshall the dir entry, starting with the search status */
3204     *tp++ = statBlockp[0];              /* Reserved */
3205     memcpy(tp, mask, 11); tp += 11;     /* FileName */
3206
3207     /* now pass back server use info, with 1st byte non-zero */
3208     *tp++ = 1;
3209     memset(tp, 0, 4); tp += 4;  /* reserved for server use */
3210
3211     memcpy(tp, statBlockp+17, 4); tp += 4;      /* reserved for consumer */
3212
3213     *tp++ = 0x8;                /* attribute: volume */
3214
3215     /* copy out time */
3216     *tp++ = 0;
3217     *tp++ = 0;
3218
3219     /* copy out date */
3220     *tp++ = 18;
3221     *tp++ = 178;
3222
3223     /* 4 byte file size */
3224     *tp++ = 0;
3225     *tp++ = 0;
3226     *tp++ = 0;
3227     *tp++ = 0;
3228
3229     /* finally, null-terminated 8.3 pathname, which we set to AFS */
3230     memset(tp, ' ', 13);
3231     strcpy(tp, "AFS");
3232
3233     /* set the length of the data part of the packet to 43 + 3, for the dir
3234      * entry plus the 5 and the length fields.
3235      */
3236     smb_SetSMBDataLength(outp, 46);
3237     return 0;
3238 }       
3239
3240 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3241                              cm_user_t *userp, cm_req_t *reqp)
3242 {
3243     long code = 0;
3244     cm_scache_t *scp;
3245     char *dptr;
3246     time_t dosTime;
3247     u_short shortTemp;
3248     char attr;
3249     smb_dirListPatch_t *patchp;
3250     smb_dirListPatch_t *npatchp;
3251
3252     for (patchp = *dirPatchespp; patchp; patchp =
3253          (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3254
3255         dptr = patchp->dptr;
3256
3257         code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3258         if (code) {
3259             if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3260                 *dptr++ = SMB_ATTR_HIDDEN;
3261             continue;
3262         }
3263         lock_ObtainMutex(&scp->mx);
3264         code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3265                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3266         if (code) {     
3267             lock_ReleaseMutex(&scp->mx);
3268             cm_ReleaseSCache(scp);
3269             if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3270                 *dptr++ = SMB_ATTR_HIDDEN;
3271             continue;
3272         }
3273
3274         attr = smb_Attributes(scp);
3275         /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3276         if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3277             attr |= SMB_ATTR_HIDDEN;
3278         *dptr++ = attr;
3279
3280         /* get dos time */
3281         smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3282                 
3283         /* copy out time */
3284         shortTemp = (unsigned short) (dosTime & 0xffff);
3285         *((u_short *)dptr) = shortTemp;
3286         dptr += 2;
3287
3288         /* and copy out date */
3289         shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3290         *((u_short *)dptr) = shortTemp;
3291         dptr += 2;
3292                 
3293         /* copy out file length */
3294         *((u_long *)dptr) = scp->length.LowPart;
3295         dptr += 4;
3296         lock_ReleaseMutex(&scp->mx);
3297         cm_ReleaseSCache(scp);
3298     }
3299         
3300     /* now free the patches */
3301     for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3302         npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3303         free(patchp);
3304     }   
3305         
3306     /* and mark the list as empty */
3307     *dirPatchespp = NULL;
3308
3309     return code;
3310 }
3311
3312 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3313 {
3314     int attribute;
3315     long nextCookie;
3316     char *tp;
3317     long code = 0;
3318     char *pathp;
3319     cm_dirEntry_t *dep;
3320     int maxCount;
3321     smb_dirListPatch_t *dirListPatchesp;
3322     smb_dirListPatch_t *curPatchp;
3323     int dataLength;
3324     cm_buf_t *bufferp;
3325     long temp;
3326     osi_hyper_t dirLength;
3327     osi_hyper_t bufferOffset;
3328     osi_hyper_t curOffset;
3329     osi_hyper_t thyper;
3330     unsigned char *inCookiep;
3331     smb_dirSearch_t *dsp;
3332     cm_scache_t *scp;
3333     long entryInDir;
3334     long entryInBuffer;
3335     unsigned long clientCookie;
3336     cm_pageHeader_t *pageHeaderp;
3337     cm_user_t *userp = NULL;
3338     int slotInPage;
3339     char shortName[13];
3340     char *actualName;
3341     char *shortNameEnd;
3342     char mask[11];
3343     int returnedNames;
3344     long nextEntryCookie;
3345     int numDirChunks;           /* # of 32 byte dir chunks in this entry */
3346     char resByte;                       /* reserved byte from the cookie */
3347     char *op;                   /* output data ptr */
3348     char *origOp;                       /* original value of op */
3349     cm_space_t *spacep;         /* for pathname buffer */
3350     int starPattern;
3351     int rootPath = 0;
3352     int caseFold;
3353     char *tidPathp;
3354     cm_req_t req;
3355     cm_fid_t fid;
3356     int fileType;
3357
3358     cm_InitReq(&req);
3359
3360     maxCount = smb_GetSMBParm(inp, 0);
3361
3362     dirListPatchesp = NULL;
3363         
3364     caseFold = CM_FLAG_CASEFOLD;
3365
3366     tp = smb_GetSMBData(inp, NULL);
3367     pathp = smb_ParseASCIIBlock(tp, &tp);
3368     if (smb_StoreAnsiFilenames)
3369         OemToChar(pathp,pathp);
3370     inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3371
3372     /* bail out if request looks bad */
3373     if (!tp || !pathp) {
3374         return CM_ERROR_BADSMB;
3375     }
3376
3377     /* We can handle long names */
3378     if (vcp->flags & SMB_VCFLAG_USENT)
3379         ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
3380
3381     /* make sure we got a whole search status */
3382     if (dataLength < 21) {
3383         nextCookie = 0;         /* start at the beginning of the dir */
3384         resByte = 0;
3385         clientCookie = 0;
3386         attribute = smb_GetSMBParm(inp, 1);
3387
3388         /* handle volume info in another function */
3389         if (attribute & 0x8)
3390             return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3391
3392         osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3393                   maxCount, osi_LogSaveString(smb_logp, pathp));
3394
3395         if (*pathp == 0) {      /* null pathp, treat as root dir */
3396             if (!(attribute & SMB_ATTR_DIRECTORY))      /* exclude dirs */
3397                 return CM_ERROR_NOFILES;
3398             rootPath = 1;
3399         }
3400
3401         dsp = smb_NewDirSearch(0);
3402         dsp->attribute = attribute;
3403         smb_Get8Dot3MaskFromPath(mask, pathp);
3404         memcpy(dsp->mask, mask, 11);
3405
3406         /* track if this is likely to match a lot of entries */
3407         if (smb_IsStarMask(mask)) starPattern = 1;
3408         else starPattern = 0;
3409     }   
3410     else {
3411         /* pull the next cookie value out of the search status block */
3412         nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3413             + (inCookiep[16]<<24);
3414         dsp = smb_FindDirSearch(inCookiep[12]);
3415         if (!dsp) {
3416             /* can't find dir search status; fatal error */
3417             return CM_ERROR_BADFD;
3418         }
3419         attribute = dsp->attribute;
3420         resByte = inCookiep[0];
3421
3422         /* copy out client cookie, in host byte order.  Don't bother
3423          * interpreting it, since we're just passing it through, anyway.
3424          */
3425         memcpy(&clientCookie, &inCookiep[17], 4);
3426
3427         memcpy(mask, dsp->mask, 11);
3428
3429         /* assume we're doing a star match if it has continued for more
3430          * than one call.
3431          */
3432         starPattern = 1;
3433     }
3434
3435     osi_Log3(smb_logp, "SMB dir search cookie 0x%x, connection %d, attr 0x%x",
3436              nextCookie, dsp->cookie, attribute);
3437
3438     userp = smb_GetUser(vcp, inp);
3439
3440     /* try to get the vnode for the path name next */
3441     lock_ObtainMutex(&dsp->mx);
3442     if (dsp->scp) {
3443         scp = dsp->scp;
3444         cm_HoldSCache(scp);
3445         code = 0;
3446     }
3447     else {
3448         spacep = inp->spacep;
3449         smb_StripLastComponent(spacep->data, NULL, pathp);
3450         code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3451         if (code) {
3452             lock_ReleaseMutex(&dsp->mx);
3453             cm_ReleaseUser(userp);
3454             smb_DeleteDirSearch(dsp);
3455             smb_ReleaseDirSearch(dsp);
3456             return CM_ERROR_NOFILES;
3457         }
3458         code = cm_NameI(cm_rootSCachep, spacep->data,
3459                         caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3460         if (code == 0) {
3461             if (dsp->scp != 0) 
3462                 cm_ReleaseSCache(dsp->scp);
3463             dsp->scp = scp;
3464             /* we need one hold for the entry we just stored into,
3465              * and one for our own processing.  When we're done with this
3466              * function, we'll drop the one for our own processing.
3467              * We held it once from the namei call, and so we do another hold
3468              * now.
3469              */
3470             cm_HoldSCache(scp);
3471             lock_ObtainMutex(&scp->mx);
3472             if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3473                  && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3474                 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3475                 dsp->flags |= SMB_DIRSEARCH_BULKST;
3476             }
3477             lock_ReleaseMutex(&scp->mx);
3478         }
3479     }
3480     lock_ReleaseMutex(&dsp->mx);
3481     if (code) {
3482         cm_ReleaseUser(userp);
3483         smb_DeleteDirSearch(dsp);
3484         smb_ReleaseDirSearch(dsp);
3485         return code;
3486     }
3487
3488     /* reserves space for parameter; we'll adjust it again later to the
3489      * real count of the # of entries we returned once we've actually
3490      * assembled the directory listing.
3491      */
3492     smb_SetSMBParm(outp, 0, 0);
3493
3494     /* get the directory size */
3495     lock_ObtainMutex(&scp->mx);
3496     code = cm_SyncOp(scp, NULL, userp, &req, 0,
3497                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3498     if (code) {
3499         lock_ReleaseMutex(&scp->mx);
3500         cm_ReleaseSCache(scp);
3501         cm_ReleaseUser(userp);
3502         smb_DeleteDirSearch(dsp);
3503         smb_ReleaseDirSearch(dsp);
3504         return code;
3505     }
3506         
3507     dirLength = scp->length;
3508     bufferp = NULL;
3509     bufferOffset.LowPart = bufferOffset.HighPart = 0;
3510     curOffset.HighPart = 0;
3511     curOffset.LowPart = nextCookie;
3512     origOp = op = smb_GetSMBData(outp, NULL);
3513     /* and write out the basic header */
3514     *op++ = 5;          /* variable block */
3515     op += 2;            /* skip vbl block length; we'll fill it in later */
3516     code = 0;
3517     returnedNames = 0;
3518     while (1) {
3519         /* make sure that curOffset.LowPart doesn't point to the first
3520          * 32 bytes in the 2nd through last dir page, and that it doesn't
3521          * point at the first 13 32-byte chunks in the first dir page,
3522          * since those are dir and page headers, and don't contain useful
3523          * information.
3524          */
3525         temp = curOffset.LowPart & (2048-1);
3526         if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3527             /* we're in the first page */
3528             if (temp < 13*32) temp = 13*32;
3529         }
3530         else {
3531             /* we're in a later dir page */
3532             if (temp < 32) temp = 32;
3533         }
3534
3535         /* make sure the low order 5 bits are zero */
3536         temp &= ~(32-1);
3537
3538         /* now put temp bits back ito curOffset.LowPart */
3539         curOffset.LowPart &= ~(2048-1);
3540         curOffset.LowPart |= temp;
3541
3542         /* check if we've returned all the names that will fit in the
3543          * response packet.
3544          */
3545         if (returnedNames >= maxCount) 
3546             break;
3547                 
3548         /* check if we've passed the dir's EOF */
3549         if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
3550
3551         /* see if we can use the bufferp we have now; compute in which page
3552          * the current offset would be, and check whether that's the offset
3553          * of the buffer we have.  If not, get the buffer.
3554          */
3555         thyper.HighPart = curOffset.HighPart;
3556         thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
3557         if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3558             /* wrong buffer */
3559             if (bufferp) {
3560                 buf_Release(bufferp);
3561                 bufferp = NULL;
3562             }   
3563             lock_ReleaseMutex(&scp->mx);
3564             lock_ObtainRead(&scp->bufCreateLock);
3565             code = buf_Get(scp, &thyper, &bufferp);
3566             lock_ReleaseRead(&scp->bufCreateLock);
3567             lock_ObtainMutex(&dsp->mx);
3568
3569             /* now, if we're doing a star match, do bulk fetching of all of 
3570              * the status info for files in the dir.
3571              */
3572             if (starPattern) {
3573                 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3574                 lock_ObtainMutex(&scp->mx);
3575                 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
3576                      LargeIntegerGreaterThanOrEqualTo(thyper, 
3577                                                       scp->bulkStatProgress)) {
3578                     /* Don't bulk stat if risking timeout */
3579                     int now = GetCurrentTime();
3580                     if (now - req.startTime > 5000) {
3581                         scp->bulkStatProgress = thyper;
3582                         scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3583                         dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3584                     } else
3585                         cm_TryBulkStat(scp, &thyper, userp, &req);
3586                 }
3587             } else {
3588                 lock_ObtainMutex(&scp->mx);
3589             }
3590             lock_ReleaseMutex(&dsp->mx);
3591             if (code) 
3592                 break;
3593
3594             bufferOffset = thyper;
3595
3596             /* now get the data in the cache */
3597             while (1) {
3598                 code = cm_SyncOp(scp, bufferp, userp, &req,
3599                                  PRSFS_LOOKUP,
3600                                  CM_SCACHESYNC_NEEDCALLBACK |
3601                                  CM_SCACHESYNC_READ);
3602                 if (code) break;
3603                                 
3604                 if (cm_HaveBuffer(scp, bufferp, 0)) break;
3605
3606                 /* otherwise, load the buffer and try again */
3607                 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
3608                 if (code) break;
3609             }
3610             if (code) {
3611                 buf_Release(bufferp);
3612                 bufferp = NULL;
3613                 break;
3614             }
3615         }       /* if (wrong buffer) ... */
3616
3617         /* now we have the buffer containing the entry we're interested in; copy
3618          * it out if it represents a non-deleted entry.
3619          */
3620         entryInDir = curOffset.LowPart & (2048-1);
3621         entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
3622
3623         /* page header will help tell us which entries are free.  Page header
3624          * can change more often than once per buffer, since AFS 3 dir page size
3625          * may be less than (but not more than a buffer package buffer.
3626          */
3627         temp = curOffset.LowPart & (buf_bufferSize - 1);  /* only look intra-buffer */
3628         temp &= ~(2048 - 1);    /* turn off intra-page bits */
3629         pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3630
3631         /* now determine which entry we're looking at in the page.  If it is
3632          * free (there's a free bitmap at the start of the dir), we should
3633          * skip these 32 bytes.
3634          */
3635         slotInPage = (entryInDir & 0x7e0) >> 5;
3636         if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
3637             /* this entry is free */
3638             numDirChunks = 1;           /* only skip this guy */
3639             goto nextEntry;
3640         }
3641
3642         tp = bufferp->datap + entryInBuffer;
3643         dep = (cm_dirEntry_t *) tp;             /* now points to AFS3 dir entry */
3644
3645         /* while we're here, compute the next entry's location, too,
3646          * since we'll need it when writing out the cookie into the dir
3647          * listing stream.
3648          *
3649          * XXXX Probably should do more sanity checking.
3650          */
3651         numDirChunks = cm_NameEntries(dep->name, NULL);
3652
3653         /* compute the offset of the cookie representing the next entry */
3654         nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3655
3656         /* Compute 8.3 name if necessary */
3657         actualName = dep->name;
3658         if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
3659             cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3660             actualName = shortName;
3661         }
3662
3663         if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
3664             /* this is one of the entries to use: it is not deleted
3665              * and it matches the star pattern we're looking for.
3666              */
3667
3668             /* Eliminate entries that don't match requested
3669              * attributes */
3670
3671             /* no hidden files */
3672             if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName))
3673                 goto nextEntry;
3674
3675             if (!(dsp->attribute & SMB_ATTR_DIRECTORY))  /* no directories */
3676             {
3677                 /* We have already done the cm_TryBulkStat above */
3678                 fid.cell = scp->fid.cell;
3679                 fid.volume = scp->fid.volume;
3680                 fid.vnode = ntohl(dep->fid.vnode);
3681                 fid.unique = ntohl(dep->fid.unique);
3682                 fileType = cm_FindFileType(&fid);
3683                 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
3684                          "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
3685                           fileType);
3686                 if (fileType == CM_SCACHETYPE_DIRECTORY)
3687                     goto nextEntry;
3688             }
3689
3690             *op++ = resByte;
3691             memcpy(op, mask, 11); op += 11;
3692             *op++ = (char) dsp->cookie; /* they say it must be non-zero */
3693             *op++ = nextEntryCookie & 0xff;
3694             *op++ = (nextEntryCookie>>8) & 0xff;
3695             *op++ = (nextEntryCookie>>16) & 0xff;
3696             *op++ = (nextEntryCookie>>24) & 0xff;
3697             memcpy(op, &clientCookie, 4); op += 4;
3698
3699             /* now we emit the attribute.  This is sort of tricky,
3700              * since we need to really stat the file to find out
3701              * what type of entry we've got.  Right now, we're
3702              * copying out data from a buffer, while holding the
3703              * scp locked, so it isn't really convenient to stat
3704              * something now.  We'll put in a place holder now,
3705              * and make a second pass before returning this to get
3706              * the real attributes.  So, we just skip the data for
3707              * now, and adjust it later.  We allocate a patch
3708              * record to make it easy to find this point later.
3709              * The replay will happen at a time when it is safe to
3710              * unlock the directory.
3711              */
3712             curPatchp = malloc(sizeof(*curPatchp));
3713             osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
3714             curPatchp->dptr = op;
3715             curPatchp->fid.cell = scp->fid.cell;
3716             curPatchp->fid.volume = scp->fid.volume;
3717             curPatchp->fid.vnode = ntohl(dep->fid.vnode);
3718             curPatchp->fid.unique = ntohl(dep->fid.unique);
3719
3720             /* do hidden attribute here since name won't be around when applying
3721              * dir list patches
3722              */
3723
3724             if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
3725                 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
3726             else
3727                 curPatchp->flags = 0;
3728
3729             op += 9;    /* skip attr, time, date and size */
3730
3731             /* zero out name area.  The spec says to pad with
3732              * spaces, but Samba doesn't, and neither do we.
3733              */
3734             memset(op, 0, 13);
3735
3736             /* finally, we get to copy out the name; we know that
3737              * it fits in 8.3 or the pattern wouldn't match, but it
3738              * never hurts to be sure.
3739              */
3740             strncpy(op, actualName, 13);
3741             if (smb_StoreAnsiFilenames)
3742                 CharToOem(op, op);
3743
3744             /* Uppercase if requested by client */
3745             if ((((smb_t *)inp)->flg2 & SMB_FLAGS2_KNOWS_LONG_NAMES) == 0)
3746                 _strupr(op);
3747
3748             op += 13;
3749
3750             /* now, adjust the # of entries copied */
3751             returnedNames++;
3752         }       /* if we're including this name */
3753
3754       nextEntry:
3755         /* and adjust curOffset to be where the new cookie is */
3756         thyper.HighPart = 0;
3757         thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
3758         curOffset = LargeIntegerAdd(thyper, curOffset);
3759     }           /* while copying data for dir listing */
3760
3761     /* release the mutex */
3762     lock_ReleaseMutex(&scp->mx);
3763     if (bufferp) buf_Release(bufferp);
3764
3765     /* apply and free last set of patches; if not doing a star match, this
3766      * will be empty, but better safe (and freeing everything) than sorry.
3767      */
3768     smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3769
3770     /* special return code for unsuccessful search */
3771     if (code == 0 && dataLength < 21 && returnedNames == 0)
3772         code = CM_ERROR_NOFILES;
3773
3774     osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
3775              returnedNames, code);
3776
3777     if (code != 0) {
3778         smb_DeleteDirSearch(dsp);
3779         smb_ReleaseDirSearch(dsp);
3780         cm_ReleaseSCache(scp);
3781         cm_ReleaseUser(userp);
3782         return code;
3783     }
3784
3785     /* finalize the output buffer */
3786     smb_SetSMBParm(outp, 0, returnedNames);
3787     temp = (long) (op - origOp);
3788     smb_SetSMBDataLength(outp, temp);
3789
3790     /* the data area is a variable block, which has a 5 (already there)
3791      * followed by the length of the # of data bytes.  We now know this to
3792      * be "temp," although that includes the 3 bytes of vbl block header.
3793      * Deduct for them and fill in the length field.
3794      */
3795     temp -= 3;          /* deduct vbl block info */
3796     osi_assert(temp == (43 * returnedNames));
3797     origOp[1] = temp & 0xff;
3798     origOp[2] = (temp>>8) & 0xff;
3799     if (returnedNames == 0) 
3800         smb_DeleteDirSearch(dsp);
3801     smb_ReleaseDirSearch(dsp);
3802     cm_ReleaseSCache(scp);
3803     cm_ReleaseUser(userp);
3804     return code;
3805 }       
3806
3807 /* verify that this is a valid path to a directory.  I don't know why they
3808  * don't use the get file attributes call.
3809  */
3810 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3811 {
3812     char *pathp;
3813     long code = 0;
3814     cm_scache_t *rootScp;
3815     cm_scache_t *newScp;
3816     cm_user_t *userp;
3817     unsigned int attrs;
3818     int caseFold;
3819     char *tidPathp;
3820     cm_req_t req;
3821
3822     cm_InitReq(&req);
3823
3824     pathp = smb_GetSMBData(inp, NULL);
3825     pathp = smb_ParseASCIIBlock(pathp, NULL);
3826     if (!pathp)
3827         return CM_ERROR_BADFD;
3828     if (smb_StoreAnsiFilenames)
3829         OemToChar(pathp,pathp);
3830     osi_Log1(smb_logp, "SMB receive check path %s",
3831              osi_LogSaveString(smb_logp, pathp));
3832         
3833     rootScp = cm_rootSCachep;
3834         
3835     userp = smb_GetUser(vcp, inp);
3836
3837     caseFold = CM_FLAG_CASEFOLD;
3838
3839     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3840     if(code) {
3841         cm_ReleaseUser(userp);
3842         return CM_ERROR_NOSUCHPATH;
3843     }
3844     code = cm_NameI(rootScp, pathp,
3845                     caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
3846                     userp, tidPathp, &req, &newScp);
3847
3848     if (code) {
3849         cm_ReleaseUser(userp);
3850         return code;
3851     }
3852         
3853     /* now lock the vnode with a callback; returns with newScp locked */
3854     lock_ObtainMutex(&newScp->mx);
3855     code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
3856                      CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3857     if (code && code != CM_ERROR_NOACCESS) {
3858         lock_ReleaseMutex(&newScp->mx);
3859         cm_ReleaseSCache(newScp);
3860         cm_ReleaseUser(userp);
3861         return code;
3862     }
3863
3864     attrs = smb_Attributes(newScp);
3865
3866     if (!(attrs & 0x10))
3867         code = CM_ERROR_NOTDIR;
3868
3869     lock_ReleaseMutex(&newScp->mx);
3870
3871     cm_ReleaseSCache(newScp);
3872     cm_ReleaseUser(userp);
3873     return code;
3874 }       
3875
3876 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3877 {
3878     char *pathp;
3879     long code = 0;
3880     cm_scache_t *rootScp;
3881     unsigned short attribute;
3882     cm_attr_t attr;
3883     cm_scache_t *newScp;
3884     time_t dosTime;
3885     cm_user_t *userp;
3886     int caseFold;
3887     char *tidPathp;
3888     cm_req_t req;
3889
3890     cm_InitReq(&req);
3891
3892     /* decode basic attributes we're passed */
3893     attribute = smb_GetSMBParm(inp, 0);
3894     dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3895
3896     pathp = smb_GetSMBData(inp, NULL);
3897     pathp = smb_ParseASCIIBlock(pathp, NULL);
3898     if (!pathp)
3899         return CM_ERROR_BADSMB;
3900     if (smb_StoreAnsiFilenames)
3901         OemToChar(pathp,pathp);
3902                
3903     osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
3904              dosTime, attribute);
3905
3906     rootScp = cm_rootSCachep;
3907         
3908     userp = smb_GetUser(vcp, inp);
3909
3910     caseFold = CM_FLAG_CASEFOLD;
3911
3912     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3913     if (code) {
3914         cm_ReleaseUser(userp);
3915         return CM_ERROR_NOSUCHFILE;
3916     }
3917     code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
3918                     tidPathp, &req, &newScp);
3919
3920     if (code) {
3921         cm_ReleaseUser(userp);
3922         return code;
3923     }
3924         
3925     /* now lock the vnode with a callback; returns with newScp locked; we
3926      * need the current status to determine what the new status is, in some
3927      * cases.
3928      */
3929     lock_ObtainMutex(&newScp->mx);
3930     code = cm_SyncOp(newScp, NULL, userp, &req, 0,
3931                      CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3932     if (code) {
3933         lock_ReleaseMutex(&newScp->mx);
3934         cm_ReleaseSCache(newScp);
3935         cm_ReleaseUser(userp);
3936         return code;
3937     }
3938
3939     /* Check for RO volume */
3940     if (newScp->flags & CM_SCACHEFLAG_RO) {
3941         lock_ReleaseMutex(&newScp->mx);
3942         cm_ReleaseSCache(newScp);
3943         cm_ReleaseUser(userp);
3944         return CM_ERROR_READONLY;
3945     }
3946
3947     /* prepare for setattr call */
3948     attr.mask = 0;
3949     if (dosTime != 0) {
3950         attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3951         smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
3952     }
3953     if ((newScp->unixModeBits & 0222) && (attribute & 1) != 0) {
3954         /* we're told to make a writable file read-only */
3955         attr.unixModeBits = newScp->unixModeBits & ~0222;
3956         attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3957     }
3958     else if ((newScp->unixModeBits & 0222) == 0 && (attribute & 1) == 0) {
3959         /* we're told to make a read-only file writable */
3960         attr.unixModeBits = newScp->unixModeBits | 0222;
3961         attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3962     }
3963     lock_ReleaseMutex(&newScp->mx);
3964
3965     /* now call setattr */
3966     if (attr.mask)
3967         code = cm_SetAttr(newScp, &attr, userp, &req);
3968     else
3969         code = 0;
3970         
3971     cm_ReleaseSCache(newScp);
3972     cm_ReleaseUser(userp);
3973
3974     return code;
3975 }
3976
3977 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3978 {
3979     char *pathp;
3980     long code = 0;
3981     cm_scache_t *rootScp;
3982     cm_scache_t *newScp, *dscp;
3983     time_t dosTime;
3984     int attrs;
3985     cm_user_t *userp;
3986     int caseFold;
3987     char *tidPathp;
3988     cm_space_t *spacep;
3989     char *lastComp;
3990     cm_req_t req;
3991
3992     cm_InitReq(&req);
3993
3994     pathp = smb_GetSMBData(inp, NULL);
3995     pathp = smb_ParseASCIIBlock(pathp, NULL);
3996     if (!pathp)
3997         return CM_ERROR_BADSMB;
3998         
3999     if (*pathp == 0)            /* null path */
4000         pathp = "\\";
4001     else
4002         if (smb_StoreAnsiFilenames)
4003             OemToChar(pathp,pathp);
4004
4005     osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
4006              osi_LogSaveString(smb_logp, pathp));
4007
4008     rootScp = cm_rootSCachep;
4009         
4010     userp = smb_GetUser(vcp, inp);
4011
4012     /* we shouldn't need this for V3 requests, but we seem to */
4013     caseFold = CM_FLAG_CASEFOLD;
4014
4015     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4016     if (code) {
4017         cm_ReleaseUser(userp);
4018         return CM_ERROR_NOSUCHFILE;
4019     }
4020
4021     /*
4022      * XXX Strange hack XXX
4023      *
4024      * As of Patch 5 (16 July 97), we are having the following problem:
4025      * In NT Explorer 4.0, whenever we click on a directory, AFS gets
4026      * requests to look up "desktop.ini" in all the subdirectories.
4027      * This can cause zillions of timeouts looking up non-existent cells
4028      * and volumes, especially in the top-level directory.
4029      *
4030      * We have not found any way to avoid this or work around it except
4031      * to explicitly ignore the requests for mount points that haven't
4032      * yet been evaluated and for directories that haven't yet been
4033      * fetched.
4034      *
4035      * We should modify this hack to provide a fake desktop.ini file
4036      * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
4037      */
4038     spacep = inp->spacep;
4039     smb_StripLastComponent(spacep->data, &lastComp, pathp);
4040 #ifndef SPECIAL_FOLDERS
4041     if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
4042         code = cm_NameI(rootScp, spacep->data,
4043                         caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
4044                         userp, tidPathp, &req, &dscp);
4045         if (code == 0) {
4046             if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT &&
4047                 !dscp->mountRootFidp)
4048                 code = CM_ERROR_NOSUCHFILE;
4049             else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
4050                 cm_buf_t *bp = buf_Find(dscp, &hzero);
4051                 if (bp)
4052                     buf_Release(bp);
4053                 else
4054                     code = CM_ERROR_NOSUCHFILE;
4055             }
4056             cm_ReleaseSCache(dscp);
4057             if (code) {
4058                 cm_ReleaseUser(userp);
4059                 return code;
4060             }
4061         }
4062     }
4063 #endif /* SPECIAL_FOLDERS */
4064
4065     code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4066                     tidPathp, &req, &newScp);
4067     if (code) {
4068         cm_ReleaseUser(userp);
4069         return code;
4070     }
4071         
4072     /* now lock the vnode with a callback; returns with newScp locked */
4073     lock_ObtainMutex(&newScp->mx);
4074     code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4075                      CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4076     if (code) {
4077         lock_ReleaseMutex(&newScp->mx);
4078         cm_ReleaseSCache(newScp);
4079         cm_ReleaseUser(userp);
4080         return code;
4081     }
4082
4083 #ifdef undef
4084     /* use smb_Attributes instead.   Also the fact that a file is 
4085      * in a readonly volume doesn't mean it shojuld be marked as RO 
4086      */
4087     if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
4088         newScp->fileType == CM_SCACHETYPE_MOUNTPOINT)
4089         attrs = SMB_ATTR_DIRECTORY;
4090     else
4091         attrs = 0;
4092     if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
4093         attrs |= SMB_ATTR_READONLY;     /* turn on read-only flag */
4094 #else
4095     attrs = smb_Attributes(newScp);
4096 #endif
4097
4098     smb_SetSMBParm(outp, 0, attrs);
4099         
4100     smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
4101     smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
4102     smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
4103     smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
4104     smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
4105     smb_SetSMBParm(outp, 5, 0);
4106     smb_SetSMBParm(outp, 6, 0);
4107     smb_SetSMBParm(outp, 7, 0);
4108     smb_SetSMBParm(outp, 8, 0);
4109     smb_SetSMBParm(outp, 9, 0);
4110     smb_SetSMBDataLength(outp, 0);
4111     lock_ReleaseMutex(&newScp->mx);
4112
4113     cm_ReleaseSCache(newScp);
4114     cm_ReleaseUser(userp);
4115
4116     return 0;
4117 }       
4118
4119 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4120 {
4121     smb_tid_t *tidp;
4122         
4123     osi_Log0(smb_logp, "SMB receive tree disconnect");
4124
4125     /* find the tree and free it */
4126     tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
4127     if (tidp) {
4128         lock_ObtainMutex(&tidp->mx);
4129         tidp->flags |= SMB_TIDFLAG_DELETE;
4130         lock_ReleaseMutex(&tidp->mx);
4131         smb_ReleaseTID(tidp);
4132     }
4133
4134     return 0;
4135 }
4136
4137 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4138 {
4139     smb_fid_t *fidp;
4140     char *pathp;
4141     char *lastNamep;
4142     int share;
4143     int attribute;
4144     long code = 0;
4145     cm_user_t *userp;
4146     cm_scache_t *scp;
4147     time_t dosTime;
4148     int caseFold;
4149     cm_space_t *spacep;
4150     char *tidPathp;
4151     cm_req_t req;
4152
4153     cm_InitReq(&req);
4154
4155     pathp = smb_GetSMBData(inp, NULL);
4156     pathp = smb_ParseASCIIBlock(pathp, NULL);
4157     if (smb_StoreAnsiFilenames)
4158         OemToChar(pathp,pathp);
4159         
4160     osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
4161
4162 #ifdef DEBUG_VERBOSE
4163     {
4164         char *hexpath;
4165
4166         hexpath = osi_HexifyString( pathp );
4167         DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
4168         free(hexpath);
4169     }
4170 #endif
4171
4172     share = smb_GetSMBParm(inp, 0);
4173     attribute = smb_GetSMBParm(inp, 1);
4174
4175     spacep = inp->spacep;
4176     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4177     if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4178         /* special case magic file name for receiving IOCTL requests
4179          * (since IOCTL calls themselves aren't getting through).
4180          */
4181         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4182         smb_SetupIoctlFid(fidp, spacep);
4183         smb_SetSMBParm(outp, 0, fidp->fid);
4184         smb_SetSMBParm(outp, 1, 0);     /* attrs */
4185         smb_SetSMBParm(outp, 2, 0);     /* next 2 are DOS time */
4186         smb_SetSMBParm(outp, 3, 0);
4187         smb_SetSMBParm(outp, 4, 0);     /* next 2 are length */
4188         smb_SetSMBParm(outp, 5, 0x7fff);
4189         /* pass the open mode back */
4190         smb_SetSMBParm(outp, 6, (share & 0xf));
4191         smb_SetSMBDataLength(outp, 0);
4192         smb_ReleaseFID(fidp);
4193         return 0;
4194     }
4195
4196     userp = smb_GetUser(vcp, inp);
4197
4198     caseFold = CM_FLAG_CASEFOLD;
4199
4200     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4201     if (code) {
4202         cm_ReleaseUser(userp);
4203         return CM_ERROR_NOSUCHPATH;
4204     }
4205     code = cm_NameI(cm_rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4206                     tidPathp, &req, &scp);
4207         
4208     if (code) {
4209         cm_ReleaseUser(userp);
4210         return code;
4211     }
4212
4213     code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
4214     if (code) {
4215         cm_ReleaseSCache(scp);
4216         cm_ReleaseUser(userp);
4217         return code;
4218     }
4219
4220     /* don't need callback to check file type, since file types never
4221      * change, and namei and cm_Lookup all stat the object at least once on
4222      * a successful return.
4223      */
4224     if (scp->fileType != CM_SCACHETYPE_FILE) {
4225         cm_ReleaseSCache(scp);
4226         cm_ReleaseUser(userp);
4227         return CM_ERROR_ISDIR;
4228     }
4229
4230     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4231     osi_assert(fidp);
4232
4233     /* save a pointer to the vnode */
4234     fidp->scp = scp;
4235
4236     if ((share & 0xf) == 0)
4237         fidp->flags |= SMB_FID_OPENREAD;
4238     else if ((share & 0xf) == 1)
4239         fidp->flags |= SMB_FID_OPENWRITE;
4240     else 
4241         fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
4242
4243     lock_ObtainMutex(&scp->mx);
4244     smb_SetSMBParm(outp, 0, fidp->fid);
4245     smb_SetSMBParm(outp, 1, smb_Attributes(scp));
4246     smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4247     smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
4248     smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
4249     smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
4250     smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
4251     /* pass the open mode back; XXXX add access checks */
4252     smb_SetSMBParm(outp, 6, (share & 0xf));
4253     smb_SetSMBDataLength(outp, 0);
4254     lock_ReleaseMutex(&scp->mx);
4255         
4256     /* notify open */
4257     cm_Open(scp, 0, userp);
4258
4259     /* send and free packet */
4260     smb_ReleaseFID(fidp);
4261     cm_ReleaseUser(userp);
4262     /* don't release scp, since we've squirreled away the pointer in the fid struct */
4263     return 0;
4264 }
4265
4266 typedef struct smb_unlinkRock {
4267     cm_scache_t *dscp;
4268     cm_user_t *userp;
4269     cm_req_t *reqp;
4270     smb_vc_t *vcp;
4271     char *maskp;                /* pointer to the star pattern */
4272     int flags;
4273     int any;
4274 } smb_unlinkRock_t;
4275
4276 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4277 {
4278     long code = 0;
4279     smb_unlinkRock_t *rockp;
4280     int caseFold;
4281     int match;
4282     char shortName[13];
4283     char *matchName;
4284         
4285     rockp = vrockp;
4286
4287     caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4288     if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4289         caseFold |= CM_FLAG_8DOT3;
4290
4291     matchName = dep->name;
4292     match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
4293     if (!match &&
4294          (rockp->flags & SMB_MASKFLAG_TILDE) &&
4295          !cm_Is8Dot3(dep->name)) {
4296         cm_Gen8Dot3Name(dep, shortName, NULL);
4297         matchName = shortName;
4298         /* 8.3 matches are always case insensitive */
4299         match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
4300     }
4301     if (match) {
4302         osi_Log1(smb_logp, "Unlinking %s",
4303                  osi_LogSaveString(smb_logp, matchName));
4304         code = cm_Unlink(dscp, dep->name, rockp->userp, rockp->reqp);
4305         if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4306             smb_NotifyChange(FILE_ACTION_REMOVED,
4307                              FILE_NOTIFY_CHANGE_FILE_NAME,
4308                              dscp, dep->name, NULL, TRUE);
4309         if (code == 0) {
4310             rockp->any = 1;
4311
4312             /* If we made a case sensitive exact match, we might as well quit now. */
4313             if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
4314                 code = CM_ERROR_STOPNOW;
4315         }
4316     }
4317     else code = 0;
4318
4319     return code;
4320 }
4321
4322 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4323 {
4324     int attribute;
4325     long code = 0;
4326     char *pathp;
4327     char *tp;
4328     cm_space_t *spacep;
4329     cm_scache_t *dscp;
4330     char *lastNamep;
4331     smb_unlinkRock_t rock;
4332     cm_user_t *userp;
4333     osi_hyper_t thyper;
4334     int caseFold;
4335     char *tidPathp;
4336     cm_req_t req;
4337
4338     cm_InitReq(&req);
4339
4340     attribute = smb_GetSMBParm(inp, 0);
4341         
4342     tp = smb_GetSMBData(inp, NULL);
4343     pathp = smb_ParseASCIIBlock(tp, &tp);
4344     if (smb_StoreAnsiFilenames)
4345         OemToChar(pathp,pathp);
4346
4347     osi_Log1(smb_logp, "SMB receive unlink %s",
4348              osi_LogSaveString(smb_logp, pathp));
4349
4350     spacep = inp->spacep;
4351     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4352
4353     userp = smb_GetUser(vcp, inp);
4354
4355     caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4356
4357     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4358     if (code) {
4359         cm_ReleaseUser(userp);
4360         return CM_ERROR_NOSUCHPATH;
4361     }
4362     code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
4363                     &req, &dscp);
4364
4365     if (code) {
4366         cm_ReleaseUser(userp);
4367         return code;
4368     }
4369         
4370     /* otherwise, scp points to the parent directory. */
4371     if (!lastNamep) 
4372         lastNamep = pathp;
4373     else 
4374         lastNamep++;
4375
4376     rock.any = 0;
4377     rock.maskp = smb_FindMask(pathp);
4378     rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4379
4380     thyper.LowPart = 0;
4381     thyper.HighPart = 0;
4382     rock.userp = userp;
4383     rock.reqp = &req;
4384     rock.dscp = dscp;
4385     rock.vcp = vcp;
4386
4387     /* Now, if we aren't dealing with a wildcard match, we first try an exact 
4388      * match.  If that fails, we do a case insensitve match. 
4389      */
4390     if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
4391         !smb_IsStarMask(rock.maskp)) {
4392         code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4393         if (!rock.any) {
4394             thyper.LowPart = 0;
4395             thyper.HighPart = 0;
4396             rock.flags |= SMB_MASKFLAG_CASEFOLD;
4397         }
4398     }
4399  
4400     if (!rock.any)
4401         code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4402     
4403     if (code == CM_ERROR_STOPNOW) 
4404         code = 0;
4405
4406     cm_ReleaseUser(userp);
4407         
4408     cm_ReleaseSCache(dscp);
4409
4410     if (code == 0 && !rock.any)
4411         code = CM_ERROR_NOSUCHFILE;
4412     return code;
4413 }       
4414
4415 typedef struct smb_renameRock {
4416     cm_scache_t *odscp; /* old dir */
4417     cm_scache_t *ndscp; /* new dir */
4418     cm_user_t *userp;   /* user */
4419     cm_req_t *reqp;             /* request struct */
4420     smb_vc_t *vcp;              /* virtual circuit */
4421     char *maskp;                /* pointer to star pattern of old file name */
4422     int flags;              /* tilde, casefold, etc */
4423     char *newNamep;             /* ptr to the new file's name */
4424 } smb_renameRock_t;
4425
4426 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4427 {
4428     long code = 0;
4429     smb_renameRock_t *rockp;
4430     int caseFold;
4431     int match;
4432     char shortName[13];
4433
4434     rockp = (smb_renameRock_t *) vrockp;
4435
4436     caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4437     if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4438         caseFold |= CM_FLAG_8DOT3;
4439
4440     match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
4441     if (!match &&
4442         (rockp->flags & SMB_MASKFLAG_TILDE) &&
4443          !cm_Is8Dot3(dep->name)) {
4444         cm_Gen8Dot3Name(dep, shortName, NULL);
4445         match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
4446     }
4447     if (match) {
4448         code = cm_Rename(rockp->odscp, dep->name,
4449                          rockp->ndscp, rockp->newNamep, rockp->userp,
4450                          rockp->reqp);  
4451         /* if the call worked, stop doing the search now, since we
4452          * really only want to rename one file.
4453          */
4454         if (code == 0) 
4455             code = CM_ERROR_STOPNOW;
4456     }       
4457     else code = 0;
4458
4459     return code;
4460 }
4461
4462
4463 long 
4464 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, int attrs)
4465 {
4466     long code = 0;
4467     cm_space_t *spacep = NULL;
4468     smb_renameRock_t rock;
4469     cm_scache_t *oldDscp = NULL;
4470     cm_scache_t *newDscp = NULL;
4471     cm_scache_t *tmpscp= NULL;
4472     cm_scache_t *tmpscp2 = NULL;
4473     char *oldLastNamep;
4474     char *newLastNamep;
4475     osi_hyper_t thyper;
4476     cm_user_t *userp;
4477     int caseFold;
4478     char *tidPathp;
4479     DWORD filter;
4480     cm_req_t req;
4481
4482     userp = smb_GetUser(vcp, inp);
4483     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4484     if (code) {
4485         cm_ReleaseUser(userp);
4486         return CM_ERROR_NOSUCHPATH;
4487     }
4488
4489     cm_InitReq(&req);
4490     spacep = inp->spacep;
4491     smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
4492
4493     /*
4494      * Changed to use CASEFOLD always.  This enables us to rename Foo/baz when
4495      * what actually exists is foo/baz.  I don't know why the code used to be
4496      * the way it was.  1/29/96
4497      *
4498      *          caseFold = ((vcp->flags & SMB_VCFLAG_USEV3) ? 0: CM_FLAG_CASEFOLD);
4499      *
4500      * Changed to use CM_FLAG_FOLLOW.  7/24/96
4501      *
4502      *  caseFold = CM_FLAG_CASEFOLD;
4503      */
4504     caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4505     code = cm_NameI(cm_rootSCachep, spacep->data, caseFold,
4506                     userp, tidPathp, &req, &oldDscp);
4507
4508     if (code) {
4509         cm_ReleaseUser(userp);
4510         return code;
4511     }
4512         
4513     smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
4514     code = cm_NameI(cm_rootSCachep, spacep->data, caseFold,
4515                     userp, tidPathp, &req, &newDscp);
4516
4517     if (code) {
4518         cm_ReleaseSCache(oldDscp);
4519         cm_ReleaseUser(userp);
4520         return code;
4521     }
4522         
4523     /* otherwise, oldDscp and newDscp point to the corresponding directories.
4524      * next, get the component names, and lower case them.
4525      */
4526
4527     /* handle the old name first */
4528     if (!oldLastNamep) 
4529         oldLastNamep = oldPathp;
4530     else 
4531         oldLastNamep++;
4532
4533     /* and handle the new name, too */
4534     if (!newLastNamep) 
4535         newLastNamep = newPathp;
4536     else 
4537         newLastNamep++;
4538
4539     /* TODO: The old name could be a wildcard.  The new name must not be */
4540
4541     /* do the vnode call */
4542     rock.odscp = oldDscp;
4543     rock.ndscp = newDscp;
4544     rock.userp = userp;
4545     rock.reqp = &req;
4546     rock.vcp = vcp;
4547     rock.maskp = oldLastNamep;
4548     rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4549     rock.newNamep = newLastNamep;
4550
4551     /* Check if the file already exists; if so return error */
4552     code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
4553     if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
4554         osi_Log2(smb_logp, "  lookup returns %ld for [%s]", code,
4555                  osi_LogSaveString(afsd_logp, newLastNamep));
4556
4557         /* Check if the old and the new names differ only in case. If so return
4558          * success, else return CM_ERROR_EXISTS 
4559          */
4560         if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
4561
4562             /* This would be a success only if the old file is *as same as* the new file */
4563             code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
4564             if (!code) {
4565                 if (tmpscp == tmpscp2) 
4566                     code = 0;
4567                 else 
4568                     code = CM_ERROR_EXISTS;
4569                 cm_ReleaseSCache(tmpscp2);
4570                                 tmpscp2 = NULL;
4571             } else {
4572                 code = CM_ERROR_NOSUCHFILE;
4573             }
4574         } else {
4575             /* file exist, do not rename, also fixes move */
4576             osi_Log0(smb_logp, "Can't rename.  Target already exists");
4577             code = CM_ERROR_EXISTS;
4578         }
4579
4580         if (tmpscp != NULL)
4581             cm_ReleaseSCache(tmpscp);
4582         cm_ReleaseSCache(newDscp);
4583         cm_ReleaseSCache(oldDscp);
4584         cm_ReleaseUser(userp);
4585         return code; 
4586     }
4587
4588     /* Now search the directory for the pattern, and do the appropriate rename when found */
4589     thyper.LowPart = 0;         /* search dir from here */
4590     thyper.HighPart = 0;
4591
4592     code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
4593
4594     if (code == CM_ERROR_STOPNOW)
4595         code = 0;
4596     else if (code == 0)
4597         code = CM_ERROR_NOSUCHFILE;
4598
4599     /* Handle Change Notification */
4600     /*
4601     * Being lazy, not distinguishing between files and dirs in this
4602     * filter, since we'd have to do a lookup.
4603     */
4604     filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
4605     if (oldDscp == newDscp) {
4606         if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4607             smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
4608                              filter, oldDscp, oldLastNamep,
4609                              newLastNamep, TRUE);
4610     } else {
4611         if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4612             smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
4613                              filter, oldDscp, oldLastNamep,
4614                              NULL, TRUE);
4615         if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4616             smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
4617                              filter, newDscp, newLastNamep,
4618                              NULL, TRUE);
4619     }
4620
4621     if (tmpscp != NULL) 
4622         cm_ReleaseSCache(tmpscp);
4623     cm_ReleaseUser(userp);
4624     cm_ReleaseSCache(oldDscp);
4625     cm_ReleaseSCache(newDscp);
4626     return code;
4627 }       
4628
4629 long 
4630 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp) 
4631 {
4632     long code = 0;
4633     cm_space_t *spacep = NULL;
4634     cm_scache_t *oldDscp = NULL;
4635     cm_scache_t *newDscp = NULL;
4636     cm_scache_t *tmpscp= NULL;
4637     cm_scache_t *tmpscp2 = NULL;
4638     cm_scache_t *sscp = NULL;
4639     char *oldLastNamep;
4640     char *newLastNamep;
4641     cm_user_t *userp;
4642     int caseFold;
4643     char *tidPathp;
4644     DWORD filter;
4645     cm_req_t req;
4646
4647     userp = smb_GetUser(vcp, inp);
4648
4649     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4650     if (code) {
4651         cm_ReleaseUser(userp);
4652         return CM_ERROR_NOSUCHPATH;
4653     }
4654
4655     cm_InitReq(&req);
4656
4657     caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4658
4659     spacep = inp->spacep;
4660     smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
4661     
4662     code = cm_NameI(cm_rootSCachep, spacep->data, caseFold,
4663                     userp, tidPathp, &req, &oldDscp);
4664     if (code) {
4665         cm_ReleaseUser(userp);
4666         return code;
4667     }
4668         
4669     smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
4670     code = cm_NameI(cm_rootSCachep, spacep->data, caseFold,
4671                     userp, tidPathp, &req, &newDscp);
4672     if (code) {
4673         cm_ReleaseSCache(oldDscp);
4674         cm_ReleaseUser(userp);
4675         return code;
4676     }
4677
4678     /* Now, although we did two lookups for the two directories (because the same
4679      * directory can be referenced through different paths), we only allow hard links
4680      * within the same directory. */
4681     if (oldDscp != newDscp) {
4682         cm_ReleaseSCache(oldDscp);
4683         cm_ReleaseSCache(newDscp);
4684         cm_ReleaseUser(userp);
4685         return CM_ERROR_CROSSDEVLINK;
4686     }
4687
4688     /* handle the old name first */
4689     if (!oldLastNamep) 
4690         oldLastNamep = oldPathp;
4691     else 
4692         oldLastNamep++;
4693
4694     /* and handle the new name, too */
4695     if (!newLastNamep) 
4696         newLastNamep = newPathp;
4697     else 
4698         newLastNamep++;
4699
4700     /* now lookup the old name */
4701     osi_Log1(smb_logp,"  looking up [%s]", osi_LogSaveString(smb_logp,oldLastNamep));
4702     code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
4703     if (code) {
4704         cm_ReleaseSCache(oldDscp);
4705         cm_ReleaseSCache(newDscp);
4706         cm_ReleaseUser(userp);
4707         return code;
4708     }
4709
4710     /* Check if the file already exists; if so return error */
4711     code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
4712     if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
4713         osi_Log2(smb_logp, "  lookup returns %ld for [%s]", code,
4714                  osi_LogSaveString(afsd_logp, newLastNamep));
4715
4716         /* if the existing link is to the same file, then we return success */
4717         if (!code) {
4718             if(sscp == tmpscp) {
4719                 code = 0;
4720             } else {
4721                 osi_Log0(smb_logp, "Can't create hardlink.  Target already exists");
4722                 code = CM_ERROR_EXISTS;
4723             }
4724         }
4725
4726         if (tmpscp != NULL)
4727             cm_ReleaseSCache(tmpscp);
4728         cm_ReleaseSCache(sscp);
4729         cm_ReleaseSCache(newDscp);
4730         cm_ReleaseSCache(oldDscp);
4731         cm_ReleaseUser(userp);
4732         return code; 
4733     }
4734
4735     /* now create the hardlink */
4736     osi_Log1(smb_logp,"  Attempting to create new link [%s]", osi_LogSaveString(smb_logp, newLastNamep));
4737     code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
4738     osi_Log1(smb_logp,"  Link returns %d", code);
4739
4740     /* Handle Change Notification */
4741     if (code == 0) {
4742         filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
4743         if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4744             smb_NotifyChange(FILE_ACTION_ADDED,
4745                              filter, newDscp, newLastNamep,
4746                              NULL, TRUE);
4747     }
4748
4749     if (tmpscp != NULL) 
4750         cm_ReleaseSCache(tmpscp);
4751     cm_ReleaseUser(userp);
4752     cm_ReleaseSCache(sscp);
4753     cm_ReleaseSCache(oldDscp);
4754     cm_ReleaseSCache(newDscp);
4755     return code;
4756 }
4757
4758 long 
4759 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4760 {
4761     char *oldPathp;
4762     char *newPathp;
4763     char *tp;
4764
4765     tp = smb_GetSMBData(inp, NULL);
4766     oldPathp = smb_ParseASCIIBlock(tp, &tp);
4767     if (smb_StoreAnsiFilenames)
4768         OemToChar(oldPathp,oldPathp);
4769     newPathp = smb_ParseASCIIBlock(tp, &tp);
4770     if (smb_StoreAnsiFilenames)
4771         OemToChar(newPathp,newPathp);
4772
4773     osi_Log2(smb_logp, "smb rename [%s] to [%s]",
4774               osi_LogSaveString(smb_logp, oldPathp),
4775               osi_LogSaveString(smb_logp, newPathp));
4776
4777     return smb_Rename(vcp,inp,oldPathp,newPathp,0);
4778 }
4779
4780
4781
4782 typedef struct smb_rmdirRock {
4783     cm_scache_t *dscp;
4784     cm_user_t *userp;
4785     cm_req_t *reqp;
4786     char *maskp;                /* pointer to the star pattern */
4787     int flags;
4788     int any;
4789 } smb_rmdirRock_t;
4790
4791 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4792 {       
4793     long code = 0;
4794     smb_rmdirRock_t *rockp;
4795     int match;
4796     char shortName[13];
4797     char *matchName;
4798         
4799     rockp = (smb_rmdirRock_t *) vrockp;
4800
4801     matchName = dep->name;
4802     if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
4803         match = (cm_stricmp(matchName, rockp->maskp) == 0);
4804     else
4805         match = (strcmp(matchName, rockp->maskp) == 0);
4806     if (!match &&
4807          (rockp->flags & SMB_MASKFLAG_TILDE) &&
4808          !cm_Is8Dot3(dep->name)) {
4809         cm_Gen8Dot3Name(dep, shortName, NULL);
4810         matchName = shortName;
4811         match = (cm_stricmp(matchName, rockp->maskp) == 0);
4812     }       
4813     if (match) {
4814         osi_Log1(smb_logp, "Removing directory %s",
4815                  osi_LogSaveString(smb_logp, matchName));
4816         code = cm_RemoveDir(dscp, dep->name, rockp->userp, rockp->reqp);
4817         if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4818             smb_NotifyChange(FILE_ACTION_REMOVED,
4819                              FILE_NOTIFY_CHANGE_DIR_NAME,
4820                              dscp, dep->name, NULL, TRUE);
4821         if (code == 0)
4822             rockp->any = 1;
4823     }
4824     else code = 0;
4825
4826     return code;
4827 }
4828
4829 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4830 {
4831     long code = 0;
4832     char *pathp;
4833     char *tp;
4834     cm_space_t *spacep;
4835     cm_scache_t *dscp;
4836     char *lastNamep;
4837     smb_rmdirRock_t rock;
4838     cm_user_t *userp;
4839     osi_hyper_t thyper;
4840     int caseFold;
4841     char *tidPathp;
4842     cm_req_t req;
4843
4844     cm_InitReq(&req);
4845
4846     tp = smb_GetSMBData(inp, NULL);
4847     pathp = smb_ParseASCIIBlock(tp, &tp);
4848     if (smb_StoreAnsiFilenames)
4849         OemToChar(pathp,pathp);
4850
4851     spacep = inp->spacep;
4852     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4853
4854     userp = smb_GetUser(vcp, inp);
4855
4856     caseFold = CM_FLAG_CASEFOLD;
4857
4858     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4859     if (code) {
4860         cm_ReleaseUser(userp);
4861         return CM_ERROR_NOSUCHPATH;
4862     }
4863     code = cm_NameI(cm_rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
4864                     userp, tidPathp, &req, &dscp);
4865
4866     if (code) {
4867         cm_ReleaseUser(userp);
4868         return code;
4869     }
4870         
4871     /* otherwise, scp points to the parent directory. */
4872     if (!lastNamep) 
4873         lastNamep = pathp;
4874     else 
4875         lastNamep++;
4876         
4877     rock.any = 0;
4878     rock.maskp = lastNamep;
4879     rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4880
4881     thyper.LowPart = 0;
4882     thyper.HighPart = 0;
4883     rock.userp = userp;
4884     rock.reqp = &req;
4885     rock.dscp = dscp;
4886     /* First do a case sensitive match, and if that fails, do a case insensitive match */
4887     code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
4888     if (code == 0 && !rock.any) {
4889         thyper.LowPart = 0;
4890         thyper.HighPart = 0;
4891         rock.flags |= SMB_MASKFLAG_CASEFOLD;
4892         code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
4893     }
4894
4895     cm_ReleaseUser(userp);
4896         
4897     cm_ReleaseSCache(dscp);
4898
4899     if (code == 0 && !rock.any)
4900         code = CM_ERROR_NOSUCHFILE;        
4901     return code;
4902 }
4903
4904 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4905 {
4906     unsigned short fid;
4907     smb_fid_t *fidp;
4908     cm_user_t *userp;
4909     long code = 0;
4910     cm_req_t req;
4911
4912     cm_InitReq(&req);
4913
4914     fid = smb_GetSMBParm(inp, 0);
4915
4916     osi_Log1(smb_logp, "SMB flush fid %d", fid);
4917
4918     fid = smb_ChainFID(fid, inp);
4919     fidp = smb_FindFID(vcp, fid, 0);
4920     if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4921         if (fidp)
4922             smb_ReleaseFID(fidp);
4923         return CM_ERROR_BADFD;
4924     }
4925         
4926     userp = smb_GetUser(vcp, inp);
4927
4928     lock_ObtainMutex(&fidp->mx);
4929     if (fidp->flags & SMB_FID_OPENWRITE)
4930         code = cm_FSync(fidp->scp, userp, &req);
4931     else 
4932         code = 0;
4933     lock_ReleaseMutex(&fidp->mx);
4934         
4935     smb_ReleaseFID(fidp);
4936         
4937     cm_ReleaseUser(userp);
4938         
4939     return code;
4940 }
4941
4942 struct smb_FullNameRock {
4943     char *name;
4944     cm_scache_t *vnode;
4945     char *fullName;
4946 };
4947
4948 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
4949                      osi_hyper_t *offp)
4950 {
4951     char shortName[13];
4952     struct smb_FullNameRock *vrockp;
4953
4954     vrockp = (struct smb_FullNameRock *)rockp;
4955
4956     if (!cm_Is8Dot3(dep->name)) {
4957         cm_Gen8Dot3Name(dep, shortName, NULL);
4958
4959         if (cm_stricmp(shortName, vrockp->name) == 0) {
4960             vrockp->fullName = strdup(dep->name);
4961             return CM_ERROR_STOPNOW;
4962         }
4963     }
4964     if (cm_stricmp(dep->name, vrockp->name) == 0 &&
4965         ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
4966         ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
4967         vrockp->fullName = strdup(dep->name);
4968         return CM_ERROR_STOPNOW;
4969     }
4970     return 0;
4971 }
4972
4973 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
4974                   char **newPathp, cm_user_t *userp, cm_req_t *reqp)
4975 {
4976     struct smb_FullNameRock rock;
4977     long code = 0;
4978
4979     rock.name = pathp;
4980     rock.vnode = scp;
4981
4982     code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL); 
4983     if (code == CM_ERROR_STOPNOW)
4984         *newPathp = rock.fullName;
4985     else
4986         *newPathp = strdup(pathp);
4987 }
4988
4989 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4990 {
4991     unsigned short fid;
4992     smb_fid_t *fidp;
4993     cm_user_t *userp;
4994     long dosTime;
4995     long code = 0;
4996     cm_req_t req;
4997
4998     cm_InitReq(&req);
4999
5000     fid = smb_GetSMBParm(inp, 0);
5001     dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5002
5003     osi_Log1(smb_logp, "SMB close fid %d", fid);
5004
5005     fid = smb_ChainFID(fid, inp);
5006     fidp = smb_FindFID(vcp, fid, 0);
5007     if (!fidp) {
5008         return CM_ERROR_BADFD;
5009     }
5010         
5011     userp = smb_GetUser(vcp, inp);
5012
5013     lock_ObtainMutex(&fidp->mx);
5014
5015     /* Don't jump the gun on an async raw write */
5016     while (fidp->raw_writers) {
5017         lock_ReleaseMutex(&fidp->mx);
5018         thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
5019         lock_ObtainMutex(&fidp->mx);
5020     }
5021
5022     fidp->flags |= SMB_FID_DELETE;
5023         
5024     /* watch for ioctl closes, and read-only opens */
5025     if (fidp->scp != NULL &&
5026         (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
5027          == SMB_FID_OPENWRITE) {
5028         if (dosTime != 0 && dosTime != -1) {
5029             fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5030             /* This fixes defect 10958 */
5031             CompensateForSmbClientLastWriteTimeBugs(&dosTime);
5032             smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
5033         }
5034         code = cm_FSync(fidp->scp, userp, &req);
5035     }
5036     else 
5037         code = 0;
5038
5039     if (fidp->flags & SMB_FID_DELONCLOSE) {
5040         cm_scache_t *dscp = fidp->NTopen_dscp;
5041         char *pathp = fidp->NTopen_pathp;
5042         char *fullPathp;
5043
5044         smb_FullName(dscp, fidp->scp, pathp, &fullPathp, userp, &req);
5045         if (fidp->scp->fileType == CM_SCACHETYPE_DIRECTORY) {
5046             code = cm_RemoveDir(dscp, fullPathp, userp, &req);
5047             if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5048                 smb_NotifyChange(FILE_ACTION_REMOVED,
5049                                  FILE_NOTIFY_CHANGE_DIR_NAME,
5050                                  dscp, fullPathp, NULL, TRUE);
5051         }
5052         else 
5053         {
5054             code = cm_Unlink(dscp, fullPathp, userp, &req);
5055             if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5056                 smb_NotifyChange(FILE_ACTION_REMOVED,
5057                                  FILE_NOTIFY_CHANGE_FILE_NAME,
5058                                  dscp, fullPathp, NULL, TRUE);
5059         }
5060         free(fullPathp);
5061     }
5062     lock_ReleaseMutex(&fidp->mx);
5063
5064     if (fidp->flags & SMB_FID_NTOPEN) {
5065         cm_ReleaseSCache(fidp->NTopen_dscp);
5066         free(fidp->NTopen_pathp);
5067     }
5068     if (fidp->NTopen_wholepathp)
5069         free(fidp->NTopen_wholepathp);
5070     
5071     smb_ReleaseFID(fidp);
5072     cm_ReleaseUser(userp);
5073     return code;
5074 }
5075
5076 /*
5077  * smb_ReadData -- common code for Read, Read And X, and Raw Read
5078  */
5079 #ifndef DJGPP
5080 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5081         cm_user_t *userp, long *readp)
5082 #else /* DJGPP */
5083 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5084         cm_user_t *userp, long *readp, int dosflag)
5085 #endif /* !DJGPP */
5086 {
5087     osi_hyper_t offset;
5088     long code = 0;
5089     cm_scache_t *scp;
5090     cm_buf_t *bufferp;
5091     osi_hyper_t fileLength;
5092     osi_hyper_t thyper;
5093     osi_hyper_t lastByte;
5094     osi_hyper_t bufferOffset;
5095     long bufIndex, nbytes;
5096     int chunk;
5097     int sequential = 0;
5098     cm_req_t req;
5099
5100     cm_InitReq(&req);
5101
5102     bufferp = NULL;
5103     offset = *offsetp;
5104
5105     lock_ObtainMutex(&fidp->mx);
5106     scp = fidp->scp;
5107     lock_ObtainMutex(&scp->mx);
5108
5109     if (offset.HighPart == 0) {
5110         chunk = offset.LowPart >> cm_logChunkSize;
5111         if (chunk != fidp->curr_chunk) {
5112             fidp->prev_chunk = fidp->curr_chunk;
5113             fidp->curr_chunk = chunk;
5114         }
5115         if (fidp->curr_chunk == fidp->prev_chunk + 1)
5116             sequential = 1;
5117     }       
5118
5119     /* start by looking up the file's end */
5120     code = cm_SyncOp(scp, NULL, userp, &req, 0,
5121                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5122     if (code) goto done;
5123
5124     /* now we have the entry locked, look up the length */
5125     fileLength = scp->length;
5126
5127     /* adjust count down so that it won't go past EOF */
5128     thyper.LowPart = count;
5129     thyper.HighPart = 0;
5130     thyper = LargeIntegerAdd(offset, thyper);   /* where read should end */
5131     lastByte = thyper;
5132     if (LargeIntegerGreaterThan(thyper, fileLength)) {
5133         /* we'd read past EOF, so just stop at fileLength bytes.
5134          * Start by computing how many bytes remain in the file.
5135          */
5136         thyper = LargeIntegerSubtract(fileLength, offset);
5137
5138         /* if we are past EOF, read 0 bytes */
5139         if (LargeIntegerLessThanZero(thyper))
5140             count = 0;
5141         else
5142             count = thyper.LowPart;
5143     }       
5144
5145     *readp = count;
5146
5147     /* now, copy the data one buffer at a time,
5148      * until we've filled the request packet
5149      */
5150     while (1) {
5151         /* if we've copied all the data requested, we're done */
5152         if (count <= 0) break;
5153
5154         /* otherwise, load up a buffer of data */
5155         thyper.HighPart = offset.HighPart;
5156         thyper.LowPart = offset.LowPart & ~(buf_bufferSize-1);
5157         if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5158             /* wrong buffer */
5159             if (bufferp) {
5160                 buf_Release(bufferp);
5161                 bufferp = NULL;
5162             }
5163             lock_ReleaseMutex(&scp->mx);
5164
5165             lock_ObtainRead(&scp->bufCreateLock);
5166             code = buf_Get(scp, &thyper, &bufferp);
5167             lock_ReleaseRead(&scp->bufCreateLock);
5168
5169             lock_ObtainMutex(&scp->mx);
5170             if (code) goto done;
5171             bufferOffset = thyper;
5172
5173             /* now get the data in the cache */
5174             while (1) {
5175                 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
5176                                  CM_SCACHESYNC_NEEDCALLBACK |
5177                                  CM_SCACHESYNC_READ);
5178                 if (code) goto done;
5179                                 
5180                 if (cm_HaveBuffer(scp, bufferp, 0)) break;
5181
5182                 /* otherwise, load the buffer and try again */
5183                 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
5184                 if (code) break;
5185             }
5186             if (code) {
5187                 buf_Release(bufferp);
5188                 bufferp = NULL;
5189                 goto done;
5190             }
5191         }       /* if (wrong buffer) ... */
5192
5193         /* now we have the right buffer loaded.  Copy out the
5194          * data from here to the user's buffer.
5195          */
5196         bufIndex = offset.LowPart & (buf_bufferSize - 1);
5197
5198         /* and figure out how many bytes we want from this buffer */
5199         nbytes = buf_bufferSize - bufIndex;     /* what remains in buffer */
5200         if (nbytes > count) nbytes = count;     /* don't go past EOF */
5201
5202         /* now copy the data */
5203 #ifdef DJGPP
5204         if (dosflag)
5205             dosmemput(bufferp->datap + bufIndex, nbytes, (dos_ptr)op);
5206         else
5207 #endif /* DJGPP */
5208             memcpy(op, bufferp->datap + bufIndex, nbytes);
5209                 
5210         /* adjust counters, pointers, etc. */
5211         op += nbytes;
5212         count -= nbytes;
5213         thyper.LowPart = nbytes;
5214         thyper.HighPart = 0;
5215         offset = LargeIntegerAdd(thyper, offset);
5216     } /* while 1 */
5217
5218   done:
5219     lock_ReleaseMutex(&scp->mx);
5220     lock_ReleaseMutex(&fidp->mx);
5221     if (bufferp) 
5222         buf_Release(bufferp);
5223
5224     if (code == 0 && sequential)
5225         cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
5226
5227     return code;
5228 }
5229
5230 /*
5231  * smb_WriteData -- common code for Write and Raw Write
5232  */
5233 #ifndef DJGPP
5234 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5235         cm_user_t *userp, long *writtenp)
5236 #else /* DJGPP */
5237 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5238         cm_user_t *userp, long *writtenp, int dosflag)
5239 #endif /* !DJGPP */
5240 {
5241     osi_hyper_t offset;
5242     long code = 0;
5243     long written = 0;
5244     cm_scache_t *scp;
5245     osi_hyper_t fileLength;     /* file's length at start of write */
5246     osi_hyper_t minLength;      /* don't read past this */
5247     long nbytes;                /* # of bytes to transfer this iteration */
5248     cm_buf_t *bufferp;
5249     osi_hyper_t thyper;         /* hyper tmp variable */
5250     osi_hyper_t bufferOffset;
5251     long bufIndex;              /* index in buffer where our data is */
5252     int doWriteBack;
5253     osi_hyper_t writeBackOffset;/* offset of region to write back when
5254                                  * I/O is done */
5255     DWORD filter = 0;
5256     cm_req_t req;
5257
5258     osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
5259               fidp->fid, offsetp->LowPart, count);
5260
5261     *writtenp = 0;
5262
5263     cm_InitReq(&req);
5264
5265     bufferp = NULL;
5266     doWriteBack = 0;
5267     offset = *offsetp;
5268
5269     lock_ObtainMutex(&fidp->mx);
5270     scp = fidp->scp;
5271     lock_ObtainMutex(&scp->mx);
5272
5273     /* start by looking up the file's end */
5274     osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|SETSTATUS|GETSTATUS",
5275               fidp->fid);
5276     code = cm_SyncOp(scp, NULL, userp, &req, 0,
5277                       CM_SCACHESYNC_NEEDCALLBACK
5278                       | CM_SCACHESYNC_SETSTATUS
5279                       | CM_SCACHESYNC_GETSTATUS);
5280     osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|SETSTATUS|GETSTATUS returns %d",
5281               fidp->fid,code);
5282     if (code) 
5283         goto done;
5284         
5285     /* make sure we have a writable FD */
5286     if (!(fidp->flags & SMB_FID_OPENWRITE)) {
5287         code = CM_ERROR_BADFDOP;
5288         goto done;
5289     }
5290
5291     /* now we have the entry locked, look up the length */
5292     fileLength = scp->length;
5293     minLength = fileLength;
5294     if (LargeIntegerGreaterThan(minLength, scp->serverLength))
5295         minLength = scp->serverLength;
5296
5297     /* adjust file length if we extend past EOF */
5298     thyper.LowPart = count;
5299     thyper.HighPart = 0;
5300     thyper = LargeIntegerAdd(offset, thyper);   /* where write should end */
5301     if (LargeIntegerGreaterThan(thyper, fileLength)) {
5302         /* we'd write past EOF, so extend the file */
5303         scp->mask |= CM_SCACHEMASK_LENGTH;
5304         scp->length = thyper;
5305         filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
5306     } else
5307         filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
5308
5309     /* now, if the new position (thyper) and the old (offset) are in
5310      * different storeback windows, remember to store back the previous
5311      * storeback window when we're done with the write.
5312      */
5313     if ((thyper.LowPart & (-cm_chunkSize)) !=
5314          (offset.LowPart & (-cm_chunkSize))) {
5315         /* they're different */
5316         doWriteBack = 1;
5317         writeBackOffset.HighPart = offset.HighPart;
5318         writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
5319     }
5320         
5321     *writtenp = count;
5322
5323     /* now, copy the data one buffer at a time, until we've filled the
5324      * request packet */
5325     while (1) {
5326         /* if we've copied all the data requested, we're done */
5327         if (count <= 0) 
5328             break;
5329
5330         /* handle over quota or out of space */
5331         if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
5332             *writtenp = written;
5333             code = CM_ERROR_QUOTA;
5334             break;
5335         }
5336
5337         /* otherwise, load up a buffer of data */
5338         thyper.HighPart = offset.HighPart;
5339         thyper.LowPart = offset.LowPart & ~(buf_bufferSize-1);
5340         if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5341             /* wrong buffer */
5342             if (bufferp) {
5343                 lock_ReleaseMutex(&bufferp->mx);
5344                 buf_Release(bufferp);
5345                 bufferp = NULL;
5346             }   
5347             lock_ReleaseMutex(&scp->mx);
5348
5349             lock_ObtainRead(&scp->bufCreateLock);
5350             code = buf_Get(scp, &thyper, &bufferp);
5351             lock_ReleaseRead(&scp->bufCreateLock);
5352
5353             lock_ObtainMutex(&bufferp->mx);
5354             lock_ObtainMutex(&scp->mx);
5355             if (code) goto done;
5356
5357             bufferOffset = thyper;
5358
5359             /* now get the data in the cache */
5360             while (1) {
5361                 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|WRITE|BUFLOCKED",
5362                           fidp->fid);
5363                 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
5364                                   CM_SCACHESYNC_NEEDCALLBACK
5365                                   | CM_SCACHESYNC_WRITE
5366                                   | CM_SCACHESYNC_BUFLOCKED);
5367                 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|WRITE|BUFLOCKED returns %d",
5368                           fidp->fid,code);
5369                 if (code) 
5370                     goto done;
5371
5372                 /* If we're overwriting the entire buffer, or
5373                  * if we're writing at or past EOF, mark the
5374                  * buffer as current so we don't call
5375                  * cm_GetBuffer.  This skips the fetch from the
5376                  * server in those cases where we're going to 
5377                  * obliterate all the data in the buffer anyway,
5378                  * or in those cases where there is no useful
5379                  * data at the server to start with.
5380                  *
5381                  * Use minLength instead of scp->length, since
5382                  * the latter has already been updated by this
5383                  * call.
5384                  */
5385                 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
5386                      || LargeIntegerEqualTo(offset, bufferp->offset)
5387                      && (count >= buf_bufferSize
5388                           || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
5389                                                                                ConvertLongToLargeInteger(count)),
5390                                                                minLength))) {
5391                     if (count < buf_bufferSize
5392                          && bufferp->dataVersion == -1)
5393                         memset(bufferp->datap, 0,
5394                                 buf_bufferSize);
5395                     bufferp->dataVersion = scp->dataVersion;
5396                 }
5397
5398                 if (cm_HaveBuffer(scp, bufferp, 1)) break;
5399
5400                 /* otherwise, load the buffer and try again */
5401                 lock_ReleaseMutex(&bufferp->mx);
5402                 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5403                                      &req);
5404                 lock_ReleaseMutex(&scp->mx);
5405                 lock_ObtainMutex(&bufferp->mx);
5406                 lock_ObtainMutex(&scp->mx);
5407                 if (code) break;
5408             }
5409             if (code) {
5410                 lock_ReleaseMutex(&bufferp->mx);
5411                 buf_Release(bufferp);
5412                 bufferp = NULL;
5413                 goto done;
5414             }
5415         }       /* if (wrong buffer) ... */
5416
5417         /* now we have the right buffer loaded.  Copy out the
5418          * data from here to the user's buffer.
5419          */
5420         bufIndex = offset.LowPart & (buf_bufferSize - 1);
5421
5422         /* and figure out how many bytes we want from this buffer */
5423         nbytes = buf_bufferSize - bufIndex;     /* what remains in buffer */
5424         if (nbytes > count) 
5425             nbytes = count;     /* don't go past end of request */
5426
5427         /* now copy the data */
5428 #ifdef DJGPP
5429         if (dosflag)
5430             dosmemget((dos_ptr)op, nbytes, bufferp->datap + bufIndex);
5431         else
5432 #endif /* DJGPP */
5433             memcpy(bufferp->datap + bufIndex, op, nbytes);
5434         buf_SetDirty(bufferp);
5435
5436         /* and record the last writer */
5437         if (bufferp->userp != userp) {
5438             cm_HoldUser(userp);
5439             if (bufferp->userp) 
5440                 cm_ReleaseUser(bufferp->userp);
5441             bufferp->userp = userp;
5442         }
5443
5444         /* adjust counters, pointers, etc. */
5445         op += nbytes;
5446         count -= nbytes;
5447         written += nbytes;
5448         thyper.LowPart = nbytes;
5449         thyper.HighPart = 0;
5450         offset = LargeIntegerAdd(thyper, offset);
5451     } /* while 1 */
5452
5453   done:
5454     lock_ReleaseMutex(&scp->mx);
5455     lock_ReleaseMutex(&fidp->mx);
5456     if (bufferp) {
5457         lock_ReleaseMutex(&bufferp->mx);
5458         buf_Release(bufferp);
5459     }
5460
5461     if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
5462          && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
5463         smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
5464                           fidp->NTopen_dscp, fidp->NTopen_pathp,
5465                           NULL, TRUE);
5466     }       
5467
5468     if (code == 0 && doWriteBack) {
5469         long code2;
5470         lock_ObtainMutex(&scp->mx);
5471         osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
5472                   fidp->fid);
5473         code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
5474         osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns %d",
5475                   fidp->fid,code2);
5476         lock_ReleaseMutex(&scp->mx);
5477         cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
5478                             writeBackOffset.HighPart, cm_chunkSize, 0, userp);
5479     }
5480
5481     osi_Log3(smb_logp, "smb_WriteData fid %d returns %d written %d",
5482               fidp->fid, code, *writtenp);
5483     return code;
5484 }
5485
5486 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5487 {
5488     osi_hyper_t offset;
5489     long count, written = 0, total_written = 0;
5490     unsigned short fd;
5491     smb_fid_t *fidp;
5492     long code = 0;
5493     cm_user_t *userp;
5494     cm_attr_t truncAttr;        /* attribute struct used for truncating file */
5495     char *op;
5496     int inDataBlockCount;
5497
5498     fd = smb_GetSMBParm(inp, 0);
5499     count = smb_GetSMBParm(inp, 1);
5500     offset.HighPart = 0;        /* too bad */
5501     offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
5502
5503     op = smb_GetSMBData(inp, NULL);
5504     op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
5505
5506     osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
5507              fd, offset.LowPart, count);
5508         
5509     fd = smb_ChainFID(fd, inp);
5510     fidp = smb_FindFID(vcp, fd, 0);
5511     if (!fidp) {
5512         return CM_ERROR_BADFD;
5513     }
5514         
5515     if (fidp->flags & SMB_FID_IOCTL)
5516         return smb_IoctlWrite(fidp, vcp, inp, outp);
5517         
5518     userp = smb_GetUser(vcp, inp);
5519
5520         /* special case: 0 bytes transferred means truncate to this position */
5521     if (count == 0) {
5522         cm_req_t req;
5523
5524         cm_InitReq(&req);
5525
5526         truncAttr.mask = CM_ATTRMASK_LENGTH;
5527         truncAttr.length.LowPart = offset.LowPart;
5528         truncAttr.length.HighPart = 0;
5529         lock_ObtainMutex(&fidp->mx);
5530         code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
5531         lock_ReleaseMutex(&fidp->mx);
5532         smb_SetSMBParm(outp, 0, /* count */ 0);
5533         smb_SetSMBDataLength(outp, 0);
5534         fidp->flags |= SMB_FID_LENGTHSETDONE;
5535         goto done;
5536     }
5537
5538     /*
5539      * Work around bug in NT client
5540      *
5541      * When copying a file, the NT client should first copy the data,
5542      * then copy the last write time.  But sometimes the NT client does
5543      * these in the wrong order, so the data copies would inadvertently
5544      * cause the last write time to be overwritten.  We try to detect this,
5545      * and don't set client mod time if we think that would go against the
5546      * intention.
5547      */
5548     if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
5549         fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5550         fidp->scp->clientModTime = time(NULL);
5551     }
5552
5553     code = 0;
5554     while ( code == 0 && count > 0 ) {
5555 #ifndef DJGPP
5556         code = smb_WriteData(fidp, &offset, count, op, userp, &written);
5557 #else /* DJGPP */
5558         code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
5559 #endif /* !DJGPP */
5560         if (code == 0 && written == 0)
5561             code = CM_ERROR_PARTIALWRITE;
5562
5563         offset.LowPart += written;
5564         count -= written;
5565         total_written += written;
5566         written = 0;
5567     }
5568     
5569     /* set the packet data length to 3 bytes for the data block header,
5570      * plus the size of the data.
5571      */
5572     smb_SetSMBParm(outp, 0, total_written);
5573     smb_SetSMBDataLength(outp, 0);
5574
5575   done:
5576     smb_ReleaseFID(fidp);
5577     cm_ReleaseUser(userp);
5578
5579     return code;
5580 }
5581
5582 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
5583                           NCB *ncbp, raw_write_cont_t *rwcp)
5584 {
5585     unsigned short fd;
5586     smb_fid_t *fidp;
5587     cm_user_t *userp;
5588 #ifndef DJGPP
5589     char *rawBuf;
5590 #else /* DJGPP */
5591     dos_ptr rawBuf;
5592 #endif /* !DJGPP */
5593     long written = 0;
5594     long code = 0;
5595
5596     fd = smb_GetSMBParm(inp, 0);
5597     fidp = smb_FindFID(vcp, fd, 0);
5598
5599     osi_Log2(smb_logp, "Completing Raw Write offset %x count %x",
5600              rwcp->offset.LowPart, rwcp->count);
5601
5602     userp = smb_GetUser(vcp, inp);
5603
5604 #ifndef DJGPP
5605     rawBuf = rwcp->buf;
5606     code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
5607                                                  &written);
5608 #else /* DJGPP */
5609     rawBuf = (dos_ptr) rwcp->buf;
5610     code = smb_WriteData(fidp, &rwcp->offset, rwcp->count,
5611                          (unsigned char *) rawBuf, userp,
5612                          &written, TRUE);
5613 #endif /* !DJGPP */
5614
5615     if (rwcp->writeMode & 0x1) {        /* synchronous */
5616         smb_t *op;
5617
5618         smb_FormatResponsePacket(vcp, inp, outp);
5619         op = (smb_t *) outp;
5620         op->com = 0x20;         /* SMB_COM_WRITE_COMPLETE */
5621         smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
5622         smb_SetSMBDataLength(outp,  0);
5623         smb_SendPacket(vcp, outp);
5624         smb_FreePacket(outp);
5625     }
5626     else {                              /* asynchronous */
5627         lock_ObtainMutex(&fidp->mx);
5628         fidp->raw_writers--;
5629         if (fidp->raw_writers == 0)
5630             thrd_SetEvent(fidp->raw_write_event);
5631         lock_ReleaseMutex(&fidp->mx);
5632     }
5633
5634     /* Give back raw buffer */
5635     lock_ObtainMutex(&smb_RawBufLock);
5636 #ifndef DJGPP
5637     *((char **)rawBuf) = smb_RawBufs;
5638 #else /* DJGPP */
5639     _farpokel(_dos_ds, rawBuf, smb_RawBufs);
5640 #endif /* !DJGPP */
5641     smb_RawBufs = rawBuf;
5642     lock_ReleaseMutex(&smb_RawBufLock);
5643
5644     smb_ReleaseFID(fidp);
5645     cm_ReleaseUser(userp);
5646 }
5647
5648 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5649 {
5650     return 0;
5651 }
5652
5653 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
5654 {
5655     osi_hyper_t offset;
5656     long count, written = 0, total_written = 0;
5657     long totalCount;
5658     unsigned short fd;
5659     smb_fid_t *fidp;
5660     long code = 0;
5661     cm_user_t *userp;
5662     char *op;
5663     unsigned short writeMode;
5664 #ifndef DJGPP
5665     char *rawBuf;
5666 #else /* DJGPP */
5667     dos_ptr rawBuf;
5668 #endif /* !DJGPP */
5669
5670     fd = smb_GetSMBParm(inp, 0);
5671     totalCount = smb_GetSMBParm(inp, 1);
5672     count = smb_GetSMBParm(inp, 10);
5673     offset.HighPart = 0;        /* too bad */
5674     offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
5675     writeMode = smb_GetSMBParm(inp, 7);
5676
5677     op = (char *) inp->data;
5678     op += smb_GetSMBParm(inp, 11);
5679
5680     osi_Log4(smb_logp,
5681              "smb_ReceiveCoreWriteRaw fd %d, off 0x%x, size 0x%x, WriteMode 0x%x",
5682              fd, offset.LowPart, count, writeMode);
5683         
5684     fd = smb_ChainFID(fd, inp);
5685     fidp = smb_FindFID(vcp, fd, 0);
5686     if (!fidp) {
5687         return CM_ERROR_BADFD;
5688     }
5689         
5690     userp = smb_GetUser(vcp, inp);
5691
5692     /*
5693      * Work around bug in NT client
5694      *
5695      * When copying a file, the NT client should first copy the data,
5696      * then copy the last write time.  But sometimes the NT client does
5697      * these in the wrong order, so the data copies would inadvertently
5698      * cause the last write time to be overwritten.  We try to detect this,
5699      * and don't set client mod time if we think that would go against the
5700      * intention.
5701      */
5702     if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
5703         fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5704         fidp->scp->clientModTime = time(NULL);
5705     }
5706
5707     code = 0;
5708     while ( code == 0 && count > 0 ) {
5709 #ifndef DJGPP
5710         code = smb_WriteData(fidp, &offset, count, op, userp, &written);
5711 #else /* DJGPP */
5712         code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
5713 #endif /* !DJGPP */
5714         if (code == 0 && written == 0)
5715             code = CM_ERROR_PARTIALWRITE;
5716
5717         offset.LowPart += written;
5718         count -= written;
5719         total_written += written;
5720         written = 0;
5721     }
5722
5723     /* Get a raw buffer */
5724     if (code == 0) {
5725         rawBuf = NULL;
5726         lock_ObtainMutex(&smb_RawBufLock);
5727         if (smb_RawBufs) {
5728             /* Get a raw buf, from head of list */
5729             rawBuf = smb_RawBufs;
5730 #ifndef DJGPP
5731             smb_RawBufs = *(char **)smb_RawBufs;
5732 #else /* DJGPP */
5733             smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
5734 #endif /* !DJGPP */
5735         }
5736         else
5737             code = CM_ERROR_USESTD;
5738                 
5739         lock_ReleaseMutex(&smb_RawBufLock);
5740     }
5741
5742     /* Don't allow a premature Close */
5743     if (code == 0 && (writeMode & 1) == 0) {
5744         lock_ObtainMutex(&fidp->mx);
5745         fidp->raw_writers++;
5746         thrd_ResetEvent(fidp->raw_write_event);
5747         lock_ReleaseMutex(&fidp->mx);
5748     }
5749
5750     smb_ReleaseFID(fidp);
5751     cm_ReleaseUser(userp);
5752
5753     if (code) {
5754         smb_SetSMBParm(outp, 0, total_written);
5755         smb_SetSMBDataLength(outp, 0);
5756         ((smb_t *)outp)->com = 0x20;    /* SMB_COM_WRITE_COMPLETE */
5757         rwcp->code = code;
5758         return code;
5759     }
5760
5761     rwcp->code = 0;
5762     rwcp->buf = rawBuf;
5763     rwcp->offset.HighPart = 0;
5764     rwcp->offset.LowPart = offset.LowPart + count;
5765     rwcp->count = totalCount - count;
5766     rwcp->writeMode = writeMode;
5767     rwcp->alreadyWritten = total_written;
5768
5769     /* set the packet data length to 3 bytes for the data block header,
5770      * plus the size of the data.
5771      */
5772     smb_SetSMBParm(outp, 0, 0xffff);
5773     smb_SetSMBDataLength(outp, 0);
5774
5775     return 0;
5776 }
5777
5778 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5779 {
5780     osi_hyper_t offset;
5781     long count, finalCount;
5782     unsigned short fd;
5783     smb_fid_t *fidp;
5784     long code = 0;
5785     cm_user_t *userp;
5786     char *op;
5787         
5788     fd = smb_GetSMBParm(inp, 0);
5789     count = smb_GetSMBParm(inp, 1);
5790     offset.HighPart = 0;        /* too bad */
5791     offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
5792         
5793     osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
5794              fd, offset.LowPart, count);
5795         
5796     fd = smb_ChainFID(fd, inp);
5797     fidp = smb_FindFID(vcp, fd, 0);
5798     if (!fidp) {
5799         return CM_ERROR_BADFD;
5800     }
5801         
5802     if (fidp->flags & SMB_FID_IOCTL) {
5803         return smb_IoctlRead(fidp, vcp, inp, outp);
5804     }
5805         
5806     userp = smb_GetUser(vcp, inp);
5807
5808     /* remember this for final results */
5809     smb_SetSMBParm(outp, 0, count);
5810     smb_SetSMBParm(outp, 1, 0);
5811     smb_SetSMBParm(outp, 2, 0);
5812     smb_SetSMBParm(outp, 3, 0);
5813     smb_SetSMBParm(outp, 4, 0);
5814
5815     /* set the packet data length to 3 bytes for the data block header,
5816      * plus the size of the data.
5817      */
5818     smb_SetSMBDataLength(outp, count+3);
5819         
5820     /* get op ptr after putting in the parms, since otherwise we don't
5821      * know where the data really is.
5822      */
5823     op = smb_GetSMBData(outp, NULL);
5824
5825     /* now emit the data block header: 1 byte of type and 2 bytes of length */
5826     *op++ = 1;  /* data block marker */
5827     *op++ = (unsigned char) (count & 0xff);
5828     *op++ = (unsigned char) ((count >> 8) & 0xff);
5829                 
5830 #ifndef DJGPP
5831     code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
5832 #else /* DJGPP */
5833     code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
5834 #endif /* !DJGPP */
5835
5836     /* fix some things up */
5837     smb_SetSMBParm(outp, 0, finalCount);
5838     smb_SetSMBDataLength(outp, finalCount+3);
5839
5840     smb_ReleaseFID(fidp);
5841         
5842     cm_ReleaseUser(userp);
5843     return code;
5844 }
5845
5846 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5847 {
5848     char *pathp;
5849     long code = 0;
5850     cm_space_t *spacep;
5851     char *tp;
5852     cm_user_t *userp;
5853     cm_scache_t *dscp;                  /* dir we're dealing with */
5854     cm_scache_t *scp;                   /* file we're creating */
5855     cm_attr_t setAttr;
5856     int initialModeBits;
5857     char *lastNamep;
5858     int caseFold;
5859     char *tidPathp;
5860     cm_req_t req;
5861
5862     cm_InitReq(&req);
5863
5864     scp = NULL;
5865         
5866     /* compute initial mode bits based on read-only flag in attributes */
5867     initialModeBits = 0777;
5868         
5869     tp = smb_GetSMBData(inp, NULL);
5870     pathp = smb_ParseASCIIBlock(tp, &tp);
5871     if (smb_StoreAnsiFilenames)
5872         OemToChar(pathp,pathp);
5873
5874     if (strcmp(pathp, "\\") == 0)
5875         return CM_ERROR_EXISTS;
5876
5877     spacep = inp->spacep;
5878     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5879
5880     userp = smb_GetUser(vcp, inp);
5881
5882     caseFold = CM_FLAG_CASEFOLD;
5883
5884     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5885     if (code) {
5886         cm_ReleaseUser(userp);
5887         return CM_ERROR_NOSUCHPATH;
5888     }
5889
5890     code = cm_NameI(cm_rootSCachep, spacep->data,
5891                     caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
5892                     userp, tidPathp, &req, &dscp);
5893
5894     if (code) {
5895         cm_ReleaseUser(userp);
5896         return code;
5897     }
5898         
5899     /* otherwise, scp points to the parent directory.  Do a lookup, and
5900      * fail if we find it.  Otherwise, we do the create.
5901      */
5902     if (!lastNamep) 
5903         lastNamep = pathp;
5904     else 
5905         lastNamep++;
5906     code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
5907     if (scp) cm_ReleaseSCache(scp);
5908     if (code != CM_ERROR_NOSUCHFILE) {
5909         if (code == 0) code = CM_ERROR_EXISTS;
5910         cm_ReleaseSCache(dscp);
5911         cm_ReleaseUser(userp);
5912         return code;
5913     }
5914         
5915     setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5916     setAttr.clientModTime = time(NULL);
5917     code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
5918     if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5919         smb_NotifyChange(FILE_ACTION_ADDED,
5920                          FILE_NOTIFY_CHANGE_DIR_NAME,
5921                          dscp, lastNamep, NULL, TRUE);
5922         
5923     /* we don't need this any longer */
5924     cm_ReleaseSCache(dscp);
5925
5926     if (code) {
5927         /* something went wrong creating or truncating the file */
5928         cm_ReleaseUser(userp);
5929         return code;
5930     }
5931         
5932     /* otherwise we succeeded */
5933     smb_SetSMBDataLength(outp, 0);
5934     cm_ReleaseUser(userp);
5935
5936     return 0;
5937 }
5938
5939 BOOL smb_IsLegalFilename(char *filename)
5940 {
5941     /* 
5942      *  Find the longest substring of filename that does not contain
5943      *  any of the chars in illegalChars.  If that substring is less
5944      *  than the length of the whole string, then one or more of the
5945      *  illegal chars is in filename. 
5946      */
5947     if (strcspn(filename, illegalChars) < strlen(filename))
5948         return FALSE;
5949
5950     return TRUE;
5951 }        
5952
5953 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5954 {
5955     char *pathp;
5956     long code = 0;
5957     cm_space_t *spacep;
5958     char *tp;
5959     int excl;
5960     cm_user_t *userp;
5961     cm_scache_t *dscp;                  /* dir we're dealing with */
5962     cm_scache_t *scp;                   /* file we're creating */
5963     cm_attr_t setAttr;
5964     int initialModeBits;
5965     smb_fid_t *fidp;
5966     int attributes;
5967     char *lastNamep;
5968     int caseFold;
5969     long dosTime;
5970     char *tidPathp;
5971     cm_req_t req;
5972
5973     cm_InitReq(&req);
5974
5975     scp = NULL;
5976     excl = (inp->inCom == 0x03)? 0 : 1;
5977         
5978     attributes = smb_GetSMBParm(inp, 0);
5979     dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5980         
5981     /* compute initial mode bits based on read-only flag in attributes */
5982     initialModeBits = 0666;
5983     if (attributes & 1) initialModeBits &= ~0222;
5984         
5985     tp = smb_GetSMBData(inp, NULL);
5986     pathp = smb_ParseASCIIBlock(tp, &tp);
5987     if (smb_StoreAnsiFilenames)
5988         OemToChar(pathp,pathp);
5989
5990     spacep = inp->spacep;
5991     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5992
5993     userp = smb_GetUser(vcp, inp);
5994
5995     caseFold = CM_FLAG_CASEFOLD;
5996
5997     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5998     if (code) {
5999         cm_ReleaseUser(userp);
6000         return CM_ERROR_NOSUCHPATH;
6001     }
6002     code = cm_NameI(cm_rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
6003                     userp, tidPathp, &req, &dscp);
6004
6005     if (code) {
6006         cm_ReleaseUser(userp);
6007         return code;
6008     }
6009         
6010     /* otherwise, scp points to the parent directory.  Do a lookup, and
6011      * truncate the file if we find it, otherwise we create the file.
6012      */
6013     if (!lastNamep) 
6014         lastNamep = pathp;
6015     else 
6016         lastNamep++;
6017
6018     if (!smb_IsLegalFilename(lastNamep))
6019         return CM_ERROR_BADNTFILENAME;
6020
6021     osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
6022 #ifdef DEBUG_VERBOSE
6023     {
6024         char *hexp;
6025         hexp = osi_HexifyString( lastNamep );
6026         DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
6027         free(hexp);
6028     }
6029 #endif    
6030
6031     code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6032     if (code && code != CM_ERROR_NOSUCHFILE) {
6033         cm_ReleaseSCache(dscp);
6034         cm_ReleaseUser(userp);
6035         return code;
6036     }
6037         
6038     /* if we get here, if code is 0, the file exists and is represented by
6039      * scp.  Otherwise, we have to create it.
6040      */
6041     if (code == 0) {
6042         if (excl) {
6043             /* oops, file shouldn't be there */
6044             cm_ReleaseSCache(dscp);
6045             cm_ReleaseSCache(scp);
6046             cm_ReleaseUser(userp);
6047             return CM_ERROR_EXISTS;
6048         }
6049
6050         setAttr.mask = CM_ATTRMASK_LENGTH;
6051         setAttr.length.LowPart = 0;
6052         setAttr.length.HighPart = 0;
6053         code = cm_SetAttr(scp, &setAttr, userp, &req);
6054     }
6055     else {
6056         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6057         smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
6058         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
6059                          &req);
6060         if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6061             smb_NotifyChange(FILE_ACTION_ADDED,
6062                              FILE_NOTIFY_CHANGE_FILE_NAME,
6063                              dscp, lastNamep, NULL, TRUE);
6064         if (!excl && code == CM_ERROR_EXISTS) {
6065             /* not an exclusive create, and someone else tried
6066              * creating it already, then we open it anyway.  We
6067              * don't bother retrying after this, since if this next
6068              * fails, that means that the file was deleted after
6069              * we started this call.
6070              */
6071             code = cm_Lookup(dscp, lastNamep, caseFold, userp,
6072                              &req, &scp);
6073             if (code == 0) {
6074                 setAttr.mask = CM_ATTRMASK_LENGTH;
6075                 setAttr.length.LowPart = 0;
6076                 setAttr.length.HighPart = 0;
6077                 code = cm_SetAttr(scp, &setAttr, userp, &req);
6078             }
6079         }
6080     }
6081         
6082     /* we don't need this any longer */
6083     cm_ReleaseSCache(dscp);
6084
6085     if (code) {
6086         /* something went wrong creating or truncating the file */
6087         if (scp) cm_ReleaseSCache(scp);
6088         cm_ReleaseUser(userp);
6089         return code;
6090     }
6091
6092     /* make sure we only open files */
6093     if (scp->fileType != CM_SCACHETYPE_FILE) {
6094         cm_ReleaseSCache(scp);
6095         cm_ReleaseUser(userp);
6096         return CM_ERROR_ISDIR;
6097     }
6098
6099     /* now all we have to do is open the file itself */
6100     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6101     osi_assert(fidp);
6102         
6103     /* save a pointer to the vnode */
6104     fidp->scp = scp;
6105         
6106     /* always create it open for read/write */
6107     fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
6108
6109     smb_ReleaseFID(fidp);
6110         
6111     smb_SetSMBParm(outp, 0, fidp->fid);
6112     smb_SetSMBDataLength(outp, 0);
6113
6114     cm_Open(scp, 0, userp);
6115
6116     cm_ReleaseUser(userp);
6117     /* leave scp held since we put it in fidp->scp */
6118     return 0;
6119 }
6120
6121 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6122 {
6123     long code = 0;
6124     long offset;
6125     int whence;
6126     unsigned short fd;
6127     smb_fid_t *fidp;
6128     cm_scache_t *scp;
6129     cm_user_t *userp;
6130     cm_req_t req;
6131
6132     cm_InitReq(&req);
6133         
6134     fd = smb_GetSMBParm(inp, 0);
6135     whence = smb_GetSMBParm(inp, 1);
6136     offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6137         
6138     /* try to find the file descriptor */
6139     fd = smb_ChainFID(fd, inp);
6140     fidp = smb_FindFID(vcp, fd, 0);
6141     if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
6142         return CM_ERROR_BADFD;
6143     }
6144         
6145     userp = smb_GetUser(vcp, inp);
6146
6147     lock_ObtainMutex(&fidp->mx);
6148     scp = fidp->scp;
6149     lock_ObtainMutex(&scp->mx);
6150     code = cm_SyncOp(scp, NULL, userp, &req, 0,
6151                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6152     if (code == 0) {
6153         if (whence == 1) {
6154             /* offset from current offset */
6155             offset += fidp->offset;
6156         }
6157         else if (whence == 2) {
6158             /* offset from current EOF */
6159             offset += scp->length.LowPart;
6160         }
6161         fidp->offset = offset;
6162         smb_SetSMBParm(outp, 0, offset & 0xffff);
6163         smb_SetSMBParm(outp, 1, (offset>>16) & 0xffff);
6164         smb_SetSMBDataLength(outp, 0);
6165     }
6166     lock_ReleaseMutex(&scp->mx);
6167     lock_ReleaseMutex(&fidp->mx);
6168     smb_ReleaseFID(fidp);
6169     cm_ReleaseUser(userp);
6170     return code;
6171 }
6172
6173 /* dispatch all of the requests received in a packet.  Due to chaining, this may
6174  * be more than one request.
6175  */
6176 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6177                         NCB *ncbp, raw_write_cont_t *rwcp)
6178 {
6179     smb_dispatch_t *dp;
6180     smb_t *smbp;
6181     unsigned long code = 0;
6182     unsigned char *outWctp;
6183     int nparms;                 /* # of bytes of parameters */
6184     char tbuffer[200];
6185     int nbytes;                 /* bytes of data, excluding count */
6186     int temp;
6187     unsigned char *tp;
6188     unsigned short errCode;
6189     unsigned long NTStatus;
6190     int noSend;
6191     unsigned char errClass;
6192     unsigned int oldGen;
6193     DWORD oldTime, newTime;
6194
6195     /* get easy pointer to the data */
6196     smbp = (smb_t *) inp->data;
6197
6198     if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
6199         /* setup the basic parms for the initial request in the packet */
6200         inp->inCom = smbp->com;
6201         inp->wctp = &smbp->wct;
6202         inp->inCount = 0;
6203         inp->ncb_length = ncbp->ncb_length;
6204     }
6205     noSend = 0;
6206
6207     /* Sanity check */
6208     if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
6209         /* log it and discard it */
6210 #ifndef DJGPP
6211         HANDLE h;
6212         char *ptbuf[1];
6213         char s[100];
6214         h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6215         sprintf(s, "SMB message too short, len %d", ncbp->ncb_length);
6216         ptbuf[0] = s;
6217         ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1007, NULL,
6218                      1, ncbp->ncb_length, ptbuf, inp);
6219         DeregisterEventSource(h);
6220 #else /* DJGPP */
6221         osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
6222 #endif /* !DJGPP */
6223         return;
6224     }
6225
6226     /* We are an ongoing op */
6227     thrd_Increment(&ongoingOps);
6228
6229     /* set up response packet for receiving output */
6230     if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
6231         smb_FormatResponsePacket(vcp, inp, outp);
6232     outWctp = outp->wctp;
6233
6234     /* Remember session generation number and time */
6235     oldGen = sessionGen;
6236     oldTime = GetCurrentTime();
6237
6238     while (inp->inCom != 0xff) {
6239         dp = &smb_dispatchTable[inp->inCom];
6240
6241         if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
6242             outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
6243             code = outp->resumeCode;
6244             goto resume;
6245         }
6246
6247         /* process each request in the packet; inCom, wctp and inCount
6248          * are already set up.
6249          */
6250         osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
6251                   ncbp->ncb_lsn);
6252
6253         /* now do the dispatch */
6254         /* start by formatting the response record a little, as a default */
6255         if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
6256             outWctp[0] = 2;
6257             outWctp[1] = 0xff;  /* no operation */
6258             outWctp[2] = 0;             /* padding */
6259             outWctp[3] = 0;
6260             outWctp[4] = 0;
6261         }
6262         else {
6263             /* not a chained request, this is a more reasonable default */
6264             outWctp[0] = 0;     /* wct of zero */
6265             outWctp[1] = 0;     /* and bcc (word) of zero */
6266             outWctp[2] = 0;
6267         }   
6268
6269         /* once set, stays set.  Doesn't matter, since we never chain
6270          * "no response" calls.
6271          */
6272         if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
6273             noSend = 1;
6274
6275         if (dp->procp) {
6276             /* we have a recognized operation */
6277
6278             if (inp->inCom == 0x1d)
6279                 /* Raw Write */
6280                 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp,
6281                                                  rwcp);
6282             else {
6283                 osi_LogEvent("AFS Dispatch %s",(myCrt_Dispatch(inp->inCom)),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
6284                 osi_Log4(smb_logp,"Dispatch %s vcp[%x] lana[%d] lsn[%d]",(myCrt_Dispatch(inp->inCom)),vcp,vcp->lana,vcp->lsn);
6285                 code = (*(dp->procp)) (vcp, inp, outp);
6286                 osi_LogEvent("AFS Dispatch return",NULL,"Code[%d]",(code==0)?0:code-CM_ERROR_BASE);
6287                 osi_Log1(smb_logp,"Dispatch return  code[%d]",(code==0)?0:code-CM_ERROR_BASE);
6288 #ifdef LOG_PACKET
6289                 if ( code == CM_ERROR_BADSMB ||
6290                      code == CM_ERROR_BADOP )
6291                 smb_LogPacket(inp);
6292 #endif /* LOG_PACKET */
6293             }   
6294
6295             if (oldGen != sessionGen) {
6296 #ifndef DJGPP
6297                 HANDLE h;
6298                 char *ptbuf[1];
6299                 char s[100];
6300                 newTime = GetCurrentTime();
6301                 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6302                 sprintf(s, "Pkt straddled session startup, took %d ms, ncb length %d",
6303                          newTime - oldTime, ncbp->ncb_length);
6304                 ptbuf[0] = s;
6305                 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
6306                              1005, NULL, 1, ncbp->ncb_length, ptbuf, smbp);
6307                 DeregisterEventSource(h);
6308 #endif /* !DJGPP */
6309                 osi_Log1(smb_logp, "Pkt straddled session startup, "
6310                           "ncb length %d", ncbp->ncb_length);
6311             }
6312         }
6313         else {
6314             /* bad opcode, fail the request, after displaying it */
6315             osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
6316 #ifdef LOG_PACKET
6317             smb_LogPacket(inp);
6318 #endif  /* LOG_PACKET */
6319
6320 #ifndef DJGPP
6321             if (showErrors) {
6322                 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
6323                 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
6324                                       MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
6325                 if (code == IDCANCEL) 
6326                     showErrors = 0;
6327             }
6328 #endif /* DJGPP */
6329             code = CM_ERROR_BADOP;
6330         }
6331
6332         /* catastrophic failure:  log as much as possible */
6333         if (code == CM_ERROR_BADSMB) {
6334 #ifndef DJGPP
6335             HANDLE h;
6336             char *ptbuf[1];
6337             char s[100];
6338
6339             osi_Log1(smb_logp,
6340                       "Invalid SMB, ncb_length %d",
6341                       ncbp->ncb_length);
6342
6343             h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6344             sprintf(s, "Invalid SMB message, length %d",
6345                      ncbp->ncb_length);
6346             ptbuf[0] = s;
6347             ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1002, NULL,
6348                          1, ncbp->ncb_length, ptbuf, smbp);
6349             DeregisterEventSource(h);
6350 #ifdef LOG_PACKET
6351             smb_LogPacket(inp);
6352 #endif /* LOG_PACKET */
6353 #endif /* !DJGPP */
6354             osi_Log1(smb_logp, "Invalid SMB message, length %d",
6355                      ncbp->ncb_length);
6356
6357             code = CM_ERROR_INVAL;
6358         }
6359
6360         if (outp->flags & SMB_PACKETFLAG_NOSEND) {
6361             thrd_Decrement(&ongoingOps);
6362             return;
6363         }
6364
6365       resume:
6366         /* now, if we failed, turn the current response into an empty
6367          * one, and fill in the response packet's error code.
6368          */
6369         if (code) {
6370             if (vcp->flags & SMB_VCFLAG_STATUS32) {
6371                 smb_MapNTError(code, &NTStatus);
6372                 outWctp = outp->wctp;
6373                 smbp = (smb_t *) &outp->data;
6374                 if (code != CM_ERROR_PARTIALWRITE
6375                      && code != CM_ERROR_BUFFERTOOSMALL 
6376                      && code != CM_ERROR_GSSCONTINUE) {
6377                     /* nuke wct and bcc.  For a partial
6378                      * write or an in-process authentication handshake, 
6379                      * assume they're OK.
6380                      */
6381                     *outWctp++ = 0;
6382                     *outWctp++ = 0;
6383                     *outWctp++ = 0;
6384                 }
6385                 smbp->rcls = (unsigned char) (NTStatus & 0xff);
6386                 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
6387                 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
6388                 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
6389                 smbp->flg2 |= SMB_FLAGS2_ERR_STATUS;
6390                 break;
6391             }
6392             else {
6393                 smb_MapCoreError(code, vcp, &errCode, &errClass);
6394                 outWctp = outp->wctp;
6395                 smbp = (smb_t *) &outp->data;
6396                 if (code != CM_ERROR_PARTIALWRITE) {
6397                     /* nuke wct and bcc.  For a partial
6398                      * write, assume they're OK.
6399                      */
6400                     *outWctp++ = 0;
6401                     *outWctp++ = 0;
6402                     *outWctp++ = 0;
6403                 }
6404                 smbp->errLow = (unsigned char) (errCode & 0xff);
6405                 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
6406                 smbp->rcls = errClass;
6407                 break;
6408             }
6409         }       /* error occurred */
6410
6411         /* if we're here, we've finished one request.  Look to see if
6412          * this is a chained opcode.  If it is, setup things to process
6413          * the chained request, and setup the output buffer to hold the
6414          * chained response.  Start by finding the next input record.
6415          */
6416         if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
6417             break;              /* not a chained req */
6418         tp = inp->wctp;         /* points to start of last request */
6419         /* in a chained request, the first two
6420          * parm fields are required, and are
6421          * AndXCommand/AndXReserved and
6422          * AndXOffset. */
6423         if (tp[0] < 2) break;   
6424         if (tp[1] == 0xff) break;       /* no more chained opcodes */
6425         inp->inCom = tp[1];
6426         inp->wctp = inp->data + tp[3] + (tp[4] << 8);
6427         inp->inCount++;
6428
6429         /* and now append the next output request to the end of this
6430          * last request.  Begin by finding out where the last response
6431          * ends, since that's where we'll put our new response.
6432          */
6433         outWctp = outp->wctp;           /* ptr to out parameters */
6434         osi_assert (outWctp[0] >= 2);   /* need this for all chained requests */
6435         nparms = outWctp[0] << 1;
6436         tp = outWctp + nparms + 1;      /* now points to bcc field */
6437         nbytes = tp[0] + (tp[1] << 8);  /* # of data bytes */
6438         tp += 2 /* for the count itself */ + nbytes;
6439         /* tp now points to the new output record; go back and patch the
6440          * second parameter (off2) to point to the new record.
6441          */
6442         temp = (unsigned int)tp - ((unsigned int) outp->data);
6443         outWctp[3] = (unsigned char) (temp & 0xff);
6444         outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
6445         outWctp[2] = 0; /* padding */
6446         outWctp[1] = inp->inCom;        /* next opcode */
6447
6448         /* finally, setup for the next iteration */
6449         outp->wctp = tp;
6450         outWctp = tp;
6451     }   /* while loop over all requests in the packet */
6452
6453     /* done logging out, turn off logging-out flag */
6454     if (!(inp->flags & SMB_PACKETFLAG_PROFILE_UPDATE_OK)) {
6455         vcp->justLoggedOut = NULL;
6456         if (loggedOut) {
6457             loggedOut = 0;
6458             free(loggedOutName);
6459             loggedOutName = NULL;
6460             smb_ReleaseUID(loggedOutUserp);
6461             loggedOutUserp = NULL;
6462         }
6463     }
6464  
6465     /* now send the output packet, and return */
6466     if (!noSend)
6467         smb_SendPacket(vcp, outp);
6468         thrd_Decrement(&ongoingOps);
6469
6470         if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
6471         if (active_vcp) {
6472             smb_ReleaseVC(active_vcp);
6473             osi_Log2(smb_logp,
6474                       "Replacing active_vcp %x with %x", active_vcp, vcp);
6475         }
6476         smb_HoldVC(vcp);
6477             active_vcp = vcp;
6478             last_msg_time = GetCurrentTime();
6479         }       
6480         else if (active_vcp == vcp) {
6481             smb_ReleaseVC(active_vcp);
6482             active_vcp = NULL;
6483     }
6484
6485     return;
6486 }
6487
6488 #ifndef DJGPP
6489 /* Wait for Netbios() calls to return, and make the results available to server
6490  * threads.  Note that server threads can't wait on the NCBevents array
6491  * themselves, because NCB events are manual-reset, and the servers would race
6492  * each other to reset them.
6493  */
6494 void smb_ClientWaiter(void *parmp)
6495 {
6496     DWORD code;
6497     int   idx;
6498
6499     while (1) {
6500         code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
6501                                                  FALSE, INFINITE);
6502         if (code == WAIT_OBJECT_0) {
6503             if (smbShutdownFlag == 1)
6504                 break;
6505             else
6506                 continue;
6507         }
6508
6509         /* error checking */
6510         if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6511         {
6512             int abandonIdx = code - WAIT_ABANDONED_0;
6513             osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6514         }
6515
6516         if (code == WAIT_IO_COMPLETION)
6517         {
6518             osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
6519             continue;
6520         }
6521         
6522         if (code == WAIT_TIMEOUT)
6523         {
6524             osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
6525         }
6526
6527         if (code == WAIT_FAILED)
6528         {
6529             osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
6530         }
6531
6532         idx = code - WAIT_OBJECT_0;
6533  
6534         /* check idx range! */
6535         if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
6536         {
6537             /* this is fatal - log as much as possible */
6538             osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
6539             osi_assert(0);
6540         }
6541         
6542         thrd_ResetEvent(NCBevents[idx]);
6543         thrd_SetEvent(NCBreturns[0][idx]);
6544     }
6545 }
6546 #endif /* !DJGPP */
6547
6548 /*
6549  * Try to have one NCBRECV request waiting for every live session.  Not more
6550  * than one, because if there is more than one, it's hard to handle Write Raw.
6551  */
6552 void smb_ServerWaiter(void *parmp)
6553 {
6554     DWORD code;
6555     int idx_session, idx_NCB;
6556     NCB *ncbp;
6557 #ifdef DJGPP
6558     dos_ptr dos_ncb;
6559 #endif /* DJGPP */
6560
6561     while (1) {
6562         /* Get a session */
6563         code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
6564                                                  FALSE, INFINITE);
6565         if (code == WAIT_OBJECT_0) {
6566             if ( smbShutdownFlag == 1 )
6567                 break;
6568             else
6569                 continue;
6570         }
6571
6572         if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
6573         {
6574             int abandonIdx = code - WAIT_ABANDONED_0;
6575             osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6576         }
6577         
6578         if (code == WAIT_IO_COMPLETION)
6579         {
6580             osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
6581             continue;
6582         }
6583         
6584         if (code == WAIT_TIMEOUT)
6585         {
6586             osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
6587         }
6588         
6589         if (code == WAIT_FAILED)
6590         {
6591             osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
6592         }
6593         
6594         idx_session = code - WAIT_OBJECT_0;
6595
6596         /* check idx range! */
6597         if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
6598         {
6599             /* this is fatal - log as much as possible */
6600             osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
6601             osi_assert(0);
6602         }
6603
6604                 /* Get an NCB */
6605       NCBretry:
6606         code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
6607                                                  FALSE, INFINITE);
6608         if (code == WAIT_OBJECT_0) {
6609             if ( smbShutdownFlag == 1 ) 
6610                 break;
6611             else
6612                 goto NCBretry;
6613         }
6614
6615         /* error checking */
6616         if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6617         {
6618             int abandonIdx = code - WAIT_ABANDONED_0;
6619             osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6620         }
6621         
6622         if (code == WAIT_IO_COMPLETION)
6623         {
6624             osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
6625             continue;
6626         }
6627         
6628         if (code == WAIT_TIMEOUT)
6629         {
6630             osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
6631         }
6632         
6633         if (code == WAIT_FAILED)
6634         {
6635             osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
6636         }
6637                 
6638         idx_NCB = code - WAIT_OBJECT_0;
6639
6640         /* check idx range! */
6641         if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
6642         {
6643             /* this is fatal - log as much as possible */
6644             osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
6645             osi_assert(0);
6646         }
6647
6648         /* Link them together */
6649         NCBsessions[idx_NCB] = idx_session;
6650
6651         /* Fire it up */
6652         ncbp = NCBs[idx_NCB];
6653         ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
6654         ncbp->ncb_command = NCBRECV | ASYNCH;
6655         ncbp->ncb_lana_num = lanas[idx_session];
6656 #ifndef DJGPP
6657         ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
6658         ncbp->ncb_event = NCBevents[idx_NCB];
6659         ncbp->ncb_length = SMB_PACKETSIZE;
6660         Netbios(ncbp);
6661 #else /* DJGPP */
6662         ncbp->ncb_buffer = bufs[idx_NCB]->dos_pkt;
6663         ((smb_ncb_t*)ncbp)->orig_pkt = bufs[idx_NCB];
6664         ncbp->ncb_event = NCBreturns[0][idx_NCB];
6665         ncbp->ncb_length = SMB_PACKETSIZE;
6666         dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6667         Netbios(ncbp, dos_ncb);
6668 #endif /* !DJGPP */
6669     }
6670 }
6671
6672 /*
6673  * The top level loop for handling SMB request messages.  Each server thread
6674  * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
6675  * NCB and buffer for the incoming request are loaned to us.
6676  *
6677  * Write Raw trickery starts here.  When we get a Write Raw, we are supposed
6678  * to immediately send a request for the rest of the data.  This must come
6679  * before any other traffic for that session, so we delay setting the session
6680  * event until that data has come in.
6681  */
6682 void smb_Server(VOID *parmp)
6683 {
6684     int myIdx = (int) parmp;
6685     NCB *ncbp;
6686     NCB *outncbp;
6687     smb_packet_t *bufp;
6688     smb_packet_t *outbufp;
6689     DWORD code, rcode;
6690     int idx_NCB, idx_session;
6691     UCHAR rc;
6692     smb_vc_t *vcp = NULL;
6693     smb_t *smbp;
6694 #ifdef DJGPP
6695     dos_ptr dos_ncb;
6696 #endif /* DJGPP */
6697
6698     outncbp = GetNCB();
6699     outbufp = GetPacket();
6700     outbufp->ncbp = outncbp;
6701
6702     while (1) {
6703         code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
6704                                                  FALSE, INFINITE);
6705
6706         /* terminate silently if shutdown flag is set */
6707         if (code == WAIT_OBJECT_0) {
6708             if (smbShutdownFlag == 1) {
6709                 thrd_SetEvent(smb_ServerShutdown[myIdx]);
6710                 break;
6711             } else
6712                 continue;
6713         }
6714
6715         /* error checking */
6716         if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6717         {
6718             int abandonIdx = code - WAIT_ABANDONED_0;
6719             osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
6720         }
6721         
6722         if (code == WAIT_IO_COMPLETION)
6723         {
6724             osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
6725             continue;
6726         }
6727         
6728         if (code == WAIT_TIMEOUT)
6729         {
6730             osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
6731         }
6732         
6733         if (code == WAIT_FAILED)
6734         {
6735             osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
6736         }
6737
6738         idx_NCB = code - WAIT_OBJECT_0;
6739         
6740         /* check idx range! */
6741         if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
6742         {
6743             /* this is fatal - log as much as possible */
6744             osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
6745             osi_assert(0);
6746         }
6747
6748         ncbp = NCBs[idx_NCB];
6749 #ifdef DJGPP
6750         dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6751 #endif /* DJGPP */
6752         idx_session = NCBsessions[idx_NCB];
6753         rc = ncbp->ncb_retcode;
6754
6755         if (rc != NRC_PENDING && rc != NRC_GOODRET)
6756             osi_Log1(smb_logp, "NCBRECV failure code %d", rc);
6757
6758         switch (rc) {
6759         case NRC_GOODRET: break;
6760
6761         case NRC_PENDING:
6762             /* Can this happen? Or is it just my
6763              * UNIX paranoia? 
6764              */
6765             continue;
6766
6767         case NRC_SCLOSED:
6768         case NRC_SNUMOUT:
6769             /* Client closed session */
6770             if (reportSessionStartups) 
6771             {
6772                 osi_Log1(smb_logp, "session [ %d ] closed", idx_session);
6773             }
6774             dead_sessions[idx_session] = TRUE;
6775             if (vcp)
6776                 smb_ReleaseVC(vcp);
6777             vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
6778             /* Should also release vcp.  [done] 2004-05-11 jaltman
6779              * Also, should do
6780              * sanity check that all TID's are gone. 
6781              *
6782              * TODO: check if we could use LSNs[idx_session] instead, 
6783              * also cleanup after dead vcp 
6784              */
6785             if (vcp) {
6786                 if (dead_vcp)
6787                     osi_Log1(smb_logp,
6788                              "dead_vcp already set, %x",
6789                              dead_vcp);
6790                 if (!dead_vcp && !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
6791                     osi_Log2(smb_logp,
6792                              "setting dead_vcp %x, user struct %x",
6793                              vcp, vcp->usersp);
6794                     smb_HoldVC(vcp);
6795                     dead_vcp = vcp;
6796                     vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
6797                 }
6798                 if (vcp->justLoggedOut) {
6799                     loggedOut = 1;
6800                     loggedOutTime = vcp->logoffTime;
6801                     loggedOutName = strdup(vcp->justLoggedOut->unp->name);
6802                     loggedOutUserp = vcp->justLoggedOut;
6803                     lock_ObtainWrite(&smb_rctLock);
6804                     loggedOutUserp->refCount++;
6805                     lock_ReleaseWrite(&smb_rctLock);
6806                 }
6807             }
6808             goto doneWithNCB;
6809
6810         case NRC_INCOMP:
6811             /* Treat as transient error */
6812             {
6813 #ifndef DJGPP
6814                 EVENT_HANDLE h;
6815                 char *ptbuf[1];
6816                 char s[100];
6817
6818                 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6819                 sprintf(s, "SMB message incomplete, length %d",
6820                          ncbp->ncb_length);
6821                 ptbuf[0] = s;
6822                 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
6823                              1001, NULL, 1,
6824                              ncbp->ncb_length, ptbuf,
6825                              bufp);
6826                 DeregisterEventSource(h);
6827 #endif /* !DJGPP */
6828                 osi_Log1(smb_logp,
6829                           "dispatch smb recv failed, message incomplete, ncb_length %d",
6830                           ncbp->ncb_length);
6831                 osi_Log1(smb_logp,
6832                           "SMB message incomplete, "
6833                           "length %d", ncbp->ncb_length);
6834
6835                 /*
6836                  * We used to discard the packet.
6837                  * Instead, try handling it normally.
6838                  *
6839                  continue;
6840                  */
6841                 break;
6842             }
6843
6844         default:
6845             /* A weird error code.  Log it, sleep, and
6846             * continue. */
6847             if (vcp && vcp->errorCount++ > 3) {
6848                 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
6849                 dead_sessions[idx_session] = TRUE;
6850             }
6851             else {
6852                 thrd_Sleep(1000);
6853                 thrd_SetEvent(SessionEvents[idx_session]);
6854             }
6855             continue;
6856         }
6857
6858         /* Success, so now dispatch on all the data in the packet */
6859
6860         smb_concurrentCalls++;
6861         if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
6862             smb_maxObsConcurrentCalls = smb_concurrentCalls;
6863
6864         if (vcp)
6865             smb_ReleaseVC(vcp);
6866         vcp = smb_FindVC(ncbp->ncb_lsn, 0, ncbp->ncb_lana_num);
6867         /*
6868          * If at this point vcp is NULL (implies that packet was invalid)
6869          * then we are in big trouble. This means either :
6870          *   a) we have the wrong NCB.
6871          *   b) Netbios screwed up the call.
6872          * Obviously this implies that 
6873          *   ( LSNs[idx_session] != ncbp->ncb_lsn ||
6874          *   lanas[idx_session] != ncbp->ncb_lana_num )
6875          * Either way, we can't do anything with this packet.
6876          * Log, sleep and resume.
6877          */
6878         if (!vcp) {
6879             HANDLE h;
6880             char buf[1000];
6881             char *ptbuf[1];
6882
6883             sprintf(buf,
6884                      "Bad vcp!! : "
6885                      "LSNs[idx_session]=[%d],"
6886                      "lanas[idx_session]=[%d],"
6887                      "ncbp->ncb_lsn=[%d],"
6888                      "ncbp->ncb_lana_num=[%d]",
6889                      LSNs[idx_session],
6890                      lanas[idx_session],
6891                      ncbp->ncb_lsn,
6892                      ncbp->ncb_lana_num);
6893
6894             ptbuf[0] = buf;
6895
6896             h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
6897             if (h) {
6898                 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,sizeof(*ncbp),ptbuf,(void*)ncbp);
6899                 DeregisterEventSource(h);
6900             }
6901
6902             /* Also log in the trace log. */
6903             osi_Log4(smb_logp, "Server: BAD VCP!"
6904                       "LSNs[idx_session]=[%d],"
6905                       "lanas[idx_session]=[%d],"
6906                       "ncbp->ncb_lsn=[%d],"
6907                       "ncbp->ncb_lana_num=[%d]",
6908                       LSNs[idx_session],
6909                       lanas[idx_session],
6910                       ncbp->ncb_lsn,
6911                       ncbp->ncb_lana_num);
6912
6913             /* thrd_Sleep(1000); Don't bother sleeping */
6914             thrd_SetEvent(SessionEvents[idx_session]);
6915             smb_concurrentCalls--;
6916             continue;
6917         }
6918
6919
6920         vcp->errorCount = 0;
6921         bufp = (struct smb_packet *) ncbp->ncb_buffer;
6922 #ifdef DJGPP
6923         bufp = ((smb_ncb_t *) ncbp)->orig_pkt;
6924         /* copy whole packet to virtual memory */
6925         /*fprintf(stderr, "smb_Server: copying dos packet at 0x%x, "
6926         "bufp=0x%x\n",
6927         bufp->dos_pkt / 16, bufp);*/
6928         fflush(stderr);
6929         dosmemget(bufp->dos_pkt, ncbp->ncb_length, bufp->data);
6930 #endif /* DJGPP */
6931         smbp = (smb_t *)bufp->data;
6932         outbufp->flags = 0;
6933
6934 #if !defined(DJGPP) && !defined(AFS_WIN32_ENV)
6935         __try
6936         {
6937 #endif
6938             if (smbp->com == 0x1d) {
6939                 /* Special handling for Write Raw */
6940                 raw_write_cont_t rwc;
6941                 EVENT_HANDLE rwevent;
6942                 char eventName[MAX_PATH];
6943             
6944                 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
6945                 if (rwc.code == 0) {
6946                     rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
6947                     if ( GetLastError() == ERROR_ALREADY_EXISTS )
6948                         osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
6949                     ncbp->ncb_command = NCBRECV | ASYNCH;
6950                     ncbp->ncb_lsn = (unsigned char) vcp->lsn;
6951                     ncbp->ncb_lana_num = vcp->lana;
6952                     ncbp->ncb_buffer = rwc.buf;
6953                     ncbp->ncb_length = 65535;
6954                     ncbp->ncb_event = rwevent;
6955 #ifndef DJGPP
6956                     Netbios(ncbp);
6957 #else
6958                     Netbios(ncbp, dos_ncb);
6959 #endif /* !DJGPP */
6960                     rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
6961                     thrd_CloseHandle(rwevent);
6962                 }
6963                 thrd_SetEvent(SessionEvents[idx_session]);
6964                 if (rwc.code == 0)
6965                     smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
6966             } 
6967             else if (smbp->com == 0xa0) {
6968                 /* 
6969                  * Serialize the handling for NT Transact 
6970                  * (defect 11626)
6971                  */
6972                 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
6973                 thrd_SetEvent(SessionEvents[idx_session]);
6974             } else {
6975                 thrd_SetEvent(SessionEvents[idx_session]);
6976                 /* TODO: what else needs to be serialized? */
6977                 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
6978             }
6979 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
6980         }
6981         __except( smb_ServerExceptionFilter() ) {
6982         }
6983 #endif
6984
6985         smb_concurrentCalls--;
6986
6987 doneWithNCB:
6988         thrd_SetEvent(NCBavails[idx_NCB]);
6989     }
6990     if (vcp)
6991         smb_ReleaseVC(vcp);
6992 }
6993
6994 /*
6995  * Exception filter for the server threads.  If an exception occurs in the
6996  * dispatch routines, which is where exceptions are most common, then do a
6997  * force trace and give control to upstream exception handlers. Useful for
6998  * debugging.
6999  */
7000 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
7001 DWORD smb_ServerExceptionFilter(void) {
7002     /* While this is not the best time to do a trace, if it succeeds, then
7003      * we have a trace (assuming tracing was enabled). Otherwise, this should
7004      * throw a second exception.
7005      */
7006     HANDLE h;
7007     char *ptbuf[1];
7008
7009     ptbuf[0] = "Unhandled exception forcing trace";
7010
7011     h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
7012     if(h) {
7013         ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,0,ptbuf,NULL);
7014         DeregisterEventSource(h);
7015     }
7016
7017     afsd_ForceTrace(TRUE);
7018     buf_ForceTrace(TRUE);
7019     return EXCEPTION_CONTINUE_SEARCH;
7020 }       
7021 #endif
7022
7023 /*
7024  * Create a new NCB and associated events, packet buffer, and "space" buffer.
7025  * If the number of server threads is M, and the number of live sessions is
7026  * N, then the number of NCB's in use at any time either waiting for, or
7027  * holding, received messages is M + N, so that is how many NCB's get created.
7028  */
7029 void InitNCBslot(int idx)
7030 {
7031     struct smb_packet *bufp;
7032     EVENT_HANDLE retHandle;
7033     int i;
7034     char eventName[MAX_PATH];
7035
7036     osi_assert( idx < (sizeof(NCBs) / sizeof(NCBs[0])) );
7037
7038     NCBs[idx] = GetNCB();
7039     sprintf(eventName,"NCBavails[%d]", idx);
7040     NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7041     if ( GetLastError() == ERROR_ALREADY_EXISTS )
7042         osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7043 #ifndef DJGPP
7044     sprintf(eventName,"NCBevents[%d]", idx);
7045     NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
7046     if ( GetLastError() == ERROR_ALREADY_EXISTS )
7047         osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7048 #endif /* !DJGPP */
7049     sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
7050     retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7051     if ( GetLastError() == ERROR_ALREADY_EXISTS )
7052         osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7053     for (i=0; i<smb_NumServerThreads; i++)
7054         NCBreturns[i][idx] = retHandle;
7055     bufp = GetPacket();
7056     bufp->spacep = cm_GetSpace();
7057     bufs[idx] = bufp;
7058 }
7059
7060 /* listen for new connections */
7061 void smb_Listener(void *parmp)
7062 {
7063     NCB *ncbp;
7064     long code = 0;
7065     long len;
7066     long i, j;
7067     smb_vc_t *vcp;
7068     int flags = 0;
7069     char rname[NCBNAMSZ+1];
7070     char cname[MAX_COMPUTERNAME_LENGTH+1];
7071     int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
7072 #ifdef DJGPP
7073     dos_ptr dos_ncb;
7074     time_t now;
7075 #endif /* DJGPP */
7076     int lana = (int) parmp;
7077
7078     ncbp = GetNCB();
7079 #ifdef DJGPP
7080     dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7081 #endif /* DJGPP */
7082
7083     /* retrieve computer name */
7084     GetComputerName(cname, &cnamelen);
7085     _strupr(cname);
7086
7087     while (1) {
7088         memset(ncbp, 0, sizeof(NCB));
7089         flags = 0;
7090
7091         ncbp->ncb_command = NCBLISTEN;
7092         ncbp->ncb_rto = 0;      /* No receive timeout */
7093         ncbp->ncb_sto = 0;      /* No send timeout */
7094
7095         /* pad out with spaces instead of null termination */
7096         len = strlen(smb_localNamep);
7097         strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
7098         for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
7099         
7100         strcpy(ncbp->ncb_callname, "*");
7101         for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
7102         
7103         ncbp->ncb_lana_num = lana;
7104
7105 #ifndef DJGPP
7106         code = Netbios(ncbp);
7107 #else /* DJGPP */
7108         code = Netbios(ncbp, dos_ncb);
7109 #endif
7110
7111         if (code != 0)
7112         {
7113 #ifndef DJGPP
7114             char tbuffer[256];
7115 #endif
7116
7117             /* terminate silently if shutdown flag is set */
7118             if (smbShutdownFlag == 1) {
7119 #ifndef DJGPP
7120                 ExitThread(1);
7121 #else
7122                 thrd_Exit(1);
7123 #endif
7124             }
7125
7126             osi_Log2(smb_logp, 
7127                      "NCBLISTEN lana=%d failed with code %d",
7128                      ncbp->ncb_lana_num, code);
7129             osi_Log0(smb_logp, 
7130                      "Client exiting due to network failure. Please restart client.\n");
7131
7132 #ifndef DJGPP
7133             sprintf(tbuffer, 
7134                      "Client exiting due to network failure.  Please restart client.\n"
7135                      "NCBLISTEN lana=%d failed with code %d",
7136                      ncbp->ncb_lana_num, code);
7137             if (showErrors)
7138                 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
7139                                       MB_OK|MB_SERVICE_NOTIFICATION);
7140             osi_assert(tbuffer);
7141             ExitThread(1);
7142 #else
7143             fprintf(stderr, "NCBLISTEN lana=%d failed with code %d\n",
7144                      ncbp->ncb_lana_num, code);
7145             fprintf(stderr, "\nClient exiting due to network failure "
7146                      "(possibly due to power-saving mode)\n");
7147             fprintf(stderr, "Please restart client.\n");
7148             afs_exit(AFS_EXITCODE_NETWORK_FAILURE);
7149 #endif /* !DJGPP */
7150         }
7151
7152         /* check for remote conns */
7153         /* first get remote name and insert null terminator */
7154         memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
7155         for (i=NCBNAMSZ; i>0; i--) {
7156             if (rname[i-1] != ' ' && rname[i-1] != 0) {
7157                 rname[i] = 0;
7158                 break;
7159             }
7160         }
7161
7162         /* compare with local name */
7163         if (!isGateway)
7164             if (strncmp(rname, cname, NCBNAMSZ) != 0)
7165                 flags |= SMB_VCFLAG_REMOTECONN;
7166
7167         osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
7168         /* lock */
7169         lock_ObtainMutex(&smb_ListenerLock);
7170
7171         /* New generation */
7172         sessionGen++;
7173
7174         /* Log session startup */
7175 #ifdef NOTSERVICE
7176         fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host "
7177                  "%s\n",
7178                  ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
7179 #endif /* NOTSERVICE */
7180         osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
7181                   ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
7182
7183         if (reportSessionStartups) {
7184 #ifndef DJGPP
7185             HANDLE h;
7186             char *ptbuf[1];
7187             char s[100];
7188
7189             h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
7190             sprintf(s, "SMB session startup, %d ongoing ops", ongoingOps);
7191             ptbuf[0] = s;
7192             ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1004, NULL,
7193                          1, 0, ptbuf, NULL);
7194             DeregisterEventSource(h);
7195 #else /* DJGPP */
7196             time(&now);
7197             fprintf(stderr, "%s: New session %d starting from host %s\n",
7198                     asctime(localtime(&now)), ncbp->ncb_lsn, rname);
7199             fflush(stderr);
7200 #endif /* !DJGPP */
7201         }
7202         osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
7203         osi_Log1(smb_logp, "SMB session startup, %d ongoing ops",
7204                   ongoingOps);
7205
7206         /* now ncbp->ncb_lsn is the connection ID */
7207         vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
7208         vcp->flags |= flags;
7209         strcpy(vcp->rname, rname);
7210
7211         /* Allocate slot in session arrays */
7212         /* Re-use dead session if possible, otherwise add one more */
7213         /* But don't look at session[0], it is reserved */
7214         for (i = 1; i < numSessions; i++) {
7215             if (dead_sessions[i]) {
7216                 osi_Log1(smb_logp, "connecting to dead session [ %d ]", i);
7217                 dead_sessions[i] = FALSE;
7218                 break;
7219             }
7220         }
7221
7222         /* assert that we do not exceed the maximum number of sessions or NCBs.
7223          * we should probably want to wait for a session to be freed in case
7224          * we run out.
7225          */
7226
7227         osi_assert(i < Sessionmax - 1);
7228         osi_assert(numNCBs < NCBmax - 1);   /* if we pass this test we can allocate one more */
7229
7230         LSNs[i] = ncbp->ncb_lsn;
7231         lanas[i] = ncbp->ncb_lana_num;
7232                 
7233         if (i == numSessions) {
7234             /* Add new NCB for new session */
7235             char eventName[MAX_PATH];
7236
7237             osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
7238
7239             InitNCBslot(numNCBs);
7240             numNCBs++;
7241             thrd_SetEvent(NCBavails[0]);
7242             thrd_SetEvent(NCBevents[0]);
7243             for (j = 0; j < smb_NumServerThreads; j++)
7244                 thrd_SetEvent(NCBreturns[j][0]);
7245             /* Also add new session event */
7246             sprintf(eventName, "SessionEvents[%d]", i);
7247             SessionEvents[i] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7248             if ( GetLastError() == ERROR_ALREADY_EXISTS )
7249                 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7250             numSessions++;
7251             osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
7252             thrd_SetEvent(SessionEvents[0]);
7253         } else {
7254             thrd_SetEvent(SessionEvents[i]);
7255         }
7256         /* unlock */
7257         lock_ReleaseMutex(&smb_ListenerLock);
7258
7259     }   /* dispatch while loop */
7260 }
7261
7262 /* initialize Netbios */
7263 void smb_NetbiosInit()
7264 {
7265     NCB *ncbp;
7266 #ifdef DJGPP
7267     dos_ptr dos_ncb;
7268 #endif /* DJGPP */
7269     int i, lana, code, l;
7270     char s[100];
7271     int delname_tried=0;
7272     int len;
7273     int lana_found = 0;
7274     OSVERSIONINFO Version;
7275
7276     /* AFAIK, this is the default for the ms loopback adapter.*/
7277     unsigned char kWLA_MAC[6] = { 0x02, 0x00, 0x4c, 0x4f, 0x4f, 0x50 };
7278     /*******************************************************************/
7279
7280     /* Get the version of Windows */
7281     memset(&Version, 0x00, sizeof(Version));
7282     Version.dwOSVersionInfoSize = sizeof(Version);
7283     GetVersionEx(&Version);
7284
7285     /* setup the NCB system */
7286     ncbp = GetNCB();
7287 #ifdef DJGPP
7288     dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7289 #endif /* DJGPP */
7290
7291 #ifndef DJGPP
7292     if (smb_LANadapter == -1) {
7293         ncbp->ncb_command = NCBENUM;
7294         ncbp->ncb_buffer = (PUCHAR)&lana_list;
7295         ncbp->ncb_length = sizeof(lana_list);
7296         code = Netbios(ncbp);
7297         if (code != 0) {
7298             sprintf(s, "Netbios NCBENUM error code %d", code);
7299             osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
7300             osi_panic(s, __FILE__, __LINE__);
7301         }
7302     }
7303     else {
7304         lana_list.length = 1;
7305         lana_list.lana[0] = smb_LANadapter;
7306     }
7307           
7308     for (i = 0; i < lana_list.length; i++) {
7309         /* reset the adaptor: in Win32, this is required for every process, and
7310          * acts as an init call, not as a real hardware reset.
7311          */
7312         ncbp->ncb_command = NCBRESET;
7313         ncbp->ncb_callname[0] = 100;
7314         ncbp->ncb_callname[2] = 100;
7315         ncbp->ncb_lana_num = lana_list.lana[i];
7316         code = Netbios(ncbp);
7317         if (code == 0) 
7318             code = ncbp->ncb_retcode;
7319         if (code != 0) {
7320             sprintf(s, "Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
7321             osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
7322             lana_list.lana[i] = 255;  /* invalid lana */
7323         } else {
7324             sprintf(s, "Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
7325             osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
7326         }
7327     }
7328 #else
7329     /* for DJGPP, there is no NCBENUM and NCBRESET is a real reset.  so
7330        we will just fake the LANA list */
7331     if (smb_LANadapter == -1) {
7332         for (i = 0; i < 8; i++)
7333             lana_list.lana[i] = i;
7334         lana_list.length = 8;
7335     }
7336     else {
7337         lana_list.length = 1;
7338         lana_list.lana[0] = smb_LANadapter;
7339     }
7340 #endif /* !DJGPP */
7341
7342     /* and declare our name so we can receive connections */
7343     memset(ncbp, 0, sizeof(*ncbp));
7344     len=lstrlen(smb_localNamep);
7345     memset(smb_sharename,' ',NCBNAMSZ);
7346     memcpy(smb_sharename,smb_localNamep,len);
7347     sprintf(s, "lana_list.length %d", lana_list.length);
7348     osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
7349
7350     /* Keep the name so we can unregister it later */
7351     for (l = 0; l < lana_list.length; l++) {
7352         lana = lana_list.lana[l];
7353
7354         ncbp->ncb_command = NCBADDNAME;
7355         ncbp->ncb_lana_num = lana;
7356         memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7357 #ifndef DJGPP
7358         code = Netbios(ncbp);
7359 #else /* DJGPP */
7360         code = Netbios(ncbp, dos_ncb);
7361 #endif /* !DJGPP */
7362           
7363         osi_Log4(smb_logp, "Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
7364                  lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
7365         {
7366             char name[NCBNAMSZ+1];
7367             name[NCBNAMSZ]=0;
7368             memcpy(name,ncbp->ncb_name,NCBNAMSZ);
7369             osi_Log1(smb_logp, "Netbios NCBADDNAME added new name >%s<",osi_LogSaveString(smb_logp, name));
7370         }
7371
7372         if (code == 0) code = ncbp->ncb_retcode;
7373         if (code == 0) {
7374             osi_Log1(smb_logp, "Netbios NCBADDNAME succeeded on lana %d\n", lana);
7375 #ifdef DJGPP
7376             /* we only use one LANA with djgpp */
7377             lana_list.lana[0] = lana;
7378             lana_list.length = 1;
7379 #endif    
7380         }
7381         else {
7382             sprintf(s, "Netbios NCBADDNAME lana %d error code %d", lana, code);
7383             osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
7384             if (code == NRC_BRIDGE) {    /* invalid LANA num */
7385                 lana_list.lana[l] = 255;
7386                 continue;
7387             }
7388             else if (code == NRC_DUPNAME) {
7389                 osi_Log0(smb_logp, "Name already exists; try to delete it");
7390                 memset(ncbp, 0, sizeof(*ncbp));
7391                 ncbp->ncb_command = NCBDELNAME;
7392                 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7393                 ncbp->ncb_lana_num = lana;
7394 #ifndef DJGPP
7395                 code = Netbios(ncbp);
7396 #else
7397                 code = Netbios(ncbp, dos_ncb);
7398 #endif /* DJGPP */
7399                 if (code == 0) 
7400                     code = ncbp->ncb_retcode;
7401                 else {
7402                     sprintf(s, "Netbios NCBDELNAME lana %d error code %d\n", lana, code);
7403                     osi_Log0(smb_logp, s);
7404                 }
7405                 if (code != 0 || delname_tried) {
7406                     lana_list.lana[l] = 255;
7407                 }
7408                 else if (code == 0) {
7409                     if (!delname_tried) {
7410                         lana--;
7411                         delname_tried = 1;
7412                         continue;
7413                     }
7414                 }
7415             }
7416             else {
7417                 sprintf(s, "Netbios NCBADDNAME lana %d error code %d", lana, code);
7418                 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
7419                 lana_list.lana[l] = 255;  /* invalid lana */
7420                 osi_panic(s, __FILE__, __LINE__);
7421             }
7422         }
7423         if (code == 0) {
7424             lana_found = 1;   /* at least one worked */
7425 #ifdef DJGPP
7426             break;
7427 #endif
7428         }
7429     }
7430
7431     osi_assert(lana_list.length >= 0);
7432     if (!lana_found) {
7433         sprintf(s, "No valid LANA numbers found!");
7434         osi_panic(s, __FILE__, __LINE__);
7435     }
7436         
7437     /* we're done with the NCB now */
7438     FreeNCB(ncbp);
7439 }
7440
7441 void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
7442               int nThreads
7443 #ifndef DJGPP
7444               , void *aMBfunc
7445 #endif
7446   )
7447
7448 {
7449     thread_t phandle;
7450     int lpid;
7451     int i;
7452     int len;
7453     struct tm myTime;
7454 #ifdef DJGPP
7455     int npar, seg, sel;
7456     dos_ptr rawBuf;
7457 #endif /* DJGPP */
7458     EVENT_HANDLE retHandle;
7459     char eventName[MAX_PATH];
7460
7461 #ifndef DJGPP
7462     smb_MBfunc = aMBfunc;
7463 #endif /* DJGPP */
7464
7465     smb_useV3 = useV3;
7466     smb_LANadapter = LANadapt;
7467
7468     /* Initialize smb_localZero */
7469     myTime.tm_isdst = -1;               /* compute whether on DST or not */
7470     myTime.tm_year = 70;
7471     myTime.tm_mon = 0;
7472     myTime.tm_mday = 1;
7473     myTime.tm_hour = 0;
7474     myTime.tm_min = 0;
7475     myTime.tm_sec = 0;
7476     smb_localZero = mktime(&myTime);
7477
7478     /* Initialize kludge-GMT */
7479     smb_CalculateNowTZ();
7480
7481 #ifdef AFS_FREELANCE_CLIENT
7482     /* Make sure the root.afs volume has the correct time */
7483     cm_noteLocalMountPointChange();
7484 #endif
7485
7486     /* initialize the remote debugging log */
7487     smb_logp = logp;
7488         
7489     /* remember the name */
7490     len = strlen(snamep);
7491     smb_localNamep = malloc(len+1);
7492     strcpy(smb_localNamep, snamep);
7493     afsi_log("smb_localNamep is >%s<", smb_localNamep);
7494
7495     /* and the global lock */
7496     lock_InitializeRWLock(&smb_globalLock, "smb global lock");
7497     lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
7498
7499     /* Raw I/O data structures */
7500     lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
7501
7502     lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
7503         
7504     /* 4 Raw I/O buffers */
7505 #ifndef DJGPP
7506     smb_RawBufs = calloc(65536,1);
7507     *((char **)smb_RawBufs) = NULL;
7508     for (i=0; i<3; i++) {
7509         char *rawBuf = calloc(65536,1);
7510         *((char **)rawBuf) = smb_RawBufs;
7511         smb_RawBufs = rawBuf;
7512     }
7513 #else /* DJGPP */
7514     npar = 65536 >> 4;  /* number of paragraphs */
7515     seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[0]);
7516     if (seg == -1) {
7517         afsi_log("Cannot allocate %d paragraphs of DOS memory",
7518                   npar);
7519         osi_panic("",__FILE__,__LINE__);
7520     }
7521     else {
7522         afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
7523                   npar, seg);
7524     }
7525     smb_RawBufs = (seg * 16) + 0;  /* DOS physical address */
7526         
7527     _farpokel(_dos_ds, smb_RawBufs, NULL);
7528     for (i=0; i<SMB_RAW_BUFS-1; i++) {
7529         npar = 65536 >> 4;  /* number of paragraphs */
7530         seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[i+1]);
7531         if (seg == -1) {
7532             afsi_log("Cannot allocate %d paragraphs of DOS memory",
7533                       npar);
7534             osi_panic("",__FILE__,__LINE__);
7535         }
7536         else {
7537             afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
7538                       npar, seg);
7539         }
7540         rawBuf = (seg * 16) + 0;  /* DOS physical address */
7541         /*_farpokel(_dos_ds, smb_RawBufs, smb_RawBufs);*/
7542         _farpokel(_dos_ds, rawBuf, smb_RawBufs);
7543         smb_RawBufs = rawBuf;
7544     }
7545 #endif /* !DJGPP */
7546
7547     /* global free lists */
7548     smb_ncbFreeListp = NULL;
7549     smb_packetFreeListp = NULL;
7550
7551     smb_NetbiosInit();
7552
7553     /* Initialize listener and server structures */
7554     numVCs = 0;
7555     memset(dead_sessions, 0, sizeof(dead_sessions));
7556     sprintf(eventName, "SessionEvents[0]");
7557     SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7558     if ( GetLastError() == ERROR_ALREADY_EXISTS )
7559         afsi_log("Event Object Already Exists: %s", eventName);
7560     numSessions = 1;
7561     smb_NumServerThreads = nThreads;
7562     sprintf(eventName, "NCBavails[0]");
7563     NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7564     if ( GetLastError() == ERROR_ALREADY_EXISTS )
7565         afsi_log("Event Object Already Exists: %s", eventName);
7566     sprintf(eventName, "NCBevents[0]");
7567     NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7568     if ( GetLastError() == ERROR_ALREADY_EXISTS )
7569         afsi_log("Event Object Already Exists: %s", eventName);
7570     NCBreturns = malloc(nThreads * sizeof(EVENT_HANDLE *));
7571     sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
7572     retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7573     if ( GetLastError() == ERROR_ALREADY_EXISTS )
7574         afsi_log("Event Object Already Exists: %s", eventName);
7575     for (i = 0; i < smb_NumServerThreads; i++) {
7576         NCBreturns[i] = malloc(NCBmax * sizeof(EVENT_HANDLE));
7577         NCBreturns[i][0] = retHandle;
7578     }
7579
7580     smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
7581     for (i = 0; i < smb_NumServerThreads; i++) {
7582         sprintf(eventName, "smb_ServerShutdown[%d]", i);
7583         smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7584         if ( GetLastError() == ERROR_ALREADY_EXISTS )
7585             afsi_log("Event Object Already Exists: %s", eventName);
7586     }
7587
7588     for (i = 1; i <= nThreads; i++)
7589         InitNCBslot(i);
7590     numNCBs = nThreads + 1;
7591
7592     /* Initialize dispatch table */
7593     memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
7594     /* Prepare the table for unknown operations */
7595     for(i=0; i<= SMB_NOPCODES; i++) {
7596         smb_dispatchTable[i].procp = smb_SendCoreBadOp;
7597     }
7598     /* Fill in the ones we do know */
7599     smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
7600     smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
7601     smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
7602     smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
7603     smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
7604     smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
7605     smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
7606     smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
7607     smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
7608     smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
7609     smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
7610     smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
7611     smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
7612     smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
7613     smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
7614     smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
7615     smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
7616     smb_dispatchTable[0x11].procp = smb_SendCoreBadOp;  /* process exit */
7617     smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
7618     smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
7619     /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
7620     smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7621     smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
7622     smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
7623     smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
7624     smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
7625     smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
7626     smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
7627     smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7628     smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
7629     smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7630     smb_dispatchTable[0x29].procp = smb_SendCoreBadOp;  /* copy file */
7631     smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
7632     /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
7633     smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7634     smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
7635     smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
7636     smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
7637     smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
7638     smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A;        /* both are same */
7639     smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7640     smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
7641     smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7642     smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
7643     smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
7644     smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
7645     smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
7646     smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
7647     smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
7648     smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
7649     smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
7650     smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
7651     smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
7652     smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
7653     smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
7654     smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
7655     smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
7656     smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
7657     smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
7658     smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
7659     smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
7660     smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
7661     smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
7662     smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7663     smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
7664     smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp;  /* Open Print File */
7665     smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp;  /* Write Print File */
7666     smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp;  /* Close Print File */
7667     smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp;  /* Get Print Queue */
7668     smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp;  /* Read Bulk */
7669     smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp;  /* Write Bulk */
7670     smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp;  /* Write Bulk Data */
7671
7672     /* setup tran 2 dispatch table */
7673     smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
7674     smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir;        /* FindFirst */
7675     smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir;        /* FindNext */
7676     smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
7677     smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
7678     smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
7679     smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
7680     smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
7681     smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
7682     smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
7683     smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
7684     smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
7685     smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
7686     smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
7687     smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
7688     smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
7689     smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
7690
7691     /* setup the rap dispatch table */
7692     memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
7693     smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
7694     smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
7695     smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
7696     smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
7697
7698     smb3_Init();
7699
7700     /* if we are doing SMB authentication we have register outselves as a logon process */
7701     if (smb_authType != SMB_AUTH_NONE) {
7702         NTSTATUS nts;
7703         LSA_STRING afsProcessName;
7704         LSA_OPERATIONAL_MODE dummy; /*junk*/
7705
7706         afsProcessName.Buffer = "OpenAFSClientDaemon";
7707         afsProcessName.Length = strlen(afsProcessName.Buffer);
7708         afsProcessName.MaximumLength = afsProcessName.Length + 1;
7709
7710         nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
7711
7712         if (nts == STATUS_SUCCESS) {
7713             LSA_STRING packageName;
7714             /* we are registered. Find out the security package id */
7715             packageName.Buffer = MSV1_0_PACKAGE_NAME;
7716             packageName.Length = strlen(packageName.Buffer);
7717             packageName.MaximumLength = packageName.Length + 1;
7718             nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
7719             if (nts == STATUS_SUCCESS) {
7720                 smb_lsaLogonOrigin.Buffer = "OpenAFS";
7721                 smb_lsaLogonOrigin.Length = strlen(smb_lsaLogonOrigin.Buffer);
7722                 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
7723             } else {
7724                 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%l]",nts);
7725             }
7726         } else {
7727             afsi_log("Can't register logon process!! NTSTATUS=[%l]",nts);
7728         }
7729
7730         if (nts != STATUS_SUCCESS) {
7731             /* something went wrong. We report the error and revert back to no authentication
7732             because we can't perform any auth requests without a successful lsa handle
7733             or sec package id. */
7734             afsi_log("Reverting to NO SMB AUTH");
7735             smb_authType = SMB_AUTH_NONE;
7736         } 
7737 #ifdef COMMENT
7738         /* Don't fallback to SMB_AUTH_NTLM.  Apparently, allowing SPNEGO to be used each
7739          * time prevents the failure of authentication when logged into Windows with an
7740          * external Kerberos principal mapped to a local account.
7741          */
7742         else if ( smb_authType == SMB_AUTH_EXTENDED) {
7743             /* Test to see if there is anything to negotiate.  If SPNEGO is not going to be used 
7744              * then the only option is NTLMSSP anyway; so just fallback. 
7745              */
7746             void * secBlob;
7747             int secBlobLength;
7748
7749             smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
7750             if (secBlobLength == 0) {
7751                 smb_authType = SMB_AUTH_NTLM;
7752                 afsi_log("Reverting to SMB AUTH NTLM");
7753             } else
7754                 free(secBlob);
7755         }
7756 #endif
7757     }
7758
7759     {
7760         DWORD bufsize;
7761         /* Now get ourselves a domain name. */
7762         /* For now we are using the local computer name as the domain name.
7763          * It is actually the domain for local logins, and we are acting as
7764          * a local SMB server. 
7765          */
7766         bufsize = sizeof(smb_ServerDomainName) - 1;
7767         GetComputerName(smb_ServerDomainName, &bufsize);
7768         smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
7769         afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
7770     }
7771
7772     /* Start listeners, waiters, servers, and daemons */
7773
7774     for (i = 0; i < lana_list.length; i++) {
7775         if (lana_list.lana[i] == 255) continue;
7776         phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
7777                                (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
7778         osi_assert(phandle != NULL);
7779         thrd_CloseHandle(phandle);
7780     }
7781
7782 #ifndef DJGPP
7783     phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
7784                           NULL, 0, &lpid, "smb_ClientWaiter");
7785     osi_assert(phandle != NULL);
7786     thrd_CloseHandle(phandle);
7787 #endif /* !DJGPP */
7788
7789     phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
7790                           NULL, 0, &lpid, "smb_ServerWaiter");
7791     osi_assert(phandle != NULL);
7792     thrd_CloseHandle(phandle);
7793
7794     for (i=0; i<nThreads; i++) {
7795         phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
7796                               (void *) i, 0, &lpid, "smb_Server");
7797         osi_assert(phandle != NULL);
7798         thrd_CloseHandle(phandle);
7799     }
7800
7801     phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
7802                           NULL, 0, &lpid, "smb_Daemon");
7803     osi_assert(phandle != NULL);
7804     thrd_CloseHandle(phandle);
7805
7806     phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
7807                           NULL, 0, &lpid, "smb_WaitingLocksDaemon");
7808     osi_assert(phandle != NULL);
7809     thrd_CloseHandle(phandle);
7810
7811 #ifdef DJGPP
7812     smb_ListShares();
7813 #endif
7814
7815     return;
7816 }
7817
7818 void smb_Shutdown(void)
7819 {
7820     NCB *ncbp;
7821 #ifdef DJGPP
7822     dos_ptr dos_ncb;
7823 #endif
7824     long code = 0;
7825     int i;
7826
7827     /*fprintf(stderr, "Entering smb_Shutdown\n");*/
7828         
7829     /* setup the NCB system */
7830     ncbp = GetNCB();
7831 #ifdef DJGPP
7832     dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7833 #endif
7834
7835     /* Block new sessions by setting shutdown flag */
7836     smbShutdownFlag = 1;
7837
7838     /* Hang up all sessions */
7839     memset((char *)ncbp, 0, sizeof(NCB));
7840     for (i = 1; i < numSessions; i++)
7841     {
7842         if (dead_sessions[i])
7843             continue;
7844       
7845         /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
7846         ncbp->ncb_command = NCBHANGUP;
7847         ncbp->ncb_lana_num = lanas[i];  /*smb_LANadapter;*/
7848         ncbp->ncb_lsn = LSNs[i];
7849 #ifndef DJGPP
7850         code = Netbios(ncbp);
7851 #else
7852         code = Netbios(ncbp, dos_ncb);
7853 #endif
7854         /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
7855         if (code == 0) code = ncbp->ncb_retcode;
7856         if (code != 0) {
7857             osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
7858             fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
7859         }
7860     }
7861
7862     /* Delete Netbios name */
7863     memset((char *)ncbp, 0, sizeof(NCB));
7864     for (i = 0; i < lana_list.length; i++) {
7865         if (lana_list.lana[i] == 255) continue;
7866         ncbp->ncb_command = NCBDELNAME;
7867         ncbp->ncb_lana_num = lana_list.lana[i];
7868         memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7869 #ifndef DJGPP
7870         code = Netbios(ncbp);
7871 #else
7872         code = Netbios(ncbp, dos_ncb);
7873 #endif
7874         if (code == 0) 
7875             code = ncbp->ncb_retcode;
7876         if (code != 0) {
7877             fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
7878                      ncbp->ncb_lana_num, code);
7879         }       
7880         fflush(stderr);
7881     }
7882
7883     /* Trigger the shutdown of all SMB threads */
7884     for (i = 0; i < smb_NumServerThreads; i++)
7885         thrd_SetEvent(NCBreturns[i][0]);
7886
7887     thrd_SetEvent(NCBevents[0]);
7888     thrd_SetEvent(SessionEvents[0]);
7889     thrd_SetEvent(NCBavails[0]);
7890
7891     for (i = 0;i < smb_NumServerThreads; i++) {
7892         DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], INFINITE);
7893         if (code == WAIT_OBJECT_0) {
7894             continue;
7895         } else {
7896             afsi_log("smb_Shutdown[%d] wait error",i);
7897         }
7898     }
7899 }
7900
7901 /* Get the UNC \\<servername>\<sharename> prefix. */
7902 char *smb_GetSharename()
7903 {
7904     char *name;
7905
7906     /* Make sure we have been properly initialized. */
7907     if (smb_localNamep == NULL)
7908         return NULL;
7909
7910     /* Allocate space for \\<servername>\<sharename>, plus the
7911      * terminator.
7912      */
7913     name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
7914     sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
7915     return name;
7916 }   
7917
7918
7919 #ifdef LOG_PACKET
7920 void smb_LogPacket(smb_packet_t *packet)
7921 {
7922     BYTE *vp, *cp;
7923     unsigned length, paramlen, datalen, i, j;
7924     char buf[81];
7925     char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
7926
7927     if (!packet) return;
7928
7929     osi_Log0(smb_logp, "*** SMB packet dump ***");
7930
7931     vp = (BYTE *) packet->data;
7932
7933     datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
7934     length = paramlen + 2 + datalen;
7935
7936
7937     for (i=0;i < length; i+=16)
7938     {
7939         memset( buf, ' ', 80 );
7940         buf[80] = 0;
7941
7942         itoa( i, buf, 16 );
7943
7944         buf[strlen(buf)] = ' ';
7945
7946         cp = (BYTE*) buf + 7;
7947
7948         for (j=0;j < 16 && (i+j)<length; j++)
7949         {
7950             *(cp++) = hex[vp[i+j] >> 4];
7951             *(cp++) = hex[vp[i+j] & 0xf];
7952             *(cp++) = ' ';
7953
7954             if (j==7)
7955             {
7956                 *(cp++) = '-';
7957                 *(cp++) = ' ';
7958             }
7959         }
7960
7961         for (j=0;j < 16 && (i+j)<length;j++)
7962         {
7963             *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
7964             if (j==7)
7965             {
7966                 *(cp++) = ' ';
7967                 *(cp++) = '-';
7968                 *(cp++) = ' ';
7969             }
7970         }
7971
7972         *cp = 0;
7973
7974         osi_Log0( smb_logp, osi_LogSaveString(smb_logp, buf));
7975     }
7976
7977     osi_Log0(smb_logp, "*** End SMB packet dump ***");
7978 }
7979 #endif /* LOG_PACKET */
7980
7981
7982 int smb_DumpVCP(FILE *outputFile, char *cookie)
7983 {
7984     int zilch;
7985     char output[1024];
7986   
7987     smb_vc_t *vcp;
7988   
7989     lock_ObtainRead(&smb_rctLock);
7990   
7991     sprintf(output, "begin dumping vcpsp\n");
7992     WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7993
7994     for(vcp = smb_allVCsp; vcp; vcp=vcp->nextp) 
7995     {
7996         smb_fid_t *fidp;
7997       
7998         sprintf(output, "%s vcp=0x%08X, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
7999                  cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
8000         WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8001       
8002         sprintf(output, "begin dumping fidsp\n");
8003         WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8004
8005         for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8006         {
8007             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", 
8008                      cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp, 
8009                      fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL", 
8010                      fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
8011             WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8012         }
8013       
8014         sprintf(output, "done dumping fidsp\n");
8015         WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8016     }
8017
8018     sprintf(output, "done dumping vcpsp\n");
8019     WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8020   
8021     lock_ReleaseRead(&smb_rctLock);
8022     return 0;
8023 }