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