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