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