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