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