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