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