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