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