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