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