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