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