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