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