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