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