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