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