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