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