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