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