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