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