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