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