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