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