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