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