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