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