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