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