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