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