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