windows-checkVCs-20081015
[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         /* on the first pass hold 'vcp' which was not held as 'nextp' */
3756         if (vcp != nextp)
3757             smb_HoldVCNoLock(vcp);
3758
3759         /* 
3760          * obtain a reference to 'nextp' now because we drop the
3761          * smb_rctLock later and the list contents could change 
3762          * or 'vcp' could be destroyed when released.
3763          */
3764         nextp = vcp->nextp;
3765         if (nextp)
3766             smb_HoldVCNoLock(nextp);
3767
3768         if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
3769             smb_ReleaseVCNoLock(vcp);
3770             continue;
3771         }
3772
3773         smb_FormatResponsePacket(vcp, NULL, outp);
3774         smbp = (smb_t *)outp;
3775         outp->inCom = smbp->com = 0x2b /* Echo */;
3776         smbp->tid = 0xFFFF;
3777         smbp->pid = 0;
3778         smbp->uid = 0;
3779         smbp->mid = 0;
3780         smbp->res[0] = 0;
3781         smbp->res[1] = 0;
3782
3783         smb_SetSMBParm(outp, 0, 0);
3784         smb_SetSMBDataLength(outp, 0);
3785         lock_ReleaseWrite(&smb_rctLock);
3786
3787         smb_SendPacket(vcp, outp);
3788
3789         lock_ObtainWrite(&smb_rctLock);
3790         smb_ReleaseVCNoLock(vcp);
3791     }
3792     lock_ReleaseWrite(&smb_rctLock);
3793     smb_FreePacket(outp);
3794 }
3795
3796 void smb_Daemon(void *parmp)
3797 {
3798     afs_uint32 count = 0;
3799     smb_username_t    **unpp;
3800     time_t              now;
3801
3802     while(smbShutdownFlag == 0) {
3803         count++;
3804         thrd_Sleep(10000);
3805
3806         if (smbShutdownFlag == 1)
3807             break;
3808         
3809         if ((count % 72) == 0)  {       /* every five minutes */
3810             struct tm myTime;
3811             time_t old_localZero = smb_localZero;
3812                  
3813             /* Initialize smb_localZero */
3814             myTime.tm_isdst = -1;               /* compute whether on DST or not */
3815             myTime.tm_year = 70;
3816             myTime.tm_mon = 0;
3817             myTime.tm_mday = 1;
3818             myTime.tm_hour = 0;
3819             myTime.tm_min = 0;
3820             myTime.tm_sec = 0;
3821             smb_localZero = mktime(&myTime);
3822
3823 #ifndef USE_NUMERIC_TIME_CONV
3824             smb_CalculateNowTZ();
3825 #endif /* USE_NUMERIC_TIME_CONV */
3826 #ifdef AFS_FREELANCE
3827             if ( smb_localZero != old_localZero )
3828                 cm_noteLocalMountPointChange();
3829 #endif
3830
3831             smb_CheckVCs();
3832         }
3833
3834         /* GC smb_username_t objects that will no longer be used */
3835         now = osi_Time();
3836         lock_ObtainWrite(&smb_rctLock);
3837         for ( unpp=&usernamesp; *unpp; ) {
3838             int deleteOk = 0;
3839             smb_username_t *unp;
3840
3841             lock_ObtainMutex(&(*unpp)->mx);
3842             if ( (*unpp)->refCount > 0 || 
3843                  ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) || 
3844                  !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
3845                 ;
3846             else if (!smb_LogoffTokenTransfer ||
3847                      ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
3848                 deleteOk = 1;
3849             lock_ReleaseMutex(&(*unpp)->mx);
3850
3851             if (deleteOk) {
3852                 cm_user_t * userp;
3853
3854                 unp = *unpp;    
3855                 *unpp = unp->nextp;
3856                 unp->nextp = NULL;
3857                 lock_FinalizeMutex(&unp->mx);
3858                 userp = unp->userp;
3859                 free(unp->name);
3860                 free(unp->machine);
3861                 free(unp);
3862                 if (userp)
3863                     cm_ReleaseUser(userp);
3864             } else {
3865                 unpp = &(*unpp)->nextp;
3866             }
3867         }
3868         lock_ReleaseWrite(&smb_rctLock);
3869
3870         /* XXX GC dir search entries */
3871     }
3872 }
3873
3874 void smb_WaitingLocksDaemon()
3875 {
3876     smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3877     smb_waitingLock_t *wl, *wlNext;
3878     int first;
3879     smb_vc_t *vcp;
3880     smb_packet_t *inp, *outp;
3881     NCB *ncbp;
3882     long code = 0;
3883
3884     while (smbShutdownFlag == 0) {
3885         lock_ObtainWrite(&smb_globalLock);
3886         nwlRequest = smb_allWaitingLocks;
3887         if (nwlRequest == NULL) {
3888             osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
3889             thrd_Sleep(1000);
3890             continue;
3891         } else {
3892             first = 1;
3893             osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
3894         }
3895
3896         do {
3897             if (first)
3898                 first = 0;
3899             else
3900                 lock_ObtainWrite(&smb_globalLock);
3901
3902             osi_Log1(smb_logp, "    Checking waiting lock request %p", nwlRequest);
3903
3904             wlRequest = nwlRequest;
3905             nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3906             lock_ReleaseWrite(&smb_globalLock);
3907
3908             code = 0;
3909
3910             for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3911                 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3912                     continue;
3913
3914                 if (wl->state == SMB_WAITINGLOCKSTATE_CANCELLED) {
3915                     code = CM_ERROR_LOCK_NOT_GRANTED;
3916                     break;
3917                 }
3918
3919                 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
3920                 
3921                 /* wl->state is either _DONE or _WAITING.  _ERROR
3922                    would no longer be on the queue. */
3923                 code = cm_RetryLock( wl->lockp,
3924                                      !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3925
3926                 if (code == 0) {
3927                     wl->state = SMB_WAITINGLOCKSTATE_DONE;
3928                 } else if (code != CM_ERROR_WOULDBLOCK) {
3929                     wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3930                     break;
3931                 }
3932             }
3933
3934             if (code == CM_ERROR_WOULDBLOCK) {
3935
3936                 /* no progress */
3937                 if (wlRequest->msTimeout != 0xffffffff
3938                      && ((osi_Time() - wlRequest->start_t) * 1000 > wlRequest->msTimeout))
3939                     goto endWait;
3940
3941                 continue;
3942             }
3943
3944           endWait:
3945
3946             if (code != 0) {
3947                 cm_scache_t * scp;
3948                 cm_req_t req;
3949
3950                 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
3951                          wlRequest);
3952
3953                 scp = wlRequest->scp;
3954                 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
3955
3956                 smb_InitReq(&req);
3957
3958                 lock_ObtainWrite(&scp->rw);
3959
3960                 for (wl = wlRequest->locks; wl; wl = wlNext) {
3961                     wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3962                 
3963                     if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3964                         cm_Unlock(scp, wlRequest->lockType, wl->LOffset, 
3965                                   wl->LLength, wl->key, NULL, &req);
3966
3967                     osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3968
3969                     free(wl);
3970                 }
3971                 
3972                 lock_ReleaseWrite(&scp->rw);
3973
3974             } else {
3975
3976                 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
3977                          wlRequest);
3978
3979                 for (wl = wlRequest->locks; wl; wl = wlNext) {
3980                     wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3981                     osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3982                     free(wl);
3983                 }
3984             }
3985
3986             vcp = wlRequest->vcp;
3987             inp = wlRequest->inp;
3988             outp = wlRequest->outp;
3989             ncbp = smb_GetNCB();
3990             ncbp->ncb_length = inp->ncb_length;
3991             inp->spacep = cm_GetSpace();
3992
3993             /* Remove waitingLock from list */
3994             lock_ObtainWrite(&smb_globalLock);
3995             osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3996                          &wlRequest->q);
3997             lock_ReleaseWrite(&smb_globalLock);
3998
3999             /* Resume packet processing */
4000             if (code == 0)
4001                 smb_SetSMBDataLength(outp, 0);
4002             outp->flags |= SMB_PACKETFLAG_SUSPENDED;
4003             outp->resumeCode = code;
4004             outp->ncbp = ncbp;
4005             smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
4006
4007             /* Clean up */
4008             cm_FreeSpace(inp->spacep);
4009             smb_FreePacket(inp);
4010             smb_FreePacket(outp);
4011             smb_ReleaseVC(vcp);
4012             cm_ReleaseSCache(wlRequest->scp);
4013             smb_FreeNCB(ncbp);
4014             free(wlRequest);
4015         } while (nwlRequest && smbShutdownFlag == 0);
4016         thrd_Sleep(1000);
4017     }
4018 }
4019
4020 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4021 {
4022     osi_Log0(smb_logp, "SMB receive get disk attributes");
4023
4024     smb_SetSMBParm(outp, 0, 32000);
4025     smb_SetSMBParm(outp, 1, 64);
4026     smb_SetSMBParm(outp, 2, 1024);
4027     smb_SetSMBParm(outp, 3, 30000);
4028     smb_SetSMBParm(outp, 4, 0);
4029     smb_SetSMBDataLength(outp, 0);
4030     return 0;
4031 }
4032
4033 /* SMB_COM_TREE_CONNECT */
4034 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
4035 {
4036     smb_tid_t *tidp;
4037     smb_user_t *uidp;
4038     unsigned short newTid;
4039     clientchar_t shareName[AFSPATHMAX];
4040     clientchar_t *sharePath;
4041     int shareFound;
4042     clientchar_t *tp;
4043     clientchar_t *pathp;
4044     cm_user_t *userp;
4045
4046     osi_Log0(smb_logp, "SMB receive tree connect");
4047
4048     /* parse input parameters */
4049     {
4050         char *tbp;
4051         tbp = smb_GetSMBData(inp, NULL);
4052         pathp = smb_ParseASCIIBlock(inp, tbp, &tbp, SMB_STRF_ANSIPATH);
4053     }
4054     tp = cm_ClientStrRChr(pathp, '\\');
4055     if (!tp)
4056         return CM_ERROR_BADSMB;
4057     cm_ClientStrCpy(shareName, lengthof(shareName), tp+1);
4058
4059     lock_ObtainMutex(&vcp->mx);
4060     newTid = vcp->tidCounter++;
4061     lock_ReleaseMutex(&vcp->mx);
4062
4063     tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
4064     uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
4065     userp = smb_GetUserFromUID(uidp);
4066     shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
4067     if (uidp)
4068         smb_ReleaseUID(uidp);
4069     if (!shareFound) {
4070         smb_ReleaseTID(tidp, FALSE);
4071         return CM_ERROR_BADSHARENAME;
4072     }
4073     lock_ObtainMutex(&tidp->mx);
4074     tidp->userp = userp;
4075     tidp->pathname = sharePath;
4076     lock_ReleaseMutex(&tidp->mx);
4077     smb_ReleaseTID(tidp, FALSE);
4078
4079     smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
4080     smb_SetSMBParm(rsp, 1, newTid);
4081     smb_SetSMBDataLength(rsp, 0);
4082
4083     osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
4084     return 0;
4085 }
4086
4087 /* set maskp to the mask part of the incoming path.
4088  * Mask is 11 bytes long (8.3 with the dot elided).
4089  * Returns true if succeeds with a valid name, otherwise it does
4090  * its best, but returns false.
4091  */
4092 int smb_Get8Dot3MaskFromPath(clientchar_t *maskp, clientchar_t *pathp)
4093 {
4094     clientchar_t *tp;
4095     clientchar_t *up;
4096     int i;
4097     int tc;
4098     int valid8Dot3;
4099
4100     /* starts off valid */
4101     valid8Dot3 = 1;
4102
4103     /* mask starts out all blanks */
4104     memset(maskp, ' ', 11);
4105     maskp[11] = '\0';
4106
4107     /* find last backslash, or use whole thing if there is none */
4108     tp = cm_ClientStrRChr(pathp, '\\');
4109     if (!tp) 
4110         tp = pathp;
4111     else 
4112         tp++;   /* skip slash */
4113         
4114     up = maskp;
4115
4116     /* names starting with a dot are illegal */
4117     if (*tp == '.') 
4118         valid8Dot3 = 0;
4119
4120     for(i=0;; i++) {
4121         tc = *tp++;
4122         if (tc == 0) 
4123             return valid8Dot3;
4124         if (tc == '.' || tc == '"') 
4125             break;
4126         if (i < 8) 
4127             *up++ = tc;
4128         else
4129             valid8Dot3 = 0;
4130     }
4131         
4132     /* if we get here, tp point after the dot */
4133     up = maskp+8;       /* ext goes here */
4134     for(i=0;;i++) {
4135         tc = *tp++;
4136         if (tc == 0) 
4137             return valid8Dot3;
4138
4139         /* too many dots */
4140         if (tc == '.' || tc == '"') 
4141             valid8Dot3 = 0;
4142
4143         /* copy extension if not too long */
4144         if (i < 3) 
4145             *up++ = tc;
4146         else 
4147             valid8Dot3 = 0;
4148     }   
4149
4150     /* unreachable */
4151 }
4152
4153 int smb_Match8Dot3Mask(clientchar_t *unixNamep, clientchar_t *maskp)
4154 {
4155     clientchar_t umask[11];
4156     int valid;
4157     int i;
4158     clientchar_t tc1;
4159     clientchar_t tc2;
4160     clientchar_t *tp1;
4161     clientchar_t *tp2;
4162
4163     /* XXX redo this, calling cm_MatchMask with a converted mask */
4164
4165     valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
4166     if (!valid) 
4167         return 0;
4168  
4169     /* otherwise, we have a valid 8.3 name; see if we have a match,
4170      * treating '?' as a wildcard in maskp (but not in the file name).
4171      */
4172     tp1 = umask;        /* real name, in mask format */
4173     tp2 = maskp;        /* mask, in mask format */
4174     for(i=0; i<11; i++) {
4175         tc1 = *tp1++;   /* clientchar_t from real name */
4176         tc2 = *tp2++;   /* clientchar_t from mask */
4177         tc1 = (clientchar_t) cm_foldUpper[(clientchar_t)tc1];
4178         tc2 = (clientchar_t) cm_foldUpper[(clientchar_t)tc2];
4179         if (tc1 == tc2) 
4180             continue;
4181         if (tc2 == '?' && tc1 != ' ') 
4182             continue;
4183         if (tc2 == '>') 
4184             continue;
4185         return 0;
4186     }
4187
4188     /* we got a match */
4189     return 1;
4190 }
4191
4192 clientchar_t *smb_FindMask(clientchar_t *pathp)
4193 {
4194     clientchar_t *tp;
4195         
4196     tp = cm_ClientStrRChr(pathp, '\\'); /* find last slash */
4197
4198     if (tp) 
4199         return tp+1;    /* skip the slash */
4200     else 
4201         return pathp;   /* no slash, return the entire path */
4202 }       
4203
4204 /* SMB_COM_SEARCH for a volume label
4205
4206    (This is called from smb_ReceiveCoreSearchDir() and not an actual
4207    dispatch function.) */
4208 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4209 {
4210     clientchar_t *pathp;
4211     unsigned char *tp;
4212     clientchar_t mask[12];
4213     unsigned char *statBlockp;
4214     unsigned char initStatBlock[21];
4215     int statLen;
4216         
4217     osi_Log0(smb_logp, "SMB receive search volume");
4218
4219     /* pull pathname and stat block out of request */
4220     tp = smb_GetSMBData(inp, NULL);
4221     pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4222                                 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4223     osi_assertx(pathp != NULL, "null path");
4224     statBlockp = smb_ParseVblBlock(tp, &tp, &statLen);
4225     osi_assertx(statBlockp != NULL, "null statBlock");
4226     if (statLen == 0) {
4227         statBlockp = initStatBlock;
4228         statBlockp[0] = 8;
4229     }
4230         
4231     /* for returning to caller */
4232     smb_Get8Dot3MaskFromPath(mask, pathp);
4233
4234     smb_SetSMBParm(outp, 0, 1);         /* we're returning one entry */
4235     tp = smb_GetSMBData(outp, NULL);
4236     *tp++ = 5;
4237     *tp++ = 43; /* bytes in a dir entry */
4238     *tp++ = 0;  /* high byte in counter */
4239
4240     /* now marshall the dir entry, starting with the search status */
4241     *tp++ = statBlockp[0];              /* Reserved */
4242     memcpy(tp, mask, 11); tp += 11;     /* FileName */
4243
4244     /* now pass back server use info, with 1st byte non-zero */
4245     *tp++ = 1;
4246     memset(tp, 0, 4); tp += 4;  /* reserved for server use */
4247
4248     memcpy(tp, statBlockp+17, 4); tp += 4;      /* reserved for consumer */
4249
4250     *tp++ = 0x8;                /* attribute: volume */
4251
4252     /* copy out time */
4253     *tp++ = 0;
4254     *tp++ = 0;
4255
4256     /* copy out date */
4257     *tp++ = 18;
4258     *tp++ = 178;
4259
4260     /* 4 byte file size */
4261     *tp++ = 0;
4262     *tp++ = 0;
4263     *tp++ = 0;
4264     *tp++ = 0;
4265
4266     /* The filename is a UCHAR buffer that is ASCII even if Unicode
4267        was negotiated. */
4268
4269     /* finally, null-terminated 8.3 pathname, which we set to AFS */
4270     memset(tp, ' ', 13);
4271     strcpy(tp, "AFS");
4272
4273     /* set the length of the data part of the packet to 43 + 3, for the dir
4274      * entry plus the 5 and the length fields.
4275      */
4276     smb_SetSMBDataLength(outp, 46);
4277     return 0;
4278 }       
4279
4280 static long 
4281 smb_ApplyDirListPatches(cm_scache_t * dscp, smb_dirListPatch_t **dirPatchespp,
4282                         clientchar_t * tidPathp, clientchar_t * relPathp,
4283                         cm_user_t *userp, cm_req_t *reqp)
4284 {
4285     long code = 0;
4286     cm_scache_t *scp;
4287     char *dptr;
4288     afs_uint32 dosTime;
4289     u_short shortTemp;
4290     char attr;
4291     smb_dirListPatch_t *patchp;
4292     smb_dirListPatch_t *npatchp;
4293     clientchar_t path[AFSPATHMAX];
4294     afs_uint32 rights;
4295     afs_int32 mustFake = 0;
4296
4297     code = cm_FindACLCache(dscp, userp, &rights);
4298     if (code == -1) {
4299         lock_ObtainWrite(&dscp->rw);
4300         code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4301                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4302         lock_ReleaseWrite(&dscp->rw);
4303         if (code == CM_ERROR_NOACCESS) {
4304             mustFake = 1;
4305             code = 0;
4306         }
4307     }
4308     if (code)
4309         goto cleanup;
4310
4311     if (!mustFake) {    /* Bulk Stat */
4312         afs_uint32 count;
4313         cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4314
4315         memset(bsp, 0, sizeof(cm_bulkStat_t));
4316
4317         for (patchp = *dirPatchespp, count=0; 
4318              patchp; 
4319              patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4320             cm_scache_t *tscp = cm_FindSCache(&patchp->fid);
4321             int i;
4322
4323             if (tscp) {
4324                 if (lock_TryWrite(&tscp->rw)) {
4325                     /* we have an entry that we can look at */
4326                     if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
4327                         /* we have a callback on it.  Don't bother
4328                         * fetching this stat entry, since we're happy
4329                         * with the info we have.
4330                         */
4331                         lock_ReleaseWrite(&tscp->rw);
4332                         cm_ReleaseSCache(tscp);
4333                         continue;
4334                     }
4335                     lock_ReleaseWrite(&tscp->rw);
4336                 } /* got lock */
4337                 cm_ReleaseSCache(tscp);
4338             }   /* found entry */
4339
4340             i = bsp->counter++;
4341             bsp->fids[i].Volume = patchp->fid.volume;
4342             bsp->fids[i].Vnode = patchp->fid.vnode;
4343             bsp->fids[i].Unique = patchp->fid.unique;
4344
4345             if (bsp->counter == AFSCBMAX) {
4346                 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4347                 memset(bsp, 0, sizeof(cm_bulkStat_t));
4348             }
4349         }
4350
4351         if (bsp->counter > 0)
4352             code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4353
4354         free(bsp);
4355     }
4356
4357     for (patchp = *dirPatchespp; patchp; patchp =
4358          (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4359
4360         dptr = patchp->dptr;
4361
4362         cm_ClientStrPrintfN(path, AFSPATHMAX, _C("%s\\%s"),
4363                             relPathp ? relPathp : _C(""), patchp->dep->name);
4364         reqp->relPathp = path;
4365         reqp->tidPathp = tidPathp;
4366
4367         code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4368         reqp->relPathp = reqp->tidPathp = NULL;
4369
4370         if (code) {
4371             if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
4372                 *dptr++ = SMB_ATTR_HIDDEN;
4373             continue;
4374         }
4375         lock_ObtainWrite(&scp->rw);
4376         if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
4377             lock_ReleaseWrite(&scp->rw);
4378
4379             /* set the attribute */
4380             switch (scp->fileType) {
4381             case CM_SCACHETYPE_DIRECTORY:
4382             case CM_SCACHETYPE_MOUNTPOINT:
4383             case CM_SCACHETYPE_SYMLINK:
4384             case CM_SCACHETYPE_INVALID:
4385                 attr = SMB_ATTR_DIRECTORY;
4386                 break;
4387             default:
4388                 /* if we get here we either have a normal file
4389                 * or we have a file for which we have never 
4390                 * received status info.  In this case, we can
4391                 * check the even/odd value of the entry's vnode.
4392                 * even means it is to be treated as a directory
4393                 * and odd means it is to be treated as a file.
4394                 */
4395                 if (mustFake && (scp->fid.vnode & 0x1))
4396                     attr = SMB_ATTR_DIRECTORY;
4397                 else
4398                     attr = SMB_ATTR_NORMAL;
4399             }
4400             *dptr++ = attr;
4401
4402             /* 1969-12-31 23:59:58 +00*/
4403             dosTime = 0xEBBFBF7D;
4404
4405             /* copy out time */
4406             shortTemp = (unsigned short) (dosTime & 0xffff);
4407             *((u_short *)dptr) = shortTemp;
4408             dptr += 2;
4409
4410             /* and copy out date */
4411             shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4412             *((u_short *)dptr) = shortTemp;
4413             dptr += 2;
4414                 
4415             /* copy out file length */
4416             *((u_long *)dptr) = 0;
4417             dptr += 4;
4418         } else {
4419             lock_ConvertWToR(&scp->rw);
4420             attr = smb_Attributes(scp);
4421             /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
4422             if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
4423                 attr |= SMB_ATTR_HIDDEN;
4424             *dptr++ = attr;
4425
4426             /* get dos time */
4427             smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4428                 
4429             /* copy out time */
4430             shortTemp = (unsigned short) (dosTime & 0xffff);
4431             *((u_short *)dptr) = shortTemp;
4432             dptr += 2;
4433
4434             /* and copy out date */
4435             shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4436             *((u_short *)dptr) = shortTemp;
4437             dptr += 2;
4438                 
4439             /* copy out file length */
4440             *((u_long *)dptr) = scp->length.LowPart;
4441             dptr += 4;
4442             lock_ReleaseRead(&scp->rw);
4443         }
4444         cm_ReleaseSCache(scp);
4445     }
4446         
4447     /* now free the patches */
4448     for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4449         npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4450         free(patchp);
4451     }   
4452         
4453     /* and mark the list as empty */
4454     *dirPatchespp = NULL;
4455
4456   cleanup:
4457     return code;
4458 }
4459
4460 /* SMB_COM_SEARCH */
4461 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4462 {
4463     int attribute;
4464     long nextCookie;
4465     unsigned char *tp;
4466     long code = 0;
4467     clientchar_t *pathp;
4468     cm_dirEntry_t *dep = 0;
4469     int maxCount;
4470     smb_dirListPatch_t *dirListPatchesp;
4471     smb_dirListPatch_t *curPatchp;
4472     int dataLength;
4473     cm_buf_t *bufferp;
4474     long temp;
4475     osi_hyper_t dirLength;
4476     osi_hyper_t bufferOffset;
4477     osi_hyper_t curOffset;
4478     osi_hyper_t thyper;
4479     unsigned char *inCookiep;
4480     smb_dirSearch_t *dsp;
4481     cm_scache_t *scp;
4482     long entryInDir;
4483     long entryInBuffer;
4484     unsigned long clientCookie;
4485     cm_pageHeader_t *pageHeaderp;
4486     cm_user_t *userp = NULL;
4487     int slotInPage;
4488     clientchar_t mask[12];
4489     int returnedNames;
4490     long nextEntryCookie;
4491     int numDirChunks;           /* # of 32 byte dir chunks in this entry */
4492     char resByte;               /* reserved byte from the cookie */
4493     char *op;                   /* output data ptr */
4494     char *origOp;               /* original value of op */
4495     cm_space_t *spacep;         /* for pathname buffer */
4496     int starPattern;
4497     int rootPath = 0;
4498     int caseFold;
4499     clientchar_t *tidPathp = 0;
4500     cm_req_t req;
4501     cm_fid_t fid;
4502     int fileType;
4503
4504     smb_InitReq(&req);
4505
4506     maxCount = smb_GetSMBParm(inp, 0);
4507
4508     dirListPatchesp = NULL;
4509         
4510     caseFold = CM_FLAG_CASEFOLD;
4511
4512     tp = smb_GetSMBData(inp, NULL);
4513     pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4514                                 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4515     inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
4516
4517     /* bail out if request looks bad */
4518     if (!tp || !pathp) {
4519         return CM_ERROR_BADSMB;
4520     }
4521
4522     /* We can handle long names */
4523     if (vcp->flags & SMB_VCFLAG_USENT)
4524         ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
4525
4526     /* make sure we got a whole search status */
4527     if (dataLength < 21) {
4528         nextCookie = 0;         /* start at the beginning of the dir */
4529         resByte = 0;
4530         clientCookie = 0;
4531         attribute = smb_GetSMBParm(inp, 1);
4532
4533         /* handle volume info in another function */
4534         if (attribute & 0x8)
4535             return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
4536
4537         osi_Log2(smb_logp, "SMB receive search dir count %d [%S]",
4538                  maxCount, osi_LogSaveClientString(smb_logp, pathp));
4539
4540         if (*pathp == 0) {      /* null pathp, treat as root dir */
4541             if (!(attribute & SMB_ATTR_DIRECTORY))      /* exclude dirs */
4542                 return CM_ERROR_NOFILES;
4543             rootPath = 1;
4544         }
4545
4546         dsp = smb_NewDirSearch(0);
4547         dsp->attribute = attribute;
4548         smb_Get8Dot3MaskFromPath(mask, pathp);
4549         memcpy(dsp->mask, mask, 12);
4550
4551         /* track if this is likely to match a lot of entries */
4552         if (smb_IsStarMask(mask)) 
4553             starPattern = 1;
4554         else 
4555             starPattern = 0;
4556     } else {
4557         /* pull the next cookie value out of the search status block */
4558         nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
4559             + (inCookiep[16]<<24);
4560         dsp = smb_FindDirSearch(inCookiep[12]);
4561         if (!dsp) {
4562             /* can't find dir search status; fatal error */
4563             osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%S]",
4564                      inCookiep[12], nextCookie, osi_LogSaveClientString(smb_logp, pathp));
4565             return CM_ERROR_BADFD;
4566         }
4567         attribute = dsp->attribute;
4568         resByte = inCookiep[0];
4569
4570         /* copy out client cookie, in host byte order.  Don't bother
4571          * interpreting it, since we're just passing it through, anyway.
4572          */
4573         memcpy(&clientCookie, &inCookiep[17], 4);
4574
4575         memcpy(mask, dsp->mask, 12);
4576
4577         /* assume we're doing a star match if it has continued for more
4578          * than one call.
4579          */
4580         starPattern = 1;
4581     }
4582
4583     osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
4584              nextCookie, dsp->cookie, attribute);
4585
4586     userp = smb_GetUserFromVCP(vcp, inp);
4587
4588     /* try to get the vnode for the path name next */
4589     lock_ObtainMutex(&dsp->mx);
4590     if (dsp->scp) {
4591         scp = dsp->scp;
4592         osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
4593         cm_HoldSCache(scp);
4594         code = 0;
4595     } else {
4596         spacep = inp->spacep;
4597         smb_StripLastComponent(spacep->wdata, NULL, pathp);
4598         code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4599         if (code) {
4600             lock_ReleaseMutex(&dsp->mx);
4601             cm_ReleaseUser(userp);
4602             smb_DeleteDirSearch(dsp);
4603             smb_ReleaseDirSearch(dsp);
4604             return CM_ERROR_NOFILES;
4605         }
4606         cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
4607         cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
4608
4609         code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
4610                         caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
4611         if (code == 0) {
4612 #ifdef DFS_SUPPORT
4613             if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4614                 int pnc;
4615
4616                 pnc  = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->wdata);
4617                 cm_ReleaseSCache(scp);
4618                 lock_ReleaseMutex(&dsp->mx);
4619                 cm_ReleaseUser(userp);
4620                 smb_DeleteDirSearch(dsp);
4621                 smb_ReleaseDirSearch(dsp);
4622                 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4623                     return CM_ERROR_PATH_NOT_COVERED;
4624                 else
4625                     return CM_ERROR_BADSHARENAME;
4626             }
4627 #endif /* DFS_SUPPORT */
4628
4629             dsp->scp = scp;
4630             osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
4631             /* we need one hold for the entry we just stored into,
4632              * and one for our own processing.  When we're done with this
4633              * function, we'll drop the one for our own processing.
4634              * We held it once from the namei call, and so we do another hold
4635              * now.
4636              */
4637             cm_HoldSCache(scp);
4638             lock_ObtainWrite(&scp->rw);
4639             dsp->flags |= SMB_DIRSEARCH_BULKST;
4640             lock_ReleaseWrite(&scp->rw);
4641         }
4642     }
4643     lock_ReleaseMutex(&dsp->mx);
4644     if (code) {
4645         cm_ReleaseUser(userp);
4646         smb_DeleteDirSearch(dsp);
4647         smb_ReleaseDirSearch(dsp);
4648         return code;
4649     }
4650
4651     /* reserves space for parameter; we'll adjust it again later to the
4652      * real count of the # of entries we returned once we've actually
4653      * assembled the directory listing.
4654      */
4655     smb_SetSMBParm(outp, 0, 0);
4656
4657     /* get the directory size */
4658     lock_ObtainWrite(&scp->rw);
4659     code = cm_SyncOp(scp, NULL, userp, &req, 0,
4660                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4661     if (code) {
4662         lock_ReleaseWrite(&scp->rw);
4663         cm_ReleaseSCache(scp);
4664         cm_ReleaseUser(userp);
4665         smb_DeleteDirSearch(dsp);
4666         smb_ReleaseDirSearch(dsp);
4667         return code;
4668     }
4669         
4670     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4671
4672     dirLength = scp->length;
4673     bufferp = NULL;
4674     bufferOffset.LowPart = bufferOffset.HighPart = 0;
4675     curOffset.HighPart = 0;
4676     curOffset.LowPart = nextCookie;
4677     origOp = op = smb_GetSMBData(outp, NULL);
4678     /* and write out the basic header */
4679     *op++ = 5;          /* variable block */
4680     op += 2;            /* skip vbl block length; we'll fill it in later */
4681     code = 0;
4682     returnedNames = 0;
4683     while (1) {
4684         clientchar_t *actualName;
4685         clientchar_t shortName[13];
4686         clientchar_t *shortNameEnd;
4687
4688         /* make sure that curOffset.LowPart doesn't point to the first
4689          * 32 bytes in the 2nd through last dir page, and that it doesn't
4690          * point at the first 13 32-byte chunks in the first dir page,
4691          * since those are dir and page headers, and don't contain useful
4692          * information.
4693          */
4694         temp = curOffset.LowPart & (2048-1);
4695         if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4696             /* we're in the first page */
4697             if (temp < 13*32) temp = 13*32;
4698         }
4699         else {
4700             /* we're in a later dir page */
4701             if (temp < 32) temp = 32;
4702         }
4703
4704         /* make sure the low order 5 bits are zero */
4705         temp &= ~(32-1);
4706
4707         /* now put temp bits back ito curOffset.LowPart */
4708         curOffset.LowPart &= ~(2048-1);
4709         curOffset.LowPart |= temp;
4710
4711         /* check if we've returned all the names that will fit in the
4712          * response packet.
4713          */
4714         if (returnedNames >= maxCount) {
4715             osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
4716                       returnedNames, maxCount);
4717             break;
4718         }
4719                 
4720         /* check if we've passed the dir's EOF */
4721         if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
4722
4723         /* see if we can use the bufferp we have now; compute in which page
4724          * the current offset would be, and check whether that's the offset
4725          * of the buffer we have.  If not, get the buffer.
4726          */
4727         thyper.HighPart = curOffset.HighPart;
4728         thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4729         if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4730             /* wrong buffer */
4731             if (bufferp) {
4732                 buf_Release(bufferp);
4733                 bufferp = NULL;
4734             }   
4735             lock_ReleaseWrite(&scp->rw);
4736             code = buf_Get(scp, &thyper, &bufferp);
4737             lock_ObtainMutex(&dsp->mx);
4738
4739             /* now, if we're doing a star match, do bulk fetching of all of 
4740              * the status info for files in the dir.
4741              */
4742             if (starPattern)
4743                 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
4744
4745             lock_ObtainWrite(&scp->rw);
4746             lock_ReleaseMutex(&dsp->mx);
4747             if (code) {
4748                 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
4749                 break;
4750             }
4751
4752             bufferOffset = thyper;
4753
4754             /* now get the data in the cache */
4755             while (1) {
4756                 code = cm_SyncOp(scp, bufferp, userp, &req,
4757                                  PRSFS_LOOKUP,
4758                                  CM_SCACHESYNC_NEEDCALLBACK |
4759                                  CM_SCACHESYNC_READ);
4760                 if (code) {
4761                     osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
4762                     break;
4763                 }
4764                                 
4765                 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
4766
4767                 if (cm_HaveBuffer(scp, bufferp, 0)) {
4768                     osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4769                     break;
4770                 }
4771
4772                 /* otherwise, load the buffer and try again */
4773                 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
4774                 if (code) {
4775                     osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d", 
4776                               scp, bufferp, code);
4777                     break;
4778                 }
4779             }
4780             if (code) {
4781                 buf_Release(bufferp);
4782                 bufferp = NULL;
4783                 break;
4784             }
4785         }       /* if (wrong buffer) ... */
4786
4787         /* now we have the buffer containing the entry we're interested in; copy
4788          * it out if it represents a non-deleted entry.
4789          */
4790         entryInDir = curOffset.LowPart & (2048-1);
4791         entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4792
4793         /* page header will help tell us which entries are free.  Page header
4794          * can change more often than once per buffer, since AFS 3 dir page size
4795          * may be less than (but not more than a buffer package buffer.
4796          */
4797         temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);  /* only look intra-buffer */
4798         temp &= ~(2048 - 1);    /* turn off intra-page bits */
4799         pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4800
4801         /* now determine which entry we're looking at in the page.  If it is
4802          * free (there's a free bitmap at the start of the dir), we should
4803          * skip these 32 bytes.
4804          */
4805         slotInPage = (entryInDir & 0x7e0) >> 5;
4806         if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
4807             /* this entry is free */
4808             numDirChunks = 1;           /* only skip this guy */
4809             goto nextEntry;
4810         }
4811
4812         tp = bufferp->datap + entryInBuffer;
4813         dep = (cm_dirEntry_t *) tp;             /* now points to AFS3 dir entry */
4814
4815         /* while we're here, compute the next entry's location, too,
4816          * since we'll need it when writing out the cookie into the dir
4817          * listing stream.
4818          *
4819          * XXXX Probably should do more sanity checking.
4820          */
4821         numDirChunks = cm_NameEntries(dep->name, NULL);
4822
4823         /* compute the offset of the cookie representing the next entry */
4824         nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4825
4826         /* Compute 8.3 name if necessary */
4827         actualName = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
4828         if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
4829             free(actualName);
4830             cm_Gen8Dot3NameInt(dep->name, &dep->fid, shortName, &shortNameEnd);
4831             actualName = shortName;
4832         }
4833
4834         osi_Log3(smb_logp, "SMB search dir vn %d name %s (%S)",
4835                  dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
4836                  osi_LogSaveClientString(smb_logp, actualName));
4837
4838         if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
4839             /* this is one of the entries to use: it is not deleted
4840              * and it matches the star pattern we're looking for.
4841              */
4842
4843             /* Eliminate entries that don't match requested
4844              * attributes */
4845
4846             /* no hidden files */
4847             if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
4848                 osi_Log0(smb_logp, "SMB search dir skipping hidden");
4849                 goto nextEntry;
4850             }
4851
4852             if (!(dsp->attribute & SMB_ATTR_DIRECTORY))  /* no directories */
4853             {
4854                 /* We have already done the cm_TryBulkStat above */
4855                 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
4856                 fileType = cm_FindFileType(&fid);
4857                 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
4858                          "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
4859                           fileType);
4860                 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4861                     fileType == CM_SCACHETYPE_MOUNTPOINT ||
4862                     fileType == CM_SCACHETYPE_DFSLINK ||
4863                     fileType == CM_SCACHETYPE_INVALID)
4864                     osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
4865                 goto nextEntry;
4866             }
4867
4868             *op++ = resByte;
4869             memcpy(op, mask, 11); op += 11;
4870             *op++ = (unsigned char) dsp->cookie;        /* they say it must be non-zero */
4871             *op++ = (unsigned char)(nextEntryCookie & 0xff);
4872             *op++ = (unsigned char)((nextEntryCookie>>8) & 0xff);
4873             *op++ = (unsigned char)((nextEntryCookie>>16) & 0xff);
4874             *op++ = (unsigned char)((nextEntryCookie>>24) & 0xff);
4875             memcpy(op, &clientCookie, 4); op += 4;
4876
4877             /* now we emit the attribute.  This is sort of tricky,
4878              * since we need to really stat the file to find out
4879              * what type of entry we've got.  Right now, we're
4880              * copying out data from a buffer, while holding the
4881              * scp locked, so it isn't really convenient to stat
4882              * something now.  We'll put in a place holder now,
4883              * and make a second pass before returning this to get
4884              * the real attributes.  So, we just skip the data for
4885              * now, and adjust it later.  We allocate a patch
4886              * record to make it easy to find this point later.
4887              * The replay will happen at a time when it is safe to
4888              * unlock the directory.
4889              */
4890             curPatchp = malloc(sizeof(*curPatchp));
4891             osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
4892             curPatchp->dptr = op;
4893             cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
4894
4895             /* do hidden attribute here since name won't be around when applying
4896              * dir list patches
4897              */
4898
4899             if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
4900                 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4901             else
4902                 curPatchp->flags = 0;
4903
4904             op += 9;    /* skip attr, time, date and size */
4905
4906             /* zero out name area.  The spec says to pad with
4907              * spaces, but Samba doesn't, and neither do we.
4908              */
4909             memset(op, 0, 13);
4910
4911             /* finally, we get to copy out the name; we know that
4912              * it fits in 8.3 or the pattern wouldn't match, but it
4913              * never hurts to be sure.
4914              */
4915             cm_ClientStringToUtf8(actualName, -1, op, 13);
4916             if (smb_StoreAnsiFilenames)
4917                 CharToOem(op, op);
4918             /* This is a UCHAR field, which is ASCII even if Unicode
4919                is negotiated. */
4920
4921             /* Uppercase if requested by client */
4922             if (!KNOWS_LONG_NAMES(inp))
4923                 _strupr(op);
4924
4925             op += 13;
4926
4927             /* now, adjust the # of entries copied */
4928             returnedNames++;
4929         }       /* if we're including this name */
4930
4931       nextEntry:
4932         /* and adjust curOffset to be where the new cookie is */
4933         thyper.HighPart = 0;
4934         thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4935         curOffset = LargeIntegerAdd(thyper, curOffset);
4936     }           /* while copying data for dir listing */
4937
4938     /* release the mutex */
4939     lock_ReleaseWrite(&scp->rw);
4940     if (bufferp) {
4941         buf_Release(bufferp);
4942         bufferp = NULL;
4943     }
4944
4945     /* apply and free last set of patches; if not doing a star match, this
4946      * will be empty, but better safe (and freeing everything) than sorry.
4947      */
4948     smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
4949
4950     /* special return code for unsuccessful search */
4951     if (code == 0 && dataLength < 21 && returnedNames == 0)
4952         code = CM_ERROR_NOFILES;
4953
4954     osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
4955              returnedNames, code);
4956
4957     if (code != 0) {
4958         smb_DeleteDirSearch(dsp);
4959         smb_ReleaseDirSearch(dsp);
4960         cm_ReleaseSCache(scp);
4961         cm_ReleaseUser(userp);
4962         return code;
4963     }
4964
4965     /* finalize the output buffer */
4966     smb_SetSMBParm(outp, 0, returnedNames);
4967     temp = (long) (op - origOp);
4968     smb_SetSMBDataLength(outp, temp);
4969
4970     /* the data area is a variable block, which has a 5 (already there)
4971      * followed by the length of the # of data bytes.  We now know this to
4972      * be "temp," although that includes the 3 bytes of vbl block header.
4973      * Deduct for them and fill in the length field.
4974      */
4975     temp -= 3;          /* deduct vbl block info */
4976     osi_assertx(temp == (43 * returnedNames), "unexpected data length");
4977     origOp[1] = (unsigned char)(temp & 0xff);
4978     origOp[2] = (unsigned char)((temp>>8) & 0xff);
4979     if (returnedNames == 0) 
4980         smb_DeleteDirSearch(dsp);
4981     smb_ReleaseDirSearch(dsp);
4982     cm_ReleaseSCache(scp);
4983     cm_ReleaseUser(userp);
4984     return code;
4985 }       
4986
4987
4988 /* verify that this is a valid path to a directory.  I don't know why they
4989  * don't use the get file attributes call.
4990  *
4991  * SMB_COM_CHECK_DIRECTORY
4992  */
4993 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4994 {
4995     clientchar_t *pathp;
4996     long code = 0;
4997     cm_scache_t *rootScp;
4998     cm_scache_t *newScp;
4999     cm_user_t *userp;
5000     unsigned int attrs;
5001     int caseFold;
5002     clientchar_t *tidPathp;
5003     cm_req_t req;
5004     char * pdata;
5005
5006     smb_InitReq(&req);
5007
5008     pdata = smb_GetSMBData(inp, NULL);
5009     pathp = smb_ParseASCIIBlock(inp, pdata, NULL, SMB_STRF_ANSIPATH);
5010     if (!pathp)
5011         return CM_ERROR_BADFD;
5012     osi_Log1(smb_logp, "SMB receive check path %S",
5013              osi_LogSaveClientString(smb_logp, pathp));
5014         
5015     rootScp = cm_data.rootSCachep;
5016         
5017     userp = smb_GetUserFromVCP(vcp, inp);
5018
5019     caseFold = CM_FLAG_CASEFOLD;
5020
5021     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5022     if (code) {
5023         cm_ReleaseUser(userp);
5024         return CM_ERROR_NOSUCHPATH;
5025     }
5026     code = cm_NameI(rootScp, pathp,
5027                     caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
5028                     userp, tidPathp, &req, &newScp);
5029
5030     if (code) {
5031         cm_ReleaseUser(userp);
5032         return code;
5033     }
5034         
5035 #ifdef DFS_SUPPORT
5036     if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5037         int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5038         cm_ReleaseSCache(newScp);
5039         cm_ReleaseUser(userp);
5040         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5041             return CM_ERROR_PATH_NOT_COVERED;
5042         else
5043             return CM_ERROR_BADSHARENAME;
5044     }
5045 #endif /* DFS_SUPPORT */
5046
5047     /* now lock the vnode with a callback; returns with newScp locked */
5048     lock_ObtainWrite(&newScp->rw);
5049     code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
5050                      CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5051     if (code) {
5052         if (code != CM_ERROR_NOACCESS) {
5053             lock_ReleaseWrite(&newScp->rw);
5054             cm_ReleaseSCache(newScp);
5055             cm_ReleaseUser(userp);
5056             return code;
5057         }
5058     } else {
5059         cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5060     }
5061
5062     attrs = smb_Attributes(newScp);
5063
5064     if (!(attrs & SMB_ATTR_DIRECTORY))
5065         code = CM_ERROR_NOTDIR;
5066
5067     lock_ReleaseWrite(&newScp->rw);
5068
5069     cm_ReleaseSCache(newScp);
5070     cm_ReleaseUser(userp);
5071     return code;
5072 }       
5073
5074 /* SMB_COM_SET_INFORMATION */
5075 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5076 {
5077     clientchar_t *pathp;
5078     long code = 0;
5079     cm_scache_t *rootScp;
5080     unsigned short attribute;
5081     cm_attr_t attr;
5082     cm_scache_t *newScp;
5083     afs_uint32 dosTime;
5084     cm_user_t *userp;
5085     int caseFold;
5086     clientchar_t *tidPathp;
5087     char * datap;
5088     cm_req_t req;
5089
5090     smb_InitReq(&req);
5091
5092     /* decode basic attributes we're passed */
5093     attribute = smb_GetSMBParm(inp, 0);
5094     dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5095
5096     datap = smb_GetSMBData(inp, NULL);
5097     pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5098     if (!pathp)
5099         return CM_ERROR_BADSMB;
5100                
5101     osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
5102              dosTime, attribute);
5103
5104     rootScp = cm_data.rootSCachep;
5105         
5106     userp = smb_GetUserFromVCP(vcp, inp);
5107
5108     caseFold = CM_FLAG_CASEFOLD;
5109
5110     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5111     if (code) {
5112         cm_ReleaseUser(userp);
5113         return CM_ERROR_NOSUCHFILE;
5114     }
5115     code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5116                     tidPathp, &req, &newScp);
5117
5118     if (code) {
5119         cm_ReleaseUser(userp);
5120         return code;
5121     }
5122
5123 #ifdef DFS_SUPPORT
5124     if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5125         int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5126         cm_ReleaseSCache(newScp);
5127         cm_ReleaseUser(userp);
5128         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5129             return CM_ERROR_PATH_NOT_COVERED;
5130         else
5131             return CM_ERROR_BADSHARENAME;
5132     }
5133 #endif /* DFS_SUPPORT */
5134
5135     /* now lock the vnode with a callback; returns with newScp locked; we
5136      * need the current status to determine what the new status is, in some
5137      * cases.
5138      */
5139     lock_ObtainWrite(&newScp->rw);
5140     code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5141                      CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5142     if (code) {
5143         lock_ReleaseWrite(&newScp->rw);
5144         cm_ReleaseSCache(newScp);
5145         cm_ReleaseUser(userp);
5146         return code;
5147     }
5148
5149     cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5150
5151     /* Check for RO volume */
5152     if (newScp->flags & CM_SCACHEFLAG_RO) {
5153         lock_ReleaseWrite(&newScp->rw);
5154         cm_ReleaseSCache(newScp);
5155         cm_ReleaseUser(userp);
5156         return CM_ERROR_READONLY;
5157     }
5158
5159     /* prepare for setattr call */
5160     attr.mask = 0;
5161     if (dosTime != 0) {
5162         attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
5163         smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
5164     }
5165     if ((newScp->unixModeBits & 0222) && (attribute & SMB_ATTR_READONLY) != 0) {
5166         /* we're told to make a writable file read-only */
5167         attr.unixModeBits = newScp->unixModeBits & ~0222;
5168         attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5169     }
5170     else if ((newScp->unixModeBits & 0222) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
5171         /* we're told to make a read-only file writable */
5172         attr.unixModeBits = newScp->unixModeBits | 0222;
5173         attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5174     }
5175     lock_ReleaseWrite(&newScp->rw);
5176
5177     /* now call setattr */
5178     if (attr.mask)
5179         code = cm_SetAttr(newScp, &attr, userp, &req);
5180     else
5181         code = 0;
5182         
5183     cm_ReleaseSCache(newScp);
5184     cm_ReleaseUser(userp);
5185
5186     return code;
5187 }
5188
5189
5190 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5191 {
5192     clientchar_t *pathp;
5193     long code = 0;
5194     cm_scache_t *rootScp;
5195     cm_scache_t *newScp, *dscp;
5196     afs_uint32 dosTime;
5197     int attrs;
5198     cm_user_t *userp;
5199     int caseFold;
5200     clientchar_t *tidPathp;
5201     cm_space_t *spacep;
5202     clientchar_t *lastComp;
5203     char * datap;
5204     cm_req_t req;
5205
5206     smb_InitReq(&req);
5207
5208     datap = smb_GetSMBData(inp, NULL);
5209     pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5210     if (!pathp)
5211         return CM_ERROR_BADSMB;
5212         
5213     if (*pathp == 0)            /* null path */
5214         pathp = _C("\\");
5215
5216     osi_Log1(smb_logp, "SMB receive getfile attributes path %S",
5217              osi_LogSaveClientString(smb_logp, pathp));
5218
5219     rootScp = cm_data.rootSCachep;
5220         
5221     userp = smb_GetUserFromVCP(vcp, inp);
5222
5223     /* we shouldn't need this for V3 requests, but we seem to */
5224     caseFold = CM_FLAG_CASEFOLD;
5225
5226     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5227     if (code) {
5228         cm_ReleaseUser(userp);
5229         return CM_ERROR_NOSUCHFILE;
5230     }
5231
5232     /*
5233      * XXX Strange hack XXX
5234      *
5235      * As of Patch 5 (16 July 97), we are having the following problem:
5236      * In NT Explorer 4.0, whenever we click on a directory, AFS gets
5237      * requests to look up "desktop.ini" in all the subdirectories.
5238      * This can cause zillions of timeouts looking up non-existent cells
5239      * and volumes, especially in the top-level directory.
5240      *
5241      * We have not found any way to avoid this or work around it except
5242      * to explicitly ignore the requests for mount points that haven't
5243      * yet been evaluated and for directories that haven't yet been
5244      * fetched.
5245      *
5246      * We should modify this hack to provide a fake desktop.ini file
5247      * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
5248      */
5249     spacep = inp->spacep;
5250     smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
5251 #ifndef SPECIAL_FOLDERS
5252     if (lastComp && cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
5253         code = cm_NameI(rootScp, spacep->wdata,
5254                         caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
5255                         userp, tidPathp, &req, &dscp);
5256         if (code == 0) {
5257 #ifdef DFS_SUPPORT
5258             if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5259                 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
5260                                                           spacep->wdata);
5261                 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5262                     return CM_ERROR_PATH_NOT_COVERED;
5263                 else
5264                     return CM_ERROR_BADSHARENAME;
5265             } else
5266 #endif /* DFS_SUPPORT */
5267             if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
5268                 code = CM_ERROR_NOSUCHFILE;
5269             else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
5270                 cm_buf_t *bp = buf_Find(dscp, &hzero);
5271                 if (bp) {
5272                     buf_Release(bp);
5273                     bp = NULL;
5274                 } else
5275                     code = CM_ERROR_NOSUCHFILE;
5276             }
5277             cm_ReleaseSCache(dscp);
5278             if (code) {
5279                 cm_ReleaseUser(userp);
5280                 return code;
5281             }
5282         }
5283     }
5284 #endif /* SPECIAL_FOLDERS */
5285
5286     code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5287                     tidPathp, &req, &newScp);
5288     if (code) {
5289         cm_ReleaseUser(userp);
5290         return code;
5291     }
5292         
5293 #ifdef DFS_SUPPORT
5294     if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5295         int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5296         cm_ReleaseSCache(newScp);
5297         cm_ReleaseUser(userp);
5298         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5299             return CM_ERROR_PATH_NOT_COVERED;
5300         else
5301             return CM_ERROR_BADSHARENAME;
5302     }
5303 #endif /* DFS_SUPPORT */
5304
5305     /* now lock the vnode with a callback; returns with newScp locked */
5306     lock_ObtainWrite(&newScp->rw);
5307     code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5308                      CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5309     if (code) {
5310         lock_ReleaseWrite(&newScp->rw);
5311         cm_ReleaseSCache(newScp);
5312         cm_ReleaseUser(userp);
5313         return code;
5314     }
5315
5316     cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5317
5318 #ifdef undef
5319     /* use smb_Attributes instead.   Also the fact that a file is 
5320      * in a readonly volume doesn't mean it shojuld be marked as RO 
5321      */
5322     if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
5323         newScp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
5324         newScp->fileType == CM_SCACHETYPE_INVALID)
5325         attrs = SMB_ATTR_DIRECTORY;
5326     else
5327         attrs = 0;
5328     if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
5329         attrs |= SMB_ATTR_READONLY;     /* turn on read-only flag */
5330 #else
5331     attrs = smb_Attributes(newScp);
5332 #endif
5333
5334     smb_SetSMBParm(outp, 0, attrs);
5335         
5336     smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
5337     smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
5338     smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
5339     smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
5340     smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
5341     smb_SetSMBParm(outp, 5, 0);
5342     smb_SetSMBParm(outp, 6, 0);
5343     smb_SetSMBParm(outp, 7, 0);
5344     smb_SetSMBParm(outp, 8, 0);
5345     smb_SetSMBParm(outp, 9, 0);
5346     smb_SetSMBDataLength(outp, 0);
5347     lock_ReleaseWrite(&newScp->rw);
5348
5349     cm_ReleaseSCache(newScp);
5350     cm_ReleaseUser(userp);
5351
5352     return 0;
5353 }       
5354
5355 /* SMB_COM_TREE_DISCONNECT */
5356 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5357 {
5358     smb_tid_t *tidp;
5359         
5360     osi_Log0(smb_logp, "SMB receive tree disconnect");
5361
5362     /* find the tree and free it */
5363     tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
5364     if (tidp) {
5365         lock_ObtainWrite(&smb_rctLock);
5366         tidp->deleteOk = 1;
5367         smb_ReleaseTID(tidp, TRUE);
5368         lock_ReleaseWrite(&smb_rctLock);
5369     }
5370
5371     return 0;
5372 }
5373
5374 /* SMB_COM_0PEN */
5375 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5376 {
5377     smb_fid_t *fidp;
5378     clientchar_t *pathp;
5379     clientchar_t *lastNamep;
5380     int share;
5381     int attribute;
5382     long code = 0;
5383     cm_user_t *userp;
5384     cm_scache_t *scp;
5385     afs_uint32 dosTime;
5386     int caseFold;
5387     cm_space_t *spacep;
5388     clientchar_t *tidPathp;
5389     char * datap;
5390     cm_req_t req;
5391
5392     smb_InitReq(&req);
5393
5394     datap = smb_GetSMBData(inp, NULL);
5395     pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5396
5397     osi_Log1(smb_logp, "SMB receive open file [%S]", osi_LogSaveClientString(smb_logp, pathp));
5398
5399 #ifdef DEBUG_VERBOSE
5400     {
5401         char *hexpath;
5402
5403         hexpath = osi_HexifyString( pathp );
5404         DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
5405         free(hexpath);
5406     }
5407 #endif
5408
5409     share = smb_GetSMBParm(inp, 0);
5410     attribute = smb_GetSMBParm(inp, 1);
5411
5412     spacep = inp->spacep;
5413     smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5414     if (lastNamep && cm_ClientStrCmp(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0) {
5415         /* special case magic file name for receiving IOCTL requests
5416          * (since IOCTL calls themselves aren't getting through).
5417          */
5418         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5419         smb_SetupIoctlFid(fidp, spacep);
5420         smb_SetSMBParm(outp, 0, fidp->fid);
5421         smb_SetSMBParm(outp, 1, 0);     /* attrs */
5422         smb_SetSMBParm(outp, 2, 0);     /* next 2 are DOS time */
5423         smb_SetSMBParm(outp, 3, 0);
5424         smb_SetSMBParm(outp, 4, 0);     /* next 2 are length */
5425         smb_SetSMBParm(outp, 5, 0x7fff);
5426         /* pass the open mode back */
5427         smb_SetSMBParm(outp, 6, (share & 0xf));
5428         smb_SetSMBDataLength(outp, 0);
5429         smb_ReleaseFID(fidp);
5430         return 0;
5431     }
5432
5433     userp = smb_GetUserFromVCP(vcp, inp);
5434
5435     caseFold = CM_FLAG_CASEFOLD;
5436
5437     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5438     if (code) {
5439         cm_ReleaseUser(userp);
5440         return CM_ERROR_NOSUCHPATH;
5441     }
5442     code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5443                     tidPathp, &req, &scp);
5444         
5445     if (code) {
5446         cm_ReleaseUser(userp);
5447         return code;
5448     }
5449
5450 #ifdef DFS_SUPPORT
5451     if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5452         int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
5453         cm_ReleaseSCache(scp);
5454         cm_ReleaseUser(userp);
5455         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5456             return CM_ERROR_PATH_NOT_COVERED;
5457         else
5458             return CM_ERROR_BADSHARENAME;
5459     }
5460 #endif /* DFS_SUPPORT */
5461
5462     code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
5463     if (code) {
5464         cm_ReleaseSCache(scp);
5465         cm_ReleaseUser(userp);
5466         return code;
5467     }
5468
5469     /* don't need callback to check file type, since file types never
5470      * change, and namei and cm_Lookup all stat the object at least once on
5471      * a successful return.
5472      */
5473     if (scp->fileType != CM_SCACHETYPE_FILE) {
5474         cm_ReleaseSCache(scp);
5475         cm_ReleaseUser(userp);
5476         return CM_ERROR_ISDIR;
5477     }
5478
5479     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5480     osi_assertx(fidp, "null smb_fid_t");
5481
5482     /* save a pointer to the vnode */
5483     fidp->scp = scp;
5484     osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
5485     lock_ObtainWrite(&scp->rw);
5486     scp->flags |= CM_SCACHEFLAG_SMB_FID;
5487     lock_ReleaseWrite(&scp->rw);
5488
5489     /* and the user */
5490     cm_HoldUser(userp);
5491     fidp->userp = userp;
5492
5493     lock_ObtainMutex(&fidp->mx);
5494     if ((share & 0xf) == 0)
5495         fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5496     else if ((share & 0xf) == 1)
5497         fidp->flags |= SMB_FID_OPENWRITE;
5498     else 
5499         fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
5500     lock_ReleaseMutex(&fidp->mx);
5501
5502     lock_ObtainRead(&scp->rw);
5503     smb_SetSMBParm(outp, 0, fidp->fid);
5504     smb_SetSMBParm(outp, 1, smb_Attributes(scp));
5505     smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5506     smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
5507     smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
5508     smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
5509     smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
5510     /* pass the open mode back; XXXX add access checks */
5511     smb_SetSMBParm(outp, 6, (share & 0xf));
5512     smb_SetSMBDataLength(outp, 0);
5513     lock_ReleaseRead(&scp->rw);
5514         
5515     /* notify open */
5516     cm_Open(scp, 0, userp);
5517
5518     /* send and free packet */
5519     smb_ReleaseFID(fidp);
5520     cm_ReleaseUser(userp);
5521     /* don't release scp, since we've squirreled away the pointer in the fid struct */
5522     return 0;
5523 }
5524
5525 typedef struct smb_unlinkRock {
5526     cm_scache_t *dscp;
5527     cm_user_t *userp;
5528     cm_req_t *reqp;
5529     smb_vc_t *vcp;
5530     clientchar_t *maskp;                /* pointer to the star pattern */
5531     int flags;
5532     int any;
5533     cm_dirEntryList_t * matches;
5534 } smb_unlinkRock_t;
5535
5536 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5537 {
5538     long code = 0;
5539     smb_unlinkRock_t *rockp;
5540     int caseFold;
5541     int match;
5542     normchar_t matchName[MAX_PATH];
5543         
5544     rockp = vrockp;
5545
5546     caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5547     if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5548         caseFold |= CM_FLAG_8DOT3;
5549
5550     cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName));
5551     match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5552     if (!match &&
5553         (rockp->flags & SMB_MASKFLAG_TILDE) &&
5554         !cm_Is8Dot3(matchName)) {
5555         cm_Gen8Dot3Name(dep, matchName, NULL);
5556         /* 8.3 matches are always case insensitive */
5557         match = cm_MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
5558     }
5559     if (match) {
5560         osi_Log1(smb_logp, "Found match %S",
5561                  osi_LogSaveClientString(smb_logp, matchName));
5562
5563         cm_DirEntryListAdd(dep->name, &rockp->matches);
5564
5565         rockp->any = 1;
5566
5567         /* If we made a case sensitive exact match, we might as well quit now. */
5568         if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !cm_ClientStrCmp(matchName, rockp->maskp))
5569             code = CM_ERROR_STOPNOW;
5570         else
5571             code = 0;
5572     }
5573     else code = 0;
5574
5575     return code;
5576 }
5577
5578 /* SMB_COM_DELETE */
5579 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5580 {
5581     int attribute;
5582     long code = 0;
5583     clientchar_t *pathp;
5584     unsigned char *tp;
5585     cm_space_t *spacep;
5586     cm_scache_t *dscp;
5587     clientchar_t *lastNamep;
5588     smb_unlinkRock_t rock;
5589     cm_user_t *userp;
5590     osi_hyper_t thyper;
5591     int caseFold;
5592     clientchar_t *tidPathp;
5593     cm_req_t req;
5594
5595     smb_InitReq(&req);
5596
5597     attribute = smb_GetSMBParm(inp, 0);
5598         
5599     tp = smb_GetSMBData(inp, NULL);
5600     pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
5601
5602     osi_Log1(smb_logp, "SMB receive unlink %S",
5603              osi_LogSaveClientString(smb_logp, pathp));
5604
5605     spacep = inp->spacep;
5606     smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5607
5608     userp = smb_GetUserFromVCP(vcp, inp);
5609
5610     caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5611
5612     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5613     if (code) {
5614         cm_ReleaseUser(userp);
5615         return CM_ERROR_NOSUCHPATH;
5616     }
5617     code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold, userp, tidPathp,
5618                     &req, &dscp);
5619     if (code) {
5620         cm_ReleaseUser(userp);
5621         return code;
5622     }
5623         
5624 #ifdef DFS_SUPPORT
5625     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5626         int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
5627         cm_ReleaseSCache(dscp);
5628         cm_ReleaseUser(userp);
5629         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5630             return CM_ERROR_PATH_NOT_COVERED;
5631         else
5632             return CM_ERROR_BADSHARENAME;
5633     }
5634 #endif /* DFS_SUPPORT */
5635
5636     /* otherwise, scp points to the parent directory. */
5637     if (!lastNamep) 
5638         lastNamep = pathp;
5639     else 
5640         lastNamep++;
5641
5642     rock.any = 0;
5643     rock.maskp = cm_ClientStringToNormStringAlloc(smb_FindMask(pathp), -1, NULL);
5644     rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5645
5646     thyper.LowPart = 0;
5647     thyper.HighPart = 0;
5648     rock.userp = userp;
5649     rock.reqp = &req;
5650     rock.dscp = dscp;
5651     rock.vcp = vcp;
5652     rock.matches = NULL;
5653
5654     /* Now, if we aren't dealing with a wildcard match, we first try an exact 
5655      * match.  If that fails, we do a case insensitve match. 
5656      */
5657     if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
5658         !smb_IsStarMask(rock.maskp)) {
5659         code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5660         if (!rock.any) {
5661             thyper.LowPart = 0;
5662             thyper.HighPart = 0;
5663             rock.flags |= SMB_MASKFLAG_CASEFOLD;
5664         }
5665     }
5666  
5667     if (!rock.any)
5668         code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5669     
5670     if (code == CM_ERROR_STOPNOW) 
5671         code = 0;
5672
5673     if (code == 0 && rock.matches) {
5674         cm_dirEntryList_t * entry;
5675
5676         for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
5677             normchar_t normalizedName[MAX_PATH];
5678
5679             /* Note: entry->name is a non-normalized name */
5680
5681             osi_Log1(smb_logp, "Unlinking %s",
5682                      osi_LogSaveString(smb_logp, entry->name));
5683
5684             cm_FsStringToNormString(entry->name, -1,
5685                                     normalizedName, lengthof(normalizedName));
5686
5687             code = cm_Unlink(dscp, entry->name, normalizedName, userp, &req);
5688
5689             if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5690                 smb_NotifyChange(FILE_ACTION_REMOVED,
5691                                  FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5692                                  dscp, normalizedName, NULL, TRUE);
5693         }
5694     }
5695
5696     cm_DirEntryListFree(&rock.matches);
5697
5698     cm_ReleaseUser(userp);
5699         
5700     cm_ReleaseSCache(dscp);
5701
5702     free(rock.maskp);
5703
5704     if (code == 0 && !rock.any)
5705         code = CM_ERROR_NOSUCHFILE;
5706     return code;
5707 }       
5708
5709 typedef struct smb_renameRock {
5710     cm_scache_t *odscp;  /* old dir */
5711     cm_scache_t *ndscp;  /* new dir */
5712     cm_user_t *userp;    /* user */
5713     cm_req_t *reqp;      /* request struct */
5714     smb_vc_t *vcp;       /* virtual circuit */
5715     normchar_t *maskp;   /* pointer to star pattern of old file name */
5716     int flags;           /* tilde, casefold, etc */
5717     clientchar_t *newNamep;     /* ptr to the new file's name */
5718     fschar_t fsOldName[MAX_PATH]; /* raw FS name */
5719     clientchar_t clOldName[MAX_PATH]; /* client name */
5720     int any;
5721 } smb_renameRock_t;
5722
5723 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5724 {
5725     long code = 0;
5726     smb_renameRock_t *rockp;
5727     int caseFold;
5728     int match;
5729     normchar_t matchName[MAX_PATH];
5730
5731     rockp = (smb_renameRock_t *) vrockp;
5732
5733     cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName));
5734     caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5735     if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5736         caseFold |= CM_FLAG_8DOT3;
5737
5738     match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5739     if (!match &&
5740         (rockp->flags & SMB_MASKFLAG_TILDE) &&
5741         !cm_Is8Dot3(matchName)) {
5742         cm_Gen8Dot3Name(dep, matchName, NULL);
5743         match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5744     }
5745
5746     if (match) {
5747         rockp->any = 1;
5748         StringCbCopyA(rockp->fsOldName, sizeof(rockp->fsOldName), dep->name);
5749         cm_ClientStrCpy(rockp->clOldName, lengthof(rockp->clOldName),
5750                         matchName);
5751         code = CM_ERROR_STOPNOW;
5752     } else {
5753         code = 0;
5754     }
5755
5756     return code;
5757 }
5758
5759
5760 long 
5761 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp, int attrs)
5762 {
5763     long code = 0;
5764     cm_space_t *spacep = NULL;
5765     smb_renameRock_t rock;
5766     cm_scache_t *oldDscp = NULL;
5767     cm_scache_t *newDscp = NULL;
5768     cm_scache_t *tmpscp= NULL;
5769     cm_scache_t *tmpscp2 = NULL;
5770     clientchar_t *oldLastNamep;
5771     clientchar_t *newLastNamep;
5772     osi_hyper_t thyper;
5773     cm_user_t *userp;
5774     int caseFold;
5775     clientchar_t *tidPathp;
5776     DWORD filter;
5777     cm_req_t req;
5778
5779     userp = smb_GetUserFromVCP(vcp, inp);
5780     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5781     if (code) {
5782         cm_ReleaseUser(userp);
5783         return CM_ERROR_NOSUCHPATH;
5784     }
5785
5786     smb_InitReq(&req);
5787     spacep = inp->spacep;
5788     smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
5789
5790     caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5791     code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
5792                     userp, tidPathp, &req, &oldDscp);
5793     if (code) {
5794         cm_ReleaseUser(userp);
5795         return code;
5796     }
5797         
5798 #ifdef DFS_SUPPORT
5799     if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5800         int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
5801         cm_ReleaseSCache(oldDscp);
5802         cm_ReleaseUser(userp);
5803         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5804             return CM_ERROR_PATH_NOT_COVERED;
5805         else
5806             return CM_ERROR_BADSHARENAME;
5807     }
5808 #endif /* DFS_SUPPORT */
5809
5810     smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
5811     code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
5812                     userp, tidPathp, &req, &newDscp);
5813
5814     if (code) {
5815         cm_ReleaseSCache(oldDscp);
5816         cm_ReleaseUser(userp);
5817         return code;
5818     }
5819
5820 #ifdef DFS_SUPPORT
5821     if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5822         int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
5823         cm_ReleaseSCache(oldDscp);
5824         cm_ReleaseSCache(newDscp);
5825         cm_ReleaseUser(userp);
5826         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5827             return CM_ERROR_PATH_NOT_COVERED;
5828         else
5829             return CM_ERROR_BADSHARENAME;
5830     }
5831 #endif /* DFS_SUPPORT */
5832
5833
5834     /* otherwise, oldDscp and newDscp point to the corresponding directories.
5835      * next, get the component names, and lower case them.
5836      */
5837
5838     /* handle the old name first */
5839     if (!oldLastNamep) 
5840         oldLastNamep = oldPathp;
5841     else 
5842         oldLastNamep++;
5843
5844     /* and handle the new name, too */
5845     if (!newLastNamep) 
5846         newLastNamep = newPathp;
5847     else 
5848         newLastNamep++;
5849
5850     /* TODO: The old name could be a wildcard.  The new name must not be */
5851
5852     /* do the vnode call */
5853     rock.odscp = oldDscp;
5854     rock.ndscp = newDscp;
5855     rock.userp = userp;
5856     rock.reqp = &req;
5857     rock.vcp = vcp;
5858     rock.maskp = cm_ClientStringToNormStringAlloc(oldLastNamep, -1, NULL);
5859     rock.flags = ((cm_ClientStrChr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5860     rock.newNamep = newLastNamep;
5861     rock.fsOldName[0] = '\0';
5862     rock.clOldName[0] = '\0';
5863     rock.any = 0;
5864
5865     /* Check if the file already exists; if so return error */
5866     code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5867     if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
5868         (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) 
5869     {
5870         osi_Log2(smb_logp, "  lookup returns %ld for [%S]", code,
5871                  osi_LogSaveClientString(smb_logp, newLastNamep));
5872
5873         /* Check if the old and the new names differ only in case. If so return
5874          * success, else return CM_ERROR_EXISTS 
5875          */
5876         if (!code && oldDscp == newDscp && !cm_ClientStrCmpI(oldLastNamep, newLastNamep)) {
5877
5878             /* This would be a success only if the old file is *as same as* the new file */
5879             code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
5880             if (!code) {
5881                 if (tmpscp == tmpscp2) 
5882                     code = 0;
5883                 else 
5884                     code = CM_ERROR_EXISTS;
5885                 cm_ReleaseSCache(tmpscp2);
5886                 tmpscp2 = NULL;
5887             } else {
5888                 code = CM_ERROR_NOSUCHFILE;
5889             }
5890         } else {
5891             /* file exist, do not rename, also fixes move */
5892             osi_Log0(smb_logp, "Can't rename.  Target already exists");
5893             code = CM_ERROR_EXISTS;
5894         }
5895
5896         if (tmpscp != NULL)
5897             cm_ReleaseSCache(tmpscp);
5898         cm_ReleaseSCache(newDscp);
5899         cm_ReleaseSCache(oldDscp);
5900         cm_ReleaseUser(userp);
5901
5902         free(rock.maskp);
5903         rock.maskp = NULL;
5904         return code; 
5905     }
5906
5907     /* Now search the directory for the pattern, and do the appropriate rename when found */
5908     thyper.LowPart = 0;         /* search dir from here */
5909     thyper.HighPart = 0;
5910
5911     code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5912     if (code == 0 && !rock.any) {
5913         thyper.LowPart = 0;
5914         thyper.HighPart = 0;
5915         rock.flags |= SMB_MASKFLAG_CASEFOLD;
5916         code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5917     }
5918     osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
5919
5920     if (code == CM_ERROR_STOPNOW && rock.fsOldName[0] != '\0') {
5921         code = cm_Rename(rock.odscp, rock.fsOldName, rock.clOldName,
5922                          rock.ndscp, rock.newNamep, rock.userp,
5923                          rock.reqp);
5924         /* if the call worked, stop doing the search now, since we
5925          * really only want to rename one file.
5926          */
5927     if (code)
5928         osi_Log0(smb_logp, "cm_Rename failure");
5929         osi_Log1(smb_logp, "cm_Rename returns %ld", code);
5930     } else if (code == 0) {
5931         code = CM_ERROR_NOSUCHFILE;
5932     }
5933
5934     /* Handle Change Notification */
5935     /*
5936     * Being lazy, not distinguishing between files and dirs in this
5937     * filter, since we'd have to do a lookup.
5938     */
5939     if (code == 0) {
5940         filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
5941         if (oldDscp == newDscp) {
5942             if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5943                 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5944                                  filter, oldDscp, rock.clOldName,
5945                                  newLastNamep, TRUE);
5946         } else {
5947             if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5948                 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5949                                   filter, oldDscp, rock.clOldName,
5950                                   NULL, TRUE);
5951             if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5952                 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
5953                                  filter, newDscp, newLastNamep,
5954                                  NULL, TRUE);
5955         }
5956     }
5957
5958     if (tmpscp != NULL) 
5959         cm_ReleaseSCache(tmpscp);
5960     cm_ReleaseUser(userp);
5961     cm_ReleaseSCache(oldDscp);
5962     cm_ReleaseSCache(newDscp);
5963
5964     free(rock.maskp);
5965     rock.maskp = NULL;
5966
5967     return code;
5968 }       
5969
5970 long 
5971 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp) 
5972 {
5973     long code = 0;
5974     cm_space_t *spacep = NULL;
5975     cm_scache_t *oldDscp = NULL;
5976     cm_scache_t *newDscp = NULL;
5977     cm_scache_t *tmpscp= NULL;
5978     cm_scache_t *tmpscp2 = NULL;
5979     cm_scache_t *sscp = NULL;
5980     clientchar_t *oldLastNamep;
5981     clientchar_t *newLastNamep;
5982     cm_user_t *userp;
5983     int caseFold;
5984     clientchar_t *tidPathp;
5985     DWORD filter;
5986     cm_req_t req;
5987
5988     userp = smb_GetUserFromVCP(vcp, inp);
5989
5990     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5991     if (code) {
5992         cm_ReleaseUser(userp);
5993         return CM_ERROR_NOSUCHPATH;
5994     }
5995
5996     smb_InitReq(&req);
5997
5998     caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5999
6000     spacep = inp->spacep;
6001     smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6002     
6003     code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6004                     userp, tidPathp, &req, &oldDscp);
6005     if (code) {
6006         cm_ReleaseUser(userp);
6007         return code;
6008     }
6009         
6010 #ifdef DFS_SUPPORT
6011     if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6012         int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6013         cm_ReleaseSCache(oldDscp);
6014         cm_ReleaseUser(userp);
6015         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6016             return CM_ERROR_PATH_NOT_COVERED;
6017         else
6018             return CM_ERROR_BADSHARENAME;
6019     }
6020 #endif /* DFS_SUPPORT */
6021
6022     smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6023     code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6024                     userp, tidPathp, &req, &newDscp);
6025     if (code) {
6026         cm_ReleaseSCache(oldDscp);
6027         cm_ReleaseUser(userp);
6028         return code;
6029     }
6030
6031 #ifdef DFS_SUPPORT
6032     if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6033         int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6034         cm_ReleaseSCache(newDscp);
6035         cm_ReleaseSCache(oldDscp);
6036         cm_ReleaseUser(userp);
6037         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6038             return CM_ERROR_PATH_NOT_COVERED;
6039         else
6040             return CM_ERROR_BADSHARENAME;
6041     }
6042 #endif /* DFS_SUPPORT */
6043
6044     /* Now, although we did two lookups for the two directories (because the same
6045      * directory can be referenced through different paths), we only allow hard links
6046      * within the same directory. */
6047     if (oldDscp != newDscp) {
6048         cm_ReleaseSCache(oldDscp);
6049         cm_ReleaseSCache(newDscp);
6050         cm_ReleaseUser(userp);
6051         return CM_ERROR_CROSSDEVLINK;
6052     }
6053
6054     /* handle the old name first */
6055     if (!oldLastNamep) 
6056         oldLastNamep = oldPathp;
6057     else 
6058         oldLastNamep++;
6059
6060     /* and handle the new name, too */
6061     if (!newLastNamep) 
6062         newLastNamep = newPathp;
6063     else 
6064         newLastNamep++;
6065
6066     /* now lookup the old name */
6067     osi_Log1(smb_logp,"  looking up [%S]", osi_LogSaveClientString(smb_logp,oldLastNamep));
6068     code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
6069     if (code) {
6070         cm_ReleaseSCache(oldDscp);
6071         cm_ReleaseSCache(newDscp);
6072         cm_ReleaseUser(userp);
6073         return code;
6074     }
6075
6076     /* Check if the file already exists; if so return error */
6077     code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6078     if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) && 
6079         (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) 
6080     {
6081         osi_Log2(smb_logp, "  lookup returns %ld for [%S]", code,
6082                  osi_LogSaveClientString(smb_logp, newLastNamep));
6083
6084         /* if the existing link is to the same file, then we return success */
6085         if (!code) {
6086             if(sscp == tmpscp) {
6087                 code = 0;
6088             } else {
6089                 osi_Log0(smb_logp, "Can't create hardlink.  Target already exists");
6090                 code = CM_ERROR_EXISTS;
6091             }
6092         }
6093
6094         if (tmpscp != NULL)
6095             cm_ReleaseSCache(tmpscp);
6096         cm_ReleaseSCache(sscp);
6097         cm_ReleaseSCache(newDscp);
6098         cm_ReleaseSCache(oldDscp);
6099         cm_ReleaseUser(userp);
6100         return code; 
6101     }
6102
6103     /* now create the hardlink */
6104     osi_Log1(smb_logp,"  Attempting to create new link [%S]", osi_LogSaveClientString(smb_logp, newLastNamep));
6105     code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
6106     osi_Log1(smb_logp,"  Link returns 0x%x", code);
6107
6108     /* Handle Change Notification */
6109     if (code == 0) {
6110         filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
6111         if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6112             smb_NotifyChange(FILE_ACTION_ADDED,
6113                              filter, newDscp, newLastNamep,
6114                              NULL, TRUE);
6115     }
6116
6117     if (tmpscp != NULL) 
6118         cm_ReleaseSCache(tmpscp);
6119     cm_ReleaseUser(userp);
6120     cm_ReleaseSCache(sscp);
6121     cm_ReleaseSCache(oldDscp);
6122     cm_ReleaseSCache(newDscp);
6123     return code;
6124 }
6125
6126 /* SMB_COM_RENAME */
6127 long 
6128 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6129 {
6130     clientchar_t *oldPathp;
6131     clientchar_t *newPathp;
6132     unsigned char *tp;
6133     long code;
6134
6135     tp = smb_GetSMBData(inp, NULL);
6136     oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6137     newPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6138
6139     osi_Log2(smb_logp, "smb rename [%S] to [%S]",
6140              osi_LogSaveClientString(smb_logp, oldPathp),
6141              osi_LogSaveClientString(smb_logp, newPathp));
6142
6143     code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
6144
6145     osi_Log1(smb_logp, "smb rename returns 0x%x", code);
6146     return code;
6147 }
6148
6149
6150
6151 typedef struct smb_rmdirRock {
6152     cm_scache_t *dscp;
6153     cm_user_t *userp;
6154     cm_req_t *reqp;
6155     normchar_t *maskp;          /* pointer to the star pattern */
6156     int flags;
6157     int any;
6158     cm_dirEntryList_t * matches;
6159 } smb_rmdirRock_t;
6160
6161 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6162 {       
6163     long code = 0;
6164     smb_rmdirRock_t *rockp;
6165     int match;
6166     normchar_t matchName[MAX_PATH];
6167         
6168     rockp = (smb_rmdirRock_t *) vrockp;
6169
6170     cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName));
6171     if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
6172         match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6173     else
6174         match = (cm_ClientStrCmp(matchName, rockp->maskp) == 0);
6175     if (!match &&
6176          (rockp->flags & SMB_MASKFLAG_TILDE) &&
6177          !cm_Is8Dot3(matchName)) {
6178         cm_Gen8Dot3Name(dep, matchName, NULL);
6179         match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6180     }       
6181
6182     if (match) {
6183         rockp->any = 1;
6184         cm_DirEntryListAdd(dep->name, &rockp->matches);
6185     }
6186
6187     return 0;
6188 }
6189
6190
6191 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6192 {
6193     long code = 0;
6194     clientchar_t *pathp;
6195     unsigned char *tp;
6196     cm_space_t *spacep;
6197     cm_scache_t *dscp;
6198     clientchar_t *lastNamep;
6199     smb_rmdirRock_t rock;
6200     cm_user_t *userp;
6201     osi_hyper_t thyper;
6202     int caseFold;
6203     clientchar_t *tidPathp;
6204     cm_req_t req;
6205
6206     smb_InitReq(&req);
6207
6208     tp = smb_GetSMBData(inp, NULL);
6209     pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6210
6211     spacep = inp->spacep;
6212     smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
6213
6214     userp = smb_GetUserFromVCP(vcp, inp);
6215
6216     caseFold = CM_FLAG_CASEFOLD;
6217
6218     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6219     if (code) {
6220         cm_ReleaseUser(userp);
6221         return CM_ERROR_NOSUCHPATH;
6222     }
6223     code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
6224                     userp, tidPathp, &req, &dscp);
6225
6226     if (code) {
6227         cm_ReleaseUser(userp);
6228         return code;
6229     }
6230         
6231 #ifdef DFS_SUPPORT
6232     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6233         int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
6234         cm_ReleaseSCache(dscp);
6235         cm_ReleaseUser(userp);
6236         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6237             return CM_ERROR_PATH_NOT_COVERED;
6238         else
6239             return CM_ERROR_BADSHARENAME;
6240     }
6241 #endif /* DFS_SUPPORT */
6242
6243     /* otherwise, scp points to the parent directory. */
6244     if (!lastNamep) 
6245         lastNamep = pathp;
6246     else 
6247         lastNamep++;
6248         
6249     rock.any = 0;
6250     rock.maskp = cm_ClientStringToNormStringAlloc(lastNamep, -1, NULL);
6251     rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6252
6253     thyper.LowPart = 0;
6254     thyper.HighPart = 0;
6255     rock.userp = userp;
6256     rock.reqp = &req;
6257     rock.dscp = dscp;
6258     rock.matches = NULL;
6259
6260     /* First do a case sensitive match, and if that fails, do a case insensitive match */
6261     code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6262     if (code == 0 && !rock.any) {
6263         thyper.LowPart = 0;
6264         thyper.HighPart = 0;
6265         rock.flags |= SMB_MASKFLAG_CASEFOLD;
6266         code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6267     }
6268
6269     if (code == 0 && rock.matches) {
6270         cm_dirEntryList_t * entry;
6271
6272         for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
6273             clientchar_t clientName[MAX_PATH];
6274
6275             cm_FsStringToClientString(entry->name, -1, clientName, lengthof(clientName));
6276
6277             osi_Log1(smb_logp, "Removing directory %s",
6278                      osi_LogSaveString(smb_logp, entry->name));
6279
6280             code = cm_RemoveDir(dscp, entry->name, clientName, userp, &req);
6281
6282             if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6283                 smb_NotifyChange(FILE_ACTION_REMOVED,
6284                                  FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6285                                  dscp, clientName, NULL, TRUE);
6286         }
6287     }
6288
6289     cm_DirEntryListFree(&rock.matches);
6290
6291     cm_ReleaseUser(userp);
6292         
6293     cm_ReleaseSCache(dscp);
6294
6295     if (code == 0 && !rock.any)
6296         code = CM_ERROR_NOSUCHFILE;        
6297
6298     free(rock.maskp);
6299     rock.maskp = NULL;
6300
6301     return code;
6302 }
6303
6304 /* SMB_COM_FLUSH */
6305 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6306 {
6307     unsigned short fid;
6308     smb_fid_t *fidp;
6309     cm_user_t *userp;
6310     long code = 0;
6311     cm_req_t req;
6312
6313     smb_InitReq(&req);
6314
6315     fid = smb_GetSMBParm(inp, 0);
6316
6317     osi_Log1(smb_logp, "SMB flush fid %d", fid);
6318
6319     fid = smb_ChainFID(fid, inp);
6320     fidp = smb_FindFID(vcp, fid, 0);
6321     if (!fidp)
6322         return CM_ERROR_BADFD;
6323     
6324     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6325         smb_CloseFID(vcp, fidp, NULL, 0);
6326         smb_ReleaseFID(fidp);
6327         return CM_ERROR_NOSUCHFILE;
6328     }
6329
6330     lock_ObtainMutex(&fidp->mx);
6331     if (fidp->flags & SMB_FID_IOCTL) {
6332         lock_ReleaseMutex(&fidp->mx);
6333         smb_ReleaseFID(fidp);
6334         return CM_ERROR_BADFD;
6335     }
6336     lock_ReleaseMutex(&fidp->mx);
6337         
6338     userp = smb_GetUserFromVCP(vcp, inp);
6339
6340     lock_ObtainMutex(&fidp->mx);
6341     if ((fidp->flags & SMB_FID_OPENWRITE) && smb_AsyncStore != 2) {
6342         cm_scache_t * scp = fidp->scp;
6343         cm_HoldSCache(scp);
6344         lock_ReleaseMutex(&fidp->mx);
6345         code = cm_FSync(scp, userp, &req);
6346         cm_ReleaseSCache(scp);
6347     } else {
6348         code = 0;
6349         lock_ReleaseMutex(&fidp->mx);
6350     }
6351         
6352     smb_ReleaseFID(fidp);
6353         
6354     cm_ReleaseUser(userp);
6355         
6356     return code;
6357 }
6358
6359 struct smb_FullNameRock {
6360     clientchar_t *name;
6361     cm_scache_t  *vnode;
6362     clientchar_t *fullName;
6363     fschar_t     *originalName;
6364 };
6365
6366 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
6367                      osi_hyper_t *offp)
6368 {
6369     normchar_t matchName[MAX_PATH];
6370     struct smb_FullNameRock *vrockp;
6371
6372     vrockp = (struct smb_FullNameRock *)rockp;
6373
6374     cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName));
6375
6376     if (!cm_Is8Dot3(matchName)) {
6377         clientchar_t shortName[13];
6378
6379         cm_Gen8Dot3Name(dep, shortName, NULL);
6380
6381         if (cm_ClientStrCmpIA(shortName, vrockp->name) == 0) {
6382             vrockp->fullName = cm_ClientStrDup(matchName);
6383             vrockp->originalName = cm_FsStrDup(dep->name);
6384             return CM_ERROR_STOPNOW;
6385         }
6386     }
6387     if (cm_ClientStrCmpI(matchName, vrockp->name) == 0 &&
6388         ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
6389         ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
6390         vrockp->fullName = cm_ClientStrDup(matchName);
6391         vrockp->originalName = cm_FsStrDup(dep->name);
6392         return CM_ERROR_STOPNOW;
6393     }
6394     return 0;
6395 }
6396
6397 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, clientchar_t *pathp,
6398                   clientchar_t **newPathp, fschar_t ** originalPathp,
6399                   cm_user_t *userp, cm_req_t *reqp)
6400 {
6401     struct smb_FullNameRock rock;
6402     long code = 0;
6403
6404     memset(&rock, 0, sizeof(rock));
6405     rock.name = pathp;
6406     rock.vnode = scp;
6407
6408     code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL); 
6409     if (code == CM_ERROR_STOPNOW) {
6410         *newPathp = rock.fullName;
6411         *originalPathp = rock.originalName;
6412     } else {
6413         *newPathp = cm_ClientStrDup(pathp);
6414         *originalPathp = cm_ClientStringToFsStringAlloc(pathp, -1, NULL);
6415     }
6416 }
6417
6418 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
6419                   afs_uint32 dosTime) {
6420     long code = 0;
6421     cm_req_t req;
6422     cm_scache_t *dscp = NULL;
6423     clientchar_t *pathp = NULL;
6424     cm_scache_t * scp = NULL;
6425     cm_scache_t *delscp = NULL;
6426     int nullcreator = 0;
6427
6428     osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
6429              fidp, fidp->fid, scp, vcp);
6430
6431     if (!userp) {
6432         lock_ObtainMutex(&fidp->mx);
6433         if (!fidp->userp && !(fidp->flags & SMB_FID_IOCTL)) {
6434             lock_ReleaseMutex(&fidp->mx);
6435             osi_Log0(smb_logp, "  No user specified.  Not closing fid");
6436             return CM_ERROR_BADFD;
6437         }
6438         
6439         userp = fidp->userp;    /* no hold required since fidp is held
6440                                    throughout the function */
6441         lock_ReleaseMutex(&fidp->mx);
6442     }
6443
6444     smb_InitReq(&req);
6445
6446     lock_ObtainWrite(&smb_rctLock);
6447     if (fidp->deleteOk) {
6448         osi_Log0(smb_logp, "  Fid already closed.");
6449         lock_ReleaseWrite(&smb_rctLock);
6450         return CM_ERROR_BADFD;
6451     }
6452     fidp->deleteOk = 1;
6453     lock_ReleaseWrite(&smb_rctLock);
6454
6455     lock_ObtainMutex(&fidp->mx);
6456     if (fidp->NTopen_dscp) {
6457         dscp = fidp->NTopen_dscp;
6458         cm_HoldSCache(dscp);
6459     }
6460
6461     if (fidp->NTopen_pathp) {
6462         pathp = cm_ClientStrDup(fidp->NTopen_pathp);
6463     }
6464
6465     if (fidp->scp) {
6466         scp = fidp->scp;
6467         cm_HoldSCache(scp);
6468     }
6469
6470     /* Don't jump the gun on an async raw write */
6471     while (fidp->raw_writers) {
6472         lock_ReleaseMutex(&fidp->mx);
6473         thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
6474         lock_ObtainMutex(&fidp->mx);
6475     }
6476
6477     /* watch for ioctl closes, and read-only opens */
6478     if (scp != NULL &&
6479         (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
6480          == SMB_FID_OPENWRITE) {
6481         if (dosTime != 0 && dosTime != -1) {
6482             scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6483             /* This fixes defect 10958 */
6484             CompensateForSmbClientLastWriteTimeBugs(&dosTime);
6485             smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
6486         }
6487         if (smb_AsyncStore != 2) {
6488             lock_ReleaseMutex(&fidp->mx);
6489             code = cm_FSync(scp, userp, &req);
6490             lock_ObtainMutex(&fidp->mx);
6491         }
6492     }
6493     else 
6494         code = 0;
6495
6496     /* unlock any pending locks */
6497     if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
6498         scp->fileType == CM_SCACHETYPE_FILE) {
6499         cm_key_t key;
6500         long tcode;
6501
6502         lock_ReleaseMutex(&fidp->mx);
6503
6504         /* CM_UNLOCK_BY_FID doesn't look at the process ID.  We pass
6505            in zero. */
6506         key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
6507         lock_ObtainWrite(&scp->rw);
6508
6509         tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
6510                           CM_SCACHESYNC_NEEDCALLBACK
6511                           | CM_SCACHESYNC_GETSTATUS
6512                           | CM_SCACHESYNC_LOCK);
6513
6514         if (tcode) {
6515             osi_Log1(smb_logp,
6516                      "smb CoreClose SyncOp failure code 0x%x", tcode);
6517             goto post_syncopdone;
6518         }
6519
6520         cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
6521
6522         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
6523
6524     post_syncopdone:
6525
6526         lock_ReleaseWrite(&scp->rw);
6527         lock_ObtainMutex(&fidp->mx);
6528     }
6529
6530     if (fidp->flags & SMB_FID_DELONCLOSE) {
6531         clientchar_t *fullPathp = NULL;
6532         fschar_t *originalNamep = NULL;
6533
6534         lock_ReleaseMutex(&fidp->mx);
6535
6536         code = cm_Lookup(dscp, pathp, CM_FLAG_NOMOUNTCHASE, userp, &req, &delscp);
6537         if (code) {
6538             cm_HoldSCache(scp);
6539             delscp = scp;
6540         }
6541         smb_FullName(dscp, delscp, pathp, &fullPathp, &originalNamep, userp, &req);
6542         if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
6543             code = cm_RemoveDir(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_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6548                                       dscp, fullPathp, NULL, TRUE);
6549             }
6550         } else {
6551             code = cm_Unlink(dscp, originalNamep, fullPathp, userp, &req);
6552             if (code == 0) {                            
6553                 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6554                     smb_NotifyChange(FILE_ACTION_REMOVED,
6555                                       FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6556                                       dscp, fullPathp, NULL, TRUE);
6557             }
6558         }
6559
6560         if (fullPathp)
6561             free(fullPathp);
6562         if (originalNamep)
6563             free(originalNamep);
6564
6565         lock_ObtainMutex(&fidp->mx);
6566         fidp->flags &= ~SMB_FID_DELONCLOSE;
6567     }
6568
6569     /* if this was a newly created file, then clear the creator
6570      * in the stat cache entry. */
6571     if (fidp->flags & SMB_FID_CREATED) {
6572         nullcreator = 1;
6573         fidp->flags &= ~SMB_FID_CREATED;
6574     }
6575
6576     if (fidp->flags & SMB_FID_NTOPEN) {
6577         cm_ReleaseSCache(fidp->NTopen_dscp);
6578         fidp->NTopen_dscp = NULL;
6579         free(fidp->NTopen_pathp);
6580         fidp->NTopen_pathp = NULL;
6581         fidp->flags &= ~SMB_FID_NTOPEN;
6582     } else {
6583         osi_assertx(fidp->NTopen_dscp == NULL, "null NTopen_dsc");
6584         osi_assertx(fidp->NTopen_pathp == NULL, "null NTopen_path");
6585     }
6586
6587     if (fidp->NTopen_wholepathp) {
6588         free(fidp->NTopen_wholepathp);
6589         fidp->NTopen_wholepathp = NULL;
6590     }
6591
6592     if (fidp->scp) {
6593         cm_ReleaseSCache(fidp->scp);
6594         fidp->scp = NULL;
6595     }
6596     lock_ReleaseMutex(&fidp->mx);
6597
6598     if (dscp)
6599         cm_ReleaseSCache(dscp);
6600
6601     if (delscp) {
6602         cm_ReleaseSCache(delscp);
6603     }
6604
6605     if (scp) {
6606         lock_ObtainWrite(&scp->rw);
6607         if (nullcreator && scp->creator == userp)
6608             scp->creator = NULL;
6609         scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
6610         lock_ReleaseWrite(&scp->rw);
6611         cm_ReleaseSCache(scp);
6612     }
6613
6614     if (pathp)
6615         free(pathp);
6616
6617     return code;
6618 }
6619
6620 /* SMB_COM_CLOSE */
6621 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6622 {
6623     unsigned short fid;
6624     smb_fid_t *fidp;
6625     cm_user_t *userp;
6626     long code = 0;
6627     afs_uint32 dosTime;
6628
6629     fid = smb_GetSMBParm(inp, 0);
6630     dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6631
6632     osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
6633
6634     fid = smb_ChainFID(fid, inp);
6635     fidp = smb_FindFID(vcp, fid, 0);
6636     if (!fidp) {
6637         return CM_ERROR_BADFD;
6638     }
6639         
6640     userp = smb_GetUserFromVCP(vcp, inp);
6641
6642     code = smb_CloseFID(vcp, fidp, userp, dosTime);
6643     
6644     smb_ReleaseFID(fidp);
6645     cm_ReleaseUser(userp);
6646     return code;
6647 }
6648
6649 /*
6650  * smb_ReadData -- common code for Read, Read And X, and Raw Read
6651  */
6652 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
6653         cm_user_t *userp, long *readp)
6654 {
6655     osi_hyper_t offset;
6656     long code = 0;
6657     cm_scache_t *scp;
6658     cm_buf_t *bufferp;
6659     osi_hyper_t fileLength;
6660     osi_hyper_t thyper;
6661     osi_hyper_t lastByte;
6662     osi_hyper_t bufferOffset;
6663     long bufIndex;
6664     afs_uint32 nbytes;
6665     int chunk;
6666     int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
6667     cm_req_t req;
6668
6669     osi_Log3(smb_logp, "smb_ReadData fid %d, off 0x%x, size 0x%x",
6670               fidp->fid, offsetp->LowPart, count);
6671
6672     *readp = 0;
6673
6674     lock_ObtainMutex(&fidp->mx);
6675     /* make sure we have a readable FD */
6676     if (!(fidp->flags & SMB_FID_OPENREAD_LISTDIR)) {
6677         osi_Log2(smb_logp, "smb_ReadData fid %d not OPENREAD_LISTDIR flags 0x%x",
6678                   fidp->fid, fidp->flags);
6679         lock_ReleaseMutex(&fidp->mx);
6680         code = CM_ERROR_BADFDOP;
6681         goto done2;
6682     }
6683     
6684     smb_InitReq(&req);
6685
6686     bufferp = NULL;
6687     offset = *offsetp;
6688
6689     scp = fidp->scp;
6690     cm_HoldSCache(scp);
6691     lock_ObtainWrite(&scp->rw);
6692
6693     if (offset.HighPart == 0) {
6694         chunk = offset.LowPart >> cm_logChunkSize;
6695         if (chunk != fidp->curr_chunk) {
6696             fidp->prev_chunk = fidp->curr_chunk;
6697             fidp->curr_chunk = chunk;
6698         }
6699         if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
6700             sequential = 1;
6701     }
6702     lock_ReleaseMutex(&fidp->mx);
6703
6704     /* start by looking up the file's end */
6705     code = cm_SyncOp(scp, NULL, userp, &req, 0,
6706                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6707     if (code) 
6708         goto done;
6709
6710     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6711
6712     /* now we have the entry locked, look up the length */
6713     fileLength = scp->length;
6714
6715     /* adjust count down so that it won't go past EOF */
6716     thyper.LowPart = count;
6717     thyper.HighPart = 0;
6718     thyper = LargeIntegerAdd(offset, thyper);   /* where read should end */
6719     lastByte = thyper;
6720     if (LargeIntegerGreaterThan(thyper, fileLength)) {
6721         /* we'd read past EOF, so just stop at fileLength bytes.
6722          * Start by computing how many bytes remain in the file.
6723          */
6724         thyper = LargeIntegerSubtract(fileLength, offset);
6725
6726         /* if we are past EOF, read 0 bytes */
6727         if (LargeIntegerLessThanZero(thyper))
6728             count = 0;
6729         else
6730             count = thyper.LowPart;
6731     }       
6732
6733     *readp = count;
6734
6735     /* now, copy the data one buffer at a time,
6736      * until we've filled the request packet
6737      */
6738     while (1) {
6739         /* if we've copied all the data requested, we're done */
6740         if (count <= 0) break;
6741
6742         /* otherwise, load up a buffer of data */
6743         thyper.HighPart = offset.HighPart;
6744         thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6745         if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6746             /* wrong buffer */
6747             if (bufferp) {
6748                 buf_Release(bufferp);
6749                 bufferp = NULL;
6750             }
6751             lock_ReleaseWrite(&scp->rw);
6752
6753             code = buf_Get(scp, &thyper, &bufferp);
6754
6755             lock_ObtainWrite(&scp->rw);
6756             if (code) goto done;
6757             bufferOffset = thyper;
6758
6759             /* now get the data in the cache */
6760             while (1) {
6761                 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6762                                  CM_SCACHESYNC_NEEDCALLBACK |
6763                                  CM_SCACHESYNC_READ);
6764                 if (code) 
6765                     goto done;
6766                     
6767                 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
6768
6769                 if (cm_HaveBuffer(scp, bufferp, 0)) break;
6770
6771                 /* otherwise, load the buffer and try again */
6772                 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
6773                 if (code) break;
6774             }
6775             if (code) {
6776                 buf_Release(bufferp);
6777                 bufferp = NULL;
6778                 goto done;
6779             }
6780         }       /* if (wrong buffer) ... */
6781
6782         /* now we have the right buffer loaded.  Copy out the
6783          * data from here to the user's buffer.
6784          */
6785         bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6786
6787         /* and figure out how many bytes we want from this buffer */
6788         nbytes = cm_data.buf_blockSize - bufIndex;      /* what remains in buffer */
6789         if (nbytes > count) nbytes = count;     /* don't go past EOF */
6790
6791         /* now copy the data */
6792         memcpy(op, bufferp->datap + bufIndex, nbytes);
6793                 
6794         /* adjust counters, pointers, etc. */
6795         op += nbytes;
6796         count -= nbytes;
6797         thyper.LowPart = nbytes;
6798         thyper.HighPart = 0;
6799         offset = LargeIntegerAdd(thyper, offset);
6800     } /* while 1 */
6801
6802   done:
6803     lock_ReleaseWrite(&scp->rw);
6804     if (bufferp)
6805         buf_Release(bufferp);
6806
6807     if (code == 0 && sequential)
6808         cm_ConsiderPrefetch(scp, &lastByte, *readp, userp, &req);
6809
6810     cm_ReleaseSCache(scp);
6811
6812   done2:
6813     osi_Log3(smb_logp, "smb_ReadData fid %d returns 0x%x read %d bytes",
6814               fidp->fid, code, *readp);
6815     return code;
6816 }
6817
6818 /*
6819  * smb_WriteData -- common code for Write and Raw Write
6820  */
6821 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
6822         cm_user_t *userp, long *writtenp)
6823 {
6824     osi_hyper_t offset = *offsetp;
6825     long code = 0;
6826     long written = 0;
6827     cm_scache_t *scp = NULL;
6828     osi_hyper_t fileLength;     /* file's length at start of write */
6829     osi_hyper_t minLength;      /* don't read past this */
6830     afs_uint32 nbytes;          /* # of bytes to transfer this iteration */
6831     cm_buf_t *bufferp = NULL;
6832     osi_hyper_t thyper;         /* hyper tmp variable */
6833     osi_hyper_t bufferOffset;
6834     afs_uint32 bufIndex;                /* index in buffer where our data is */
6835     int doWriteBack = 0;
6836     osi_hyper_t writeBackOffset;/* offset of region to write back when I/O is done */
6837     DWORD filter = 0;
6838     cm_req_t req;
6839
6840     osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
6841               fidp->fid, offsetp->LowPart, count);
6842
6843     *writtenp = 0;
6844
6845     lock_ObtainMutex(&fidp->mx);
6846     /* make sure we have a writable FD */
6847     if (!(fidp->flags & SMB_FID_OPENWRITE)) {
6848         osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
6849                   fidp->fid, fidp->flags);
6850         lock_ReleaseMutex(&fidp->mx);
6851         code = CM_ERROR_BADFDOP;
6852         goto done2;
6853     }
6854     
6855     smb_InitReq(&req);
6856
6857     scp = fidp->scp;
6858     cm_HoldSCache(scp);
6859     lock_ReleaseMutex(&fidp->mx);
6860
6861     lock_ObtainWrite(&scp->rw);
6862     /* start by looking up the file's end */
6863     code = cm_SyncOp(scp, NULL, userp, &req, 0,
6864                       CM_SCACHESYNC_NEEDCALLBACK
6865                       | CM_SCACHESYNC_SETSTATUS
6866                       | CM_SCACHESYNC_GETSTATUS);
6867     if (code) 
6868         goto done;
6869         
6870     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
6871
6872     /* now we have the entry locked, look up the length */
6873     fileLength = scp->length;
6874     minLength = fileLength;
6875     if (LargeIntegerGreaterThan(minLength, scp->serverLength))
6876         minLength = scp->serverLength;
6877
6878     /* adjust file length if we extend past EOF */
6879     thyper.LowPart = count;
6880     thyper.HighPart = 0;
6881     thyper = LargeIntegerAdd(offset, thyper);   /* where write should end */
6882     if (LargeIntegerGreaterThan(thyper, fileLength)) {
6883         /* we'd write past EOF, so extend the file */
6884         scp->mask |= CM_SCACHEMASK_LENGTH;
6885         scp->length = thyper;
6886         filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
6887     } else
6888         filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
6889
6890     /* now, if the new position (thyper) and the old (offset) are in
6891      * different storeback windows, remember to store back the previous
6892      * storeback window when we're done with the write.
6893      *
6894      * the purpose of this logic is to slow down the CIFS client 
6895      * in order to avoid the client disconnecting during the CLOSE
6896      * operation if there are too many dirty buffers left to write
6897      * than can be accomplished during 45 seconds.  This used to be
6898      * based upon cm_chunkSize but we desire cm_chunkSize to be large
6899      * so that we can read larger amounts of data at a time.
6900      */
6901     if (smb_AsyncStore == 1 && 
6902          (thyper.LowPart & ~(smb_AsyncStoreSize-1)) !=
6903          (offset.LowPart & ~(smb_AsyncStoreSize-1))) {
6904         /* they're different */
6905         doWriteBack = 1;
6906         writeBackOffset.HighPart = offset.HighPart;
6907         writeBackOffset.LowPart = offset.LowPart & ~(smb_AsyncStoreSize-1);
6908     }
6909
6910     *writtenp = count;
6911
6912     /* now, copy the data one buffer at a time, until we've filled the
6913      * request packet */
6914     while (1) {
6915         /* if we've copied all the data requested, we're done */
6916         if (count <= 0) 
6917             break;
6918
6919         /* handle over quota or out of space */
6920         if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
6921             *writtenp = written;
6922             code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
6923             break;
6924         }
6925
6926         /* otherwise, load up a buffer of data */
6927         thyper.HighPart = offset.HighPart;
6928         thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6929         if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6930             /* wrong buffer */
6931             if (bufferp) {
6932                 lock_ReleaseMutex(&bufferp->mx);
6933                 buf_Release(bufferp);
6934                 bufferp = NULL;
6935             }   
6936             lock_ReleaseWrite(&scp->rw);
6937
6938             code = buf_Get(scp, &thyper, &bufferp);
6939
6940             lock_ObtainMutex(&bufferp->mx);
6941             lock_ObtainWrite(&scp->rw);
6942             if (code) goto done;
6943
6944             bufferOffset = thyper;
6945
6946             /* now get the data in the cache */
6947             while (1) {
6948                 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6949                                   CM_SCACHESYNC_NEEDCALLBACK
6950                                   | CM_SCACHESYNC_WRITE
6951                                   | CM_SCACHESYNC_BUFLOCKED);
6952                 if (code) 
6953                     goto done;
6954
6955                 cm_SyncOpDone(scp, bufferp, 
6956                                CM_SCACHESYNC_NEEDCALLBACK 
6957                                | CM_SCACHESYNC_WRITE 
6958                                | CM_SCACHESYNC_BUFLOCKED);
6959
6960                 /* If we're overwriting the entire buffer, or
6961                  * if we're writing at or past EOF, mark the
6962                  * buffer as current so we don't call
6963                  * cm_GetBuffer.  This skips the fetch from the
6964                  * server in those cases where we're going to 
6965                  * obliterate all the data in the buffer anyway,
6966                  * or in those cases where there is no useful
6967                  * data at the server to start with.
6968                  *
6969                  * Use minLength instead of scp->length, since
6970                  * the latter has already been updated by this
6971                  * call.
6972                  */
6973                 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
6974                      || LargeIntegerEqualTo(offset, bufferp->offset)
6975                      && (count >= cm_data.buf_blockSize
6976                           || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
6977                                                                                ConvertLongToLargeInteger(count)),
6978                                                                minLength))) {
6979                     if (count < cm_data.buf_blockSize
6980                          && bufferp->dataVersion == CM_BUF_VERSION_BAD)
6981                         memset(bufferp->datap, 0,
6982                                 cm_data.buf_blockSize);
6983                     bufferp->dataVersion = scp->dataVersion;
6984                 }
6985
6986                 if (cm_HaveBuffer(scp, bufferp, 1)) break;
6987
6988                 /* otherwise, load the buffer and try again */
6989                 lock_ReleaseMutex(&bufferp->mx);
6990                 code = cm_GetBuffer(scp, bufferp, NULL, userp,
6991                                      &req);
6992                 lock_ReleaseWrite(&scp->rw);
6993                 lock_ObtainMutex(&bufferp->mx);
6994                 lock_ObtainWrite(&scp->rw);
6995                 if (code) break;
6996             }
6997             if (code) {
6998                 lock_ReleaseMutex(&bufferp->mx);
6999                 buf_Release(bufferp);
7000                 bufferp = NULL;
7001                 goto done;
7002             }
7003         }       /* if (wrong buffer) ... */
7004
7005         /* now we have the right buffer loaded.  Copy out the
7006          * data from here to the user's buffer.
7007          */
7008         bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7009
7010         /* and figure out how many bytes we want from this buffer */
7011         nbytes = cm_data.buf_blockSize - bufIndex;      /* what remains in buffer */
7012         if (nbytes > count) 
7013             nbytes = count;     /* don't go past end of request */
7014
7015         /* now copy the data */
7016         memcpy(bufferp->datap + bufIndex, op, nbytes);
7017         buf_SetDirty(bufferp, bufIndex, nbytes, userp);
7018
7019         /* adjust counters, pointers, etc. */
7020         op += nbytes;
7021         count -= nbytes;
7022         written += nbytes;
7023         thyper.LowPart = nbytes;
7024         thyper.HighPart = 0;
7025         offset = LargeIntegerAdd(thyper, offset);
7026     } /* while 1 */
7027
7028   done:
7029     lock_ReleaseWrite(&scp->rw);
7030
7031     if (bufferp) {
7032         lock_ReleaseMutex(&bufferp->mx);
7033         buf_Release(bufferp);
7034     }
7035
7036     lock_ObtainMutex(&fidp->mx);
7037     if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
7038          && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) 
7039     {
7040         lock_ReleaseMutex(&fidp->mx);
7041         smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
7042                           fidp->NTopen_dscp, fidp->NTopen_pathp,
7043                           NULL, TRUE);
7044     } else {
7045         lock_ReleaseMutex(&fidp->mx);
7046     }
7047
7048     if (code == 0) {
7049         if (smb_AsyncStore > 0) {
7050             if (doWriteBack) {
7051                 long code2;
7052
7053                 lock_ObtainWrite(&scp->rw);
7054                 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
7055                           fidp->fid);
7056                 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
7057                 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
7058                           fidp->fid, code2);
7059                 lock_ReleaseWrite(&scp->rw);
7060                 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
7061                                     writeBackOffset.HighPart, 
7062                                     smb_AsyncStoreSize, 0, userp);
7063                 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
7064             }
7065         } else {
7066             cm_BufWrite(scp, offsetp, *writtenp, 0, userp, &req);
7067         }
7068     }
7069
7070     cm_ReleaseSCache(scp);
7071
7072   done2:
7073     osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
7074               fidp->fid, code, *writtenp);
7075     return code;
7076 }
7077
7078 /* SMB_COM_WRITE */
7079 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7080 {
7081     unsigned short fd;
7082     unsigned short count;
7083     osi_hyper_t offset;
7084     unsigned short hint;
7085     long written = 0, total_written = 0;
7086     unsigned pid;
7087     smb_fid_t *fidp;
7088     smb_t* smbp = (smb_t*) inp;
7089     long code = 0;
7090     cm_user_t *userp;
7091     cm_attr_t truncAttr;        /* attribute struct used for truncating file */
7092     char *op;
7093     int inDataBlockCount;
7094
7095     fd = smb_GetSMBParm(inp, 0);
7096     count = smb_GetSMBParm(inp, 1);
7097     offset.HighPart = 0;        /* too bad */
7098     offset.LowPart = smb_GetSMBParmLong(inp, 2);
7099     hint = smb_GetSMBParm(inp, 4);
7100
7101     op = smb_GetSMBData(inp, NULL);
7102     op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
7103
7104     osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
7105              fd, offset.LowPart, count);
7106         
7107     fd = smb_ChainFID(fd, inp);
7108     fidp = smb_FindFID(vcp, fd, 0);
7109     if (!fidp) {
7110         osi_Log0(smb_logp, "smb_ReceiveCoreWrite fid not found");
7111         return CM_ERROR_BADFD;
7112     }
7113         
7114     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7115         smb_CloseFID(vcp, fidp, NULL, 0);
7116         smb_ReleaseFID(fidp);
7117         return CM_ERROR_NOSUCHFILE;
7118     }
7119
7120     lock_ObtainMutex(&fidp->mx);
7121     if (fidp->flags & SMB_FID_IOCTL) {
7122         lock_ReleaseMutex(&fidp->mx);
7123         code = smb_IoctlWrite(fidp, vcp, inp, outp);
7124         smb_ReleaseFID(fidp);
7125         osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
7126         return code;
7127     }
7128     lock_ReleaseMutex(&fidp->mx);
7129     userp = smb_GetUserFromVCP(vcp, inp);
7130
7131     {
7132         cm_key_t key;
7133         LARGE_INTEGER LOffset;
7134         LARGE_INTEGER LLength;
7135
7136         pid = smbp->pid;
7137         key = cm_GenerateKey(vcp->vcID, pid, fd);
7138
7139         LOffset.HighPart = offset.HighPart;
7140         LOffset.LowPart = offset.LowPart;
7141         LLength.HighPart = 0;
7142         LLength.LowPart = count;
7143
7144         lock_ObtainWrite(&fidp->scp->rw);
7145         code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
7146         lock_ReleaseWrite(&fidp->scp->rw);
7147
7148         if (code) {
7149             osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
7150             goto done;
7151         }
7152     }
7153
7154     /* special case: 0 bytes transferred means truncate to this position */
7155     if (count == 0) {
7156         cm_req_t req;
7157
7158         osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
7159         
7160         smb_InitReq(&req);
7161
7162         truncAttr.mask = CM_ATTRMASK_LENGTH;
7163         truncAttr.length.LowPart = offset.LowPart;
7164         truncAttr.length.HighPart = 0;
7165         lock_ObtainMutex(&fidp->mx);
7166         code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
7167         fidp->flags |= SMB_FID_LENGTHSETDONE;
7168         lock_ReleaseMutex(&fidp->mx);
7169         smb_SetSMBParm(outp, 0, 0 /* count */);
7170         smb_SetSMBDataLength(outp, 0);
7171         goto done;
7172     }
7173
7174     /*
7175      * Work around bug in NT client
7176      *
7177      * When copying a file, the NT client should first copy the data,
7178      * then copy the last write time.  But sometimes the NT client does
7179      * these in the wrong order, so the data copies would inadvertently
7180      * cause the last write time to be overwritten.  We try to detect this,
7181      * and don't set client mod time if we think that would go against the
7182      * intention.
7183      */
7184     lock_ObtainMutex(&fidp->mx);
7185     if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
7186         fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7187         fidp->scp->clientModTime = time(NULL);
7188     }
7189     lock_ReleaseMutex(&fidp->mx);
7190
7191     code = 0;
7192     while ( code == 0 && count > 0 ) {
7193         code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7194         if (code == 0 && written == 0)
7195             code = CM_ERROR_PARTIALWRITE;
7196
7197         offset = LargeIntegerAdd(offset,
7198                                  ConvertLongToLargeInteger(written));
7199         count -= (unsigned short)written;
7200         total_written += written;
7201         written = 0;
7202     }
7203     
7204     osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
7205              total_written, code);
7206         
7207     /* set the packet data length to 3 bytes for the data block header,
7208      * plus the size of the data.
7209      */
7210     smb_SetSMBParm(outp, 0, total_written);
7211     smb_SetSMBParmLong(outp, 1, offset.LowPart);
7212     smb_SetSMBParm(outp, 3, hint);
7213     smb_SetSMBDataLength(outp, 0);
7214
7215   done:
7216     smb_ReleaseFID(fidp);
7217     cm_ReleaseUser(userp);
7218
7219     return code;
7220 }
7221
7222 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7223                           NCB *ncbp, raw_write_cont_t *rwcp)
7224 {
7225     unsigned short fd;
7226     smb_fid_t *fidp;
7227     cm_user_t *userp;
7228     char *rawBuf;
7229     long written = 0;
7230     long code = 0;
7231
7232     fd = smb_GetSMBParm(inp, 0);
7233     fidp = smb_FindFID(vcp, fd, 0);
7234
7235     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7236         smb_CloseFID(vcp, fidp, NULL, 0);
7237         smb_ReleaseFID(fidp);
7238         return;
7239     }
7240
7241     osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
7242              rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
7243
7244     userp = smb_GetUserFromVCP(vcp, inp);
7245
7246     rawBuf = rwcp->buf;
7247     code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
7248                                                  &written);
7249     if (rwcp->writeMode & 0x1) {        /* synchronous */
7250         smb_t *op;
7251
7252         smb_FormatResponsePacket(vcp, inp, outp);
7253         op = (smb_t *) outp;
7254         op->com = 0x20;         /* SMB_COM_WRITE_COMPLETE */
7255         smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
7256         smb_SetSMBDataLength(outp,  0);
7257         smb_SendPacket(vcp, outp);
7258         smb_FreePacket(outp);
7259     }
7260     else {                              /* asynchronous */
7261         lock_ObtainMutex(&fidp->mx);
7262         fidp->raw_writers--;
7263         if (fidp->raw_writers == 0)
7264             thrd_SetEvent(fidp->raw_write_event);
7265         lock_ReleaseMutex(&fidp->mx);
7266     }
7267
7268     /* Give back raw buffer */
7269     lock_ObtainMutex(&smb_RawBufLock);
7270     *((char **)rawBuf) = smb_RawBufs;
7271     smb_RawBufs = rawBuf;
7272     lock_ReleaseMutex(&smb_RawBufLock);
7273
7274     smb_ReleaseFID(fidp);
7275     cm_ReleaseUser(userp);
7276 }
7277
7278 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7279 {
7280     return 0;
7281 }
7282
7283 /* SMB_COM_WRITE_RAW */
7284 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
7285 {
7286     osi_hyper_t offset;
7287     long count, written = 0, total_written = 0;
7288     long totalCount;
7289     unsigned short fd;
7290     smb_fid_t *fidp;
7291     smb_t *smbp = (smb_t*) inp;
7292     long code = 0;
7293     cm_user_t *userp;
7294     char *op;
7295     unsigned short writeMode;
7296     char *rawBuf;
7297     fd = smb_GetSMBParm(inp, 0);
7298     totalCount = smb_GetSMBParm(inp, 1);
7299     count = smb_GetSMBParm(inp, 10);
7300     writeMode = smb_GetSMBParm(inp, 7);
7301
7302     op = (char *) inp->data;
7303     op += smb_GetSMBParm(inp, 11);
7304
7305     offset.HighPart = 0;
7306     offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
7307
7308     if (*inp->wctp == 14) {
7309         /* we received a 64-bit file offset */
7310 #ifdef AFS_LARGEFILES
7311         offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
7312
7313         if (LargeIntegerLessThanZero(offset)) {
7314             osi_Log2(smb_logp,
7315                      "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
7316                      offset.HighPart, offset.LowPart);
7317             return CM_ERROR_BADSMB;
7318         }
7319 #else
7320         if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
7321             osi_Log0(smb_logp,
7322                      "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files");
7323             return CM_ERROR_BADSMB;
7324         }
7325
7326         offset.HighPart = 0;
7327 #endif
7328     } else {
7329         offset.HighPart = 0;    /* 32-bit file offset */
7330     }
7331     
7332     osi_Log4(smb_logp,
7333              "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
7334              fd, offset.HighPart, offset.LowPart, count);
7335     osi_Log1(smb_logp,
7336              "               WriteRaw WriteMode 0x%x",
7337              writeMode);
7338         
7339     fd = smb_ChainFID(fd, inp);
7340     fidp = smb_FindFID(vcp, fd, 0);
7341     if (!fidp) {
7342         return CM_ERROR_BADFD;
7343     }
7344
7345     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7346         smb_CloseFID(vcp, fidp, NULL, 0);
7347         smb_ReleaseFID(fidp);
7348         return CM_ERROR_NOSUCHFILE;
7349     }
7350
7351     {
7352         unsigned pid;
7353         cm_key_t key;
7354         LARGE_INTEGER LOffset;
7355         LARGE_INTEGER LLength;
7356
7357         pid = smbp->pid;
7358         key = cm_GenerateKey(vcp->vcID, pid, fd);
7359
7360         LOffset.HighPart = offset.HighPart;
7361         LOffset.LowPart = offset.LowPart;
7362         LLength.HighPart = 0;
7363         LLength.LowPart = count;
7364
7365         lock_ObtainWrite(&fidp->scp->rw);
7366         code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
7367         lock_ReleaseWrite(&fidp->scp->rw);
7368
7369         if (code) {
7370             smb_ReleaseFID(fidp);
7371             return code;
7372         }
7373     }
7374         
7375     userp = smb_GetUserFromVCP(vcp, inp);
7376
7377     /*
7378      * Work around bug in NT client
7379      *
7380      * When copying a file, the NT client should first copy the data,
7381      * then copy the last write time.  But sometimes the NT client does
7382      * these in the wrong order, so the data copies would inadvertently
7383      * cause the last write time to be overwritten.  We try to detect this,
7384      * and don't set client mod time if we think that would go against the
7385      * intention.
7386      */
7387     lock_ObtainMutex(&fidp->mx);
7388     if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
7389         fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7390         fidp->scp->clientModTime = time(NULL);
7391     }
7392     lock_ReleaseMutex(&fidp->mx);
7393
7394     code = 0;
7395     while ( code == 0 && count > 0 ) {
7396         code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7397         if (code == 0 && written == 0)
7398             code = CM_ERROR_PARTIALWRITE;
7399
7400         offset = LargeIntegerAdd(offset,
7401                                  ConvertLongToLargeInteger(written));
7402
7403         count -= written;
7404         total_written += written;
7405         written = 0;
7406     }
7407
7408     /* Get a raw buffer */
7409     if (code == 0) {
7410         rawBuf = NULL;
7411         lock_ObtainMutex(&smb_RawBufLock);
7412         if (smb_RawBufs) {
7413             /* Get a raw buf, from head of list */
7414             rawBuf = smb_RawBufs;
7415             smb_RawBufs = *(char **)smb_RawBufs;
7416         }
7417         else
7418             code = CM_ERROR_USESTD;
7419                 
7420         lock_ReleaseMutex(&smb_RawBufLock);
7421     }
7422
7423     /* Don't allow a premature Close */
7424     if (code == 0 && (writeMode & 1) == 0) {
7425         lock_ObtainMutex(&fidp->mx);
7426         fidp->raw_writers++;
7427         thrd_ResetEvent(fidp->raw_write_event);
7428         lock_ReleaseMutex(&fidp->mx);
7429     }
7430
7431     smb_ReleaseFID(fidp);
7432     cm_ReleaseUser(userp);
7433
7434     if (code) {
7435         smb_SetSMBParm(outp, 0, total_written);
7436         smb_SetSMBDataLength(outp, 0);
7437         ((smb_t *)outp)->com = 0x20;    /* SMB_COM_WRITE_COMPLETE */
7438         rwcp->code = code;
7439         return code;
7440     }
7441
7442     offset = LargeIntegerAdd(offset,
7443                              ConvertLongToLargeInteger(count));
7444
7445     rwcp->code = 0;
7446     rwcp->buf = rawBuf;
7447     rwcp->offset.HighPart = offset.HighPart;
7448     rwcp->offset.LowPart = offset.LowPart;
7449     rwcp->count = totalCount - count;
7450     rwcp->writeMode = writeMode;
7451     rwcp->alreadyWritten = total_written;
7452
7453     /* set the packet data length to 3 bytes for the data block header,
7454      * plus the size of the data.
7455      */
7456     smb_SetSMBParm(outp, 0, 0xffff);
7457     smb_SetSMBDataLength(outp, 0);
7458
7459     return 0;
7460 }
7461
7462 /* SMB_COM_READ */
7463 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7464 {
7465     osi_hyper_t offset;
7466     long count, finalCount;
7467     unsigned short fd;
7468     unsigned pid;
7469     smb_fid_t *fidp;
7470     smb_t *smbp = (smb_t*) inp;
7471     long code = 0;
7472     cm_user_t *userp;
7473     char *op;
7474         
7475     fd = smb_GetSMBParm(inp, 0);
7476     count = smb_GetSMBParm(inp, 1);
7477     offset.HighPart = 0;        /* too bad */
7478     offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7479         
7480     osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
7481              fd, offset.LowPart, count);
7482         
7483     fd = smb_ChainFID(fd, inp);
7484     fidp = smb_FindFID(vcp, fd, 0);
7485     if (!fidp)
7486         return CM_ERROR_BADFD;
7487         
7488     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7489         smb_CloseFID(vcp, fidp, NULL, 0);
7490         smb_ReleaseFID(fidp);
7491         return CM_ERROR_NOSUCHFILE;
7492     }
7493
7494     lock_ObtainMutex(&fidp->mx);
7495     if (fidp->flags & SMB_FID_IOCTL) {
7496         lock_ReleaseMutex(&fidp->mx);
7497         code = smb_IoctlRead(fidp, vcp, inp, outp);
7498         smb_ReleaseFID(fidp);
7499         return code;
7500     }
7501     lock_ReleaseMutex(&fidp->mx);
7502
7503     {
7504         LARGE_INTEGER LOffset, LLength;
7505         cm_key_t key;
7506
7507         pid = smbp->pid;
7508         key = cm_GenerateKey(vcp->vcID, pid, fd);
7509
7510         LOffset.HighPart = 0;
7511         LOffset.LowPart = offset.LowPart;
7512         LLength.HighPart = 0;
7513         LLength.LowPart = count;
7514         
7515         lock_ObtainWrite(&fidp->scp->rw);
7516         code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
7517         lock_ReleaseWrite(&fidp->scp->rw);
7518     }
7519     if (code) {
7520         smb_ReleaseFID(fidp);
7521         return code;
7522     }
7523         
7524     userp = smb_GetUserFromVCP(vcp, inp);
7525
7526     /* remember this for final results */
7527     smb_SetSMBParm(outp, 0, count);
7528     smb_SetSMBParm(outp, 1, 0);
7529     smb_SetSMBParm(outp, 2, 0);
7530     smb_SetSMBParm(outp, 3, 0);
7531     smb_SetSMBParm(outp, 4, 0);
7532
7533     /* set the packet data length to 3 bytes for the data block header,
7534      * plus the size of the data.
7535      */
7536     smb_SetSMBDataLength(outp, count+3);
7537         
7538     /* get op ptr after putting in the parms, since otherwise we don't
7539      * know where the data really is.
7540      */
7541     op = smb_GetSMBData(outp, NULL);
7542
7543     /* now emit the data block header: 1 byte of type and 2 bytes of length */
7544     *op++ = 1;  /* data block marker */
7545     *op++ = (unsigned char) (count & 0xff);
7546     *op++ = (unsigned char) ((count >> 8) & 0xff);
7547                 
7548     code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
7549
7550     /* fix some things up */
7551     smb_SetSMBParm(outp, 0, finalCount);
7552     smb_SetSMBDataLength(outp, finalCount+3);
7553
7554     smb_ReleaseFID(fidp);
7555         
7556     cm_ReleaseUser(userp);
7557     return code;
7558 }
7559
7560 /* SMB_COM_CREATE_DIRECTORY */
7561 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7562 {
7563     clientchar_t *pathp;
7564     long code = 0;
7565     cm_space_t *spacep;
7566     unsigned char *tp;
7567     cm_user_t *userp;
7568     cm_scache_t *dscp;                  /* dir we're dealing with */
7569     cm_scache_t *scp;                   /* file we're creating */
7570     cm_attr_t setAttr;
7571     int initialModeBits;
7572     clientchar_t *lastNamep;
7573     int caseFold;
7574     clientchar_t *tidPathp;
7575     cm_req_t req;
7576
7577     smb_InitReq(&req);
7578
7579     scp = NULL;
7580         
7581     /* compute initial mode bits based on read-only flag in attributes */
7582     initialModeBits = 0777;
7583         
7584     tp = smb_GetSMBData(inp, NULL);
7585     pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
7586
7587     if (cm_ClientStrCmp(pathp, _C("\\")) == 0)
7588         return CM_ERROR_EXISTS;
7589
7590     spacep = inp->spacep;
7591     smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
7592
7593     userp = smb_GetUserFromVCP(vcp, inp);
7594
7595     caseFold = CM_FLAG_CASEFOLD;
7596
7597     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7598     if (code) {
7599         cm_ReleaseUser(userp);
7600         return CM_ERROR_NOSUCHPATH;
7601     }
7602
7603     code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
7604                     caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
7605                     userp, tidPathp, &req, &dscp);
7606
7607     if (code) {
7608         cm_ReleaseUser(userp);
7609         return code;
7610     }
7611         
7612 #ifdef DFS_SUPPORT
7613     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7614         int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
7615         cm_ReleaseSCache(dscp);
7616         cm_ReleaseUser(userp);
7617         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7618             return CM_ERROR_PATH_NOT_COVERED;
7619         else
7620             return CM_ERROR_BADSHARENAME;
7621     }
7622 #endif /* DFS_SUPPORT */
7623
7624     /* otherwise, scp points to the parent directory.  Do a lookup, and
7625      * fail if we find it.  Otherwise, we do the create.
7626      */
7627     if (!lastNamep) 
7628         lastNamep = pathp;
7629     else 
7630         lastNamep++;
7631     code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
7632     if (scp) cm_ReleaseSCache(scp);
7633     if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7634         if (code == 0) code = CM_ERROR_EXISTS;
7635         cm_ReleaseSCache(dscp);
7636         cm_ReleaseUser(userp);
7637         return code;
7638     }
7639         
7640     setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7641     setAttr.clientModTime = time(NULL);
7642     code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
7643     if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7644         smb_NotifyChange(FILE_ACTION_ADDED,
7645                          FILE_NOTIFY_CHANGE_DIR_NAME,
7646                          dscp, lastNamep, NULL, TRUE);
7647         
7648     /* we don't need this any longer */
7649     cm_ReleaseSCache(dscp);
7650
7651     if (code) {
7652         /* something went wrong creating or truncating the file */
7653         cm_ReleaseUser(userp);
7654         return code;
7655     }
7656         
7657     /* otherwise we succeeded */
7658     smb_SetSMBDataLength(outp, 0);
7659     cm_ReleaseUser(userp);
7660
7661     return 0;
7662 }
7663
7664 BOOL smb_IsLegalFilename(clientchar_t *filename)
7665 {
7666     /* 
7667      *  Find the longest substring of filename that does not contain
7668      *  any of the chars in illegalChars.  If that substring is less
7669      *  than the length of the whole string, then one or more of the
7670      *  illegal chars is in filename. 
7671      */
7672     if (cm_ClientStrCSpn(filename, illegalChars) < cm_ClientStrLen(filename))
7673         return FALSE;
7674
7675     return TRUE;
7676 }
7677
7678 /* SMB_COM_CREATE and SMB_COM_CREATE_NEW */
7679 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7680 {
7681     clientchar_t *pathp;
7682     long code = 0;
7683     cm_space_t *spacep;
7684     unsigned char *tp;
7685     int excl;
7686     cm_user_t *userp;
7687     cm_scache_t *dscp;                  /* dir we're dealing with */
7688     cm_scache_t *scp;                   /* file we're creating */
7689     cm_attr_t setAttr;
7690     int initialModeBits;
7691     smb_fid_t *fidp;
7692     int attributes;
7693     clientchar_t *lastNamep;
7694     int caseFold;
7695     afs_uint32 dosTime;
7696     clientchar_t *tidPathp;
7697     cm_req_t req;
7698     int created = 0;                    /* the file was new */
7699
7700     smb_InitReq(&req);
7701
7702     scp = NULL;
7703     excl = (inp->inCom == 0x03)? 0 : 1;
7704         
7705     attributes = smb_GetSMBParm(inp, 0);
7706     dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
7707         
7708     /* compute initial mode bits based on read-only flag in attributes */
7709     initialModeBits = 0666;
7710     if (attributes & SMB_ATTR_READONLY) 
7711         initialModeBits &= ~0222;
7712         
7713     tp = smb_GetSMBData(inp, NULL);
7714     pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
7715
7716     spacep = inp->spacep;
7717     smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
7718
7719     userp = smb_GetUserFromVCP(vcp, inp);
7720
7721     caseFold = CM_FLAG_CASEFOLD;
7722
7723     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7724     if (code) {
7725         cm_ReleaseUser(userp);
7726         return CM_ERROR_NOSUCHPATH;
7727     }
7728     code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
7729                     userp, tidPathp, &req, &dscp);
7730
7731     if (code) {
7732         cm_ReleaseUser(userp);
7733         return code;
7734     }
7735         
7736 #ifdef DFS_SUPPORT
7737     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7738         int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
7739         cm_ReleaseSCache(dscp);
7740         cm_ReleaseUser(userp);
7741         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7742             return CM_ERROR_PATH_NOT_COVERED;
7743         else
7744             return CM_ERROR_BADSHARENAME;
7745     }
7746 #endif /* DFS_SUPPORT */
7747
7748     /* otherwise, scp points to the parent directory.  Do a lookup, and
7749      * truncate the file if we find it, otherwise we create the file.
7750      */
7751     if (!lastNamep) 
7752         lastNamep = pathp;
7753     else 
7754         lastNamep++;
7755
7756     if (!smb_IsLegalFilename(lastNamep))
7757         return CM_ERROR_BADNTFILENAME;
7758
7759     osi_Log1(smb_logp, "SMB receive create [%S]", osi_LogSaveClientString( smb_logp, pathp ));
7760 #ifdef DEBUG_VERBOSE
7761     {
7762         char *hexp;
7763         hexp = osi_HexifyString( lastNamep );
7764         DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
7765         free(hexp);
7766     }
7767 #endif    
7768
7769     code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
7770     if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7771         cm_ReleaseSCache(dscp);
7772         cm_ReleaseUser(userp);
7773         return code;
7774     }
7775         
7776     /* if we get here, if code is 0, the file exists and is represented by
7777      * scp.  Otherwise, we have to create it.
7778      */
7779     if (code == 0) {
7780         if (excl) {
7781             /* oops, file shouldn't be there */
7782             cm_ReleaseSCache(dscp);
7783             cm_ReleaseSCache(scp);
7784             cm_ReleaseUser(userp);
7785             return CM_ERROR_EXISTS;
7786         }
7787
7788         setAttr.mask = CM_ATTRMASK_LENGTH;
7789         setAttr.length.LowPart = 0;
7790         setAttr.length.HighPart = 0;
7791         code = cm_SetAttr(scp, &setAttr, userp, &req);
7792     }
7793     else {
7794         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7795         smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
7796         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7797                          &req);
7798         if (code == 0) {
7799             created = 1;
7800             if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7801                 smb_NotifyChange(FILE_ACTION_ADDED,     
7802                                  FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7803                                  dscp, lastNamep, NULL, TRUE);
7804         } else if (!excl && code == CM_ERROR_EXISTS) {
7805             /* not an exclusive create, and someone else tried
7806              * creating it already, then we open it anyway.  We
7807              * don't bother retrying after this, since if this next
7808              * fails, that means that the file was deleted after
7809              * we started this call.
7810              */
7811             code = cm_Lookup(dscp, lastNamep, caseFold, userp,
7812                              &req, &scp);
7813             if (code == 0) {
7814                 setAttr.mask = CM_ATTRMASK_LENGTH;
7815                 setAttr.length.LowPart = 0;
7816                 setAttr.length.HighPart = 0;
7817                 code = cm_SetAttr(scp, &setAttr, userp, &req);
7818             }
7819         }
7820     }
7821         
7822     /* we don't need this any longer */
7823     cm_ReleaseSCache(dscp);
7824
7825     if (code) {
7826         /* something went wrong creating or truncating the file */
7827         if (scp) cm_ReleaseSCache(scp);
7828         cm_ReleaseUser(userp);
7829         return code;
7830     }
7831
7832     /* make sure we only open files */
7833     if (scp->fileType != CM_SCACHETYPE_FILE) {
7834         cm_ReleaseSCache(scp);
7835         cm_ReleaseUser(userp);
7836         return CM_ERROR_ISDIR;
7837     }
7838
7839     /* now all we have to do is open the file itself */
7840     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7841     osi_assertx(fidp, "null smb_fid_t");
7842         
7843     cm_HoldUser(userp);
7844
7845     lock_ObtainMutex(&fidp->mx);
7846     /* always create it open for read/write */
7847     fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
7848
7849     /* remember that the file was newly created */
7850     if (created)
7851         fidp->flags |= SMB_FID_CREATED;
7852
7853     osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
7854
7855     /* save a pointer to the vnode */
7856     fidp->scp = scp;
7857     lock_ObtainWrite(&scp->rw);
7858     scp->flags |= CM_SCACHEFLAG_SMB_FID;
7859     lock_ReleaseWrite(&scp->rw);
7860     
7861     /* and the user */
7862     fidp->userp = userp;
7863     lock_ReleaseMutex(&fidp->mx);
7864
7865     smb_SetSMBParm(outp, 0, fidp->fid);
7866     smb_SetSMBDataLength(outp, 0);
7867
7868     cm_Open(scp, 0, userp);
7869
7870     smb_ReleaseFID(fidp);
7871     cm_ReleaseUser(userp);
7872     /* leave scp held since we put it in fidp->scp */
7873     return 0;
7874 }
7875
7876 /* SMB_COM_SEEK */
7877 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7878 {
7879     long code = 0;
7880     osi_hyper_t new_offset;
7881     long offset;
7882     int whence;
7883     unsigned short fd;
7884     smb_fid_t *fidp;
7885     cm_scache_t *scp;
7886     cm_user_t *userp;
7887     cm_req_t req;
7888
7889     smb_InitReq(&req);
7890         
7891     fd = smb_GetSMBParm(inp, 0);
7892     whence = smb_GetSMBParm(inp, 1);
7893     offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7894         
7895     /* try to find the file descriptor */
7896     fd = smb_ChainFID(fd, inp);
7897     fidp = smb_FindFID(vcp, fd, 0);
7898     if (!fidp)
7899         return CM_ERROR_BADFD;
7900     
7901     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7902         smb_CloseFID(vcp, fidp, NULL, 0);
7903         smb_ReleaseFID(fidp);
7904         return CM_ERROR_NOSUCHFILE;
7905     }
7906
7907     lock_ObtainMutex(&fidp->mx);
7908     if (fidp->flags & SMB_FID_IOCTL) {
7909         lock_ReleaseMutex(&fidp->mx);
7910         smb_ReleaseFID(fidp);
7911         return CM_ERROR_BADFD;
7912     }
7913     lock_ReleaseMutex(&fidp->mx);
7914         
7915     userp = smb_GetUserFromVCP(vcp, inp);
7916
7917     lock_ObtainMutex(&fidp->mx);
7918     scp = fidp->scp;
7919     cm_HoldSCache(scp);
7920     lock_ReleaseMutex(&fidp->mx);
7921     lock_ObtainWrite(&scp->rw);
7922     code = cm_SyncOp(scp, NULL, userp, &req, 0,
7923                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7924     if (code == 0) {
7925         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7926         if (whence == 1) {
7927             /* offset from current offset */
7928             new_offset = LargeIntegerAdd(fidp->offset,
7929                                          ConvertLongToLargeInteger(offset));
7930         }
7931         else if (whence == 2) {
7932             /* offset from current EOF */
7933             new_offset = LargeIntegerAdd(scp->length,
7934                                          ConvertLongToLargeInteger(offset));
7935         } else {
7936             new_offset = ConvertLongToLargeInteger(offset);
7937         }
7938
7939         fidp->offset = new_offset;
7940         smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
7941         smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
7942         smb_SetSMBDataLength(outp, 0);
7943     }
7944     lock_ReleaseWrite(&scp->rw);
7945     smb_ReleaseFID(fidp);
7946     cm_ReleaseSCache(scp);
7947     cm_ReleaseUser(userp);
7948     return code;
7949 }
7950
7951 /* dispatch all of the requests received in a packet.  Due to chaining, this may
7952  * be more than one request.
7953  */
7954 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7955                         NCB *ncbp, raw_write_cont_t *rwcp)
7956 {
7957     smb_dispatch_t *dp;
7958     smb_t *smbp;
7959     unsigned long code = 0;
7960     unsigned char *outWctp;
7961     int nparms;                 /* # of bytes of parameters */
7962     char tbuffer[200];
7963     int nbytes;                 /* bytes of data, excluding count */
7964     int temp;
7965     unsigned char *tp;
7966     unsigned short errCode;
7967     unsigned long NTStatus;
7968     int noSend;
7969     unsigned char errClass;
7970     unsigned int oldGen;
7971     DWORD oldTime, newTime;
7972
7973     /* get easy pointer to the data */
7974     smbp = (smb_t *) inp->data;
7975
7976     if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
7977         /* setup the basic parms for the initial request in the packet */
7978         inp->inCom = smbp->com;
7979         inp->wctp = &smbp->wct;
7980         inp->inCount = 0;
7981         inp->ncb_length = ncbp->ncb_length;
7982     }
7983     noSend = 0;
7984
7985     /* Sanity check */
7986     if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
7987         /* log it and discard it */
7988         LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT, 
7989                  __FILE__, __LINE__, ncbp->ncb_length);
7990         osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
7991         return;
7992     }
7993
7994     /* We are an ongoing op */
7995     thrd_Increment(&ongoingOps);
7996
7997     /* set up response packet for receiving output */
7998     if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
7999         smb_FormatResponsePacket(vcp, inp, outp);
8000     outWctp = outp->wctp;
8001
8002     /* Remember session generation number and time */
8003     oldGen = sessionGen;
8004     oldTime = GetTickCount();
8005
8006     while (inp->inCom != 0xff) {
8007         dp = &smb_dispatchTable[inp->inCom];
8008
8009         if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
8010             outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
8011             code = outp->resumeCode;
8012             goto resume;
8013         }
8014
8015         /* process each request in the packet; inCom, wctp and inCount
8016          * are already set up.
8017          */
8018         osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
8019                   ncbp->ncb_lsn);
8020
8021         /* now do the dispatch */
8022         /* start by formatting the response record a little, as a default */
8023         if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
8024             outWctp[0] = 2;
8025             outWctp[1] = 0xff;  /* no operation */
8026             outWctp[2] = 0;             /* padding */
8027             outWctp[3] = 0;
8028             outWctp[4] = 0;
8029         }
8030         else {
8031             /* not a chained request, this is a more reasonable default */
8032             outWctp[0] = 0;     /* wct of zero */
8033             outWctp[1] = 0;     /* and bcc (word) of zero */
8034             outWctp[2] = 0;
8035         }   
8036
8037         /* once set, stays set.  Doesn't matter, since we never chain
8038          * "no response" calls.
8039          */
8040         if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
8041             noSend = 1;
8042
8043         if (dp->procp) {
8044             /* we have a recognized operation */
8045             char * opName = myCrt_Dispatch(inp->inCom);
8046
8047             if (inp->inCom == 0x1d)
8048                 /* Raw Write */
8049                 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
8050             else {
8051                 osi_Log4(smb_logp,"Dispatch %s vcp 0x%p lana %d lsn %d",
8052                          opName,vcp,vcp->lana,vcp->lsn);
8053                 code = (*(dp->procp)) (vcp, inp, outp);
8054                 osi_Log4(smb_logp,"Dispatch return  code 0x%x vcp 0x%p lana %d lsn %d",
8055                          code,vcp,vcp->lana,vcp->lsn);
8056 #ifdef LOG_PACKET
8057                 if ( code == CM_ERROR_BADSMB ||
8058                      code == CM_ERROR_BADOP )
8059                      smb_LogPacket(inp);
8060 #endif /* LOG_PACKET */
8061             }   
8062
8063             newTime = GetTickCount();
8064             osi_Log2(smb_logp, "Dispatch %s duration %d ms", opName, newTime - oldTime);
8065
8066             if (oldGen != sessionGen) {
8067                 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION, 
8068                          newTime - oldTime, ncbp->ncb_length);
8069                 osi_Log3(smb_logp, "Request %s straddled session startup, "
8070                           "took %d ms, ncb length %d", opName, newTime - oldTime, ncbp->ncb_length);
8071             }
8072
8073             FreeSMBStrings(inp);
8074         } else {
8075             /* bad opcode, fail the request, after displaying it */
8076             osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
8077 #ifdef LOG_PACKET
8078             smb_LogPacket(inp);
8079 #endif  /* LOG_PACKET */
8080
8081             if (showErrors) {
8082                 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
8083                 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
8084                                       MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
8085                 if (code == IDCANCEL) 
8086                     showErrors = 0;
8087             }
8088             code = CM_ERROR_BADOP;
8089         }
8090
8091         /* catastrophic failure:  log as much as possible */
8092         if (code == CM_ERROR_BADSMB) {
8093             LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID, 
8094                      ncbp->ncb_length);
8095 #ifdef LOG_PACKET
8096             smb_LogPacket(inp);
8097 #endif /* LOG_PACKET */
8098             osi_Log1(smb_logp, "Invalid SMB message, length %d",
8099                      ncbp->ncb_length);
8100
8101             code = CM_ERROR_INVAL;
8102         }
8103
8104         if (outp->flags & SMB_PACKETFLAG_NOSEND) {
8105             thrd_Decrement(&ongoingOps);
8106             return;
8107         }
8108
8109       resume:
8110         /* now, if we failed, turn the current response into an empty
8111          * one, and fill in the response packet's error code.
8112          */
8113         if (code) {
8114             if (vcp->flags & SMB_VCFLAG_STATUS32) {
8115                 smb_MapNTError(code, &NTStatus);
8116                 outWctp = outp->wctp;
8117                 smbp = (smb_t *) &outp->data;
8118                 if (code != CM_ERROR_PARTIALWRITE
8119                      && code != CM_ERROR_BUFFERTOOSMALL 
8120                      && code != CM_ERROR_GSSCONTINUE) {
8121                     /* nuke wct and bcc.  For a partial
8122                      * write or an in-process authentication handshake, 
8123                      * assume they're OK.
8124                      */
8125                     *outWctp++ = 0;
8126                     *outWctp++ = 0;
8127                     *outWctp++ = 0;
8128                 }
8129                 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8130                 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8131                 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8132                 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8133                 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8134                 break;
8135             }
8136             else {
8137                 smb_MapCoreError(code, vcp, &errCode, &errClass);
8138                 outWctp = outp->wctp;
8139                 smbp = (smb_t *) &outp->data;
8140                 if (code != CM_ERROR_PARTIALWRITE) {
8141                     /* nuke wct and bcc.  For a partial
8142                      * write, assume they're OK.
8143                      */
8144                     *outWctp++ = 0;
8145                     *outWctp++ = 0;
8146                     *outWctp++ = 0;
8147                 }
8148                 smbp->errLow = (unsigned char) (errCode & 0xff);
8149                 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8150                 smbp->rcls = errClass;
8151                 break;
8152             }
8153         }       /* error occurred */
8154
8155         /* if we're here, we've finished one request.  Look to see if
8156          * this is a chained opcode.  If it is, setup things to process
8157          * the chained request, and setup the output buffer to hold the
8158          * chained response.  Start by finding the next input record.
8159          */
8160         if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
8161             break;              /* not a chained req */
8162         tp = inp->wctp;         /* points to start of last request */
8163         /* in a chained request, the first two
8164          * parm fields are required, and are
8165          * AndXCommand/AndXReserved and
8166          * AndXOffset. */
8167         if (tp[0] < 2) break;   
8168         if (tp[1] == 0xff) break;       /* no more chained opcodes */
8169         inp->inCom = tp[1];
8170         inp->wctp = inp->data + tp[3] + (tp[4] << 8);
8171         inp->inCount++;
8172
8173         /* and now append the next output request to the end of this
8174          * last request.  Begin by finding out where the last response
8175          * ends, since that's where we'll put our new response.
8176          */
8177         outWctp = outp->wctp;           /* ptr to out parameters */
8178         osi_assert (outWctp[0] >= 2);   /* need this for all chained requests */
8179         nparms = outWctp[0] << 1;
8180         tp = outWctp + nparms + 1;      /* now points to bcc field */
8181         nbytes = tp[0] + (tp[1] << 8);  /* # of data bytes */
8182         tp += 2 /* for the count itself */ + nbytes;
8183         /* tp now points to the new output record; go back and patch the
8184          * second parameter (off2) to point to the new record.
8185          */
8186         temp = (unsigned int)(tp - outp->data);
8187         outWctp[3] = (unsigned char) (temp & 0xff);
8188         outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
8189         outWctp[2] = 0; /* padding */
8190         outWctp[1] = inp->inCom;        /* next opcode */
8191
8192         /* finally, setup for the next iteration */
8193         outp->wctp = tp;
8194         outWctp = tp;
8195     }   /* while loop over all requests in the packet */
8196
8197     /* now send the output packet, and return */
8198     if (!noSend)
8199         smb_SendPacket(vcp, outp);
8200     thrd_Decrement(&ongoingOps);
8201
8202     return;
8203 }
8204
8205 /* Wait for Netbios() calls to return, and make the results available to server
8206  * threads.  Note that server threads can't wait on the NCBevents array
8207  * themselves, because NCB events are manual-reset, and the servers would race
8208  * each other to reset them.
8209  */
8210 void smb_ClientWaiter(void *parmp)
8211 {
8212     DWORD code;
8213     int   idx;
8214
8215     while (smbShutdownFlag == 0) {
8216         code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
8217                                                  FALSE, INFINITE);
8218         if (code == WAIT_OBJECT_0)
8219             continue;
8220
8221         /* error checking */
8222         if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8223         {
8224             int abandonIdx = code - WAIT_ABANDONED_0;
8225             osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8226         }
8227
8228         if (code == WAIT_IO_COMPLETION)
8229         {
8230             osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
8231             continue;
8232         }
8233         
8234         if (code == WAIT_TIMEOUT)
8235         {
8236             osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
8237         }
8238
8239         if (code == WAIT_FAILED)
8240         {
8241             osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
8242         }
8243
8244         idx = code - WAIT_OBJECT_0;
8245  
8246         /* check idx range! */
8247         if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
8248         {
8249             /* this is fatal - log as much as possible */
8250             osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
8251             osi_assertx(0, "invalid index");
8252         }
8253         
8254         thrd_ResetEvent(NCBevents[idx]);
8255         thrd_SetEvent(NCBreturns[0][idx]);
8256     }
8257 }
8258
8259 /*
8260  * Try to have one NCBRECV request waiting for every live session.  Not more
8261  * than one, because if there is more than one, it's hard to handle Write Raw.
8262  */
8263 void smb_ServerWaiter(void *parmp)
8264 {
8265     DWORD code;
8266     int idx_session, idx_NCB;
8267     NCB *ncbp;
8268
8269     while (smbShutdownFlag == 0) {
8270         /* Get a session */
8271         code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
8272                                                  FALSE, INFINITE);
8273         if (code == WAIT_OBJECT_0)
8274             continue;
8275
8276         if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
8277         {
8278             int abandonIdx = code - WAIT_ABANDONED_0;
8279             osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8280         }
8281         
8282         if (code == WAIT_IO_COMPLETION)
8283         {
8284             osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
8285             continue;
8286         }
8287         
8288         if (code == WAIT_TIMEOUT)
8289         {
8290             osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
8291         }
8292         
8293         if (code == WAIT_FAILED)
8294         {
8295             osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
8296         }
8297         
8298         idx_session = code - WAIT_OBJECT_0;
8299
8300         /* check idx range! */
8301         if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
8302         {
8303             /* this is fatal - log as much as possible */
8304             osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
8305             osi_assertx(0, "invalid index");
8306         }
8307
8308                 /* Get an NCB */
8309       NCBretry:
8310         code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
8311                                                  FALSE, INFINITE);
8312         if (code == WAIT_OBJECT_0) {
8313             if (smbShutdownFlag == 1) 
8314                 break;
8315             else
8316                 goto NCBretry;
8317         }
8318
8319         /* error checking */
8320         if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8321         {
8322             int abandonIdx = code - WAIT_ABANDONED_0;
8323             osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8324         }
8325         
8326         if (code == WAIT_IO_COMPLETION)
8327         {
8328             osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
8329             continue;
8330         }
8331         
8332         if (code == WAIT_TIMEOUT)
8333         {
8334             osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
8335         }
8336         
8337         if (code == WAIT_FAILED)
8338         {
8339             osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
8340         }
8341                 
8342         idx_NCB = code - WAIT_OBJECT_0;
8343
8344         /* check idx range! */
8345         if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
8346         {
8347             /* this is fatal - log as much as possible */
8348             osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
8349             osi_assertx(0, "invalid index");
8350         }
8351
8352         /* Link them together */
8353         NCBsessions[idx_NCB] = idx_session;
8354
8355         /* Fire it up */
8356         ncbp = NCBs[idx_NCB];
8357         ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
8358         ncbp->ncb_command = NCBRECV | ASYNCH;
8359         ncbp->ncb_lana_num = lanas[idx_session];
8360         ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
8361         ncbp->ncb_event = NCBevents[idx_NCB];
8362         ncbp->ncb_length = SMB_PACKETSIZE;
8363         Netbios(ncbp);
8364     }
8365 }
8366
8367 /*
8368  * The top level loop for handling SMB request messages.  Each server thread
8369  * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
8370  * NCB and buffer for the incoming request are loaned to us.
8371  *
8372  * Write Raw trickery starts here.  When we get a Write Raw, we are supposed
8373  * to immediately send a request for the rest of the data.  This must come
8374  * before any other traffic for that session, so we delay setting the session
8375  * event until that data has come in.
8376  */
8377 void smb_Server(VOID *parmp)
8378 {
8379     INT_PTR myIdx = (INT_PTR) parmp;
8380     NCB *ncbp;
8381     NCB *outncbp;
8382     smb_packet_t *bufp;
8383     smb_packet_t *outbufp;
8384     DWORD code, rcode;
8385     int idx_NCB, idx_session;
8386     UCHAR rc;
8387     smb_vc_t *vcp = NULL;
8388     smb_t *smbp;
8389     extern void rx_StartClientThread(void);
8390
8391     rx_StartClientThread();
8392
8393     outncbp = smb_GetNCB();
8394     outbufp = smb_GetPacket();
8395     outbufp->ncbp = outncbp;
8396
8397     while (1) {
8398         if (vcp) {
8399             smb_ReleaseVC(vcp);
8400             vcp = NULL;
8401         }
8402
8403         smb_ResetServerPriority();
8404
8405         code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
8406                                                  FALSE, INFINITE);
8407
8408         /* terminate silently if shutdown flag is set */
8409         if (code == WAIT_OBJECT_0) {
8410             if (smbShutdownFlag == 1) {
8411                 thrd_SetEvent(smb_ServerShutdown[myIdx]);
8412                 break;
8413             } else
8414                 continue;
8415         }
8416
8417         /* error checking */
8418         if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8419         {
8420             int abandonIdx = code - WAIT_ABANDONED_0;
8421             osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
8422         }
8423         
8424         if (code == WAIT_IO_COMPLETION)
8425         {
8426             osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
8427             continue;
8428         }
8429         
8430         if (code == WAIT_TIMEOUT)
8431         {
8432             osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
8433         }
8434         
8435         if (code == WAIT_FAILED)
8436         {
8437             osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
8438         }
8439
8440         idx_NCB = code - WAIT_OBJECT_0;
8441         
8442         /* check idx range! */
8443         if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
8444         {
8445             /* this is fatal - log as much as possible */
8446             osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
8447             osi_assertx(0, "invalid index");
8448         }
8449
8450         ncbp = NCBs[idx_NCB];
8451         idx_session = NCBsessions[idx_NCB];
8452         rc = ncbp->ncb_retcode;
8453
8454         if (rc != NRC_PENDING && rc != NRC_GOODRET)
8455             osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
8456
8457         switch (rc) {
8458         case NRC_GOODRET: 
8459             vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8460             break;
8461
8462         case NRC_PENDING:
8463             /* Can this happen? Or is it just my UNIX paranoia? */
8464             osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
8465             continue;
8466
8467         case NRC_SNUMOUT:
8468         case NRC_SABORT:
8469             LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
8470             /* fallthrough */
8471         case NRC_SCLOSED:
8472             /* Client closed session */
8473             vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8474             if (vcp) {
8475                 lock_ObtainMutex(&vcp->mx);
8476                 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8477                     osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8478                              vcp, vcp->usersp);
8479                     vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8480                     lock_ReleaseMutex(&vcp->mx);
8481                     lock_ObtainWrite(&smb_globalLock);
8482                     dead_sessions[vcp->session] = TRUE;
8483                     lock_ReleaseWrite(&smb_globalLock);
8484                 } else {
8485                     lock_ReleaseMutex(&vcp->mx);
8486                 }
8487                 smb_CleanupDeadVC(vcp);
8488                 smb_ReleaseVC(vcp);
8489                 vcp = NULL;
8490             }
8491             goto doneWithNCB;
8492
8493         case NRC_INCOMP:
8494             /* Treat as transient error */
8495             LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE, 
8496                      ncbp->ncb_length);
8497             osi_Log1(smb_logp,
8498                      "dispatch smb recv failed, message incomplete, ncb_length %d",
8499                      ncbp->ncb_length);
8500             osi_Log1(smb_logp,
8501                      "SMB message incomplete, "
8502                      "length %d", ncbp->ncb_length);
8503
8504             /*
8505              * We used to discard the packet.
8506              * Instead, try handling it normally.
8507              *
8508              continue;
8509              */
8510             vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8511             break;
8512
8513         default:
8514             /* A weird error code.  Log it, sleep, and continue. */
8515             vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8516             if (vcp) {
8517                 lock_ObtainMutex(&vcp->mx);
8518                 if (vcp->errorCount++ > 3) {
8519                     osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
8520                     if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8521                         osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8522                                  vcp, vcp->usersp);
8523                         vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8524                         lock_ReleaseMutex(&vcp->mx);
8525                         lock_ObtainWrite(&smb_globalLock);
8526                         dead_sessions[vcp->session] = TRUE;
8527                         lock_ReleaseWrite(&smb_globalLock);
8528                     } else {
8529                         lock_ReleaseMutex(&vcp->mx);
8530                     }
8531                     smb_CleanupDeadVC(vcp);
8532                     smb_ReleaseVC(vcp);
8533                     vcp = NULL;
8534                     goto doneWithNCB;
8535                 }
8536                 else {
8537                     lock_ReleaseMutex(&vcp->mx);
8538                     smb_ReleaseVC(vcp);
8539                     vcp = NULL;
8540                     Sleep(10);
8541                     thrd_SetEvent(SessionEvents[idx_session]);
8542                 }
8543             }
8544             continue;
8545         }
8546
8547         /* Success, so now dispatch on all the data in the packet */
8548
8549         smb_concurrentCalls++;
8550         if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
8551             smb_maxObsConcurrentCalls = smb_concurrentCalls;
8552
8553         /*
8554          * If at this point vcp is NULL (implies that packet was invalid)
8555          * then we are in big trouble. This means either :
8556          *   a) we have the wrong NCB.
8557          *   b) Netbios screwed up the call.
8558          *   c) The VC was already marked dead before we were able to
8559          *      process the call
8560          * Obviously this implies that 
8561          *   ( LSNs[idx_session] != ncbp->ncb_lsn ||
8562          *   lanas[idx_session] != ncbp->ncb_lana_num )
8563          * Either way, we can't do anything with this packet.
8564          * Log, sleep and resume.
8565          */
8566         if (!vcp) {
8567             LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
8568                      LSNs[idx_session],
8569                      lanas[idx_session],
8570                      ncbp->ncb_lsn,
8571                      ncbp->ncb_lana_num);
8572
8573             /* Also log in the trace log. */
8574             osi_Log4(smb_logp, "Server: VCP does not exist!"
8575                       "LSNs[idx_session]=[%d],"
8576                       "lanas[idx_session]=[%d],"
8577                       "ncbp->ncb_lsn=[%d],"
8578                       "ncbp->ncb_lana_num=[%d]",
8579                       LSNs[idx_session],
8580                       lanas[idx_session],
8581                       ncbp->ncb_lsn,
8582                       ncbp->ncb_lana_num);
8583
8584             /* thrd_Sleep(1000); Don't bother sleeping */
8585             thrd_SetEvent(SessionEvents[idx_session]);
8586             smb_concurrentCalls--;
8587             continue;
8588         }
8589
8590         smb_SetRequestStartTime();
8591
8592         vcp->errorCount = 0;
8593         bufp = (struct smb_packet *) ncbp->ncb_buffer;
8594         smbp = (smb_t *)bufp->data;
8595         outbufp->flags = 0;
8596
8597 #ifndef NOTRACE
8598         __try
8599         {
8600 #endif
8601             if (smbp->com == 0x1d) {
8602                 /* Special handling for Write Raw */
8603                 raw_write_cont_t rwc;
8604                 EVENT_HANDLE rwevent;
8605                 char eventName[MAX_PATH];
8606             
8607                 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
8608                 if (rwc.code == 0) {
8609                     rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
8610                     if ( GetLastError() == ERROR_ALREADY_EXISTS )
8611                         osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8612                     ncbp->ncb_command = NCBRECV | ASYNCH;
8613                     ncbp->ncb_lsn = (unsigned char) vcp->lsn;
8614                     ncbp->ncb_lana_num = vcp->lana;
8615                     ncbp->ncb_buffer = rwc.buf;
8616                     ncbp->ncb_length = 65535;
8617                     ncbp->ncb_event = rwevent;
8618                     Netbios(ncbp);
8619                     rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
8620                     thrd_CloseHandle(rwevent);
8621                 }
8622                 thrd_SetEvent(SessionEvents[idx_session]);
8623                 if (rwc.code == 0)
8624                     smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
8625             } 
8626             else if (smbp->com == 0xa0) {
8627                 /* 
8628                  * Serialize the handling for NT Transact 
8629                  * (defect 11626)
8630                  */
8631                 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
8632                 thrd_SetEvent(SessionEvents[idx_session]);
8633             } else {
8634                 thrd_SetEvent(SessionEvents[idx_session]);
8635                 /* TODO: what else needs to be serialized? */
8636                 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
8637             }
8638 #ifndef NOTRACE        
8639         }
8640         __except( smb_ServerExceptionFilter() ) {
8641         }
8642 #endif
8643
8644         smb_concurrentCalls--;
8645
8646       doneWithNCB:
8647         thrd_SetEvent(NCBavails[idx_NCB]);
8648     }
8649     if (vcp)
8650         smb_ReleaseVC(vcp);
8651     if (outbufp)
8652         smb_FreePacket(outbufp);
8653     if (outncbp)
8654         smb_FreeNCB(outncbp);
8655 }
8656
8657 /*
8658  * Exception filter for the server threads.  If an exception occurs in the
8659  * dispatch routines, which is where exceptions are most common, then do a
8660  * force trace and give control to upstream exception handlers. Useful for
8661  * debugging.
8662  */
8663 DWORD smb_ServerExceptionFilter(void) {
8664     /* While this is not the best time to do a trace, if it succeeds, then
8665      * we have a trace (assuming tracing was enabled). Otherwise, this should
8666      * throw a second exception.
8667      */
8668     LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
8669     afsd_ForceTrace(TRUE);
8670     buf_ForceTrace(TRUE);
8671     return EXCEPTION_CONTINUE_SEARCH;
8672 }       
8673
8674 /*
8675  * Create a new NCB and associated events, packet buffer, and "space" buffer.
8676  * If the number of server threads is M, and the number of live sessions is
8677  * N, then the number of NCB's in use at any time either waiting for, or
8678  * holding, received messages is M + N, so that is how many NCB's get created.
8679  */
8680 void InitNCBslot(int idx)
8681 {
8682     struct smb_packet *bufp;
8683     EVENT_HANDLE retHandle;
8684     afs_uint32 i;
8685     char eventName[MAX_PATH];
8686
8687     osi_assertx( idx < (sizeof(NCBs) / sizeof(NCBs[0])), "invalid index" );
8688
8689     NCBs[idx] = smb_GetNCB();
8690     sprintf(eventName,"NCBavails[%d]", idx);
8691     NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8692     if ( GetLastError() == ERROR_ALREADY_EXISTS )
8693         osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8694     sprintf(eventName,"NCBevents[%d]", idx);
8695     NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
8696     if ( GetLastError() == ERROR_ALREADY_EXISTS )
8697         osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8698     sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
8699     retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8700     if ( GetLastError() == ERROR_ALREADY_EXISTS )
8701         osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8702     for (i=0; i<smb_NumServerThreads; i++)
8703         NCBreturns[i][idx] = retHandle;
8704     bufp = smb_GetPacket();
8705     bufp->spacep = cm_GetSpace();
8706     bufs[idx] = bufp;
8707 }
8708
8709 /* listen for new connections */
8710 void smb_Listener(void *parmp)
8711 {
8712     NCB *ncbp;
8713     long code = 0;
8714     long len;
8715     long i;
8716     afs_uint32  session, thread;
8717     smb_vc_t *vcp = NULL;
8718     int flags = 0;
8719     char rname[NCBNAMSZ+1];
8720     char cname[MAX_COMPUTERNAME_LENGTH+1];
8721     int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
8722     INT_PTR lana = (INT_PTR) parmp;
8723     char eventName[MAX_PATH];
8724
8725     sprintf(eventName,"smb_Listener_lana_%d", (unsigned char)lana);
8726     ListenerShutdown[lana] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8727     if ( GetLastError() == ERROR_ALREADY_EXISTS )
8728         thrd_ResetEvent(ListenerShutdown[lana]);
8729
8730     ncbp = smb_GetNCB();
8731
8732     /* retrieve computer name */
8733     GetComputerName(cname, &cnamelen);
8734     _strupr(cname);
8735
8736     while (smb_ListenerState == SMB_LISTENER_STARTED) {
8737         memset(ncbp, 0, sizeof(NCB));
8738         flags = 0;
8739
8740         ncbp->ncb_command = NCBLISTEN;
8741         ncbp->ncb_rto = 0;      /* No receive timeout */
8742         ncbp->ncb_sto = 0;      /* No send timeout */
8743
8744         /* pad out with spaces instead of null termination */
8745         len = (long)strlen(smb_localNamep);
8746         strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
8747         for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
8748         
8749         strcpy(ncbp->ncb_callname, "*");
8750         for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
8751         
8752         ncbp->ncb_lana_num = (UCHAR)lana;
8753
8754         code = Netbios(ncbp);
8755
8756         if (code == NRC_NAMERR) {
8757           /* An smb shutdown or Vista resume must have taken place */
8758           osi_Log2(smb_logp,
8759                    "NCBLISTEN lana=%d failed with NRC_NAMERR.",
8760                    ncbp->ncb_lana_num, code);
8761
8762             if (lock_TryMutex(&smb_StartedLock)) {
8763                 lana_list.lana[i] = LANA_INVALID;
8764                 lock_ReleaseMutex(&smb_StartedLock);
8765             }
8766             break;
8767         } else if (code ==  NRC_BRIDGE || code != 0) {
8768             int lanaRemaining = 0;
8769
8770             while (!lock_TryMutex(&smb_StartedLock)) {
8771                 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
8772                     goto exit_thread;
8773                 Sleep(50);
8774             }
8775  
8776             osi_Log2(smb_logp,
8777                       "NCBLISTEN lana=%d failed with %s.  Listener thread exiting.",
8778                       ncbp->ncb_lana_num, ncb_error_string(code));
8779
8780             for (i = 0; i < lana_list.length; i++) {
8781                 if (lana_list.lana[i] == lana) {
8782                     smb_StopListener(ncbp, lana_list.lana[i], FALSE);
8783                     lana_list.lana[i] = LANA_INVALID;
8784                 }
8785                 if (lana_list.lana[i] != LANA_INVALID)
8786                     lanaRemaining++;
8787             }
8788
8789             if (lanaRemaining == 0) {
8790                 cm_VolStatus_Network_Stopped(cm_NetbiosName
8791 #ifdef _WIN64
8792                                              ,cm_NetbiosName
8793 #endif
8794                                               );
8795                 smb_ListenerState = SMB_LISTENER_STOPPED;
8796                 smb_LANadapter = LANA_INVALID;
8797                 lana_list.length = 0;
8798             }
8799             lock_ReleaseMutex(&smb_StartedLock);
8800             break;
8801         }
8802 #if 0
8803         else if (code != 0) {
8804             char tbuffer[AFSPATHMAX];
8805
8806             /* terminate silently if shutdown flag is set */
8807             while (!lock_TryMutex(&smb_StartedLock)) {
8808                 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
8809                     goto exit_thread;
8810                 Sleep(50);
8811             }
8812
8813             osi_Log3(smb_logp, 
8814                      "NCBLISTEN lana=%d failed with code %d [%s]",
8815                      ncbp->ncb_lana_num, code, ncb_error_string(code));
8816             osi_Log0(smb_logp, 
8817                      "Client exiting due to network failure. Please restart client.\n");
8818
8819             sprintf(tbuffer, 
8820                      "Client exiting due to network failure.  Please restart client.\n"
8821                      "NCBLISTEN lana=%d failed with code %d [%s]",
8822                      ncbp->ncb_lana_num, code, ncb_error_string(code));
8823             if (showErrors)
8824                 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
8825                                       MB_OK|MB_SERVICE_NOTIFICATION);
8826             osi_panic(tbuffer, __FILE__, __LINE__);
8827
8828             lock_ReleaseMutex(&smb_StartedLock);
8829             break;
8830         }
8831 #endif /* 0 */
8832
8833         /* check for remote conns */
8834         /* first get remote name and insert null terminator */
8835         memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
8836         for (i=NCBNAMSZ; i>0; i--) {
8837             if (rname[i-1] != ' ' && rname[i-1] != 0) {
8838                 rname[i] = 0;
8839                 break;
8840             }
8841         }
8842
8843         /* compare with local name */
8844         if (!isGateway)
8845             if (strncmp(rname, cname, NCBNAMSZ) != 0)
8846                 flags |= SMB_VCFLAG_REMOTECONN;
8847
8848         /* lock */
8849         lock_ObtainMutex(&smb_ListenerLock);
8850
8851         osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
8852         osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
8853
8854         /* now ncbp->ncb_lsn is the connection ID */
8855         vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
8856         if (vcp->session == 0) {
8857             /* New generation */
8858             osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
8859             sessionGen++;
8860
8861             /* Log session startup */
8862 #ifdef NOTSERVICE
8863             fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8864                     ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8865 #endif /* NOTSERVICE */
8866             osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8867                      ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8868
8869             if (reportSessionStartups) {
8870                 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8871             }
8872             
8873             lock_ObtainMutex(&vcp->mx);
8874             cm_Utf8ToUtf16(rname, -1, vcp->rname, lengthof(vcp->rname));
8875             vcp->flags |= flags;
8876             lock_ReleaseMutex(&vcp->mx);
8877
8878             /* Allocate slot in session arrays */
8879             /* Re-use dead session if possible, otherwise add one more */
8880             /* But don't look at session[0], it is reserved */
8881             lock_ObtainWrite(&smb_globalLock);
8882             for (session = 1; session < numSessions; session++) {
8883                 if (dead_sessions[session]) {
8884                     osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
8885                     dead_sessions[session] = FALSE;
8886                     break;
8887                 }
8888             }
8889             lock_ReleaseWrite(&smb_globalLock);
8890         } else {
8891             /* We are re-using an existing VC because the lsn and lana 
8892              * were re-used */
8893             session = vcp->session;
8894
8895             osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
8896
8897             /* Log session startup */
8898 #ifdef NOTSERVICE
8899             fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8900                     ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8901 #endif /* NOTSERVICE */
8902             osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8903                      ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8904
8905             if (reportSessionStartups) {
8906                 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8907             }
8908         }
8909
8910         if (session >= SESSION_MAX - 1  || numNCBs >= NCB_MAX - 1) {
8911             unsigned long code = CM_ERROR_ALLBUSY;
8912             smb_packet_t * outp = smb_GetPacket();
8913             unsigned char *outWctp;
8914             smb_t *smbp;
8915             
8916             smb_FormatResponsePacket(vcp, NULL, outp);
8917             outp->ncbp = ncbp;
8918
8919             if (vcp->flags & SMB_VCFLAG_STATUS32) {
8920                 unsigned long NTStatus;
8921                 smb_MapNTError(code, &NTStatus);
8922                 outWctp = outp->wctp;
8923                 smbp = (smb_t *) &outp->data;
8924                 *outWctp++ = 0;
8925                 *outWctp++ = 0;
8926                 *outWctp++ = 0;
8927                 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8928                 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8929                 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8930                 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8931                 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8932             } else {
8933                 unsigned short errCode;
8934                 unsigned char errClass;
8935                 smb_MapCoreError(code, vcp, &errCode, &errClass);
8936                 outWctp = outp->wctp;
8937                 smbp = (smb_t *) &outp->data;
8938                 *outWctp++ = 0;
8939                 *outWctp++ = 0;
8940                 *outWctp++ = 0;
8941                 smbp->errLow = (unsigned char) (errCode & 0xff);
8942                 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8943                 smbp->rcls = errClass;
8944             }
8945
8946             smb_SendPacket(vcp, outp);
8947             smb_FreePacket(outp);
8948
8949             lock_ObtainMutex(&vcp->mx);
8950             if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8951                 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8952                           vcp, vcp->usersp);
8953                 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8954                 lock_ReleaseMutex(&vcp->mx);
8955                 lock_ObtainWrite(&smb_globalLock);
8956                 dead_sessions[vcp->session] = TRUE;
8957                 lock_ReleaseWrite(&smb_globalLock);
8958                 smb_CleanupDeadVC(vcp);
8959             } else {
8960                 lock_ReleaseMutex(&vcp->mx);
8961             }
8962         } else {
8963             /* assert that we do not exceed the maximum number of sessions or NCBs.
8964              * we should probably want to wait for a session to be freed in case
8965              * we run out.
8966              */
8967             osi_assertx(session < SESSION_MAX - 1, "invalid session");
8968             osi_assertx(numNCBs < NCB_MAX - 1, "invalid numNCBs");   /* if we pass this test we can allocate one more */
8969
8970             lock_ObtainMutex(&vcp->mx);
8971             vcp->session   = session;
8972             lock_ReleaseMutex(&vcp->mx);
8973             lock_ObtainWrite(&smb_globalLock);
8974             LSNs[session]  = ncbp->ncb_lsn;
8975             lanas[session] = ncbp->ncb_lana_num;
8976             lock_ReleaseWrite(&smb_globalLock);
8977                 
8978             if (session == numSessions) {
8979                 /* Add new NCB for new session */
8980                 char eventName[MAX_PATH];
8981
8982                 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
8983
8984                 InitNCBslot(numNCBs);
8985                 lock_ObtainWrite(&smb_globalLock);
8986                 numNCBs++;
8987                 lock_ReleaseWrite(&smb_globalLock);
8988                 thrd_SetEvent(NCBavails[0]);
8989                 thrd_SetEvent(NCBevents[0]);
8990                 for (thread = 0; thread < smb_NumServerThreads; thread++)
8991                     thrd_SetEvent(NCBreturns[thread][0]);
8992                 /* Also add new session event */
8993                 sprintf(eventName, "SessionEvents[%d]", session);
8994                 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8995                 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8996                     osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8997                 lock_ObtainWrite(&smb_globalLock);
8998                 numSessions++;
8999                 lock_ReleaseWrite(&smb_globalLock);
9000                 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
9001                 thrd_SetEvent(SessionEvents[0]);
9002             } else {
9003                 thrd_SetEvent(SessionEvents[session]);
9004             }
9005         }
9006         smb_ReleaseVC(vcp);
9007
9008         /* unlock */
9009         lock_ReleaseMutex(&smb_ListenerLock);
9010     }   /* dispatch while loop */
9011
9012 exit_thread:
9013     smb_FreeNCB(ncbp);
9014     thrd_SetEvent(ListenerShutdown[lana]);
9015     return;
9016 }
9017
9018 static void
9019 smb_LanAdapterChangeThread(void *param)
9020 {
9021     /* 
9022      * Give the IPAddrDaemon thread a chance
9023      * to block before we trigger.
9024      */
9025     Sleep(30000);
9026     smb_LanAdapterChange(0);
9027 }
9028
9029 void smb_SetLanAdapterChangeDetected(void)
9030 {
9031     int lpid;
9032     thread_t phandle;
9033
9034     lock_ObtainMutex(&smb_StartedLock);
9035
9036     if (!powerStateSuspended) {
9037         phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_LanAdapterChangeThread,
9038                               NULL, 0, &lpid, "smb_LanAdapterChange");
9039         osi_assertx(phandle != NULL, "smb_LanAdapterChangeThread thread creation failure");
9040         thrd_CloseHandle(phandle);
9041     }
9042
9043     smb_LanAdapterChangeDetected = 1;
9044     lock_ReleaseMutex(&smb_StartedLock);
9045 }
9046
9047 void smb_LanAdapterChange(int locked) {
9048     lana_number_t lanaNum;
9049     BOOL          bGateway;
9050     char          NetbiosName[MAX_NB_NAME_LENGTH] = "";
9051     int           change = 0;
9052     LANA_ENUM     temp_list;           
9053     long          code;
9054     int           i;
9055
9056
9057     afsi_log("smb_LanAdapterChange");
9058
9059     if (!locked)
9060         lock_ObtainMutex(&smb_StartedLock);
9061     
9062     smb_LanAdapterChangeDetected = 0;
9063
9064     if (!powerStateSuspended && 
9065         SUCCEEDED(lana_GetUncServerNameEx(NetbiosName, &lanaNum, &bGateway, 
9066                                           LANA_NETBIOS_NAME_FULL)) &&
9067         lanaNum != LANA_INVALID && smb_LANadapter != lanaNum) {
9068         if ( isGateway != bGateway ||
9069              strcmp(cm_NetbiosName, NetbiosName) ) {
9070             change = 1;
9071         } else {
9072             NCB *ncbp = smb_GetNCB();
9073             ncbp->ncb_command = NCBENUM;
9074             ncbp->ncb_buffer = (PUCHAR)&temp_list;
9075             ncbp->ncb_length = sizeof(temp_list);
9076             code = Netbios(ncbp);
9077             if (code == 0) {
9078                 if (temp_list.length != lana_list.length)
9079                     change = 1;
9080                 else {
9081                     for (i=0; i<lana_list.length; i++) {
9082                         if ( temp_list.lana[i] != lana_list.lana[i] ) {
9083                             change = 1;
9084                             break;
9085                         }
9086                     }
9087                 }
9088             }
9089             smb_FreeNCB(ncbp);
9090         }
9091     } 
9092
9093     if (change) {
9094         afsi_log("Lan Adapter Change detected");
9095         smb_StopListeners(1);
9096         smb_RestartListeners(1);
9097     }
9098     if (!locked)
9099         lock_ReleaseMutex(&smb_StartedLock);
9100 }
9101
9102 /* initialize Netbios */
9103 int smb_NetbiosInit(int locked)
9104 {
9105     NCB *ncbp;
9106     int i, lana, code, l;
9107     char s[100];
9108     int delname_tried=0;
9109     int len;
9110     int lana_found = 0;
9111     lana_number_t lanaNum;
9112
9113     if (!locked)
9114         lock_ObtainMutex(&smb_StartedLock);
9115
9116     if (smb_ListenerState != SMB_LISTENER_UNINITIALIZED &&
9117          smb_ListenerState != SMB_LISTENER_STOPPED) {
9118
9119         if (!locked)
9120             lock_ReleaseMutex(&smb_StartedLock);
9121         return 0;
9122     }
9123     /* setup the NCB system */
9124     ncbp = smb_GetNCB();
9125
9126     /* Call lanahelper to get Netbios name, lan adapter number and gateway flag */
9127     if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
9128         smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
9129
9130         if (smb_LANadapter != LANA_INVALID)
9131             afsi_log("LAN adapter number %d", smb_LANadapter);
9132         else
9133             afsi_log("LAN adapter number not determined");
9134
9135         if (isGateway)
9136             afsi_log("Set for gateway service");
9137
9138         afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
9139     } else {
9140         /* something went horribly wrong.  We can't proceed without a netbios name */
9141         char buf[128];
9142         StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
9143         osi_panic(buf, __FILE__, __LINE__);
9144     }
9145
9146     /* remember the name */
9147     len = (int)strlen(cm_NetbiosName);
9148     if (smb_localNamep)
9149         free(smb_localNamep);
9150     smb_localNamep = malloc(len+1);
9151     strcpy(smb_localNamep, cm_NetbiosName);
9152     afsi_log("smb_localNamep is >%s<", smb_localNamep);
9153
9154     /* Also copy the value to the client character encoded string */
9155     cm_Utf8ToClientString(cm_NetbiosName, -1, cm_NetbiosNameC, MAX_NB_NAME_LENGTH);
9156
9157     if (smb_LANadapter == LANA_INVALID) {
9158         ncbp->ncb_command = NCBENUM;
9159         ncbp->ncb_buffer = (PUCHAR)&lana_list;
9160         ncbp->ncb_length = sizeof(lana_list);
9161         code = Netbios(ncbp);
9162         if (code != 0) {
9163             afsi_log("Netbios NCBENUM error code %d", code);
9164             osi_panic(s, __FILE__, __LINE__);
9165         }
9166     }
9167     else {
9168         lana_list.length = 1;
9169         lana_list.lana[0] = smb_LANadapter;
9170     }
9171           
9172     for (i = 0; i < lana_list.length; i++) {
9173         /* reset the adaptor: in Win32, this is required for every process, and
9174          * acts as an init call, not as a real hardware reset.
9175          */
9176         ncbp->ncb_command = NCBRESET;
9177         ncbp->ncb_callname[0] = 100;
9178         ncbp->ncb_callname[2] = 100;
9179         ncbp->ncb_lana_num = lana_list.lana[i];
9180         code = Netbios(ncbp);
9181         if (code == 0) 
9182             code = ncbp->ncb_retcode;
9183         if (code != 0) {
9184             afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
9185             lana_list.lana[i] = LANA_INVALID;  /* invalid lana */
9186         } else {
9187             afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
9188         }
9189     }
9190
9191     /* and declare our name so we can receive connections */
9192     memset(ncbp, 0, sizeof(*ncbp));
9193     len=lstrlen(smb_localNamep);
9194     memset(smb_sharename,' ',NCBNAMSZ);
9195     memcpy(smb_sharename,smb_localNamep,len);
9196     afsi_log("lana_list.length %d", lana_list.length);
9197
9198     /* Keep the name so we can unregister it later */
9199     for (l = 0; l < lana_list.length; l++) {
9200         lana = lana_list.lana[l];
9201
9202         ncbp->ncb_command = NCBADDNAME;
9203         ncbp->ncb_lana_num = lana;
9204         memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9205         code = Netbios(ncbp);
9206           
9207         afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
9208                  lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
9209         {
9210             char name[NCBNAMSZ+1];
9211             name[NCBNAMSZ]=0;
9212             memcpy(name,ncbp->ncb_name,NCBNAMSZ);
9213             afsi_log("Netbios NCBADDNAME added new name >%s<",name);
9214         }
9215
9216         if (code == 0) 
9217             code = ncbp->ncb_retcode;
9218
9219         if (code == 0) {
9220             afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
9221         }
9222         else {
9223             afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
9224             if (code == NRC_BRIDGE) {    /* invalid LANA num */
9225                 lana_list.lana[l] = LANA_INVALID;
9226                 continue;
9227             }
9228             else if (code == NRC_DUPNAME) {
9229                 afsi_log("Name already exists; try to delete it");
9230                 memset(ncbp, 0, sizeof(*ncbp));
9231                 ncbp->ncb_command = NCBDELNAME;
9232                 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9233                 ncbp->ncb_lana_num = lana;
9234                 code = Netbios(ncbp);
9235                 if (code == 0) 
9236                     code = ncbp->ncb_retcode;
9237                 else {
9238                     afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
9239                 }
9240                 if (code != 0 || delname_tried) {
9241                     lana_list.lana[l] = LANA_INVALID;
9242                 }
9243                 else if (code == 0) {
9244                     if (!delname_tried) {
9245                         lana--;
9246                         delname_tried = 1;
9247                         continue;
9248                     }
9249                 }
9250             }
9251             else {
9252                 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
9253                 lana_list.lana[l] = LANA_INVALID;  /* invalid lana */
9254             }
9255         }
9256         if (code == 0) {
9257             smb_LANadapter = lana;
9258             lana_found = 1;   /* at least one worked */
9259         }
9260     }
9261
9262     osi_assertx(lana_list.length >= 0, "empty lana list");
9263     if (!lana_found) {
9264         afsi_log("No valid LANA numbers found!");
9265         lana_list.length = 0;
9266         smb_LANadapter = LANA_INVALID;
9267         smb_ListenerState = SMB_LISTENER_STOPPED;
9268         cm_VolStatus_Network_Stopped(cm_NetbiosName
9269 #ifdef _WIN64
9270                                       ,cm_NetbiosName
9271 #endif
9272                                       );
9273     }
9274         
9275     /* we're done with the NCB now */
9276     smb_FreeNCB(ncbp);
9277
9278     afsi_log("smb_NetbiosInit smb_LANadapter=%d",smb_LANadapter);
9279     if (lana_list.length > 0)
9280         osi_assert(smb_LANadapter != LANA_INVALID);
9281
9282     if (!locked)
9283         lock_ReleaseMutex(&smb_StartedLock);
9284
9285     return (lana_list.length > 0 ? 1 : 0);
9286 }
9287
9288 void smb_StartListeners(int locked)
9289 {
9290     int i;
9291     int lpid;
9292     thread_t phandle;
9293
9294     if (!locked)
9295         lock_ObtainMutex(&smb_StartedLock);
9296
9297     if (smb_ListenerState == SMB_LISTENER_STARTED) {
9298         if (!locked)
9299             lock_ReleaseMutex(&smb_StartedLock);
9300         return;
9301     }
9302
9303     afsi_log("smb_StartListeners");
9304     smb_ListenerState = SMB_LISTENER_STARTED;
9305     cm_VolStatus_Network_Started(cm_NetbiosName
9306 #ifdef _WIN64
9307                                   , cm_NetbiosName
9308 #endif
9309                                   );
9310
9311     for (i = 0; i < lana_list.length; i++) {
9312         if (lana_list.lana[i] == LANA_INVALID) 
9313             continue;
9314         phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
9315                                (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
9316         osi_assertx(phandle != NULL, "smb_Listener thread creation failure");
9317         thrd_CloseHandle(phandle);
9318     }
9319     if (!locked)
9320         lock_ReleaseMutex(&smb_StartedLock);
9321 }
9322
9323 void smb_RestartListeners(int locked)
9324 {
9325     if (!locked)
9326         lock_ObtainMutex(&smb_StartedLock);
9327
9328     if (powerStateSuspended)
9329         afsi_log("smb_RestartListeners called while suspended");
9330
9331     if (!powerStateSuspended && smb_ListenerState != SMB_LISTENER_UNINITIALIZED) {
9332         if (smb_ListenerState == SMB_LISTENER_STOPPED) {
9333             if (smb_NetbiosInit(1))
9334                 smb_StartListeners(1);
9335         } else if (smb_LanAdapterChangeDetected) {
9336             smb_LanAdapterChange(1);
9337         }
9338     }
9339     if (!locked)
9340         lock_ReleaseMutex(&smb_StartedLock);
9341 }
9342
9343 void smb_StopListener(NCB *ncbp, int lana, int wait)
9344 {
9345     long code;
9346
9347     memset(ncbp, 0, sizeof(*ncbp));
9348     ncbp->ncb_command = NCBDELNAME;
9349     ncbp->ncb_lana_num = lana;
9350     memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9351     code = Netbios(ncbp);
9352           
9353     afsi_log("Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
9354               lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
9355
9356     /* and then reset the LANA; this will cause the listener threads to exit */
9357     ncbp->ncb_command = NCBRESET;
9358     ncbp->ncb_callname[0] = 100;
9359     ncbp->ncb_callname[2] = 100;
9360     ncbp->ncb_lana_num = lana;
9361     code = Netbios(ncbp);
9362     if (code == 0) 
9363         code = ncbp->ncb_retcode;
9364     if (code != 0) {
9365         afsi_log("Netbios NCBRESET lana %d error code %d", lana, code);
9366     } else {
9367         afsi_log("Netbios NCBRESET lana %d succeeded", lana);
9368     }
9369
9370     if (wait)
9371         thrd_WaitForSingleObject_Event(ListenerShutdown[lana], INFINITE);
9372 }
9373
9374 void smb_StopListeners(int locked)
9375 {
9376     NCB *ncbp;
9377     int lana, l;
9378
9379     if (!locked)
9380         lock_ObtainMutex(&smb_StartedLock);
9381
9382     if (smb_ListenerState == SMB_LISTENER_STOPPED) {
9383         if (!locked)
9384             lock_ReleaseMutex(&smb_StartedLock);
9385         return;
9386     }
9387
9388     afsi_log("smb_StopListeners");
9389     smb_ListenerState = SMB_LISTENER_STOPPED;
9390     cm_VolStatus_Network_Stopped(cm_NetbiosName
9391 #ifdef _WIN64
9392                                   , cm_NetbiosName
9393 #endif
9394                                   );
9395
9396     ncbp = smb_GetNCB();
9397
9398     /* Unregister the SMB name */
9399     for (l = 0; l < lana_list.length; l++) {
9400         lana = lana_list.lana[l];
9401
9402         if (lana != LANA_INVALID) {
9403             smb_StopListener(ncbp, lana, TRUE);
9404
9405             /* mark the adapter invalid */
9406             lana_list.lana[l] = LANA_INVALID;  /* invalid lana */
9407         }
9408     }
9409
9410     /* force a re-evaluation of the network adapters */
9411     lana_list.length = 0;
9412     smb_LANadapter = LANA_INVALID;
9413     smb_FreeNCB(ncbp);
9414     if (!locked)
9415         lock_ReleaseMutex(&smb_StartedLock);
9416 }
9417
9418 void smb_Init(osi_log_t *logp, int useV3,
9419               int nThreads
9420               , void *aMBfunc
9421   )
9422
9423 {
9424     thread_t phandle;
9425     int lpid;
9426     INT_PTR i;
9427     struct tm myTime;
9428     EVENT_HANDLE retHandle;
9429     char eventName[MAX_PATH];
9430     int startListeners = 0;
9431
9432     smb_TlsRequestSlot = TlsAlloc();
9433
9434     smb_MBfunc = aMBfunc;
9435
9436     smb_useV3 = useV3;
9437
9438     /* Initialize smb_localZero */
9439     myTime.tm_isdst = -1;               /* compute whether on DST or not */
9440     myTime.tm_year = 70;
9441     myTime.tm_mon = 0;
9442     myTime.tm_mday = 1;
9443     myTime.tm_hour = 0;
9444     myTime.tm_min = 0;
9445     myTime.tm_sec = 0;
9446     smb_localZero = mktime(&myTime);
9447
9448 #ifndef USE_NUMERIC_TIME_CONV
9449     /* Initialize kludge-GMT */
9450     smb_CalculateNowTZ();
9451 #endif /* USE_NUMERIC_TIME_CONV */
9452 #ifdef AFS_FREELANCE_CLIENT
9453     /* Make sure the root.afs volume has the correct time */
9454     cm_noteLocalMountPointChange();
9455 #endif
9456
9457     /* initialize the remote debugging log */
9458     smb_logp = logp;
9459         
9460     /* and the global lock */
9461     lock_InitializeRWLock(&smb_globalLock, "smb global lock", LOCK_HIERARCHY_SMB_GLOBAL);
9462     lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock", LOCK_HIERARCHY_SMB_RCT_GLOBAL);
9463
9464     /* Raw I/O data structures */
9465     lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock", LOCK_HIERARCHY_SMB_RAWBUF);
9466
9467     lock_InitializeMutex(&smb_ListenerLock, "smb listener lock", LOCK_HIERARCHY_SMB_LISTENER);
9468     lock_InitializeMutex(&smb_StartedLock, "smb started lock", LOCK_HIERARCHY_SMB_STARTED);
9469         
9470     /* 4 Raw I/O buffers */
9471     smb_RawBufs = calloc(65536,1);
9472     *((char **)smb_RawBufs) = NULL;
9473     for (i=0; i<3; i++) {
9474         char *rawBuf = calloc(65536,1);
9475         *((char **)rawBuf) = smb_RawBufs;
9476         smb_RawBufs = rawBuf;
9477     }
9478
9479     /* global free lists */
9480     smb_ncbFreeListp = NULL;
9481     smb_packetFreeListp = NULL;
9482
9483     lock_ObtainMutex(&smb_StartedLock);
9484     startListeners = smb_NetbiosInit(1);
9485
9486     /* Initialize listener and server structures */
9487     numVCs = 0;
9488     memset(dead_sessions, 0, sizeof(dead_sessions));
9489     sprintf(eventName, "SessionEvents[0]");
9490     SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9491     if ( GetLastError() == ERROR_ALREADY_EXISTS )
9492         afsi_log("Event Object Already Exists: %s", eventName);
9493     numSessions = 1;
9494     smb_NumServerThreads = nThreads;
9495     sprintf(eventName, "NCBavails[0]");
9496     NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9497     if ( GetLastError() == ERROR_ALREADY_EXISTS )
9498         afsi_log("Event Object Already Exists: %s", eventName);
9499     sprintf(eventName, "NCBevents[0]");
9500     NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9501     if ( GetLastError() == ERROR_ALREADY_EXISTS )
9502         afsi_log("Event Object Already Exists: %s", eventName);
9503     NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
9504     sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
9505     retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9506     if ( GetLastError() == ERROR_ALREADY_EXISTS )
9507         afsi_log("Event Object Already Exists: %s", eventName);
9508     for (i = 0; i < smb_NumServerThreads; i++) {
9509         NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
9510         NCBreturns[i][0] = retHandle;
9511     }
9512
9513     smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
9514     for (i = 0; i < smb_NumServerThreads; i++) {
9515         sprintf(eventName, "smb_ServerShutdown[%d]", i);
9516         smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9517         if ( GetLastError() == ERROR_ALREADY_EXISTS )
9518             afsi_log("Event Object Already Exists: %s", eventName);
9519         InitNCBslot((int)(i+1));
9520     }
9521     numNCBs = smb_NumServerThreads + 1;
9522
9523     /* Initialize dispatch table */
9524     memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
9525     /* Prepare the table for unknown operations */
9526     for(i=0; i<= SMB_NOPCODES; i++) {
9527         smb_dispatchTable[i].procp = smb_SendCoreBadOp;
9528     }
9529     /* Fill in the ones we do know */
9530     smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
9531     smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
9532     smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
9533     smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
9534     smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
9535     smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
9536     smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
9537     smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
9538     smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
9539     smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
9540     smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
9541     smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
9542     smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
9543     smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
9544     smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
9545     smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
9546     smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
9547     smb_dispatchTable[0x11].procp = smb_SendCoreBadOp;  /* process exit */
9548     smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
9549     smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
9550     /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
9551     smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9552     smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
9553     smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
9554     smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
9555     smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
9556     smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
9557     smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
9558     smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9559     smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
9560     smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9561     smb_dispatchTable[0x29].procp = smb_SendCoreBadOp;  /* copy file */
9562     smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
9563     /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
9564     smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9565     smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
9566     smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
9567     smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
9568     smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
9569     smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
9570     smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
9571     smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A;        /* both are same */
9572     smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9573     smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
9574     smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9575     smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
9576     smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
9577     smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
9578     smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
9579     smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
9580     smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
9581     smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
9582     smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
9583     smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
9584     smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
9585     smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
9586     smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
9587     smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
9588     smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
9589     smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
9590     smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
9591     smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
9592     smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
9593     smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
9594     smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
9595     smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9596     smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
9597     smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp;  /* Open Print File */
9598     smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp;  /* Write Print File */
9599     smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp;  /* Close Print File */
9600     smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp;  /* Get Print Queue */
9601     smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp;  /* Read Bulk */
9602     smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp;  /* Write Bulk */
9603     smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp;  /* Write Bulk Data */
9604
9605     /* setup tran 2 dispatch table */
9606     smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
9607     smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir;        /* FindFirst */
9608     smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir;        /* FindNext */
9609     smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
9610     smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
9611     smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
9612     smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
9613     smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
9614     smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
9615     smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
9616     smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
9617     smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
9618     smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
9619     smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
9620     smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
9621     smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
9622     smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
9623     smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
9624
9625     /* setup the rap dispatch table */
9626     memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
9627     smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
9628     smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
9629     smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
9630     smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
9631
9632     smb3_Init();
9633
9634     /* if we are doing SMB authentication we have register outselves as a logon process */
9635     if (smb_authType != SMB_AUTH_NONE) {
9636         NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
9637         LSA_STRING afsProcessName;
9638         LSA_OPERATIONAL_MODE dummy; /*junk*/
9639
9640         afsProcessName.Buffer = "OpenAFSClientDaemon";
9641         afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
9642         afsProcessName.MaximumLength = afsProcessName.Length + 1;
9643
9644         nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
9645
9646         if (nts == STATUS_SUCCESS) {
9647             LSA_STRING packageName;
9648             /* we are registered. Find out the security package id */
9649             packageName.Buffer = MSV1_0_PACKAGE_NAME;
9650             packageName.Length = (USHORT)strlen(packageName.Buffer);
9651             packageName.MaximumLength = packageName.Length + 1;
9652             nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
9653             if (nts == STATUS_SUCCESS) {
9654                 /* BEGIN 
9655                  * This code forces Windows to authenticate against the Logon Cache 
9656                  * first instead of attempting to authenticate against the Domain 
9657                  * Controller.  When the Windows logon cache is enabled this improves
9658                  * performance by removing the network access and works around a bug
9659                  * seen at sites which are using a MIT Kerberos principal to login
9660                  * to machines joined to a non-root domain in a multi-domain forest.
9661                  * MsV1_0SetProcessOption was added in Windows XP.
9662                  */
9663                 PVOID pResponse = NULL;
9664                 ULONG cbResponse = 0;
9665                 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
9666
9667                 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
9668                 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
9669                 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST; 
9670                 OptionsRequest.DisableOptions = FALSE;
9671
9672                 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
9673                                                     smb_lsaSecPackage,
9674                                                     &OptionsRequest,
9675                                                     sizeof(OptionsRequest),
9676                                                     &pResponse,
9677                                                     &cbResponse,
9678                                                     &ntsEx
9679                                                     );
9680
9681                 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
9682                     char message[AFSPATHMAX];
9683                     sprintf(message,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
9684                                        nts, ntsEx);
9685                     OutputDebugString(message);
9686                     afsi_log(message);
9687                 } else {
9688                     OutputDebugString("MsV1_0SetProcessOption success");
9689                     afsi_log("MsV1_0SetProcessOption success");
9690                 }
9691                 /* END - code from Larry */
9692
9693                 smb_lsaLogonOrigin.Buffer = "OpenAFS";
9694                 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
9695                 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
9696             } else {
9697                 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
9698
9699                 /* something went wrong. We report the error and revert back to no authentication
9700                 because we can't perform any auth requests without a successful lsa handle
9701                 or sec package id. */
9702                 afsi_log("Reverting to NO SMB AUTH");
9703                 smb_authType = SMB_AUTH_NONE;
9704             }
9705         } else {
9706             afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
9707
9708             /* something went wrong. We report the error and revert back to no authentication
9709             because we can't perform any auth requests without a successful lsa handle
9710             or sec package id. */
9711             afsi_log("Reverting to NO SMB AUTH");
9712             smb_authType = SMB_AUTH_NONE;
9713         }
9714
9715 #ifdef COMMENT
9716         /* Don't fallback to SMB_AUTH_NTLM.  Apparently, allowing SPNEGO to be used each
9717          * time prevents the failure of authentication when logged into Windows with an
9718          * external Kerberos principal mapped to a local account.
9719          */
9720         else if ( smb_authType == SMB_AUTH_EXTENDED) {
9721             /* Test to see if there is anything to negotiate.  If SPNEGO is not going to be used 
9722              * then the only option is NTLMSSP anyway; so just fallback. 
9723              */
9724             void * secBlob;
9725             int secBlobLength;
9726
9727             smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
9728             if (secBlobLength == 0) {
9729                 smb_authType = SMB_AUTH_NTLM;
9730                 afsi_log("Reverting to SMB AUTH NTLM");
9731             } else
9732                 free(secBlob);
9733         }
9734 #endif
9735     }
9736
9737     {
9738         DWORD bufsize;
9739         /* Now get ourselves a domain name. */
9740         /* For now we are using the local computer name as the domain name.
9741          * It is actually the domain for local logins, and we are acting as
9742          * a local SMB server. 
9743          */
9744         bufsize = lengthof(smb_ServerDomainName) - 1;
9745         GetComputerNameW(smb_ServerDomainName, &bufsize);
9746         smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
9747         afsi_log("Setting SMB server domain name to [%S]", smb_ServerDomainName);
9748     }
9749
9750     /* Start listeners, waiters, servers, and daemons */
9751     if (startListeners)
9752         smb_StartListeners(1);
9753
9754     phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
9755                           NULL, 0, &lpid, "smb_ClientWaiter");
9756     osi_assertx(phandle != NULL, "smb_ClientWaiter thread creation failure");
9757     thrd_CloseHandle(phandle);
9758
9759     phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
9760                           NULL, 0, &lpid, "smb_ServerWaiter");
9761     osi_assertx(phandle != NULL, "smb_ServerWaiter thread creation failure");
9762     thrd_CloseHandle(phandle);
9763
9764     for (i=0; i<smb_NumServerThreads; i++) {
9765         phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
9766                               (void *) i, 0, &lpid, "smb_Server");
9767         osi_assertx(phandle != NULL, "smb_Server thread creation failure");
9768         thrd_CloseHandle(phandle);
9769     }
9770
9771     phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
9772                           NULL, 0, &lpid, "smb_Daemon");
9773     osi_assertx(phandle != NULL, "smb_Daemon thread creation failure");
9774     thrd_CloseHandle(phandle);
9775
9776     phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
9777                           NULL, 0, &lpid, "smb_WaitingLocksDaemon");
9778     osi_assertx(phandle != NULL, "smb_WaitingLocksDaemon thread creation failure");
9779     thrd_CloseHandle(phandle);
9780
9781     lock_ReleaseMutex(&smb_StartedLock);
9782     return;
9783 }
9784
9785 void smb_Shutdown(void)
9786 {
9787     NCB *ncbp;
9788     long code = 0;
9789     afs_uint32 i;
9790     smb_vc_t *vcp;
9791
9792     /*fprintf(stderr, "Entering smb_Shutdown\n");*/
9793         
9794     /* setup the NCB system */
9795     ncbp = smb_GetNCB();
9796
9797     /* Block new sessions by setting shutdown flag */
9798     smbShutdownFlag = 1;
9799
9800     /* Hang up all sessions */
9801     memset((char *)ncbp, 0, sizeof(NCB));
9802     for (i = 1; i < numSessions; i++)
9803     {
9804         if (dead_sessions[i])
9805             continue;
9806       
9807         /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
9808         ncbp->ncb_command = NCBHANGUP;
9809         ncbp->ncb_lana_num = lanas[i];  /*smb_LANadapter;*/
9810         ncbp->ncb_lsn = (UCHAR)LSNs[i];
9811         code = Netbios(ncbp);
9812         /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
9813         if (code == 0) code = ncbp->ncb_retcode;
9814         if (code != 0) {
9815             osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
9816             fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
9817         }
9818     }
9819
9820     /* Trigger the shutdown of all SMB threads */                                
9821     for (i = 0; i < smb_NumServerThreads; i++)                                   
9822         thrd_SetEvent(NCBreturns[i][0]);                                         
9823                                                                                  
9824     thrd_SetEvent(NCBevents[0]);                                                 
9825     thrd_SetEvent(SessionEvents[0]);                                             
9826     thrd_SetEvent(NCBavails[0]);                                                 
9827                                                                                  
9828     for (i = 0;i < smb_NumServerThreads; i++) {                                  
9829         DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500); 
9830         if (code == WAIT_OBJECT_0) {                                             
9831             continue;                                                            
9832         } else {                                                                 
9833             afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);      
9834             thrd_SetEvent(NCBreturns[i--][0]);                                   
9835         }                                                                        
9836     }                                                                            
9837
9838     /* Delete Netbios name */
9839     memset((char *)ncbp, 0, sizeof(NCB));
9840     for (i = 0; i < lana_list.length; i++) {
9841         if (lana_list.lana[i] == LANA_INVALID) continue;
9842         ncbp->ncb_command = NCBDELNAME;
9843         ncbp->ncb_lana_num = lana_list.lana[i];
9844         memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9845         code = Netbios(ncbp);
9846         if (code == 0) 
9847             code = ncbp->ncb_retcode;
9848         if (code != 0) {
9849             fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
9850                      ncbp->ncb_lana_num, code);
9851         }       
9852         fflush(stderr);
9853     }
9854
9855     /* Release the reference counts held by the VCs */
9856     lock_ObtainWrite(&smb_rctLock);
9857     for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) 
9858     {
9859         smb_fid_t *fidp;
9860         smb_tid_t *tidp;
9861      
9862         if (vcp->magic != SMB_VC_MAGIC)
9863             osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp", 
9864                        __FILE__, __LINE__);
9865
9866         for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9867         {
9868             if (fidp->scp != NULL) {
9869                 cm_scache_t * scp;
9870
9871                 lock_ReleaseWrite(&smb_rctLock);
9872                 lock_ObtainMutex(&fidp->mx);
9873                 if (fidp->scp != NULL) {
9874                     scp = fidp->scp;
9875                     fidp->scp = NULL;
9876                     lock_ObtainWrite(&scp->rw);
9877                     scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
9878                     lock_ReleaseWrite(&scp->rw);
9879                     osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
9880                     cm_ReleaseSCache(scp);
9881                 }
9882                 lock_ReleaseMutex(&fidp->mx);
9883                 lock_ObtainWrite(&smb_rctLock);
9884             }
9885         }
9886
9887         for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
9888             if (tidp->vcp)
9889                 smb_ReleaseVCNoLock(tidp->vcp);
9890             if (tidp->userp) {
9891                 cm_user_t *userp = tidp->userp;
9892                 tidp->userp = NULL;
9893                 cm_ReleaseUser(userp);
9894             }
9895         }
9896     }
9897     lock_ReleaseWrite(&smb_rctLock);
9898     smb_FreeNCB(ncbp);
9899     TlsFree(smb_TlsRequestSlot);
9900 }
9901
9902 /* Get the UNC \\<servername>\<sharename> prefix. */
9903 char *smb_GetSharename()
9904 {
9905     char *name;
9906     size_t len;
9907
9908     /* Make sure we have been properly initialized. */
9909     if (smb_localNamep == NULL)
9910         return NULL;
9911
9912     /* Allocate space for \\<servername>\<sharename>, plus the
9913      * terminator.
9914      */
9915     len = (strlen(smb_localNamep) + strlen("ALL") + 4) * sizeof(char);
9916     name = malloc(len);
9917     snprintf(name, len, "\\\\%s\\%s", smb_localNamep, "ALL");
9918     return name;
9919 }
9920
9921
9922 #ifdef LOG_PACKET
9923 void smb_LogPacket(smb_packet_t *packet)
9924 {
9925     BYTE *vp, *cp;
9926     smb_t * smbp;
9927     unsigned length, paramlen, datalen, i, j;
9928     char buf[81];
9929     char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
9930
9931     if (!packet) return;
9932
9933     osi_Log0(smb_logp, "*** SMB packet dump ***");
9934
9935     smbp = (smb_t *) packet->data;
9936     vp = (BYTE *) packet->data;
9937
9938     paramlen = smbp->wct * 2;
9939     datalen = *((WORD *) (smbp->vdata + paramlen));
9940     length = sizeof(*smbp) + paramlen + 1 + datalen;
9941
9942     for (i=0;i < length; i+=16)
9943     {
9944         memset( buf, ' ', 80 );
9945         buf[80] = 0;
9946
9947         itoa( i, buf, 16 );
9948
9949         buf[strlen(buf)] = ' ';
9950
9951         cp = (BYTE*) buf + 7;
9952
9953         for (j=0;j < 16 && (i+j)<length; j++)
9954         {
9955             *(cp++) = hex[vp[i+j] >> 4];
9956             *(cp++) = hex[vp[i+j] & 0xf];
9957             *(cp++) = ' ';
9958
9959             if (j==7)
9960             {
9961                 *(cp++) = '-';
9962                 *(cp++) = ' ';
9963             }
9964         }
9965
9966         for (j=0;j < 16 && (i+j)<length;j++)
9967         {
9968             *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
9969             if (j==7)
9970             {
9971                 *(cp++) = ' ';
9972                 *(cp++) = '-';
9973                 *(cp++) = ' ';
9974             }
9975         }
9976
9977         *cp = 0;
9978
9979         osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
9980     }
9981
9982     osi_Log0(smb_logp, "*** End SMB packet dump ***");
9983 }
9984 #endif /* LOG_PACKET */
9985
9986
9987 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
9988 {
9989     int zilch;
9990     char output[4196];
9991   
9992     smb_vc_t *vcp;
9993     smb_username_t *unp;
9994     smb_waitingLockRequest_t *wlrp;
9995
9996     if (lock)
9997         lock_ObtainRead(&smb_rctLock);
9998   
9999     sprintf(output, "begin dumping smb_username_t\r\n");
10000     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10001     for (unp = usernamesp; unp; unp=unp->nextp) 
10002     {
10003         cm_ucell_t *ucellp;
10004
10005         sprintf(output, "%s -- smb_unp=0x%p, refCount=%d, cm_userp=0x%p, flags=0x%x, logoff=%u, name=%S, machine=%S\r\n", 
10006                 cookie, unp, unp->refCount, unp->userp, unp->flags, unp->last_logoff_t,
10007                 unp->name ? unp->name : _C("NULL"), 
10008                 unp->machine ? unp->machine : _C("NULL"));
10009         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10010
10011         sprintf(output, "  begin dumping cm_ucell_t\r\n");
10012         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10013
10014         for ( ucellp = unp->userp->cellInfop; ucellp; ucellp = ucellp->nextp ) {
10015             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", 
10016                      cookie, ucellp, ucellp->cellp, ucellp->flags, ucellp->ticketLen, ucellp->kvno, 
10017                      ucellp->expirationTime, ucellp->gen, 
10018                      ucellp->userName,
10019                      ucellp->cellp->name);
10020             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10021         }
10022
10023         sprintf(output, "  done dumping cm_ucell_t\r\n");
10024         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10025
10026     }
10027     sprintf(output, "done dumping smb_username_t\r\n");
10028     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10029
10030
10031     sprintf(output, "begin dumping smb_waitingLockRequest_t\r\n");
10032     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10033
10034
10035     for ( wlrp = smb_allWaitingLocks; wlrp; wlrp = (smb_waitingLockRequest_t *) osi_QNext(&wlrp->q)) {
10036         smb_waitingLock_t *lockp;
10037
10038         sprintf(output, "%s wlrp=0x%p vcp=0x%p, scp=0x%p, type=0x%x, start_t=0x%I64u msTimeout=0x%x\r\n",
10039                  cookie, wlrp, wlrp->vcp, wlrp->scp, wlrp->lockType, wlrp->start_t, wlrp->msTimeout);
10040         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10041       
10042         sprintf(output, "  begin dumping smb_waitingLock_t\r\n");
10043         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10044         for (lockp = wlrp->locks; lockp; lockp = (smb_waitingLock_t *) osi_QNext(&lockp->q)) {
10045             sprintf(output, "  %s -- waitlockp=0x%p lockp=0x%p key=0x%I64x offset=0x%I64x length=0x%I64x state=0x%x\r\n", 
10046                     cookie, lockp, lockp->lockp, lockp->key, lockp->LOffset.QuadPart, lockp->LLength.QuadPart, lockp->state);
10047             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10048         }
10049         sprintf(output, "  done dumping smb_waitingLock_t\r\n");
10050         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10051     }
10052
10053     sprintf(output, "done dumping smb_waitingLockRequest_t\r\n");
10054     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10055
10056     sprintf(output, "begin dumping smb_vc_t\r\n");
10057     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10058
10059     for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) 
10060     {
10061         smb_fid_t *fidp;
10062         smb_tid_t *tidp;
10063         smb_user_t *userp;
10064       
10065         sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
10066                  cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
10067         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10068       
10069         sprintf(output, "  begin dumping smb_user_t\r\n");
10070         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10071         for (userp = vcp->usersp; userp; userp = userp->nextp) {
10072             sprintf(output, "  %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n", 
10073                     cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
10074             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10075         }
10076         sprintf(output, "  done dumping smb_user_t\r\n");
10077         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10078
10079         sprintf(output, "  begin dumping smb_tid_t\r\n");
10080         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10081         for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10082             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", 
10083                     cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
10084                     tidp->pathname ? tidp->pathname : _C("NULL"));
10085             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10086         }
10087         sprintf(output, "  done dumping smb_tid_t\r\n");
10088         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10089
10090         sprintf(output, "  begin dumping smb_fid_t\r\n");
10091         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10092
10093         for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10094         {
10095             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", 
10096                     cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
10097                     fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"), 
10098                     fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
10099             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10100         }
10101       
10102         sprintf(output, "  done dumping smb_fid_t\r\n");
10103         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10104     }
10105
10106     sprintf(output, "done dumping smb_vc_t\r\n");
10107     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10108   
10109     sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
10110     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10111
10112     for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp) 
10113     {
10114         smb_fid_t *fidp;
10115         smb_tid_t *tidp;
10116         smb_user_t *userp;
10117
10118         sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
10119                 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
10120         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10121       
10122         sprintf(output, "  begin dumping smb_user_t\r\n");
10123         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10124         for (userp = vcp->usersp; userp; userp = userp->nextp) {
10125             sprintf(output, "  %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n", 
10126                     cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
10127             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10128         }
10129         sprintf(output, "  done dumping smb_user_t\r\n");
10130         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10131
10132         sprintf(output, "  begin dumping smb_tid_t\r\n");
10133         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10134         for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10135             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", 
10136                     cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
10137                     tidp->pathname ? tidp->pathname : _C("NULL"));
10138             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10139         }
10140         sprintf(output, "  done dumping smb_tid_t\r\n");
10141         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10142
10143         sprintf(output, "  begin dumping smb_fid_t\r\n");
10144         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10145
10146         for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10147         {
10148             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", 
10149                     cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
10150                     fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"), 
10151                     fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
10152             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10153         }
10154       
10155         sprintf(output, "  done dumping smb_fid_t\r\n");
10156         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10157     }
10158
10159     sprintf(output, "done dumping DEAD smb_vc_t\r\n");
10160     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10161   
10162     if (lock)
10163         lock_ReleaseRead(&smb_rctLock);
10164     return 0;
10165 }
10166
10167 long smb_IsNetworkStarted(void)
10168 {
10169     long rc;
10170     lock_ObtainWrite(&smb_globalLock);
10171     rc = (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);
10172     lock_ReleaseWrite(&smb_globalLock);
10173     return rc;
10174 }