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