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