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