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