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