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