a3fcd6e60834d1a93a5679ba3c7ce01b4dd442da
[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);
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);
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 /*
8882  * The top level loop for handling SMB request messages.  Each server thread
8883  * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
8884  * NCB and buffer for the incoming request are loaned to us.
8885  *
8886  * Write Raw trickery starts here.  When we get a Write Raw, we are supposed
8887  * to immediately send a request for the rest of the data.  This must come
8888  * before any other traffic for that session, so we delay setting the session
8889  * event until that data has come in.
8890  */
8891 void smb_Server(VOID *parmp)
8892 {
8893     INT_PTR myIdx = (INT_PTR) parmp;
8894     NCB *ncbp;
8895     NCB *outncbp;
8896     smb_packet_t *bufp;
8897     smb_packet_t *outbufp;
8898     DWORD code, rcode;
8899     int idx_NCB, idx_session;
8900     UCHAR rc;
8901     smb_vc_t *vcp = NULL;
8902     smb_t *smbp;
8903     extern void rx_StartClientThread(void);
8904
8905     rx_StartClientThread();
8906
8907     outncbp = smb_GetNCB();
8908     outbufp = smb_GetPacket();
8909     outbufp->ncbp = outncbp;
8910
8911     while (1) {
8912         if (vcp) {
8913             smb_ReleaseVC(vcp);
8914             vcp = NULL;
8915         }
8916
8917         cm_ResetServerPriority();
8918
8919         code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
8920                                                  FALSE, INFINITE);
8921
8922         /* terminate silently if shutdown flag is set */
8923         if (code == WAIT_OBJECT_0) {
8924             if (smbShutdownFlag == 1) {
8925                 thrd_SetEvent(smb_ServerShutdown[myIdx]);
8926                 break;
8927             } else
8928                 continue;
8929         }
8930
8931         /* error checking */
8932         if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8933         {
8934             int abandonIdx = code - WAIT_ABANDONED_0;
8935             osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
8936         }
8937         
8938         if (code == WAIT_IO_COMPLETION)
8939         {
8940             osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
8941             continue;
8942         }
8943         
8944         if (code == WAIT_TIMEOUT)
8945         {
8946             osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
8947         }
8948         
8949         if (code == WAIT_FAILED)
8950         {
8951             osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
8952         }
8953
8954         idx_NCB = code - WAIT_OBJECT_0;
8955         
8956         /* check idx range! */
8957         if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
8958         {
8959             /* this is fatal - log as much as possible */
8960             osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
8961             osi_assertx(0, "invalid index");
8962         }
8963
8964         ncbp = NCBs[idx_NCB];
8965         idx_session = NCBsessions[idx_NCB];
8966         rc = ncbp->ncb_retcode;
8967
8968         if (rc != NRC_PENDING && rc != NRC_GOODRET)
8969             osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
8970
8971         switch (rc) {
8972         case NRC_GOODRET: 
8973             vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8974             break;
8975
8976         case NRC_PENDING:
8977             /* Can this happen? Or is it just my UNIX paranoia? */
8978             osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
8979             continue;
8980
8981         case NRC_SNUMOUT:
8982         case NRC_SABORT:
8983             LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
8984             /* fallthrough */
8985         case NRC_SCLOSED:
8986             /* Client closed session */
8987             vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8988             if (vcp) {
8989                 lock_ObtainMutex(&vcp->mx);
8990                 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8991                     osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8992                              vcp, vcp->usersp);
8993                     vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8994                     lock_ReleaseMutex(&vcp->mx);
8995                     lock_ObtainWrite(&smb_globalLock);
8996                     dead_sessions[vcp->session] = TRUE;
8997                     lock_ReleaseWrite(&smb_globalLock);
8998                 } else {
8999                     lock_ReleaseMutex(&vcp->mx);
9000                 }
9001                 smb_CleanupDeadVC(vcp);
9002                 smb_ReleaseVC(vcp);
9003                 vcp = NULL;
9004             }
9005             goto doneWithNCB;
9006
9007         case NRC_INCOMP:
9008             /* Treat as transient error */
9009             LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE, 
9010                      ncbp->ncb_length);
9011             osi_Log1(smb_logp,
9012                      "dispatch smb recv failed, message incomplete, ncb_length %d",
9013                      ncbp->ncb_length);
9014             osi_Log1(smb_logp,
9015                      "SMB message incomplete, "
9016                      "length %d", ncbp->ncb_length);
9017
9018             /*
9019              * We used to discard the packet.
9020              * Instead, try handling it normally.
9021              *
9022              continue;
9023              */
9024             vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9025             break;
9026
9027         default:
9028             /* A weird error code.  Log it, sleep, and continue. */
9029             vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9030             if (vcp) {
9031                 lock_ObtainMutex(&vcp->mx);
9032                 if (vcp->errorCount++ > 3) {
9033                     osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
9034                     if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9035                         osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9036                                  vcp, vcp->usersp);
9037                         vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9038                         lock_ReleaseMutex(&vcp->mx);
9039                         lock_ObtainWrite(&smb_globalLock);
9040                         dead_sessions[vcp->session] = TRUE;
9041                         lock_ReleaseWrite(&smb_globalLock);
9042                     } else {
9043                         lock_ReleaseMutex(&vcp->mx);
9044                     }
9045                     smb_CleanupDeadVC(vcp);
9046                     smb_ReleaseVC(vcp);
9047                     vcp = NULL;
9048                     goto doneWithNCB;
9049                 }
9050                 else {
9051                     lock_ReleaseMutex(&vcp->mx);
9052                     smb_ReleaseVC(vcp);
9053                     vcp = NULL;
9054                     Sleep(10);
9055                     thrd_SetEvent(SessionEvents[idx_session]);
9056                 }
9057             }
9058             continue;
9059         }
9060
9061         /* Success, so now dispatch on all the data in the packet */
9062
9063         smb_concurrentCalls++;
9064         if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
9065             smb_maxObsConcurrentCalls = smb_concurrentCalls;
9066
9067         /*
9068          * If at this point vcp is NULL (implies that packet was invalid)
9069          * then we are in big trouble. This means either :
9070          *   a) we have the wrong NCB.
9071          *   b) Netbios screwed up the call.
9072          *   c) The VC was already marked dead before we were able to
9073          *      process the call
9074          * Obviously this implies that 
9075          *   ( LSNs[idx_session] != ncbp->ncb_lsn ||
9076          *   lanas[idx_session] != ncbp->ncb_lana_num )
9077          * Either way, we can't do anything with this packet.
9078          * Log, sleep and resume.
9079          */
9080         if (!vcp) {
9081             LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
9082                      LSNs[idx_session],
9083                      lanas[idx_session],
9084                      ncbp->ncb_lsn,
9085                      ncbp->ncb_lana_num);
9086
9087             /* Also log in the trace log. */
9088             osi_Log4(smb_logp, "Server: VCP does not exist!"
9089                       "LSNs[idx_session]=[%d],"
9090                       "lanas[idx_session]=[%d],"
9091                       "ncbp->ncb_lsn=[%d],"
9092                       "ncbp->ncb_lana_num=[%d]",
9093                       LSNs[idx_session],
9094                       lanas[idx_session],
9095                       ncbp->ncb_lsn,
9096                       ncbp->ncb_lana_num);
9097
9098             /* thrd_Sleep(1000); Don't bother sleeping */
9099             thrd_SetEvent(SessionEvents[idx_session]);
9100             smb_concurrentCalls--;
9101             continue;
9102         }
9103
9104         cm_SetRequestStartTime();
9105
9106         vcp->errorCount = 0;
9107         bufp = (struct smb_packet *) ncbp->ncb_buffer;
9108         smbp = (smb_t *)bufp->data;
9109         outbufp->flags = 0;
9110
9111 #ifndef NOTRACE
9112         __try
9113         {
9114 #endif
9115             if (smbp->com == 0x1d) {
9116                 /* Special handling for Write Raw */
9117                 raw_write_cont_t rwc;
9118             
9119                 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
9120                 if (rwc.code == 0) {
9121                     EVENT_HANDLE rwevent;
9122                     char eventName[MAX_PATH];
9123
9124                     snprintf(eventName, MAX_PATH, "smb_Server() rwevent %d", myIdx);
9125                     rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9126                     if ( GetLastError() == ERROR_ALREADY_EXISTS )
9127                         osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9128
9129                     ncbp->ncb_command = NCBRECV | ASYNCH;
9130                     ncbp->ncb_lsn = (unsigned char) vcp->lsn;
9131                     ncbp->ncb_lana_num = vcp->lana;
9132                     ncbp->ncb_buffer = rwc.buf;
9133                     ncbp->ncb_length = 65535;
9134                     ncbp->ncb_event = rwevent;
9135                     Netbios(ncbp);
9136                     rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
9137                     thrd_CloseHandle(rwevent);
9138                 }
9139                 thrd_SetEvent(SessionEvents[idx_session]);
9140                 if (rwc.code == 0)
9141                     smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
9142             } 
9143             else if (smbp->com == 0xa0) {
9144                 /* 
9145                  * Serialize the handling for NT Transact 
9146                  * (defect 11626)
9147                  */
9148                 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
9149                 thrd_SetEvent(SessionEvents[idx_session]);
9150             } else {
9151                 thrd_SetEvent(SessionEvents[idx_session]);
9152                 /* TODO: what else needs to be serialized? */
9153                 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
9154             }
9155 #ifndef NOTRACE        
9156         }
9157         __except( smb_ServerExceptionFilter() ) {
9158         }
9159 #endif
9160
9161         smb_concurrentCalls--;
9162
9163       doneWithNCB:
9164         thrd_SetEvent(NCBavails[idx_NCB]);
9165     }
9166     if (vcp)
9167         smb_ReleaseVC(vcp);
9168     if (outbufp)
9169         smb_FreePacket(outbufp);
9170     if (outncbp)
9171         smb_FreeNCB(outncbp);
9172 }
9173
9174 /*
9175  * Exception filter for the server threads.  If an exception occurs in the
9176  * dispatch routines, which is where exceptions are most common, then do a
9177  * force trace and give control to upstream exception handlers. Useful for
9178  * debugging.
9179  */
9180 DWORD smb_ServerExceptionFilter(void) {
9181     /* While this is not the best time to do a trace, if it succeeds, then
9182      * we have a trace (assuming tracing was enabled). Otherwise, this should
9183      * throw a second exception.
9184      */
9185     LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
9186     afsd_ForceTrace(TRUE);
9187     buf_ForceTrace(TRUE);
9188     return EXCEPTION_CONTINUE_SEARCH;
9189 }       
9190
9191 /*
9192  * Create a new NCB and associated events, packet buffer, and "space" buffer.
9193  * If the number of server threads is M, and the number of live sessions is
9194  * N, then the number of NCB's in use at any time either waiting for, or
9195  * holding, received messages is M + N, so that is how many NCB's get created.
9196  */
9197 void InitNCBslot(int idx)
9198 {
9199     struct smb_packet *bufp;
9200     EVENT_HANDLE retHandle;
9201     afs_uint32 i;
9202     char eventName[MAX_PATH];
9203
9204     osi_assertx( idx < (sizeof(NCBs) / sizeof(NCBs[0])), "invalid index" );
9205
9206     NCBs[idx] = smb_GetNCB();
9207     sprintf(eventName,"NCBavails[%d]", idx);
9208     NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9209     if ( GetLastError() == ERROR_ALREADY_EXISTS )
9210         osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9211     sprintf(eventName,"NCBevents[%d]", idx);
9212     NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
9213     if ( GetLastError() == ERROR_ALREADY_EXISTS )
9214         osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9215     sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
9216     retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9217     if ( GetLastError() == ERROR_ALREADY_EXISTS )
9218         osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9219     for (i=0; i<smb_NumServerThreads; i++)
9220         NCBreturns[i][idx] = retHandle;
9221     bufp = smb_GetPacket();
9222     bufp->spacep = cm_GetSpace();
9223     bufs[idx] = bufp;
9224 }
9225
9226 /* listen for new connections */
9227 void smb_Listener(void *parmp)
9228 {
9229     NCB *ncbp;
9230     long code = 0;
9231     long len;
9232     long i;
9233     afs_uint32  session, thread;
9234     smb_vc_t *vcp = NULL;
9235     int flags = 0;
9236     char rname[NCBNAMSZ+1];
9237     char cname[MAX_COMPUTERNAME_LENGTH+1];
9238     int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
9239     INT_PTR lana = (INT_PTR) parmp;
9240     char eventName[MAX_PATH];
9241     int bridgeCount = 0;
9242     int nowildCount = 0;
9243
9244     sprintf(eventName,"smb_Listener_lana_%d", (unsigned char)lana);
9245     ListenerShutdown[lana] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9246     if ( GetLastError() == ERROR_ALREADY_EXISTS )
9247         thrd_ResetEvent(ListenerShutdown[lana]);
9248
9249     ncbp = smb_GetNCB();
9250
9251     /* retrieve computer name */
9252     GetComputerName(cname, &cnamelen);
9253     _strupr(cname);
9254
9255     while (smb_ListenerState == SMB_LISTENER_STARTED) {
9256         memset(ncbp, 0, sizeof(NCB));
9257         flags = 0;
9258
9259         ncbp->ncb_command = NCBLISTEN;
9260         ncbp->ncb_rto = 0;      /* No receive timeout */
9261         ncbp->ncb_sto = 0;      /* No send timeout */
9262
9263         /* pad out with spaces instead of null termination */
9264         len = (long)strlen(smb_localNamep);
9265         strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9266         for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9267         
9268         strcpy(ncbp->ncb_callname, "*");
9269         for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
9270         
9271         ncbp->ncb_lana_num = (UCHAR)lana;
9272
9273         code = Netbios(ncbp);
9274
9275         if (code == NRC_NAMERR) {
9276           /* An smb shutdown or Vista resume must have taken place */
9277           osi_Log1(smb_logp,
9278                    "NCBLISTEN lana=%d failed with NRC_NAMERR.",
9279                    ncbp->ncb_lana_num);
9280           afsi_log("NCBLISTEN lana=%d failed with NRC_NAMERR.", ncbp->ncb_lana_num);
9281
9282             if (lock_TryMutex(&smb_StartedLock)) {
9283                 lana_list.lana[i] = LANA_INVALID;
9284                 lock_ReleaseMutex(&smb_StartedLock);
9285             }
9286             break;
9287         } else if (code ==  NRC_BRIDGE || code != 0) {
9288             int lanaRemaining = 0;
9289
9290             if (code == NRC_BRIDGE) {
9291                 if (++bridgeCount <= 5) {
9292                     afsi_log("NCBLISTEN lana=%d failed with NRC_BRIDGE, retrying ...", ncbp->ncb_lana_num);
9293                     continue;
9294                 }
9295             } else if (code == NRC_NOWILD) {
9296                 if (++nowildCount <= 5) {
9297                     afsi_log("NCBLISTEN lana=%d failed with NRC_NOWILD, retrying ...", ncbp->ncb_lana_num);
9298
9299                     if (bridgeCount > 0) {
9300                         memset(ncbp, 0, sizeof(*ncbp));
9301                         ncbp->ncb_command = NCBADDNAME;
9302                         ncbp->ncb_lana_num = (UCHAR)lana;
9303                         /* pad out with spaces instead of null termination */
9304                         len = (long)strlen(smb_localNamep);
9305                         strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9306                         for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9307                         code = Netbios(ncbp);
9308                     }
9309                     continue;
9310                 }
9311             }
9312
9313             while (!lock_TryMutex(&smb_StartedLock)) {
9314                 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9315                     goto exit_thread;
9316                 Sleep(50);
9317             }
9318  
9319             osi_Log2(smb_logp,
9320                       "NCBLISTEN lana=%d failed with %s.  Listener thread exiting.",
9321                       ncbp->ncb_lana_num, ncb_error_string(code));
9322             afsi_log("NCBLISTEN lana=%d failed with %s.  Listener thread exiting.",
9323                      ncbp->ncb_lana_num, ncb_error_string(code));
9324
9325             for (i = 0; i < lana_list.length; i++) {
9326                 if (lana_list.lana[i] == lana) {
9327                     smb_StopListener(ncbp, lana_list.lana[i], FALSE);
9328                     lana_list.lana[i] = LANA_INVALID;
9329                 }
9330                 if (lana_list.lana[i] != LANA_INVALID)
9331                     lanaRemaining++;
9332             }
9333
9334             if (lanaRemaining == 0) {
9335                 cm_VolStatus_Network_Stopped(cm_NetbiosName
9336 #ifdef _WIN64
9337                                              ,cm_NetbiosName
9338 #endif
9339                                               );
9340                 smb_ListenerState = SMB_LISTENER_STOPPED;
9341                 smb_LANadapter = LANA_INVALID;
9342                 lana_list.length = 0;
9343             }
9344             lock_ReleaseMutex(&smb_StartedLock);
9345             break;
9346         }
9347 #if 0
9348         else if (code != 0) {
9349             char tbuffer[AFSPATHMAX];
9350
9351             /* terminate silently if shutdown flag is set */
9352             while (!lock_TryMutex(&smb_StartedLock)) {
9353                 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9354                     goto exit_thread;
9355                 Sleep(50);
9356             }
9357
9358             osi_Log3(smb_logp, 
9359                      "NCBLISTEN lana=%d failed with code %d [%s]",
9360                      ncbp->ncb_lana_num, code, ncb_error_string(code));
9361             osi_Log0(smb_logp, 
9362                      "Client exiting due to network failure. Please restart client.\n");
9363
9364             sprintf(tbuffer, 
9365                      "Client exiting due to network failure.  Please restart client.\n"
9366                      "NCBLISTEN lana=%d failed with code %d [%s]",
9367                      ncbp->ncb_lana_num, code, ncb_error_string(code));
9368             if (showErrors)
9369                 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
9370                                       MB_OK|MB_SERVICE_NOTIFICATION);
9371             osi_panic(tbuffer, __FILE__, __LINE__);
9372
9373             lock_ReleaseMutex(&smb_StartedLock);
9374             break;
9375         }
9376 #endif /* 0 */
9377
9378         /* a successful packet received.  clear bridge error count */
9379         bridgeCount = 0;
9380         nowildCount = 0;
9381
9382         /* check for remote conns */
9383         /* first get remote name and insert null terminator */
9384         memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
9385         for (i=NCBNAMSZ; i>0; i--) {
9386             if (rname[i-1] != ' ' && rname[i-1] != 0) {
9387                 rname[i] = 0;
9388                 break;
9389             }
9390         }
9391
9392         /* compare with local name */
9393         if (!isGateway)
9394             if (strncmp(rname, cname, NCBNAMSZ) != 0)
9395                 flags |= SMB_VCFLAG_REMOTECONN;
9396
9397         /* lock */
9398         lock_ObtainMutex(&smb_ListenerLock);
9399
9400         osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
9401         osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
9402
9403         /* now ncbp->ncb_lsn is the connection ID */
9404         vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
9405         if (vcp->session == 0) {
9406             /* New generation */
9407             osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
9408             sessionGen++;
9409
9410             /* Log session startup */
9411 #ifdef NOTSERVICE
9412             fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9413                     ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9414 #endif /* NOTSERVICE */
9415             osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9416                      ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9417
9418             if (reportSessionStartups) {
9419                 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9420             }
9421             
9422             lock_ObtainMutex(&vcp->mx);
9423             cm_Utf8ToUtf16(rname, -1, vcp->rname, lengthof(vcp->rname));
9424             vcp->flags |= flags;
9425             lock_ReleaseMutex(&vcp->mx);
9426
9427             /* Allocate slot in session arrays */
9428             /* Re-use dead session if possible, otherwise add one more */
9429             /* But don't look at session[0], it is reserved */
9430             lock_ObtainWrite(&smb_globalLock);
9431             for (session = 1; session < numSessions; session++) {
9432                 if (dead_sessions[session]) {
9433                     osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
9434                     dead_sessions[session] = FALSE;
9435                     break;
9436                 }
9437             }
9438             lock_ReleaseWrite(&smb_globalLock);
9439         } else {
9440             /* We are re-using an existing VC because the lsn and lana 
9441              * were re-used */
9442             session = vcp->session;
9443
9444             osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
9445
9446             /* Log session startup */
9447 #ifdef NOTSERVICE
9448             fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9449                     ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9450 #endif /* NOTSERVICE */
9451             osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9452                      ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9453
9454             if (reportSessionStartups) {
9455                 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9456             }
9457         }
9458
9459         if (session >= SESSION_MAX - 1  || numNCBs >= NCB_MAX - 1) {
9460             unsigned long code = CM_ERROR_ALLBUSY;
9461             smb_packet_t * outp = smb_GetPacket();
9462             unsigned char *outWctp;
9463             smb_t *smbp;
9464             
9465             smb_FormatResponsePacket(vcp, NULL, outp);
9466             outp->ncbp = ncbp;
9467
9468             if (vcp->flags & SMB_VCFLAG_STATUS32) {
9469                 unsigned long NTStatus;
9470                 smb_MapNTError(code, &NTStatus);
9471                 outWctp = outp->wctp;
9472                 smbp = (smb_t *) &outp->data;
9473                 *outWctp++ = 0;
9474                 *outWctp++ = 0;
9475                 *outWctp++ = 0;
9476                 smbp->rcls = (unsigned char) (NTStatus & 0xff);
9477                 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
9478                 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
9479                 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
9480                 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9481             } else {
9482                 unsigned short errCode;
9483                 unsigned char errClass;
9484                 smb_MapCoreError(code, vcp, &errCode, &errClass);
9485                 outWctp = outp->wctp;
9486                 smbp = (smb_t *) &outp->data;
9487                 *outWctp++ = 0;
9488                 *outWctp++ = 0;
9489                 *outWctp++ = 0;
9490                 smbp->errLow = (unsigned char) (errCode & 0xff);
9491                 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
9492                 smbp->rcls = errClass;
9493             }
9494
9495             smb_SendPacket(vcp, outp);
9496             smb_FreePacket(outp);
9497
9498             lock_ObtainMutex(&vcp->mx);
9499             if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9500                 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9501                           vcp, vcp->usersp);
9502                 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9503                 lock_ReleaseMutex(&vcp->mx);
9504                 lock_ObtainWrite(&smb_globalLock);
9505                 dead_sessions[vcp->session] = TRUE;
9506                 lock_ReleaseWrite(&smb_globalLock);
9507                 smb_CleanupDeadVC(vcp);
9508             } else {
9509                 lock_ReleaseMutex(&vcp->mx);
9510             }
9511         } else {
9512             /* assert that we do not exceed the maximum number of sessions or NCBs.
9513              * we should probably want to wait for a session to be freed in case
9514              * we run out.
9515              */
9516             osi_assertx(session < SESSION_MAX - 1, "invalid session");
9517             osi_assertx(numNCBs < NCB_MAX - 1, "invalid numNCBs");   /* if we pass this test we can allocate one more */
9518
9519             lock_ObtainMutex(&vcp->mx);
9520             vcp->session   = session;
9521             lock_ReleaseMutex(&vcp->mx);
9522             lock_ObtainWrite(&smb_globalLock);
9523             LSNs[session]  = ncbp->ncb_lsn;
9524             lanas[session] = ncbp->ncb_lana_num;
9525             lock_ReleaseWrite(&smb_globalLock);
9526                 
9527             if (session == numSessions) {
9528                 /* Add new NCB for new session */
9529                 char eventName[MAX_PATH];
9530
9531                 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
9532
9533                 InitNCBslot(numNCBs);
9534                 lock_ObtainWrite(&smb_globalLock);
9535                 numNCBs++;
9536                 lock_ReleaseWrite(&smb_globalLock);
9537                 thrd_SetEvent(NCBavails[0]);
9538                 thrd_SetEvent(NCBevents[0]);
9539                 for (thread = 0; thread < smb_NumServerThreads; thread++)
9540                     thrd_SetEvent(NCBreturns[thread][0]);
9541                 /* Also add new session event */
9542                 sprintf(eventName, "SessionEvents[%d]", session);
9543                 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9544                 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9545                     osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9546                 lock_ObtainWrite(&smb_globalLock);
9547                 numSessions++;
9548                 lock_ReleaseWrite(&smb_globalLock);
9549                 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
9550                 thrd_SetEvent(SessionEvents[0]);
9551             } else {
9552                 thrd_SetEvent(SessionEvents[session]);
9553             }
9554         }
9555         smb_ReleaseVC(vcp);
9556
9557         /* unlock */
9558         lock_ReleaseMutex(&smb_ListenerLock);
9559     }   /* dispatch while loop */
9560
9561 exit_thread:
9562     smb_FreeNCB(ncbp);
9563     thrd_SetEvent(ListenerShutdown[lana]);
9564     return;
9565 }
9566
9567 static void
9568 configureBackConnectionHostNames(void)
9569 {
9570     /* On Windows XP SP2, Windows 2003 SP1, and all future Windows operating systems
9571      * there is a restriction on the use of SMB authentication on loopback connections.
9572      * There are two work arounds available:
9573      * 
9574      *   (1) We can disable the check for matching host names.  This does not
9575      *   require a reboot:
9576      *   [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa]
9577      *     "DisableLoopbackCheck"=dword:00000001
9578      *
9579      *   (2) We can add the AFS SMB/CIFS service name to an approved list.  This
9580      *   does require a reboot:
9581      *   [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0]
9582      *     "BackConnectionHostNames"=multi-sz
9583      *
9584      * The algorithm will be:
9585      *   (1) Check to see if cm_NetbiosName exists in the BackConnectionHostNames list
9586      *   (2a) If not, add it to the list.  (This will not take effect until the next reboot.)
9587      *   (2b1)    and check to see if DisableLoopbackCheck is set.
9588      *   (2b2)    If not set, set the DisableLoopbackCheck value to 0x1 
9589      *   (2b3)                and create HKLM\SOFTWARE\OpenAFS\Client  UnsetDisableLoopbackCheck
9590      *   (2c) else If cm_NetbiosName exists in the BackConnectionHostNames list,
9591      *             check for the UnsetDisableLoopbackCheck value.  
9592      *             If set, set the DisableLoopbackCheck flag to 0x0 
9593      *             and delete the UnsetDisableLoopbackCheck value
9594      *
9595      * Starting in Longhorn Beta 1, an entry in the BackConnectionHostNames value will
9596      * force Windows to use the loopback authentication mechanism for the specified 
9597      * services.
9598      * 
9599      * Do not permit the "DisableLoopbackCheck" value to be removed within the same
9600      * service session that set it.  
9601      */
9602     HKEY hkLsa;
9603     HKEY hkMSV10;
9604     HKEY hkClient;
9605     DWORD dwType;
9606     DWORD dwSize, dwAllocSize;
9607     DWORD dwValue;
9608     PBYTE pHostNames = NULL, pName = NULL;
9609     BOOL  bNameFound = FALSE;   
9610     static BOOL bLoopbackCheckDisabled = FALSE;
9611
9612     /* BackConnectionHostNames and DisableLoopbackCheck */
9613     if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, 
9614                        "SYSTEM\\CurrentControlSet\\Control\\Lsa\\MSV1_0",
9615                        0,
9616                        KEY_READ|KEY_WRITE,
9617                        &hkMSV10) == ERROR_SUCCESS )
9618     {
9619         if ((RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0, 
9620                              &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
9621             (dwType == REG_MULTI_SZ)) 
9622         {
9623             dwAllocSize += 1 /* in case the source string is not nul terminated */
9624                 + (DWORD)strlen(cm_NetbiosName) + 2;
9625             pHostNames = malloc(dwAllocSize);
9626             dwSize = dwAllocSize;
9627             if (RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0, &dwType, 
9628                                  pHostNames, &dwSize) == ERROR_SUCCESS) 
9629             {
9630                 for (pName = pHostNames; 
9631                      (pName - pHostNames < (int) dwSize) && *pName ; 
9632                      pName += strlen(pName) + 1)
9633                 {
9634                     if ( !stricmp(pName, cm_NetbiosName) ) {
9635                         bNameFound = TRUE;
9636                         break;
9637                     }   
9638                 }
9639             }
9640         }
9641              
9642         if ( !bNameFound ) {
9643             size_t size = strlen(cm_NetbiosName) + 2;
9644             if ( !pHostNames ) {
9645                 pHostNames = malloc(size);
9646                 pName = pHostNames;
9647             }
9648             StringCbCopyA(pName, size, cm_NetbiosName);
9649             pName += size - 1;
9650             *pName = '\0';  /* add a second nul terminator */
9651
9652             dwType = REG_MULTI_SZ;
9653             dwSize = (DWORD)(pName - pHostNames + 1);
9654             RegSetValueEx( hkMSV10, "BackConnectionHostNames", 0, dwType, pHostNames, dwSize);
9655
9656             if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, 
9657                                "SYSTEM\\CurrentControlSet\\Control\\Lsa",
9658                                0,
9659                                KEY_READ|KEY_WRITE,
9660                                &hkLsa) == ERROR_SUCCESS )
9661             {
9662                 dwSize = sizeof(DWORD);
9663                 if ( RegQueryValueEx( hkLsa, "DisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) != ERROR_SUCCESS ||
9664                      dwValue == 0 ) {
9665                     dwType = REG_DWORD;
9666                     dwSize = sizeof(DWORD);
9667                     dwValue = 1;
9668                     RegSetValueEx( hkLsa, "DisableLoopbackCheck", 0, dwType, (LPBYTE)&dwValue, dwSize);
9669
9670                     if (RegCreateKeyEx( HKEY_LOCAL_MACHINE, 
9671                                         AFSREG_CLT_OPENAFS_SUBKEY,
9672                                         0,
9673                                         NULL,
9674                                         REG_OPTION_NON_VOLATILE,
9675                                         KEY_READ|KEY_WRITE,
9676                                         NULL,
9677                                         &hkClient,
9678                                         NULL) == ERROR_SUCCESS) {
9679
9680                         dwType = REG_DWORD;
9681                         dwSize = sizeof(DWORD);
9682                         dwValue = 1;
9683                         RegSetValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, dwType, (LPBYTE)&dwValue, dwSize);
9684                         bLoopbackCheckDisabled = TRUE;
9685                         RegCloseKey(hkClient);
9686                     }
9687                     RegCloseKey(hkLsa);
9688                 }
9689             }
9690         } else if (!bLoopbackCheckDisabled) {
9691             if (RegCreateKeyEx( HKEY_LOCAL_MACHINE, 
9692                                 AFSREG_CLT_OPENAFS_SUBKEY,
9693                                 0,
9694                                 NULL,
9695                                 REG_OPTION_NON_VOLATILE,
9696                                 KEY_READ|KEY_WRITE,
9697                                 NULL,
9698                                 &hkClient,
9699                                 NULL) == ERROR_SUCCESS) {
9700
9701                 dwSize = sizeof(DWORD);
9702                 if ( RegQueryValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) == ERROR_SUCCESS &&
9703                      dwValue == 1 ) {
9704                     if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, 
9705                                        "SYSTEM\\CurrentControlSet\\Control\\Lsa",
9706                                        0,
9707                                        KEY_READ|KEY_WRITE,
9708                                        &hkLsa) == ERROR_SUCCESS )
9709                     {
9710                         RegDeleteValue(hkLsa, "DisableLoopbackCheck");
9711                         RegCloseKey(hkLsa);
9712                     }
9713                 }
9714                 RegDeleteValue(hkClient, "RemoveDisableLoopbackCheck");
9715                 RegCloseKey(hkClient);
9716             }
9717         }
9718
9719         if (pHostNames) {
9720             free(pHostNames);
9721             pHostNames = NULL;
9722         }
9723
9724         RegCloseKey(hkMSV10);
9725     }
9726 }
9727
9728
9729 static void
9730 configureExtendedSMBSessionTimeouts(void)
9731 {
9732     /*
9733      * In a Hot Fix to Windows 2003 SP2, the smb redirector was given the following
9734      * new functionality:
9735      *
9736      *  [HKLM\SYSTEM\CurrentControlSet\Services\LanManWorkstation\Parameters]
9737      *   "ReconnectableServers"            REG_MULTI_SZ
9738      *   "ExtendedSessTimeout"             REG_DWORD  (seconds)
9739      *   "ServersWithExtendedSessTimeout"  REG_MULTI_SZ 
9740      *  
9741      * These values can be used to prevent the smb redirector from timing out
9742      * smb connection to the afs smb server prematurely.
9743      */
9744     HKEY hkLanMan;
9745     DWORD dwType;
9746     DWORD dwSize, dwAllocSize;
9747     DWORD dwValue;
9748     PBYTE pHostNames = NULL, pName = NULL;
9749     BOOL  bNameFound = FALSE;   
9750
9751     if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, 
9752                        "SYSTEM\\CurrentControlSet\\Services\\LanManWorkstation\\Parameters",
9753                        0,
9754                        KEY_READ|KEY_WRITE,
9755                        &hkLanMan) == ERROR_SUCCESS )
9756     {
9757         if ((RegQueryValueEx( hkLanMan, "ReconnectableServers", 0, 
9758                              &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
9759             (dwType == REG_MULTI_SZ)) 
9760         {
9761             dwAllocSize += 1 /* in case the source string is not nul terminated */
9762                 + (DWORD)strlen(cm_NetbiosName) + 2;
9763             pHostNames = malloc(dwAllocSize);
9764             dwSize = dwAllocSize;
9765             if (RegQueryValueEx( hkLanMan, "ReconnectableServers", 0, &dwType, 
9766                                  pHostNames, &dwSize) == ERROR_SUCCESS) 
9767             {
9768                 for (pName = pHostNames; 
9769                      (pName - pHostNames < (int) dwSize) && *pName ; 
9770                      pName += strlen(pName) + 1)
9771                 {
9772                     if ( !stricmp(pName, cm_NetbiosName) ) {
9773                         bNameFound = TRUE;
9774                         break;
9775                     }   
9776                 }
9777             }
9778         }
9779              
9780         if ( !bNameFound ) {
9781             size_t size = strlen(cm_NetbiosName) + 2;
9782             if ( !pHostNames ) {
9783                 pHostNames = malloc(size);
9784                 pName = pHostNames;
9785             }
9786             StringCbCopyA(pName, size, cm_NetbiosName);
9787             pName += size - 1;
9788             *pName = '\0';  /* add a second nul terminator */
9789
9790             dwType = REG_MULTI_SZ;
9791             dwSize = (DWORD)(pName - pHostNames + 1);
9792             RegSetValueEx( hkLanMan, "ReconnectableServers", 0, dwType, pHostNames, dwSize);
9793         }
9794
9795         if (pHostNames) {
9796             free(pHostNames);
9797             pHostNames = NULL;
9798         }
9799         
9800         if ((RegQueryValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0, 
9801                              &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
9802             (dwType == REG_MULTI_SZ)) 
9803         {
9804             dwAllocSize += 1 /* in case the source string is not nul terminated */
9805                 + (DWORD)strlen(cm_NetbiosName) + 2;
9806             pHostNames = malloc(dwAllocSize);
9807             dwSize = dwAllocSize;
9808             if (RegQueryValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0, &dwType, 
9809                                  pHostNames, &dwSize) == ERROR_SUCCESS) 
9810             {
9811                 for (pName = pHostNames; 
9812                      (pName - pHostNames < (int) dwSize) && *pName ; 
9813                      pName += strlen(pName) + 1)
9814                 {
9815                     if ( !stricmp(pName, cm_NetbiosName) ) {
9816                         bNameFound = TRUE;
9817                         break;
9818                     }   
9819                 }
9820             }
9821         }
9822              
9823         if ( !bNameFound ) {
9824             size_t size = strlen(cm_NetbiosName) + 2;
9825             if ( !pHostNames ) {
9826                 pHostNames = malloc(size);
9827                 pName = pHostNames;
9828             }
9829             StringCbCopyA(pName, size, cm_NetbiosName);
9830             pName += size - 1;
9831             *pName = '\0';  /* add a second nul terminator */
9832
9833             dwType = REG_MULTI_SZ;
9834             dwSize = (DWORD)(pName - pHostNames + 1);
9835             RegSetValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0, dwType, pHostNames, dwSize);
9836         }
9837
9838         if (pHostNames) {
9839             free(pHostNames);
9840             pHostNames = NULL;
9841         }
9842
9843         if ((RegQueryValueEx( hkLanMan, "ExtendedSessTimeout", 0, 
9844                               &dwType, (LPBYTE)&dwValue, &dwAllocSize) != ERROR_SUCCESS) ||
9845              (dwType != REG_DWORD)) 
9846         {
9847             dwType = REG_DWORD;
9848             dwSize = sizeof(dwValue);
9849             dwValue = 300;      /* 5 minutes */
9850             RegSetValueEx( hkLanMan, "ExtendedSessTimeout", 0, dwType, (const BYTE *)&dwValue, dwSize);
9851         }
9852         RegCloseKey(hkLanMan);
9853     }
9854 }
9855
9856 static void
9857 smb_LanAdapterChangeThread(void *param)
9858 {
9859     /* 
9860      * Give the IPAddrDaemon thread a chance
9861      * to block before we trigger.
9862      */
9863     Sleep(30000);
9864     smb_LanAdapterChange(0);
9865 }
9866
9867 void smb_SetLanAdapterChangeDetected(void)
9868 {
9869     int lpid;
9870     thread_t phandle;
9871
9872     lock_ObtainMutex(&smb_StartedLock);
9873
9874     if (!powerStateSuspended) {
9875         phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_LanAdapterChangeThread,
9876                               NULL, 0, &lpid, "smb_LanAdapterChange");
9877         osi_assertx(phandle != NULL, "smb_LanAdapterChangeThread thread creation failure");
9878         thrd_CloseHandle(phandle);
9879     }
9880
9881     smb_LanAdapterChangeDetected = 1;
9882     lock_ReleaseMutex(&smb_StartedLock);
9883 }
9884
9885 void smb_LanAdapterChange(int locked) {
9886     lana_number_t lanaNum;
9887     BOOL          bGateway;
9888     char          NetbiosName[MAX_NB_NAME_LENGTH] = "";
9889     int           change = 0;
9890     LANA_ENUM     temp_list;           
9891     long          code;
9892     int           i;
9893
9894
9895     afsi_log("smb_LanAdapterChange");
9896
9897     if (!locked)
9898         lock_ObtainMutex(&smb_StartedLock);
9899     
9900     smb_LanAdapterChangeDetected = 0;
9901
9902     if (!powerStateSuspended && 
9903         SUCCEEDED(lana_GetUncServerNameEx(NetbiosName, &lanaNum, &bGateway, 
9904                                           LANA_NETBIOS_NAME_FULL)) &&
9905         lanaNum != LANA_INVALID && smb_LANadapter != lanaNum) {
9906         if ( isGateway != bGateway ) {
9907             afsi_log("Lan Adapter Change detected (%d != %d): gateway %d != %d",
9908                       smb_LANadapter, lanaNum, isGateway, bGateway);
9909             change = 1;
9910         } else if (strcmp(cm_NetbiosName, NetbiosName) ) {
9911             afsi_log("Lan Adapter Change detected (%d != %d): name %s != %s",
9912                       smb_LANadapter, lanaNum, cm_NetbiosName, NetbiosName);
9913             change = 1;
9914         } else {
9915             NCB *ncbp = smb_GetNCB();
9916             ncbp->ncb_command = NCBENUM;
9917             ncbp->ncb_buffer = (PUCHAR)&temp_list;
9918             ncbp->ncb_length = sizeof(temp_list);
9919             code = Netbios(ncbp);
9920             if (code == 0) {
9921                 if (temp_list.length != lana_list.length) {
9922                     afsi_log("Lan Adapter Change detected (%d != %d): lan list length changed %d != %d",
9923                               smb_LANadapter, lanaNum, temp_list.length, lana_list.length);
9924                     change = 1;
9925                 } else {
9926                     for (i=0; i<lana_list.length; i++) {
9927                         if ( temp_list.lana[i] != lana_list.lana[i] ) {
9928                             afsi_log("Lan Adapter Change detected (%d != %d): lana[%d] %d != %d",
9929                                       smb_LANadapter, lanaNum, i, temp_list.lana[i], lana_list.lana[i]);
9930                             change = 1;
9931                             break;
9932                         }
9933                     }
9934                 }
9935             }
9936             smb_FreeNCB(ncbp);
9937         }
9938     } 
9939
9940     if (change) {
9941         smb_StopListeners(1);
9942         smb_RestartListeners(1);
9943     }
9944     if (!locked)
9945         lock_ReleaseMutex(&smb_StartedLock);
9946 }
9947
9948 /* initialize Netbios */
9949 int smb_NetbiosInit(int locked)
9950 {
9951     NCB *ncbp;
9952     int i, lana, code, l;
9953     char s[100];
9954     int delname_tried=0;
9955     int len;
9956     int lana_found = 0;
9957     lana_number_t lanaNum;
9958
9959     if (!locked)
9960         lock_ObtainMutex(&smb_StartedLock);
9961
9962     if (smb_ListenerState != SMB_LISTENER_UNINITIALIZED &&
9963          smb_ListenerState != SMB_LISTENER_STOPPED) {
9964
9965         if (!locked)
9966             lock_ReleaseMutex(&smb_StartedLock);
9967         return 0;
9968     }
9969     /* setup the NCB system */
9970     ncbp = smb_GetNCB();
9971
9972     /* Call lanahelper to get Netbios name, lan adapter number and gateway flag */
9973     if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
9974         smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
9975
9976         if (smb_LANadapter != LANA_INVALID)
9977             afsi_log("LAN adapter number %d", smb_LANadapter);
9978         else
9979             afsi_log("LAN adapter number not determined");
9980
9981         if (isGateway)
9982             afsi_log("Set for gateway service");
9983
9984         afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
9985     } else {
9986         /* something went horribly wrong.  We can't proceed without a netbios name */
9987         char buf[128];
9988         StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
9989         osi_panic(buf, __FILE__, __LINE__);
9990     }
9991
9992     /* remember the name */
9993     len = (int)strlen(cm_NetbiosName);
9994     if (smb_localNamep)
9995         free(smb_localNamep);
9996     smb_localNamep = malloc(len+1);
9997     strcpy(smb_localNamep, cm_NetbiosName);
9998     afsi_log("smb_localNamep is >%s<", smb_localNamep);
9999
10000     /* Also copy the value to the client character encoded string */
10001     cm_Utf8ToClientString(cm_NetbiosName, -1, cm_NetbiosNameC, MAX_NB_NAME_LENGTH);
10002
10003     if (smb_LANadapter == LANA_INVALID) {
10004         ncbp->ncb_command = NCBENUM;
10005         ncbp->ncb_buffer = (PUCHAR)&lana_list;
10006         ncbp->ncb_length = sizeof(lana_list);
10007         code = Netbios(ncbp);
10008         if (code != 0) {
10009             afsi_log("Netbios NCBENUM error code %d", code);
10010             osi_panic(s, __FILE__, __LINE__);
10011         }
10012     }
10013     else {
10014         lana_list.length = 1;
10015         lana_list.lana[0] = smb_LANadapter;
10016     }
10017           
10018     for (i = 0; i < lana_list.length; i++) {
10019         /* reset the adaptor: in Win32, this is required for every process, and
10020          * acts as an init call, not as a real hardware reset.
10021          */
10022         ncbp->ncb_command = NCBRESET;
10023         ncbp->ncb_callname[0] = 100;
10024         ncbp->ncb_callname[2] = 100;
10025         ncbp->ncb_lana_num = lana_list.lana[i];
10026         code = Netbios(ncbp);
10027         if (code == 0) 
10028             code = ncbp->ncb_retcode;
10029         if (code != 0) {
10030             afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
10031             lana_list.lana[i] = LANA_INVALID;  /* invalid lana */
10032         } else {
10033             afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
10034         }
10035     }
10036
10037     /* and declare our name so we can receive connections */
10038     memset(ncbp, 0, sizeof(*ncbp));
10039     len=lstrlen(smb_localNamep);
10040     memset(smb_sharename,' ',NCBNAMSZ);
10041     memcpy(smb_sharename,smb_localNamep,len);
10042     afsi_log("lana_list.length %d", lana_list.length);
10043
10044     /* Keep the name so we can unregister it later */
10045     for (l = 0; l < lana_list.length; l++) {
10046         lana = lana_list.lana[l];
10047
10048         ncbp->ncb_command = NCBADDNAME;
10049         ncbp->ncb_lana_num = lana;
10050         memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10051         code = Netbios(ncbp);
10052           
10053         afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
10054                  lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
10055         {
10056             char name[NCBNAMSZ+1];
10057             name[NCBNAMSZ]=0;
10058             memcpy(name,ncbp->ncb_name,NCBNAMSZ);
10059             afsi_log("Netbios NCBADDNAME added new name >%s<",name);
10060         }
10061
10062         if (code == 0) 
10063             code = ncbp->ncb_retcode;
10064
10065         if (code == 0) {
10066             afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
10067         }
10068         else {
10069             afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
10070             if (code == NRC_BRIDGE) {    /* invalid LANA num */
10071                 lana_list.lana[l] = LANA_INVALID;
10072                 continue;
10073             }
10074             else if (code == NRC_DUPNAME) {
10075                 afsi_log("Name already exists; try to delete it");
10076                 memset(ncbp, 0, sizeof(*ncbp));
10077                 ncbp->ncb_command = NCBDELNAME;
10078                 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10079                 ncbp->ncb_lana_num = lana;
10080                 code = Netbios(ncbp);
10081                 if (code == 0) 
10082                     code = ncbp->ncb_retcode;
10083                 else {
10084                     afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
10085                 }
10086                 if (code != 0 || delname_tried) {
10087                     lana_list.lana[l] = LANA_INVALID;
10088                 }
10089                 else if (code == 0) {
10090                     if (!delname_tried) {
10091                         lana--;
10092                         delname_tried = 1;
10093                         continue;
10094                     }
10095                 }
10096             }
10097             else {
10098                 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
10099                 lana_list.lana[l] = LANA_INVALID;  /* invalid lana */
10100             }
10101         }
10102         if (code == 0) {
10103             smb_LANadapter = lana;
10104             lana_found = 1;   /* at least one worked */
10105         }
10106     }
10107
10108     osi_assertx(lana_list.length >= 0, "empty lana list");
10109     if (!lana_found) {
10110         afsi_log("No valid LANA numbers found!");
10111         lana_list.length = 0;
10112         smb_LANadapter = LANA_INVALID;
10113         smb_ListenerState = SMB_LISTENER_STOPPED;
10114         cm_VolStatus_Network_Stopped(cm_NetbiosName
10115 #ifdef _WIN64
10116                                       ,cm_NetbiosName
10117 #endif
10118                                       );
10119     }
10120         
10121     /* we're done with the NCB now */
10122     smb_FreeNCB(ncbp);
10123
10124     afsi_log("smb_NetbiosInit smb_LANadapter=%d",smb_LANadapter);
10125     if (lana_list.length > 0)
10126         osi_assert(smb_LANadapter != LANA_INVALID);
10127
10128     if (!locked)
10129         lock_ReleaseMutex(&smb_StartedLock);
10130
10131     return (lana_list.length > 0 ? 1 : 0);
10132 }
10133
10134 void smb_StartListeners(int locked)
10135 {
10136     int i;
10137     int lpid;
10138     thread_t phandle;
10139
10140     if (!locked)
10141         lock_ObtainMutex(&smb_StartedLock);
10142
10143     if (smb_ListenerState == SMB_LISTENER_STARTED) {
10144         if (!locked)
10145             lock_ReleaseMutex(&smb_StartedLock);
10146         return;
10147     }
10148
10149     afsi_log("smb_StartListeners");
10150     /* Ensure the AFS Netbios Name is registered to allow loopback access */
10151     configureBackConnectionHostNames();
10152
10153     /* Configure Extended SMB Session Timeouts */
10154     if (msftSMBRedirectorSupportsExtendedTimeouts()) {
10155         afsi_log("Microsoft SMB Redirector supports Extended Timeouts");
10156         configureExtendedSMBSessionTimeouts();
10157     }
10158
10159     smb_ListenerState = SMB_LISTENER_STARTED;
10160     cm_VolStatus_Network_Started(cm_NetbiosName
10161 #ifdef _WIN64
10162                                   , cm_NetbiosName
10163 #endif
10164                                   );
10165
10166     for (i = 0; i < lana_list.length; i++) {
10167         if (lana_list.lana[i] == LANA_INVALID) 
10168             continue;
10169         phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
10170                                (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
10171         osi_assertx(phandle != NULL, "smb_Listener thread creation failure");
10172         thrd_CloseHandle(phandle);
10173     }
10174     if (!locked)
10175         lock_ReleaseMutex(&smb_StartedLock);
10176 }
10177
10178 void smb_RestartListeners(int locked)
10179 {
10180     if (!locked)
10181         lock_ObtainMutex(&smb_StartedLock);
10182
10183     if (powerStateSuspended)
10184         afsi_log("smb_RestartListeners called while suspended");
10185
10186     if (!powerStateSuspended && smb_ListenerState != SMB_LISTENER_UNINITIALIZED) {
10187         if (smb_ListenerState == SMB_LISTENER_STOPPED) {
10188             if (smb_NetbiosInit(1))
10189                 smb_StartListeners(1);
10190         } else if (smb_LanAdapterChangeDetected) {
10191             smb_LanAdapterChange(1);
10192         }
10193     }
10194     if (!locked)
10195         lock_ReleaseMutex(&smb_StartedLock);
10196 }
10197
10198 void smb_StopListener(NCB *ncbp, int lana, int wait)
10199 {
10200     long code;
10201
10202     memset(ncbp, 0, sizeof(*ncbp));
10203     ncbp->ncb_command = NCBDELNAME;
10204     ncbp->ncb_lana_num = lana;
10205     memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10206     code = Netbios(ncbp);
10207           
10208     afsi_log("StopListener: Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
10209               lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
10210
10211     /* and then reset the LANA; this will cause the listener threads to exit */
10212     ncbp->ncb_command = NCBRESET;
10213     ncbp->ncb_callname[0] = 100;
10214     ncbp->ncb_callname[2] = 100;
10215     ncbp->ncb_lana_num = lana;
10216     code = Netbios(ncbp);
10217     if (code == 0) 
10218         code = ncbp->ncb_retcode;
10219     if (code != 0) {
10220         afsi_log("StopListener: Netbios NCBRESET lana %d error code %d", lana, code);
10221     } else {
10222         afsi_log("StopListener: Netbios NCBRESET lana %d succeeded", lana);
10223     }
10224
10225     if (wait)
10226         thrd_WaitForSingleObject_Event(ListenerShutdown[lana], INFINITE);
10227 }
10228
10229 void smb_StopListeners(int locked)
10230 {
10231     NCB *ncbp;
10232     int lana, l;
10233
10234     if (!locked)
10235         lock_ObtainMutex(&smb_StartedLock);
10236
10237     if (smb_ListenerState == SMB_LISTENER_STOPPED) {
10238         if (!locked)
10239             lock_ReleaseMutex(&smb_StartedLock);
10240         return;
10241     }
10242
10243     afsi_log("smb_StopListeners");
10244     smb_ListenerState = SMB_LISTENER_STOPPED;
10245     cm_VolStatus_Network_Stopped(cm_NetbiosName
10246 #ifdef _WIN64
10247                                   , cm_NetbiosName
10248 #endif
10249                                   );
10250
10251     ncbp = smb_GetNCB();
10252
10253     /* Unregister the SMB name */
10254     for (l = 0; l < lana_list.length; l++) {
10255         lana = lana_list.lana[l];
10256
10257         if (lana != LANA_INVALID) {
10258             smb_StopListener(ncbp, lana, TRUE);
10259
10260             /* mark the adapter invalid */
10261             lana_list.lana[l] = LANA_INVALID;  /* invalid lana */
10262         }
10263     }
10264
10265     /* force a re-evaluation of the network adapters */
10266     lana_list.length = 0;
10267     smb_LANadapter = LANA_INVALID;
10268     smb_FreeNCB(ncbp);
10269     if (!locked)
10270         lock_ReleaseMutex(&smb_StartedLock);
10271 }
10272
10273 void smb_Init(osi_log_t *logp, int useV3,
10274               int nThreads
10275               , void *aMBfunc
10276   )
10277
10278 {
10279     thread_t phandle;
10280     int lpid;
10281     UINT_PTR i;
10282     struct tm myTime;
10283     EVENT_HANDLE retHandle;
10284     char eventName[MAX_PATH];
10285     int startListeners = 0;
10286
10287     smb_MBfunc = aMBfunc;
10288
10289     smb_useV3 = useV3;
10290
10291     /* Initialize smb_localZero */
10292     myTime.tm_isdst = -1;               /* compute whether on DST or not */
10293     myTime.tm_year = 70;
10294     myTime.tm_mon = 0;
10295     myTime.tm_mday = 1;
10296     myTime.tm_hour = 0;
10297     myTime.tm_min = 0;
10298     myTime.tm_sec = 0;
10299     smb_localZero = mktime(&myTime);
10300
10301 #ifdef AFS_FREELANCE_CLIENT
10302     /* Make sure the root.afs volume has the correct time */
10303     cm_noteLocalMountPointChange();
10304 #endif
10305
10306     /* initialize the remote debugging log */
10307     smb_logp = logp;
10308         
10309     /* and the global lock */
10310     lock_InitializeRWLock(&smb_globalLock, "smb global lock", LOCK_HIERARCHY_SMB_GLOBAL);
10311     lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock", LOCK_HIERARCHY_SMB_RCT_GLOBAL);
10312
10313     /* Raw I/O data structures */
10314     lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock", LOCK_HIERARCHY_SMB_RAWBUF);
10315
10316     lock_InitializeMutex(&smb_ListenerLock, "smb listener lock", LOCK_HIERARCHY_SMB_LISTENER);
10317     lock_InitializeMutex(&smb_StartedLock, "smb started lock", LOCK_HIERARCHY_SMB_STARTED);
10318         
10319     /* 4 Raw I/O buffers */
10320     smb_RawBufs = calloc(65536,1);
10321     *((char **)smb_RawBufs) = NULL;
10322     for (i=0; i<3; i++) {
10323         char *rawBuf = calloc(65536,1);
10324         *((char **)rawBuf) = smb_RawBufs;
10325         smb_RawBufs = rawBuf;
10326     }
10327
10328     /* global free lists */
10329     smb_ncbFreeListp = NULL;
10330     smb_packetFreeListp = NULL;
10331
10332     lock_ObtainMutex(&smb_StartedLock);
10333     startListeners = smb_NetbiosInit(1);
10334
10335     /* Initialize listener and server structures */
10336     numVCs = 0;
10337     memset(dead_sessions, 0, sizeof(dead_sessions));
10338     sprintf(eventName, "SessionEvents[0]");
10339     SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10340     if ( GetLastError() == ERROR_ALREADY_EXISTS )
10341         afsi_log("Event Object Already Exists: %s", eventName);
10342     numSessions = 1;
10343     smb_NumServerThreads = nThreads;
10344     sprintf(eventName, "NCBavails[0]");
10345     NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10346     if ( GetLastError() == ERROR_ALREADY_EXISTS )
10347         afsi_log("Event Object Already Exists: %s", eventName);
10348     sprintf(eventName, "NCBevents[0]");
10349     NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10350     if ( GetLastError() == ERROR_ALREADY_EXISTS )
10351         afsi_log("Event Object Already Exists: %s", eventName);
10352     NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
10353     sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
10354     retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10355     if ( GetLastError() == ERROR_ALREADY_EXISTS )
10356         afsi_log("Event Object Already Exists: %s", eventName);
10357     for (i = 0; i < smb_NumServerThreads; i++) {
10358         NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
10359         NCBreturns[i][0] = retHandle;
10360     }
10361
10362     smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
10363     for (i = 0; i < smb_NumServerThreads; i++) {
10364         sprintf(eventName, "smb_ServerShutdown[%d]", i);
10365         smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10366         if ( GetLastError() == ERROR_ALREADY_EXISTS )
10367             afsi_log("Event Object Already Exists: %s", eventName);
10368         InitNCBslot((int)(i+1));
10369     }
10370     numNCBs = smb_NumServerThreads + 1;
10371
10372     /* Initialize dispatch table */
10373     memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
10374     /* Prepare the table for unknown operations */
10375     for(i=0; i<= SMB_NOPCODES; i++) {
10376         smb_dispatchTable[i].procp = smb_SendCoreBadOp;
10377     }
10378     /* Fill in the ones we do know */
10379     smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
10380     smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
10381     smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
10382     smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
10383     smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
10384     smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
10385     smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
10386     smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
10387     smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
10388     smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
10389     smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
10390     smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
10391     smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
10392     smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
10393     smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
10394     smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
10395     smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
10396     smb_dispatchTable[0x11].procp = smb_SendCoreBadOp;  /* process exit */
10397     smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
10398     smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
10399     /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
10400     smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10401     smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
10402     smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
10403     smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
10404     smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
10405     smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
10406     smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
10407     smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10408     smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
10409     smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10410     smb_dispatchTable[0x29].procp = smb_SendCoreBadOp;  /* copy file */
10411     smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
10412     /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
10413     smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10414     smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
10415     smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
10416     smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
10417     smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
10418     smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
10419     smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
10420     smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A;        /* both are same */
10421     smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10422     smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
10423     smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10424     smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
10425     smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
10426     smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
10427     smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
10428     smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
10429     smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
10430     smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
10431     smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
10432     smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
10433     smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
10434     smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
10435     smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
10436     smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
10437     smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
10438     smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
10439     smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
10440     smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
10441     smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
10442     smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
10443     smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
10444     smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10445     smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
10446     smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp;  /* Open Print File */
10447     smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp;  /* Write Print File */
10448     smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp;  /* Close Print File */
10449     smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp;  /* Get Print Queue */
10450     smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp;  /* Read Bulk */
10451     smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp;  /* Write Bulk */
10452     smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp;  /* Write Bulk Data */
10453
10454     /* setup tran 2 dispatch table */
10455     smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
10456     smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir;        /* FindFirst */
10457     smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir;        /* FindNext */
10458     smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
10459     smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
10460     smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
10461     smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
10462     smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
10463     smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
10464     smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
10465     smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
10466     smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
10467     smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
10468     smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
10469     smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
10470     smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
10471     smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
10472     smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
10473
10474     /* setup the rap dispatch table */
10475     memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
10476     smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
10477     smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
10478     smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
10479     smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
10480
10481     smb3_Init();
10482
10483     /* if we are doing SMB authentication we have register outselves as a logon process */
10484     if (smb_authType != SMB_AUTH_NONE) {
10485         NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
10486         LSA_STRING afsProcessName;
10487         LSA_OPERATIONAL_MODE dummy; /*junk*/
10488
10489         afsProcessName.Buffer = "OpenAFSClientDaemon";
10490         afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
10491         afsProcessName.MaximumLength = afsProcessName.Length + 1;
10492
10493         nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
10494
10495         if (nts == STATUS_SUCCESS) {
10496             LSA_STRING packageName;
10497             /* we are registered. Find out the security package id */
10498             packageName.Buffer = MSV1_0_PACKAGE_NAME;
10499             packageName.Length = (USHORT)strlen(packageName.Buffer);
10500             packageName.MaximumLength = packageName.Length + 1;
10501             nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
10502             if (nts == STATUS_SUCCESS) {
10503                 /* BEGIN 
10504                  * This code forces Windows to authenticate against the Logon Cache 
10505                  * first instead of attempting to authenticate against the Domain 
10506                  * Controller.  When the Windows logon cache is enabled this improves
10507                  * performance by removing the network access and works around a bug
10508                  * seen at sites which are using a MIT Kerberos principal to login
10509                  * to machines joined to a non-root domain in a multi-domain forest.
10510                  * MsV1_0SetProcessOption was added in Windows XP.
10511                  */
10512                 PVOID pResponse = NULL;
10513                 ULONG cbResponse = 0;
10514                 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
10515
10516                 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
10517                 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
10518                 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST; 
10519                 OptionsRequest.DisableOptions = FALSE;
10520
10521                 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
10522                                                     smb_lsaSecPackage,
10523                                                     &OptionsRequest,
10524                                                     sizeof(OptionsRequest),
10525                                                     &pResponse,
10526                                                     &cbResponse,
10527                                                     &ntsEx
10528                                                     );
10529
10530                 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
10531                     osi_Log2(smb_logp, "MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
10532                              nts, ntsEx);
10533
10534                     afsi_log("MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x", nts, ntsEx);
10535                 } else {
10536                     osi_Log0(smb_logp, "MsV1_0SetProcessOption success");
10537                     afsi_log("MsV1_0SetProcessOption success");
10538                 }
10539                 /* END - code from Larry */
10540
10541                 smb_lsaLogonOrigin.Buffer = "OpenAFS";
10542                 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
10543                 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
10544             } else {
10545                 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
10546
10547                 /* something went wrong. We report the error and revert back to no authentication
10548                 because we can't perform any auth requests without a successful lsa handle
10549                 or sec package id. */
10550                 afsi_log("Reverting to NO SMB AUTH");
10551                 smb_authType = SMB_AUTH_NONE;
10552             }
10553         } else {
10554             afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
10555
10556             /* something went wrong. We report the error and revert back to no authentication
10557             because we can't perform any auth requests without a successful lsa handle
10558             or sec package id. */
10559             afsi_log("Reverting to NO SMB AUTH");
10560             smb_authType = SMB_AUTH_NONE;
10561         }
10562
10563 #ifdef COMMENT
10564         /* Don't fallback to SMB_AUTH_NTLM.  Apparently, allowing SPNEGO to be used each
10565          * time prevents the failure of authentication when logged into Windows with an
10566          * external Kerberos principal mapped to a local account.
10567          */
10568         else if ( smb_authType == SMB_AUTH_EXTENDED) {
10569             /* Test to see if there is anything to negotiate.  If SPNEGO is not going to be used 
10570              * then the only option is NTLMSSP anyway; so just fallback. 
10571              */
10572             void * secBlob;
10573             int secBlobLength;
10574
10575             smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
10576             if (secBlobLength == 0) {
10577                 smb_authType = SMB_AUTH_NTLM;
10578                 afsi_log("Reverting to SMB AUTH NTLM");
10579             } else
10580                 free(secBlob);
10581         }
10582 #endif
10583     }
10584
10585     {
10586         DWORD bufsize;
10587         /* Now get ourselves a domain name. */
10588         /* For now we are using the local computer name as the domain name.
10589          * It is actually the domain for local logins, and we are acting as
10590          * a local SMB server. 
10591          */
10592         bufsize = lengthof(smb_ServerDomainName) - 1;
10593         GetComputerNameW(smb_ServerDomainName, &bufsize);
10594         smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
10595         afsi_log("Setting SMB server domain name to [%S]", smb_ServerDomainName);
10596     }
10597
10598     /* Start listeners, waiters, servers, and daemons */
10599     if (startListeners)
10600         smb_StartListeners(1);
10601
10602     phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
10603                           NULL, 0, &lpid, "smb_ClientWaiter");
10604     osi_assertx(phandle != NULL, "smb_ClientWaiter thread creation failure");
10605     thrd_CloseHandle(phandle);
10606
10607     phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
10608                           NULL, 0, &lpid, "smb_ServerWaiter");
10609     osi_assertx(phandle != NULL, "smb_ServerWaiter thread creation failure");
10610     thrd_CloseHandle(phandle);
10611
10612     for (i=0; i<smb_NumServerThreads; i++) {
10613         phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
10614                               (void *) i, 0, &lpid, "smb_Server");
10615         osi_assertx(phandle != NULL, "smb_Server thread creation failure");
10616         thrd_CloseHandle(phandle);
10617     }
10618
10619     phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
10620                           NULL, 0, &lpid, "smb_Daemon");
10621     osi_assertx(phandle != NULL, "smb_Daemon thread creation failure");
10622     thrd_CloseHandle(phandle);
10623
10624     phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
10625                           NULL, 0, &lpid, "smb_WaitingLocksDaemon");
10626     osi_assertx(phandle != NULL, "smb_WaitingLocksDaemon thread creation failure");
10627     thrd_CloseHandle(phandle);
10628
10629     lock_ReleaseMutex(&smb_StartedLock);
10630     return;
10631 }
10632
10633 void smb_Shutdown(void)
10634 {
10635     NCB *ncbp;
10636     long code = 0;
10637     afs_uint32 i;
10638     smb_vc_t *vcp;
10639
10640     /*fprintf(stderr, "Entering smb_Shutdown\n");*/
10641         
10642     /* setup the NCB system */
10643     ncbp = smb_GetNCB();
10644
10645     /* Block new sessions by setting shutdown flag */
10646     smbShutdownFlag = 1;
10647
10648     /* Hang up all sessions */
10649     memset(ncbp, 0, sizeof(NCB));
10650     for (i = 1; i < numSessions; i++)
10651     {
10652         if (dead_sessions[i])
10653             continue;
10654       
10655         /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
10656         ncbp->ncb_command = NCBHANGUP;
10657         ncbp->ncb_lana_num = lanas[i];  /*smb_LANadapter;*/
10658         ncbp->ncb_lsn = (UCHAR)LSNs[i];
10659         code = Netbios(ncbp);
10660         /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
10661         if (code == 0) code = ncbp->ncb_retcode;
10662         if (code != 0) {
10663             osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
10664             fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
10665         }
10666     }
10667
10668     /* Trigger the shutdown of all SMB threads */                                
10669     for (i = 0; i < smb_NumServerThreads; i++)                                   
10670         thrd_SetEvent(NCBreturns[i][0]);                                         
10671                                                                                  
10672     thrd_SetEvent(NCBevents[0]);                                                 
10673     thrd_SetEvent(SessionEvents[0]);                                             
10674     thrd_SetEvent(NCBavails[0]);                                                 
10675                                                                                  
10676     for (i = 0;i < smb_NumServerThreads; i++) {                                  
10677         DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500); 
10678         if (code == WAIT_OBJECT_0) {                                             
10679             continue;                                                            
10680         } else {                                                                 
10681             afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);      
10682             thrd_SetEvent(NCBreturns[i--][0]);                                   
10683         }                                                                        
10684     }                                                                            
10685
10686     /* Delete Netbios name */
10687     memset(ncbp, 0, sizeof(NCB));
10688     for (i = 0; i < lana_list.length; i++) {
10689         if (lana_list.lana[i] == LANA_INVALID) continue;
10690         ncbp->ncb_command = NCBDELNAME;
10691         ncbp->ncb_lana_num = lana_list.lana[i];
10692         memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10693         code = Netbios(ncbp);
10694         if (code == 0) 
10695             code = ncbp->ncb_retcode;
10696         if (code != 0) {
10697             fprintf(stderr, "Shutdown: Netbios NCBDELNAME lana %d error code %d",
10698                      ncbp->ncb_lana_num, code);
10699         }       
10700         fflush(stderr);
10701     }
10702
10703     /* Release the reference counts held by the VCs */
10704     lock_ObtainWrite(&smb_rctLock);
10705     for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) 
10706     {
10707         smb_fid_t *fidp;
10708         smb_tid_t *tidp;
10709      
10710         if (vcp->magic != SMB_VC_MAGIC)
10711             osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp", 
10712                        __FILE__, __LINE__);
10713
10714         for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10715         {
10716             if (fidp->scp != NULL) {
10717                 cm_scache_t * scp;
10718
10719                 lock_ReleaseWrite(&smb_rctLock);
10720                 lock_ObtainMutex(&fidp->mx);
10721                 if (fidp->scp != NULL) {
10722                     scp = fidp->scp;
10723                     fidp->scp = NULL;
10724                     lock_ObtainWrite(&scp->rw);
10725                     scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
10726                     lock_ReleaseWrite(&scp->rw);
10727                     osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
10728                     cm_ReleaseSCache(scp);
10729                 }
10730                 lock_ReleaseMutex(&fidp->mx);
10731                 lock_ObtainWrite(&smb_rctLock);
10732             }
10733         }
10734
10735         for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10736             if (tidp->vcp)
10737                 smb_ReleaseVCNoLock(tidp->vcp);
10738             if (tidp->userp) {
10739                 cm_user_t *userp = tidp->userp;
10740                 tidp->userp = NULL;
10741                 cm_ReleaseUser(userp);
10742             }
10743         }
10744     }
10745     lock_ReleaseWrite(&smb_rctLock);
10746     smb_FreeNCB(ncbp);
10747 }
10748
10749 /* Get the UNC \\<servername>\<sharename> prefix. */
10750 char *smb_GetSharename()
10751 {
10752     char *name;
10753     size_t len;
10754
10755     /* Make sure we have been properly initialized. */
10756     if (smb_localNamep == NULL)
10757         return NULL;
10758
10759     /* Allocate space for \\<servername>\<sharename>, plus the
10760      * terminator.
10761      */
10762     len = (strlen(smb_localNamep) + strlen("ALL") + 4) * sizeof(char);
10763     name = malloc(len);
10764     snprintf(name, len, "\\\\%s\\%s", smb_localNamep, "ALL");
10765     return name;
10766 }
10767
10768
10769 #ifdef LOG_PACKET
10770 void smb_LogPacket(smb_packet_t *packet)
10771 {
10772     BYTE *vp, *cp;
10773     smb_t * smbp;
10774     unsigned length, paramlen, datalen, i, j;
10775     char buf[81];
10776     char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
10777
10778     if (!packet) return;
10779
10780     osi_Log0(smb_logp, "*** SMB packet dump ***");
10781
10782     smbp = (smb_t *) packet->data;
10783     vp = (BYTE *) packet->data;
10784
10785     paramlen = smbp->wct * 2;
10786     datalen = *((WORD *) (smbp->vdata + paramlen));
10787     length = sizeof(*smbp) + paramlen + 1 + datalen;
10788
10789     for (i=0;i < length; i+=16)
10790     {
10791         memset( buf, ' ', 80 );
10792         buf[80] = 0;
10793
10794         itoa( i, buf, 16 );
10795
10796         buf[strlen(buf)] = ' ';
10797
10798         cp = (BYTE*) buf + 7;
10799
10800         for (j=0;j < 16 && (i+j)<length; j++)
10801         {
10802             *(cp++) = hex[vp[i+j] >> 4];
10803             *(cp++) = hex[vp[i+j] & 0xf];
10804             *(cp++) = ' ';
10805
10806             if (j==7)
10807             {
10808                 *(cp++) = '-';
10809                 *(cp++) = ' ';
10810             }
10811         }
10812
10813         for (j=0;j < 16 && (i+j)<length;j++)
10814         {
10815             *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
10816             if (j==7)
10817             {
10818                 *(cp++) = ' ';
10819                 *(cp++) = '-';
10820                 *(cp++) = ' ';
10821             }
10822         }
10823
10824         *cp = 0;
10825
10826         osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
10827     }
10828
10829     osi_Log0(smb_logp, "*** End SMB packet dump ***");
10830 }
10831 #endif /* LOG_PACKET */
10832
10833
10834 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
10835 {
10836     int zilch;
10837     char output[4196];
10838   
10839     smb_vc_t *vcp;
10840     smb_username_t *unp;
10841     smb_waitingLockRequest_t *wlrp;
10842
10843     if (lock)
10844         lock_ObtainRead(&smb_rctLock);
10845   
10846     sprintf(output, "begin dumping smb_username_t\r\n");
10847     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10848     for (unp = usernamesp; unp; unp=unp->nextp) 
10849     {
10850         cm_ucell_t *ucellp;
10851
10852         sprintf(output, "%s -- smb_unp=0x%p, refCount=%d, cm_userp=0x%p, flags=0x%x, logoff=%u, name=%S, machine=%S\r\n", 
10853                 cookie, unp, unp->refCount, unp->userp, unp->flags, unp->last_logoff_t,
10854                 unp->name ? unp->name : _C("NULL"), 
10855                 unp->machine ? unp->machine : _C("NULL"));
10856         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10857
10858         sprintf(output, "  begin dumping cm_ucell_t\r\n");
10859         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10860
10861         for ( ucellp = unp->userp->cellInfop; ucellp; ucellp = ucellp->nextp ) {
10862             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", 
10863                      cookie, ucellp, ucellp->cellp, ucellp->flags, ucellp->ticketLen, ucellp->kvno, 
10864                      ucellp->expirationTime, ucellp->gen, 
10865                      ucellp->userName,
10866                      ucellp->cellp->name);
10867             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10868         }
10869
10870         sprintf(output, "  done dumping cm_ucell_t\r\n");
10871         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10872
10873     }
10874     sprintf(output, "done dumping smb_username_t\r\n");
10875     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10876
10877
10878     sprintf(output, "begin dumping smb_waitingLockRequest_t\r\n");
10879     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10880
10881
10882     for ( wlrp = smb_allWaitingLocks; wlrp; wlrp = (smb_waitingLockRequest_t *) osi_QNext(&wlrp->q)) {
10883         smb_waitingLock_t *lockp;
10884
10885         sprintf(output, "%s wlrp=0x%p vcp=0x%p, scp=0x%p, type=0x%x, start_t=0x%I64u msTimeout=0x%x\r\n",
10886                  cookie, wlrp, wlrp->vcp, wlrp->scp, wlrp->lockType, wlrp->start_t, wlrp->msTimeout);
10887         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10888       
10889         sprintf(output, "  begin dumping smb_waitingLock_t\r\n");
10890         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10891         for (lockp = wlrp->locks; lockp; lockp = (smb_waitingLock_t *) osi_QNext(&lockp->q)) {
10892             sprintf(output, "  %s -- waitlockp=0x%p lockp=0x%p key=0x%I64x offset=0x%I64x length=0x%I64x state=0x%x\r\n", 
10893                     cookie, lockp, lockp->lockp, lockp->key, lockp->LOffset.QuadPart, lockp->LLength.QuadPart, lockp->state);
10894             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10895         }
10896         sprintf(output, "  done dumping smb_waitingLock_t\r\n");
10897         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10898     }
10899
10900     sprintf(output, "done dumping smb_waitingLockRequest_t\r\n");
10901     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10902
10903     sprintf(output, "begin dumping smb_vc_t\r\n");
10904     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10905
10906     for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) 
10907     {
10908         smb_fid_t *fidp;
10909         smb_tid_t *tidp;
10910         smb_user_t *userp;
10911       
10912         sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
10913                  cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
10914         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10915       
10916         sprintf(output, "  begin dumping smb_user_t\r\n");
10917         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10918         for (userp = vcp->usersp; userp; userp = userp->nextp) {
10919             sprintf(output, "  %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n", 
10920                     cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
10921             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10922         }
10923         sprintf(output, "  done dumping smb_user_t\r\n");
10924         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10925
10926         sprintf(output, "  begin dumping smb_tid_t\r\n");
10927         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10928         for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10929             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", 
10930                     cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
10931                     tidp->pathname ? tidp->pathname : _C("NULL"));
10932             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10933         }
10934         sprintf(output, "  done dumping smb_tid_t\r\n");
10935         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10936
10937         sprintf(output, "  begin dumping smb_fid_t\r\n");
10938         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10939
10940         for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10941         {
10942             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", 
10943                     cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
10944                     fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"), 
10945                     fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
10946             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10947         }
10948       
10949         sprintf(output, "  done dumping smb_fid_t\r\n");
10950         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10951     }
10952
10953     sprintf(output, "done dumping smb_vc_t\r\n");
10954     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10955   
10956     sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
10957     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10958
10959     for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp) 
10960     {
10961         smb_fid_t *fidp;
10962         smb_tid_t *tidp;
10963         smb_user_t *userp;
10964
10965         sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
10966                 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
10967         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10968       
10969         sprintf(output, "  begin dumping smb_user_t\r\n");
10970         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10971         for (userp = vcp->usersp; userp; userp = userp->nextp) {
10972             sprintf(output, "  %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n", 
10973                     cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
10974             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10975         }
10976         sprintf(output, "  done dumping smb_user_t\r\n");
10977         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10978
10979         sprintf(output, "  begin dumping smb_tid_t\r\n");
10980         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10981         for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10982             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", 
10983                     cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
10984                     tidp->pathname ? tidp->pathname : _C("NULL"));
10985             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10986         }
10987         sprintf(output, "  done dumping smb_tid_t\r\n");
10988         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10989
10990         sprintf(output, "  begin dumping smb_fid_t\r\n");
10991         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10992
10993         for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10994         {
10995             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", 
10996                     cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
10997                     fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"), 
10998                     fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
10999             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11000         }
11001       
11002         sprintf(output, "  done dumping smb_fid_t\r\n");
11003         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11004     }
11005
11006     sprintf(output, "done dumping DEAD smb_vc_t\r\n");
11007     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11008   
11009     if (lock)
11010         lock_ReleaseRead(&smb_rctLock);
11011     return 0;
11012 }
11013
11014 long smb_IsNetworkStarted(void)
11015 {
11016     long rc;
11017     lock_ObtainWrite(&smb_globalLock);
11018     rc = (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);
11019     lock_ReleaseWrite(&smb_globalLock);
11020     return rc;
11021 }