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