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