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