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