windows-magic-share-names-20070613
[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);
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_DFSLINK ||
4241                     fileType == CM_SCACHETYPE_INVALID)
4242                     osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
4243                 goto nextEntry;
4244             }
4245
4246             *op++ = resByte;
4247             memcpy(op, mask, 11); op += 11;
4248             *op++ = (char) dsp->cookie; /* they say it must be non-zero */
4249             *op++ = (char)(nextEntryCookie & 0xff);
4250             *op++ = (char)((nextEntryCookie>>8) & 0xff);
4251             *op++ = (char)((nextEntryCookie>>16) & 0xff);
4252             *op++ = (char)((nextEntryCookie>>24) & 0xff);
4253             memcpy(op, &clientCookie, 4); op += 4;
4254
4255             /* now we emit the attribute.  This is sort of tricky,
4256              * since we need to really stat the file to find out
4257              * what type of entry we've got.  Right now, we're
4258              * copying out data from a buffer, while holding the
4259              * scp locked, so it isn't really convenient to stat
4260              * something now.  We'll put in a place holder now,
4261              * and make a second pass before returning this to get
4262              * the real attributes.  So, we just skip the data for
4263              * now, and adjust it later.  We allocate a patch
4264              * record to make it easy to find this point later.
4265              * The replay will happen at a time when it is safe to
4266              * unlock the directory.
4267              */
4268             curPatchp = malloc(sizeof(*curPatchp));
4269             osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
4270             curPatchp->dptr = op;
4271             curPatchp->fid.cell = scp->fid.cell;
4272             curPatchp->fid.volume = scp->fid.volume;
4273             curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4274             curPatchp->fid.unique = ntohl(dep->fid.unique);
4275
4276             /* do hidden attribute here since name won't be around when applying
4277              * dir list patches
4278              */
4279
4280             if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
4281                 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4282             else
4283                 curPatchp->flags = 0;
4284
4285             op += 9;    /* skip attr, time, date and size */
4286
4287             /* zero out name area.  The spec says to pad with
4288              * spaces, but Samba doesn't, and neither do we.
4289              */
4290             memset(op, 0, 13);
4291
4292             /* finally, we get to copy out the name; we know that
4293              * it fits in 8.3 or the pattern wouldn't match, but it
4294              * never hurts to be sure.
4295              */
4296             strncpy(op, actualName, 13);
4297             if (smb_StoreAnsiFilenames)
4298                 CharToOem(op, op);
4299
4300             /* Uppercase if requested by client */
4301             if (!KNOWS_LONG_NAMES(inp))
4302                 _strupr(op);
4303
4304             op += 13;
4305
4306             /* now, adjust the # of entries copied */
4307             returnedNames++;
4308         }       /* if we're including this name */
4309
4310       nextEntry:
4311         /* and adjust curOffset to be where the new cookie is */
4312         thyper.HighPart = 0;
4313         thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4314         curOffset = LargeIntegerAdd(thyper, curOffset);
4315     }           /* while copying data for dir listing */
4316
4317     /* release the mutex */
4318     lock_ReleaseMutex(&scp->mx);
4319     if (bufferp) {
4320         buf_Release(bufferp);
4321         bufferp = NULL;
4322     }
4323
4324     /* apply and free last set of patches; if not doing a star match, this
4325      * will be empty, but better safe (and freeing everything) than sorry.
4326      */
4327     smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
4328
4329     /* special return code for unsuccessful search */
4330     if (code == 0 && dataLength < 21 && returnedNames == 0)
4331         code = CM_ERROR_NOFILES;
4332
4333     osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
4334              returnedNames, code);
4335
4336     if (code != 0) {
4337         smb_DeleteDirSearch(dsp);
4338         smb_ReleaseDirSearch(dsp);
4339         cm_ReleaseSCache(scp);
4340         cm_ReleaseUser(userp);
4341         return code;
4342     }
4343
4344     /* finalize the output buffer */
4345     smb_SetSMBParm(outp, 0, returnedNames);
4346     temp = (long) (op - origOp);
4347     smb_SetSMBDataLength(outp, temp);
4348
4349     /* the data area is a variable block, which has a 5 (already there)
4350      * followed by the length of the # of data bytes.  We now know this to
4351      * be "temp," although that includes the 3 bytes of vbl block header.
4352      * Deduct for them and fill in the length field.
4353      */
4354     temp -= 3;          /* deduct vbl block info */
4355     osi_assert(temp == (43 * returnedNames));
4356     origOp[1] = (char)(temp & 0xff);
4357     origOp[2] = (char)((temp>>8) & 0xff);
4358     if (returnedNames == 0) 
4359         smb_DeleteDirSearch(dsp);
4360     smb_ReleaseDirSearch(dsp);
4361     cm_ReleaseSCache(scp);
4362     cm_ReleaseUser(userp);
4363     return code;
4364 }       
4365
4366 /* verify that this is a valid path to a directory.  I don't know why they
4367  * don't use the get file attributes call.
4368  */
4369 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4370 {
4371     char *pathp;
4372     long code = 0;
4373     cm_scache_t *rootScp;
4374     cm_scache_t *newScp;
4375     cm_user_t *userp;
4376     unsigned int attrs;
4377     int caseFold;
4378     char *tidPathp;
4379     cm_req_t req;
4380
4381     cm_InitReq(&req);
4382
4383     pathp = smb_GetSMBData(inp, NULL);
4384     pathp = smb_ParseASCIIBlock(pathp, NULL);
4385     if (!pathp)
4386         return CM_ERROR_BADFD;
4387     if (smb_StoreAnsiFilenames)
4388         OemToChar(pathp,pathp);
4389     osi_Log1(smb_logp, "SMB receive check path %s",
4390              osi_LogSaveString(smb_logp, pathp));
4391         
4392     rootScp = cm_data.rootSCachep;
4393         
4394     userp = smb_GetUserFromVCP(vcp, inp);
4395
4396     caseFold = CM_FLAG_CASEFOLD;
4397
4398     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4399     if (code) {
4400         cm_ReleaseUser(userp);
4401         return CM_ERROR_NOSUCHPATH;
4402     }
4403     code = cm_NameI(rootScp, pathp,
4404                     caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
4405                     userp, tidPathp, &req, &newScp);
4406
4407     if (code) {
4408         cm_ReleaseUser(userp);
4409         return code;
4410     }
4411         
4412 #ifdef DFS_SUPPORT
4413     if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4414         cm_ReleaseSCache(newScp);
4415         cm_ReleaseUser(userp);
4416         if ( WANTS_DFS_PATHNAMES(inp) )
4417             return CM_ERROR_PATH_NOT_COVERED;
4418         else
4419             return CM_ERROR_BADSHARENAME;
4420     }
4421 #endif /* DFS_SUPPORT */
4422
4423     /* now lock the vnode with a callback; returns with newScp locked */
4424     lock_ObtainMutex(&newScp->mx);
4425     code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
4426                      CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4427     if (code) {
4428         if (code != CM_ERROR_NOACCESS) {
4429             lock_ReleaseMutex(&newScp->mx);
4430             cm_ReleaseSCache(newScp);
4431             cm_ReleaseUser(userp);
4432             return code;
4433         }
4434     } else {
4435         cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4436     }
4437
4438     attrs = smb_Attributes(newScp);
4439
4440     if (!(attrs & SMB_ATTR_DIRECTORY))
4441         code = CM_ERROR_NOTDIR;
4442
4443     lock_ReleaseMutex(&newScp->mx);
4444
4445     cm_ReleaseSCache(newScp);
4446     cm_ReleaseUser(userp);
4447     return code;
4448 }       
4449
4450 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4451 {
4452     char *pathp;
4453     long code = 0;
4454     cm_scache_t *rootScp;
4455     unsigned short attribute;
4456     cm_attr_t attr;
4457     cm_scache_t *newScp;
4458     afs_uint32 dosTime;
4459     cm_user_t *userp;
4460     int caseFold;
4461     char *tidPathp;
4462     cm_req_t req;
4463
4464     cm_InitReq(&req);
4465
4466     /* decode basic attributes we're passed */
4467     attribute = smb_GetSMBParm(inp, 0);
4468     dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4469
4470     pathp = smb_GetSMBData(inp, NULL);
4471     pathp = smb_ParseASCIIBlock(pathp, NULL);
4472     if (!pathp)
4473         return CM_ERROR_BADSMB;
4474     if (smb_StoreAnsiFilenames)
4475         OemToChar(pathp,pathp);
4476                
4477     osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
4478              dosTime, attribute);
4479
4480     rootScp = cm_data.rootSCachep;
4481         
4482     userp = smb_GetUserFromVCP(vcp, inp);
4483
4484     caseFold = CM_FLAG_CASEFOLD;
4485
4486     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4487     if (code) {
4488         cm_ReleaseUser(userp);
4489         return CM_ERROR_NOSUCHFILE;
4490     }
4491     code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4492                     tidPathp, &req, &newScp);
4493
4494     if (code) {
4495         cm_ReleaseUser(userp);
4496         return code;
4497     }
4498
4499 #ifdef DFS_SUPPORT
4500     if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4501         cm_ReleaseSCache(newScp);
4502         cm_ReleaseUser(userp);
4503         if ( WANTS_DFS_PATHNAMES(inp) )
4504             return CM_ERROR_PATH_NOT_COVERED;
4505         else
4506             return CM_ERROR_BADSHARENAME;
4507     }
4508 #endif /* DFS_SUPPORT */
4509
4510     /* now lock the vnode with a callback; returns with newScp locked; we
4511      * need the current status to determine what the new status is, in some
4512      * cases.
4513      */
4514     lock_ObtainMutex(&newScp->mx);
4515     code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4516                      CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4517     if (code) {
4518         lock_ReleaseMutex(&newScp->mx);
4519         cm_ReleaseSCache(newScp);
4520         cm_ReleaseUser(userp);
4521         return code;
4522     }
4523
4524     cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4525
4526     /* Check for RO volume */
4527     if (newScp->flags & CM_SCACHEFLAG_RO) {
4528         lock_ReleaseMutex(&newScp->mx);
4529         cm_ReleaseSCache(newScp);
4530         cm_ReleaseUser(userp);
4531         return CM_ERROR_READONLY;
4532     }
4533
4534     /* prepare for setattr call */
4535     attr.mask = 0;
4536     if (dosTime != 0) {
4537         attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
4538         smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
4539     }
4540     if ((newScp->unixModeBits & 0222) && (attribute & SMB_ATTR_READONLY) != 0) {
4541         /* we're told to make a writable file read-only */
4542         attr.unixModeBits = newScp->unixModeBits & ~0222;
4543         attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4544     }
4545     else if ((newScp->unixModeBits & 0222) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
4546         /* we're told to make a read-only file writable */
4547         attr.unixModeBits = newScp->unixModeBits | 0222;
4548         attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4549     }
4550     lock_ReleaseMutex(&newScp->mx);
4551
4552     /* now call setattr */
4553     if (attr.mask)
4554         code = cm_SetAttr(newScp, &attr, userp, &req);
4555     else
4556         code = 0;
4557         
4558     cm_ReleaseSCache(newScp);
4559     cm_ReleaseUser(userp);
4560
4561     return code;
4562 }
4563
4564 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4565 {
4566     char *pathp;
4567     long code = 0;
4568     cm_scache_t *rootScp;
4569     cm_scache_t *newScp, *dscp;
4570     afs_uint32 dosTime;
4571     int attrs;
4572     cm_user_t *userp;
4573     int caseFold;
4574     char *tidPathp;
4575     cm_space_t *spacep;
4576     char *lastComp;
4577     cm_req_t req;
4578
4579     cm_InitReq(&req);
4580
4581     pathp = smb_GetSMBData(inp, NULL);
4582     pathp = smb_ParseASCIIBlock(pathp, NULL);
4583     if (!pathp)
4584         return CM_ERROR_BADSMB;
4585         
4586     if (*pathp == 0)            /* null path */
4587         pathp = "\\";
4588     else
4589         if (smb_StoreAnsiFilenames)
4590             OemToChar(pathp,pathp);
4591
4592     osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
4593              osi_LogSaveString(smb_logp, pathp));
4594
4595     rootScp = cm_data.rootSCachep;
4596         
4597     userp = smb_GetUserFromVCP(vcp, inp);
4598
4599     /* we shouldn't need this for V3 requests, but we seem to */
4600     caseFold = CM_FLAG_CASEFOLD;
4601
4602     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4603     if (code) {
4604         cm_ReleaseUser(userp);
4605         return CM_ERROR_NOSUCHFILE;
4606     }
4607
4608     /*
4609      * XXX Strange hack XXX
4610      *
4611      * As of Patch 5 (16 July 97), we are having the following problem:
4612      * In NT Explorer 4.0, whenever we click on a directory, AFS gets
4613      * requests to look up "desktop.ini" in all the subdirectories.
4614      * This can cause zillions of timeouts looking up non-existent cells
4615      * and volumes, especially in the top-level directory.
4616      *
4617      * We have not found any way to avoid this or work around it except
4618      * to explicitly ignore the requests for mount points that haven't
4619      * yet been evaluated and for directories that haven't yet been
4620      * fetched.
4621      *
4622      * We should modify this hack to provide a fake desktop.ini file
4623      * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
4624      */
4625     spacep = inp->spacep;
4626     smb_StripLastComponent(spacep->data, &lastComp, pathp);
4627 #ifndef SPECIAL_FOLDERS
4628     if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
4629         code = cm_NameI(rootScp, spacep->data,
4630                         caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
4631                         userp, tidPathp, &req, &dscp);
4632         if (code == 0) {
4633 #ifdef DFS_SUPPORT
4634             if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4635                 if ( WANTS_DFS_PATHNAMES(inp) )
4636                     return CM_ERROR_PATH_NOT_COVERED;
4637                 else
4638                     return CM_ERROR_BADSHARENAME;
4639             } else
4640 #endif /* DFS_SUPPORT */
4641             if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
4642                 code = CM_ERROR_NOSUCHFILE;
4643             else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
4644                 cm_buf_t *bp = buf_Find(dscp, &hzero);
4645                 if (bp) {
4646                     buf_Release(bp);
4647                     bp = NULL;
4648                 } else
4649                     code = CM_ERROR_NOSUCHFILE;
4650             }
4651             cm_ReleaseSCache(dscp);
4652             if (code) {
4653                 cm_ReleaseUser(userp);
4654                 return code;
4655             }
4656         }
4657     }
4658 #endif /* SPECIAL_FOLDERS */
4659
4660     code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4661                     tidPathp, &req, &newScp);
4662     if (code) {
4663         cm_ReleaseUser(userp);
4664         return code;
4665     }
4666         
4667 #ifdef DFS_SUPPORT
4668     if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4669         cm_ReleaseSCache(newScp);
4670         cm_ReleaseUser(userp);
4671         if ( WANTS_DFS_PATHNAMES(inp) )
4672             return CM_ERROR_PATH_NOT_COVERED;
4673         else
4674             return CM_ERROR_BADSHARENAME;
4675     }
4676 #endif /* DFS_SUPPORT */
4677
4678     /* now lock the vnode with a callback; returns with newScp locked */
4679     lock_ObtainMutex(&newScp->mx);
4680     code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4681                      CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4682     if (code) {
4683         lock_ReleaseMutex(&newScp->mx);
4684         cm_ReleaseSCache(newScp);
4685         cm_ReleaseUser(userp);
4686         return code;
4687     }
4688
4689     cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4690
4691 #ifdef undef
4692     /* use smb_Attributes instead.   Also the fact that a file is 
4693      * in a readonly volume doesn't mean it shojuld be marked as RO 
4694      */
4695     if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
4696         newScp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
4697         newScp->fileType == CM_SCACHETYPE_INVALID)
4698         attrs = SMB_ATTR_DIRECTORY;
4699     else
4700         attrs = 0;
4701     if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
4702         attrs |= SMB_ATTR_READONLY;     /* turn on read-only flag */
4703 #else
4704     attrs = smb_Attributes(newScp);
4705 #endif
4706
4707     smb_SetSMBParm(outp, 0, attrs);
4708         
4709     smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
4710     smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
4711     smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
4712     smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
4713     smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
4714     smb_SetSMBParm(outp, 5, 0);
4715     smb_SetSMBParm(outp, 6, 0);
4716     smb_SetSMBParm(outp, 7, 0);
4717     smb_SetSMBParm(outp, 8, 0);
4718     smb_SetSMBParm(outp, 9, 0);
4719     smb_SetSMBDataLength(outp, 0);
4720     lock_ReleaseMutex(&newScp->mx);
4721
4722     cm_ReleaseSCache(newScp);
4723     cm_ReleaseUser(userp);
4724
4725     return 0;
4726 }       
4727
4728 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4729 {
4730     smb_tid_t *tidp;
4731         
4732     osi_Log0(smb_logp, "SMB receive tree disconnect");
4733
4734     /* find the tree and free it */
4735     tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
4736     if (tidp) {
4737         lock_ObtainWrite(&smb_rctLock);
4738         tidp->delete = 1;
4739         lock_ReleaseWrite(&smb_rctLock);
4740         smb_ReleaseTID(tidp);
4741     }
4742
4743     return 0;
4744 }
4745
4746 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4747 {
4748     smb_fid_t *fidp;
4749     char *pathp;
4750     char *lastNamep;
4751     int share;
4752     int attribute;
4753     long code = 0;
4754     cm_user_t *userp;
4755     cm_scache_t *scp;
4756     afs_uint32 dosTime;
4757     int caseFold;
4758     cm_space_t *spacep;
4759     char *tidPathp;
4760     cm_req_t req;
4761
4762     cm_InitReq(&req);
4763
4764     pathp = smb_GetSMBData(inp, NULL);
4765     pathp = smb_ParseASCIIBlock(pathp, NULL);
4766     if (smb_StoreAnsiFilenames)
4767         OemToChar(pathp,pathp);
4768         
4769     osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
4770
4771 #ifdef DEBUG_VERBOSE
4772     {
4773         char *hexpath;
4774
4775         hexpath = osi_HexifyString( pathp );
4776         DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
4777         free(hexpath);
4778     }
4779 #endif
4780
4781     share = smb_GetSMBParm(inp, 0);
4782     attribute = smb_GetSMBParm(inp, 1);
4783
4784     spacep = inp->spacep;
4785     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4786     if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4787         /* special case magic file name for receiving IOCTL requests
4788          * (since IOCTL calls themselves aren't getting through).
4789          */
4790         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4791         smb_SetupIoctlFid(fidp, spacep);
4792         smb_SetSMBParm(outp, 0, fidp->fid);
4793         smb_SetSMBParm(outp, 1, 0);     /* attrs */
4794         smb_SetSMBParm(outp, 2, 0);     /* next 2 are DOS time */
4795         smb_SetSMBParm(outp, 3, 0);
4796         smb_SetSMBParm(outp, 4, 0);     /* next 2 are length */
4797         smb_SetSMBParm(outp, 5, 0x7fff);
4798         /* pass the open mode back */
4799         smb_SetSMBParm(outp, 6, (share & 0xf));
4800         smb_SetSMBDataLength(outp, 0);
4801         smb_ReleaseFID(fidp);
4802         return 0;
4803     }
4804
4805     userp = smb_GetUserFromVCP(vcp, inp);
4806
4807     caseFold = CM_FLAG_CASEFOLD;
4808
4809     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4810     if (code) {
4811         cm_ReleaseUser(userp);
4812         return CM_ERROR_NOSUCHPATH;
4813     }
4814     code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4815                     tidPathp, &req, &scp);
4816         
4817     if (code) {
4818         cm_ReleaseUser(userp);
4819         return code;
4820     }
4821
4822 #ifdef DFS_SUPPORT
4823     if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4824         cm_ReleaseSCache(scp);
4825         cm_ReleaseUser(userp);
4826         if ( WANTS_DFS_PATHNAMES(inp) )
4827             return CM_ERROR_PATH_NOT_COVERED;
4828         else
4829             return CM_ERROR_BADSHARENAME;
4830     }
4831 #endif /* DFS_SUPPORT */
4832
4833     code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
4834     if (code) {
4835         cm_ReleaseSCache(scp);
4836         cm_ReleaseUser(userp);
4837         return code;
4838     }
4839
4840     /* don't need callback to check file type, since file types never
4841      * change, and namei and cm_Lookup all stat the object at least once on
4842      * a successful return.
4843      */
4844     if (scp->fileType != CM_SCACHETYPE_FILE) {
4845         cm_ReleaseSCache(scp);
4846         cm_ReleaseUser(userp);
4847         return CM_ERROR_ISDIR;
4848     }
4849
4850     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4851     osi_assert(fidp);
4852
4853     /* save a pointer to the vnode */
4854     fidp->scp = scp;
4855     osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
4856     lock_ObtainMutex(&scp->mx);
4857     scp->flags |= CM_SCACHEFLAG_SMB_FID;
4858     lock_ReleaseMutex(&scp->mx);
4859
4860     /* and the user */
4861     cm_HoldUser(userp);
4862     fidp->userp = userp;
4863
4864     lock_ObtainMutex(&fidp->mx);
4865     if ((share & 0xf) == 0)
4866         fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
4867     else if ((share & 0xf) == 1)
4868         fidp->flags |= SMB_FID_OPENWRITE;
4869     else 
4870         fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
4871     lock_ReleaseMutex(&fidp->mx);
4872
4873     lock_ObtainMutex(&scp->mx);
4874     smb_SetSMBParm(outp, 0, fidp->fid);
4875     smb_SetSMBParm(outp, 1, smb_Attributes(scp));
4876     smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4877     smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
4878     smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
4879     smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
4880     smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
4881     /* pass the open mode back; XXXX add access checks */
4882     smb_SetSMBParm(outp, 6, (share & 0xf));
4883     smb_SetSMBDataLength(outp, 0);
4884     lock_ReleaseMutex(&scp->mx);
4885         
4886     /* notify open */
4887     cm_Open(scp, 0, userp);
4888
4889     /* send and free packet */
4890     smb_ReleaseFID(fidp);
4891     cm_ReleaseUser(userp);
4892     /* don't release scp, since we've squirreled away the pointer in the fid struct */
4893     return 0;
4894 }
4895
4896 typedef struct smb_unlinkRock {
4897     cm_scache_t *dscp;
4898     cm_user_t *userp;
4899     cm_req_t *reqp;
4900     smb_vc_t *vcp;
4901     char *maskp;                /* pointer to the star pattern */
4902     int flags;
4903     int any;
4904 } smb_unlinkRock_t;
4905
4906 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4907 {
4908     long code = 0;
4909     smb_unlinkRock_t *rockp;
4910     int caseFold;
4911     int match;
4912     char shortName[13];
4913     char *matchName;
4914         
4915     rockp = vrockp;
4916
4917     caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4918     if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4919         caseFold |= CM_FLAG_8DOT3;
4920
4921     matchName = dep->name;
4922     match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
4923     if (!match &&
4924          (rockp->flags & SMB_MASKFLAG_TILDE) &&
4925          !cm_Is8Dot3(dep->name)) {
4926         cm_Gen8Dot3Name(dep, shortName, NULL);
4927         matchName = shortName;
4928         /* 8.3 matches are always case insensitive */
4929         match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
4930     }
4931     if (match) {
4932         osi_Log1(smb_logp, "Unlinking %s",
4933                  osi_LogSaveString(smb_logp, matchName));
4934         code = cm_Unlink(dscp, dep->name, rockp->userp, rockp->reqp);
4935         if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4936             smb_NotifyChange(FILE_ACTION_REMOVED,
4937                              FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
4938                              dscp, dep->name, NULL, TRUE);
4939         if (code == 0) {
4940             rockp->any = 1;
4941
4942             /* If we made a case sensitive exact match, we might as well quit now. */
4943             if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
4944                 code = CM_ERROR_STOPNOW;
4945         }
4946     }
4947     else code = 0;
4948
4949     return code;
4950 }
4951
4952 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4953 {
4954     int attribute;
4955     long code = 0;
4956     char *pathp;
4957     char *tp;
4958     cm_space_t *spacep;
4959     cm_scache_t *dscp;
4960     char *lastNamep;
4961     smb_unlinkRock_t rock;
4962     cm_user_t *userp;
4963     osi_hyper_t thyper;
4964     int caseFold;
4965     char *tidPathp;
4966     cm_req_t req;
4967
4968     cm_InitReq(&req);
4969
4970     attribute = smb_GetSMBParm(inp, 0);
4971         
4972     tp = smb_GetSMBData(inp, NULL);
4973     pathp = smb_ParseASCIIBlock(tp, &tp);
4974     if (smb_StoreAnsiFilenames)
4975         OemToChar(pathp,pathp);
4976
4977     osi_Log1(smb_logp, "SMB receive unlink %s",
4978              osi_LogSaveString(smb_logp, pathp));
4979
4980     spacep = inp->spacep;
4981     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4982
4983     userp = smb_GetUserFromVCP(vcp, inp);
4984
4985     caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4986
4987     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4988     if (code) {
4989         cm_ReleaseUser(userp);
4990         return CM_ERROR_NOSUCHPATH;
4991     }
4992     code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
4993                     &req, &dscp);
4994     if (code) {
4995         cm_ReleaseUser(userp);
4996         return code;
4997     }
4998         
4999 #ifdef DFS_SUPPORT
5000     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5001         cm_ReleaseSCache(dscp);
5002         cm_ReleaseUser(userp);
5003         if ( WANTS_DFS_PATHNAMES(inp) )
5004             return CM_ERROR_PATH_NOT_COVERED;
5005         else
5006             return CM_ERROR_BADSHARENAME;
5007     }
5008 #endif /* DFS_SUPPORT */
5009
5010     /* otherwise, scp points to the parent directory. */
5011     if (!lastNamep) 
5012         lastNamep = pathp;
5013     else 
5014         lastNamep++;
5015
5016     rock.any = 0;
5017     rock.maskp = smb_FindMask(pathp);
5018     rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5019
5020     thyper.LowPart = 0;
5021     thyper.HighPart = 0;
5022     rock.userp = userp;
5023     rock.reqp = &req;
5024     rock.dscp = dscp;
5025     rock.vcp = vcp;
5026
5027     /* Now, if we aren't dealing with a wildcard match, we first try an exact 
5028      * match.  If that fails, we do a case insensitve match. 
5029      */
5030     if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
5031         !smb_IsStarMask(rock.maskp)) {
5032         code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5033         if (!rock.any) {
5034             thyper.LowPart = 0;
5035             thyper.HighPart = 0;
5036             rock.flags |= SMB_MASKFLAG_CASEFOLD;
5037         }
5038     }
5039  
5040     if (!rock.any)
5041         code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5042     
5043     if (code == CM_ERROR_STOPNOW) 
5044         code = 0;
5045
5046     cm_ReleaseUser(userp);
5047         
5048     cm_ReleaseSCache(dscp);
5049
5050     if (code == 0 && !rock.any)
5051         code = CM_ERROR_NOSUCHFILE;
5052     return code;
5053 }       
5054
5055 typedef struct smb_renameRock {
5056     cm_scache_t *odscp; /* old dir */
5057     cm_scache_t *ndscp; /* new dir */
5058     cm_user_t *userp;   /* user */
5059     cm_req_t *reqp;             /* request struct */
5060     smb_vc_t *vcp;              /* virtual circuit */
5061     char *maskp;                /* pointer to star pattern of old file name */
5062     int flags;              /* tilde, casefold, etc */
5063     char *newNamep;             /* ptr to the new file's name */
5064     int any;
5065 } smb_renameRock_t;
5066
5067 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5068 {
5069     long code = 0;
5070     smb_renameRock_t *rockp;
5071     int caseFold;
5072     int match;
5073     char shortName[13]="";
5074
5075     rockp = (smb_renameRock_t *) vrockp;
5076
5077     caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5078     if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5079         caseFold |= CM_FLAG_8DOT3;
5080
5081     match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
5082     if (!match &&
5083         (rockp->flags & SMB_MASKFLAG_TILDE) &&
5084          !cm_Is8Dot3(dep->name)) {
5085         cm_Gen8Dot3Name(dep, shortName, NULL);
5086         match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
5087     }
5088     if (match) {
5089         rockp->any = 1;
5090
5091         code = cm_Rename(rockp->odscp, dep->name,
5092                          rockp->ndscp, rockp->newNamep, rockp->userp,
5093                          rockp->reqp);  
5094         /* if the call worked, stop doing the search now, since we
5095          * really only want to rename one file.
5096          */
5097         osi_Log1(smb_logp, "cm_Rename returns %ld", code);
5098         if (code == 0) 
5099             code = CM_ERROR_STOPNOW;
5100     }       
5101     else 
5102         code = 0;
5103
5104     return code;
5105 }
5106
5107
5108 long 
5109 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, int attrs)
5110 {
5111     long code = 0;
5112     cm_space_t *spacep = NULL;
5113     smb_renameRock_t rock;
5114     cm_scache_t *oldDscp = NULL;
5115     cm_scache_t *newDscp = NULL;
5116     cm_scache_t *tmpscp= NULL;
5117     cm_scache_t *tmpscp2 = NULL;
5118     char *oldLastNamep;
5119     char *newLastNamep;
5120     osi_hyper_t thyper;
5121     cm_user_t *userp;
5122     int caseFold;
5123     char *tidPathp;
5124     DWORD filter;
5125     cm_req_t req;
5126
5127     userp = smb_GetUserFromVCP(vcp, inp);
5128     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5129     if (code) {
5130         cm_ReleaseUser(userp);
5131         return CM_ERROR_NOSUCHPATH;
5132     }
5133
5134     cm_InitReq(&req);
5135     spacep = inp->spacep;
5136     smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5137
5138     caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5139     code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5140                     userp, tidPathp, &req, &oldDscp);
5141     if (code) {
5142         cm_ReleaseUser(userp);
5143         return code;
5144     }
5145         
5146 #ifdef DFS_SUPPORT
5147     if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5148         cm_ReleaseSCache(oldDscp);
5149         cm_ReleaseUser(userp);
5150         if ( WANTS_DFS_PATHNAMES(inp) )
5151             return CM_ERROR_PATH_NOT_COVERED;
5152         else
5153             return CM_ERROR_BADSHARENAME;
5154     }
5155 #endif /* DFS_SUPPORT */
5156
5157     smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5158     code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5159                     userp, tidPathp, &req, &newDscp);
5160
5161     if (code) {
5162         cm_ReleaseSCache(oldDscp);
5163         cm_ReleaseUser(userp);
5164         return code;
5165     }
5166
5167 #ifdef DFS_SUPPORT
5168     if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5169         cm_ReleaseSCache(oldDscp);
5170         cm_ReleaseSCache(newDscp);
5171         cm_ReleaseUser(userp);
5172         if ( WANTS_DFS_PATHNAMES(inp) )
5173             return CM_ERROR_PATH_NOT_COVERED;
5174         else
5175             return CM_ERROR_BADSHARENAME;
5176     }
5177 #endif /* DFS_SUPPORT */
5178
5179
5180     /* otherwise, oldDscp and newDscp point to the corresponding directories.
5181      * next, get the component names, and lower case them.
5182      */
5183
5184     /* handle the old name first */
5185     if (!oldLastNamep) 
5186         oldLastNamep = oldPathp;
5187     else 
5188         oldLastNamep++;
5189
5190     /* and handle the new name, too */
5191     if (!newLastNamep) 
5192         newLastNamep = newPathp;
5193     else 
5194         newLastNamep++;
5195
5196     /* TODO: The old name could be a wildcard.  The new name must not be */
5197
5198     /* do the vnode call */
5199     rock.odscp = oldDscp;
5200     rock.ndscp = newDscp;
5201     rock.userp = userp;
5202     rock.reqp = &req;
5203     rock.vcp = vcp;
5204     rock.maskp = oldLastNamep;
5205     rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5206     rock.newNamep = newLastNamep;
5207     rock.any = 0;
5208
5209     /* Check if the file already exists; if so return error */
5210     code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5211     if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
5212         osi_Log2(smb_logp, "  lookup returns %ld for [%s]", code,
5213                  osi_LogSaveString(smb_logp, newLastNamep));
5214
5215         /* Check if the old and the new names differ only in case. If so return
5216          * success, else return CM_ERROR_EXISTS 
5217          */
5218         if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
5219
5220             /* This would be a success only if the old file is *as same as* the new file */
5221             code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
5222             if (!code) {
5223                 if (tmpscp == tmpscp2) 
5224                     code = 0;
5225                 else 
5226                     code = CM_ERROR_EXISTS;
5227                 cm_ReleaseSCache(tmpscp2);
5228                 tmpscp2 = NULL;
5229             } else {
5230                 code = CM_ERROR_NOSUCHFILE;
5231             }
5232         } else {
5233             /* file exist, do not rename, also fixes move */
5234             osi_Log0(smb_logp, "Can't rename.  Target already exists");
5235             code = CM_ERROR_EXISTS;
5236         }
5237
5238         if (tmpscp != NULL)
5239             cm_ReleaseSCache(tmpscp);
5240         cm_ReleaseSCache(newDscp);
5241         cm_ReleaseSCache(oldDscp);
5242         cm_ReleaseUser(userp);
5243         return code; 
5244     }
5245
5246     /* Now search the directory for the pattern, and do the appropriate rename when found */
5247     thyper.LowPart = 0;         /* search dir from here */
5248     thyper.HighPart = 0;
5249
5250     code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5251     if (code == 0 && !rock.any) {
5252         thyper.LowPart = 0;
5253         thyper.HighPart = 0;
5254         rock.flags |= SMB_MASKFLAG_CASEFOLD;
5255         code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5256     }
5257     osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
5258
5259     if (code == CM_ERROR_STOPNOW)
5260         code = 0;
5261     else if (code == 0)
5262         code = CM_ERROR_NOSUCHFILE;
5263
5264     /* Handle Change Notification */
5265     /*
5266     * Being lazy, not distinguishing between files and dirs in this
5267     * filter, since we'd have to do a lookup.
5268     */
5269     filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
5270     if (oldDscp == newDscp) {
5271         if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5272             smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5273                              filter, oldDscp, oldLastNamep,
5274                              newLastNamep, TRUE);
5275     } else {
5276         if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5277             smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5278                              filter, oldDscp, oldLastNamep,
5279                              NULL, TRUE);
5280         if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5281             smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
5282                              filter, newDscp, newLastNamep,
5283                              NULL, TRUE);
5284     }
5285
5286     if (tmpscp != NULL) 
5287         cm_ReleaseSCache(tmpscp);
5288     cm_ReleaseUser(userp);
5289     cm_ReleaseSCache(oldDscp);
5290     cm_ReleaseSCache(newDscp);
5291     return code;
5292 }       
5293
5294 long 
5295 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp) 
5296 {
5297     long code = 0;
5298     cm_space_t *spacep = NULL;
5299     cm_scache_t *oldDscp = NULL;
5300     cm_scache_t *newDscp = NULL;
5301     cm_scache_t *tmpscp= NULL;
5302     cm_scache_t *tmpscp2 = NULL;
5303     cm_scache_t *sscp = NULL;
5304     char *oldLastNamep;
5305     char *newLastNamep;
5306     cm_user_t *userp;
5307     int caseFold;
5308     char *tidPathp;
5309     DWORD filter;
5310     cm_req_t req;
5311
5312     userp = smb_GetUserFromVCP(vcp, inp);
5313
5314     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5315     if (code) {
5316         cm_ReleaseUser(userp);
5317         return CM_ERROR_NOSUCHPATH;
5318     }
5319
5320     cm_InitReq(&req);
5321
5322     caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5323
5324     spacep = inp->spacep;
5325     smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5326     
5327     code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5328                     userp, tidPathp, &req, &oldDscp);
5329     if (code) {
5330         cm_ReleaseUser(userp);
5331         return code;
5332     }
5333         
5334 #ifdef DFS_SUPPORT
5335     if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5336         cm_ReleaseSCache(oldDscp);
5337         cm_ReleaseUser(userp);
5338         if ( WANTS_DFS_PATHNAMES(inp) )
5339             return CM_ERROR_PATH_NOT_COVERED;
5340         else
5341             return CM_ERROR_BADSHARENAME;
5342     }
5343 #endif /* DFS_SUPPORT */
5344
5345     smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5346     code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5347                     userp, tidPathp, &req, &newDscp);
5348     if (code) {
5349         cm_ReleaseSCache(oldDscp);
5350         cm_ReleaseUser(userp);
5351         return code;
5352     }
5353
5354 #ifdef DFS_SUPPORT
5355     if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5356         cm_ReleaseSCache(newDscp);
5357         cm_ReleaseSCache(oldDscp);
5358         cm_ReleaseUser(userp);
5359         if ( WANTS_DFS_PATHNAMES(inp) )
5360             return CM_ERROR_PATH_NOT_COVERED;
5361         else
5362             return CM_ERROR_BADSHARENAME;
5363     }
5364 #endif /* DFS_SUPPORT */
5365
5366     /* Now, although we did two lookups for the two directories (because the same
5367      * directory can be referenced through different paths), we only allow hard links
5368      * within the same directory. */
5369     if (oldDscp != newDscp) {
5370         cm_ReleaseSCache(oldDscp);
5371         cm_ReleaseSCache(newDscp);
5372         cm_ReleaseUser(userp);
5373         return CM_ERROR_CROSSDEVLINK;
5374     }
5375
5376     /* handle the old name first */
5377     if (!oldLastNamep) 
5378         oldLastNamep = oldPathp;
5379     else 
5380         oldLastNamep++;
5381
5382     /* and handle the new name, too */
5383     if (!newLastNamep) 
5384         newLastNamep = newPathp;
5385     else 
5386         newLastNamep++;
5387
5388     /* now lookup the old name */
5389     osi_Log1(smb_logp,"  looking up [%s]", osi_LogSaveString(smb_logp,oldLastNamep));
5390     code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
5391     if (code) {
5392         cm_ReleaseSCache(oldDscp);
5393         cm_ReleaseSCache(newDscp);
5394         cm_ReleaseUser(userp);
5395         return code;
5396     }
5397
5398     /* Check if the file already exists; if so return error */
5399     code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5400     if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
5401         osi_Log2(smb_logp, "  lookup returns %ld for [%s]", code,
5402                  osi_LogSaveString(smb_logp, newLastNamep));
5403
5404         /* if the existing link is to the same file, then we return success */
5405         if (!code) {
5406             if(sscp == tmpscp) {
5407                 code = 0;
5408             } else {
5409                 osi_Log0(smb_logp, "Can't create hardlink.  Target already exists");
5410                 code = CM_ERROR_EXISTS;
5411             }
5412         }
5413
5414         if (tmpscp != NULL)
5415             cm_ReleaseSCache(tmpscp);
5416         cm_ReleaseSCache(sscp);
5417         cm_ReleaseSCache(newDscp);
5418         cm_ReleaseSCache(oldDscp);
5419         cm_ReleaseUser(userp);
5420         return code; 
5421     }
5422
5423     /* now create the hardlink */
5424     osi_Log1(smb_logp,"  Attempting to create new link [%s]", osi_LogSaveString(smb_logp, newLastNamep));
5425     code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
5426     osi_Log1(smb_logp,"  Link returns 0x%x", code);
5427
5428     /* Handle Change Notification */
5429     if (code == 0) {
5430         filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
5431         if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5432             smb_NotifyChange(FILE_ACTION_ADDED,
5433                              filter, newDscp, newLastNamep,
5434                              NULL, TRUE);
5435     }
5436
5437     if (tmpscp != NULL) 
5438         cm_ReleaseSCache(tmpscp);
5439     cm_ReleaseUser(userp);
5440     cm_ReleaseSCache(sscp);
5441     cm_ReleaseSCache(oldDscp);
5442     cm_ReleaseSCache(newDscp);
5443     return code;
5444 }
5445
5446 long 
5447 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5448 {
5449     char *oldPathp;
5450     char *newPathp;
5451     char *tp;
5452     long code;
5453
5454     tp = smb_GetSMBData(inp, NULL);
5455     oldPathp = smb_ParseASCIIBlock(tp, &tp);
5456     if (smb_StoreAnsiFilenames)
5457         OemToChar(oldPathp,oldPathp);
5458     newPathp = smb_ParseASCIIBlock(tp, &tp);
5459     if (smb_StoreAnsiFilenames)
5460         OemToChar(newPathp,newPathp);
5461
5462     osi_Log2(smb_logp, "smb rename [%s] to [%s]",
5463              osi_LogSaveString(smb_logp, oldPathp),
5464              osi_LogSaveString(smb_logp, newPathp));
5465
5466     code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
5467
5468     osi_Log1(smb_logp, "smb rename returns 0x%x", code);
5469     return code;
5470 }
5471
5472
5473
5474 typedef struct smb_rmdirRock {
5475     cm_scache_t *dscp;
5476     cm_user_t *userp;
5477     cm_req_t *reqp;
5478     char *maskp;                /* pointer to the star pattern */
5479     int flags;
5480     int any;
5481 } smb_rmdirRock_t;
5482
5483 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5484 {       
5485     long code = 0;
5486     smb_rmdirRock_t *rockp;
5487     int match;
5488     char shortName[13];
5489     char *matchName;
5490         
5491     rockp = (smb_rmdirRock_t *) vrockp;
5492
5493     matchName = dep->name;
5494     if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
5495         match = (cm_stricmp(matchName, rockp->maskp) == 0);
5496     else
5497         match = (strcmp(matchName, rockp->maskp) == 0);
5498     if (!match &&
5499          (rockp->flags & SMB_MASKFLAG_TILDE) &&
5500          !cm_Is8Dot3(dep->name)) {
5501         cm_Gen8Dot3Name(dep, shortName, NULL);
5502         matchName = shortName;
5503         match = (cm_stricmp(matchName, rockp->maskp) == 0);
5504     }       
5505     if (match) {
5506         osi_Log1(smb_logp, "Removing directory %s",
5507                  osi_LogSaveString(smb_logp, matchName));
5508         code = cm_RemoveDir(dscp, dep->name, rockp->userp, rockp->reqp);
5509         if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5510             smb_NotifyChange(FILE_ACTION_REMOVED,
5511                              FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
5512                              dscp, dep->name, NULL, TRUE);
5513         if (code == 0)
5514             rockp->any = 1;
5515     }
5516     else code = 0;
5517
5518     return code;
5519 }
5520
5521 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5522 {
5523     long code = 0;
5524     char *pathp;
5525     char *tp;
5526     cm_space_t *spacep;
5527     cm_scache_t *dscp;
5528     char *lastNamep;
5529     smb_rmdirRock_t rock;
5530     cm_user_t *userp;
5531     osi_hyper_t thyper;
5532     int caseFold;
5533     char *tidPathp;
5534     cm_req_t req;
5535
5536     cm_InitReq(&req);
5537
5538     tp = smb_GetSMBData(inp, NULL);
5539     pathp = smb_ParseASCIIBlock(tp, &tp);
5540     if (smb_StoreAnsiFilenames)
5541         OemToChar(pathp,pathp);
5542
5543     spacep = inp->spacep;
5544     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5545
5546     userp = smb_GetUserFromVCP(vcp, inp);
5547
5548     caseFold = CM_FLAG_CASEFOLD;
5549
5550     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5551     if (code) {
5552         cm_ReleaseUser(userp);
5553         return CM_ERROR_NOSUCHPATH;
5554     }
5555     code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5556                     userp, tidPathp, &req, &dscp);
5557
5558     if (code) {
5559         cm_ReleaseUser(userp);
5560         return code;
5561     }
5562         
5563 #ifdef DFS_SUPPORT
5564     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5565         cm_ReleaseSCache(dscp);
5566         cm_ReleaseUser(userp);
5567         if ( WANTS_DFS_PATHNAMES(inp) )
5568             return CM_ERROR_PATH_NOT_COVERED;
5569         else
5570             return CM_ERROR_BADSHARENAME;
5571     }
5572 #endif /* DFS_SUPPORT */
5573
5574     /* otherwise, scp points to the parent directory. */
5575     if (!lastNamep) 
5576         lastNamep = pathp;
5577     else 
5578         lastNamep++;
5579         
5580     rock.any = 0;
5581     rock.maskp = lastNamep;
5582     rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5583
5584     thyper.LowPart = 0;
5585     thyper.HighPart = 0;
5586     rock.userp = userp;
5587     rock.reqp = &req;
5588     rock.dscp = dscp;
5589
5590     /* First do a case sensitive match, and if that fails, do a case insensitive match */
5591     code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5592     if (code == 0 && !rock.any) {
5593         thyper.LowPart = 0;
5594         thyper.HighPart = 0;
5595         rock.flags |= SMB_MASKFLAG_CASEFOLD;
5596         code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5597     }
5598
5599     cm_ReleaseUser(userp);
5600         
5601     cm_ReleaseSCache(dscp);
5602
5603     if (code == 0 && !rock.any)
5604         code = CM_ERROR_NOSUCHFILE;        
5605     return code;
5606 }
5607
5608 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5609 {
5610     unsigned short fid;
5611     smb_fid_t *fidp;
5612     cm_user_t *userp;
5613     long code = 0;
5614     cm_req_t req;
5615
5616     cm_InitReq(&req);
5617
5618     fid = smb_GetSMBParm(inp, 0);
5619
5620     osi_Log1(smb_logp, "SMB flush fid %d", fid);
5621
5622     fid = smb_ChainFID(fid, inp);
5623     fidp = smb_FindFID(vcp, fid, 0);
5624     if (!fidp)
5625         return CM_ERROR_BADFD;
5626     
5627     lock_ObtainMutex(&fidp->mx);
5628     if (fidp->flags & SMB_FID_IOCTL) {
5629         lock_ReleaseMutex(&fidp->mx);
5630         smb_ReleaseFID(fidp);
5631         return CM_ERROR_BADFD;
5632     }
5633     lock_ReleaseMutex(&fidp->mx);
5634         
5635     userp = smb_GetUserFromVCP(vcp, inp);
5636
5637     lock_ObtainMutex(&fidp->mx);
5638     if (fidp->flags & SMB_FID_OPENWRITE) {
5639         cm_scache_t * scp = fidp->scp;
5640         cm_HoldSCache(scp);
5641         lock_ReleaseMutex(&fidp->mx);
5642         code = cm_FSync(scp, userp, &req);
5643         cm_ReleaseSCache(scp);
5644     } else {
5645         code = 0;
5646         lock_ReleaseMutex(&fidp->mx);
5647     }
5648         
5649     smb_ReleaseFID(fidp);
5650         
5651     cm_ReleaseUser(userp);
5652         
5653     return code;
5654 }
5655
5656 struct smb_FullNameRock {
5657     char *name;
5658     cm_scache_t *vnode;
5659     char *fullName;
5660 };
5661
5662 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
5663                      osi_hyper_t *offp)
5664 {
5665     char shortName[13];
5666     struct smb_FullNameRock *vrockp;
5667
5668     vrockp = (struct smb_FullNameRock *)rockp;
5669
5670     if (!cm_Is8Dot3(dep->name)) {
5671         cm_Gen8Dot3Name(dep, shortName, NULL);
5672
5673         if (cm_stricmp(shortName, vrockp->name) == 0) {
5674             vrockp->fullName = strdup(dep->name);
5675             return CM_ERROR_STOPNOW;
5676         }
5677     }
5678     if (cm_stricmp(dep->name, vrockp->name) == 0 &&
5679         ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
5680         ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
5681         vrockp->fullName = strdup(dep->name);
5682         return CM_ERROR_STOPNOW;
5683     }
5684     return 0;
5685 }
5686
5687 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
5688                   char **newPathp, cm_user_t *userp, cm_req_t *reqp)
5689 {
5690     struct smb_FullNameRock rock;
5691     long code = 0;
5692
5693     rock.name = pathp;
5694     rock.vnode = scp;
5695
5696     code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL); 
5697     if (code == CM_ERROR_STOPNOW)
5698         *newPathp = rock.fullName;
5699     else
5700         *newPathp = strdup(pathp);
5701 }
5702
5703 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
5704                   afs_uint32 dosTime) {
5705     long code = 0;
5706     cm_req_t req;
5707     cm_scache_t *dscp = NULL;
5708     char *pathp = NULL;
5709     cm_scache_t * scp = NULL;
5710     int deleted = 0;
5711     int nullcreator = 0;
5712
5713     osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
5714              fidp, fidp->fid, scp, vcp);
5715
5716     if (!userp) {
5717         lock_ObtainMutex(&fidp->mx);
5718         if (!fidp->userp && !(fidp->flags & SMB_FID_IOCTL)) {
5719             lock_ReleaseMutex(&fidp->mx);
5720             osi_Log0(smb_logp, "  No user specified.  Not closing fid");
5721             return CM_ERROR_BADFD;
5722         }
5723         
5724         userp = fidp->userp;    /* no hold required since fidp is held
5725                                    throughout the function */
5726         lock_ReleaseMutex(&fidp->mx);
5727     }
5728
5729     cm_InitReq(&req);
5730
5731     lock_ObtainWrite(&smb_rctLock);
5732     if (fidp->delete) {
5733         osi_Log0(smb_logp, "  Fid already closed.");
5734         lock_ReleaseWrite(&smb_rctLock);
5735         return CM_ERROR_BADFD;
5736     }
5737     fidp->delete = 1;
5738     lock_ReleaseWrite(&smb_rctLock);
5739
5740     lock_ObtainMutex(&fidp->mx);
5741     if (fidp->NTopen_dscp) {
5742         dscp = fidp->NTopen_dscp;
5743         cm_HoldSCache(dscp);
5744     }
5745
5746     if (fidp->NTopen_pathp) {
5747         pathp = strdup(fidp->NTopen_pathp);
5748     }
5749
5750     if (fidp->scp) {
5751         scp = fidp->scp;
5752         cm_HoldSCache(scp);
5753     }
5754
5755     /* Don't jump the gun on an async raw write */
5756     while (fidp->raw_writers) {
5757         lock_ReleaseMutex(&fidp->mx);
5758         thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
5759         lock_ObtainMutex(&fidp->mx);
5760     }
5761
5762     /* watch for ioctl closes, and read-only opens */
5763     if (scp != NULL &&
5764         (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
5765          == SMB_FID_OPENWRITE) {
5766         if (dosTime != 0 && dosTime != -1) {
5767             scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5768             /* This fixes defect 10958 */
5769             CompensateForSmbClientLastWriteTimeBugs(&dosTime);
5770             smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
5771         }
5772         lock_ReleaseMutex(&fidp->mx);
5773         code = cm_FSync(scp, userp, &req);
5774         lock_ObtainMutex(&fidp->mx);
5775     }
5776     else 
5777         code = 0;
5778
5779     /* unlock any pending locks */
5780     if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
5781         scp->fileType == CM_SCACHETYPE_FILE) {
5782         cm_key_t key;
5783         long tcode;
5784
5785         lock_ReleaseMutex(&fidp->mx);
5786
5787         /* CM_UNLOCK_BY_FID doesn't look at the process ID.  We pass
5788            in zero. */
5789         key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
5790         lock_ObtainMutex(&scp->mx);
5791
5792         tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
5793                           CM_SCACHESYNC_NEEDCALLBACK
5794                           | CM_SCACHESYNC_GETSTATUS
5795                           | CM_SCACHESYNC_LOCK);
5796
5797         if (tcode) {
5798             osi_Log1(smb_logp,
5799                      "smb CoreClose SyncOp failure code 0x%x", tcode);
5800             goto post_syncopdone;
5801         }
5802
5803         cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
5804
5805         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
5806
5807     post_syncopdone:
5808
5809         lock_ReleaseMutex(&scp->mx);
5810         lock_ObtainMutex(&fidp->mx);
5811     }
5812
5813     if (fidp->flags & SMB_FID_DELONCLOSE) {
5814         char *fullPathp;
5815
5816         lock_ReleaseMutex(&fidp->mx);
5817         smb_FullName(dscp, scp, pathp, &fullPathp, userp, &req);
5818         if (scp->fileType == CM_SCACHETYPE_DIRECTORY) {
5819             code = cm_RemoveDir(dscp, fullPathp, userp, &req);
5820             if (code == 0) {
5821                 deleted = 1;
5822                 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5823                     smb_NotifyChange(FILE_ACTION_REMOVED,
5824                                       FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
5825                                       dscp, fullPathp, NULL, TRUE);
5826             }
5827         } else {
5828             code = cm_Unlink(dscp, fullPathp, userp, &req);
5829             if (code == 0) {                            
5830                 deleted = 1;
5831                 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5832                     smb_NotifyChange(FILE_ACTION_REMOVED,
5833                                       FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5834                                       dscp, fullPathp, NULL, TRUE);
5835             }
5836         }
5837         free(fullPathp);
5838         lock_ObtainMutex(&fidp->mx);
5839         fidp->flags &= ~SMB_FID_DELONCLOSE;
5840     }
5841
5842     /* if this was a newly created file, then clear the creator
5843      * in the stat cache entry. */
5844     if (fidp->flags & SMB_FID_CREATED) {
5845         nullcreator = 1;
5846         fidp->flags &= ~SMB_FID_CREATED;
5847     }
5848
5849     if (fidp->flags & SMB_FID_NTOPEN) {
5850         cm_ReleaseSCache(fidp->NTopen_dscp);
5851         fidp->NTopen_dscp = NULL;
5852         free(fidp->NTopen_pathp);
5853         fidp->NTopen_pathp = NULL;
5854         fidp->flags &= ~SMB_FID_NTOPEN;
5855     } else {
5856         osi_assert(fidp->NTopen_dscp == NULL);
5857         osi_assert(fidp->NTopen_pathp == NULL);
5858     }
5859
5860     if (fidp->NTopen_wholepathp) {
5861         free(fidp->NTopen_wholepathp);
5862         fidp->NTopen_wholepathp = NULL;
5863     }
5864
5865     if (fidp->scp) {
5866         cm_ReleaseSCache(fidp->scp);
5867         fidp->scp = NULL;
5868     }
5869     lock_ReleaseMutex(&fidp->mx);
5870
5871     if (dscp)
5872         cm_ReleaseSCache(dscp);
5873
5874     if (scp) {
5875         if (deleted || nullcreator) {
5876             lock_ObtainMutex(&scp->mx);
5877             if (nullcreator && scp->creator == userp)
5878                 scp->creator = NULL;
5879             if (deleted)
5880                 scp->flags |= CM_SCACHEFLAG_DELETED;
5881             lock_ReleaseMutex(&scp->mx);
5882         }
5883         lock_ObtainMutex(&scp->mx);
5884         scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
5885         lock_ReleaseMutex(&scp->mx);
5886         cm_ReleaseSCache(scp);
5887     }
5888
5889     if (pathp)
5890         free(pathp);
5891
5892     return code;
5893 }
5894
5895 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5896 {
5897     unsigned short fid;
5898     smb_fid_t *fidp;
5899     cm_user_t *userp;
5900     long code = 0;
5901     afs_uint32 dosTime;
5902
5903     fid = smb_GetSMBParm(inp, 0);
5904     dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5905
5906     osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
5907
5908     fid = smb_ChainFID(fid, inp);
5909     fidp = smb_FindFID(vcp, fid, 0);
5910     if (!fidp) {
5911         return CM_ERROR_BADFD;
5912     }
5913         
5914     userp = smb_GetUserFromVCP(vcp, inp);
5915
5916     code = smb_CloseFID(vcp, fidp, userp, dosTime);
5917     
5918     smb_ReleaseFID(fidp);
5919     cm_ReleaseUser(userp);
5920     return code;
5921 }
5922
5923 /*
5924  * smb_ReadData -- common code for Read, Read And X, and Raw Read
5925  */
5926 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5927         cm_user_t *userp, long *readp)
5928 {
5929     osi_hyper_t offset;
5930     long code = 0;
5931     cm_scache_t *scp;
5932     cm_buf_t *bufferp;
5933     osi_hyper_t fileLength;
5934     osi_hyper_t thyper;
5935     osi_hyper_t lastByte;
5936     osi_hyper_t bufferOffset;
5937     long bufIndex, nbytes;
5938     int chunk;
5939     int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
5940     cm_req_t req;
5941
5942     cm_InitReq(&req);
5943
5944     bufferp = NULL;
5945     offset = *offsetp;
5946
5947     lock_ObtainMutex(&fidp->mx);
5948     scp = fidp->scp;
5949     cm_HoldSCache(scp);
5950     lock_ObtainMutex(&scp->mx);
5951
5952     if (offset.HighPart == 0) {
5953         chunk = offset.LowPart >> cm_logChunkSize;
5954         if (chunk != fidp->curr_chunk) {
5955             fidp->prev_chunk = fidp->curr_chunk;
5956             fidp->curr_chunk = chunk;
5957         }
5958         if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
5959             sequential = 1;
5960     }
5961     lock_ReleaseMutex(&fidp->mx);
5962
5963     /* start by looking up the file's end */
5964     code = cm_SyncOp(scp, NULL, userp, &req, 0,
5965                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5966     if (code) 
5967         goto done;
5968
5969     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5970
5971     /* now we have the entry locked, look up the length */
5972     fileLength = scp->length;
5973
5974     /* adjust count down so that it won't go past EOF */
5975     thyper.LowPart = count;
5976     thyper.HighPart = 0;
5977     thyper = LargeIntegerAdd(offset, thyper);   /* where read should end */
5978     lastByte = thyper;
5979     if (LargeIntegerGreaterThan(thyper, fileLength)) {
5980         /* we'd read past EOF, so just stop at fileLength bytes.
5981          * Start by computing how many bytes remain in the file.
5982          */
5983         thyper = LargeIntegerSubtract(fileLength, offset);
5984
5985         /* if we are past EOF, read 0 bytes */
5986         if (LargeIntegerLessThanZero(thyper))
5987             count = 0;
5988         else
5989             count = thyper.LowPart;
5990     }       
5991
5992     *readp = count;
5993
5994     /* now, copy the data one buffer at a time,
5995      * until we've filled the request packet
5996      */
5997     while (1) {
5998         /* if we've copied all the data requested, we're done */
5999         if (count <= 0) break;
6000
6001         /* otherwise, load up a buffer of data */
6002         thyper.HighPart = offset.HighPart;
6003         thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6004         if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6005             /* wrong buffer */
6006             if (bufferp) {
6007                 buf_Release(bufferp);
6008                 bufferp = NULL;
6009             }
6010             lock_ReleaseMutex(&scp->mx);
6011
6012             lock_ObtainRead(&scp->bufCreateLock);
6013             code = buf_Get(scp, &thyper, &bufferp);
6014             lock_ReleaseRead(&scp->bufCreateLock);
6015
6016             lock_ObtainMutex(&scp->mx);
6017             if (code) goto done;
6018             bufferOffset = thyper;
6019
6020             /* now get the data in the cache */
6021             while (1) {
6022                 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6023                                  CM_SCACHESYNC_NEEDCALLBACK |
6024                                  CM_SCACHESYNC_READ);
6025                 if (code) 
6026                     goto done;
6027                     
6028                 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
6029
6030                 if (cm_HaveBuffer(scp, bufferp, 0)) break;
6031
6032                 /* otherwise, load the buffer and try again */
6033                 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
6034                 if (code) break;
6035             }
6036             if (code) {
6037                 buf_Release(bufferp);
6038                 bufferp = NULL;
6039                 goto done;
6040             }
6041         }       /* if (wrong buffer) ... */
6042
6043         /* now we have the right buffer loaded.  Copy out the
6044          * data from here to the user's buffer.
6045          */
6046         bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6047
6048         /* and figure out how many bytes we want from this buffer */
6049         nbytes = cm_data.buf_blockSize - bufIndex;      /* what remains in buffer */
6050         if (nbytes > count) nbytes = count;     /* don't go past EOF */
6051
6052         /* now copy the data */
6053         memcpy(op, bufferp->datap + bufIndex, nbytes);
6054                 
6055         /* adjust counters, pointers, etc. */
6056         op += nbytes;
6057         count -= nbytes;
6058         thyper.LowPart = nbytes;
6059         thyper.HighPart = 0;
6060         offset = LargeIntegerAdd(thyper, offset);
6061     } /* while 1 */
6062
6063   done:
6064     lock_ReleaseMutex(&scp->mx);
6065     if (bufferp)
6066         buf_Release(bufferp);
6067
6068     if (code == 0 && sequential)
6069         cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
6070
6071     cm_ReleaseSCache(scp);
6072
6073     return code;
6074 }
6075
6076 /*
6077  * smb_WriteData -- common code for Write and Raw Write
6078  */
6079 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
6080         cm_user_t *userp, long *writtenp)
6081 {
6082     osi_hyper_t offset;
6083     long code = 0;
6084     long written = 0;
6085     cm_scache_t *scp;
6086     osi_hyper_t fileLength;     /* file's length at start of write */
6087     osi_hyper_t minLength;      /* don't read past this */
6088     long nbytes;                /* # of bytes to transfer this iteration */
6089     cm_buf_t *bufferp;
6090     osi_hyper_t thyper;         /* hyper tmp variable */
6091     osi_hyper_t bufferOffset;
6092     long bufIndex;              /* index in buffer where our data is */
6093     int doWriteBack;
6094     osi_hyper_t writeBackOffset;/* offset of region to write back when
6095                                  * I/O is done */
6096     DWORD filter = 0;
6097     cm_req_t req;
6098
6099     osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
6100               fidp->fid, offsetp->LowPart, count);
6101
6102     *writtenp = 0;
6103
6104     cm_InitReq(&req);
6105
6106     bufferp = NULL;
6107     doWriteBack = 0;
6108     offset = *offsetp;
6109
6110     lock_ObtainMutex(&fidp->mx);
6111     /* make sure we have a writable FD */
6112     if (!(fidp->flags & SMB_FID_OPENWRITE)) {
6113         osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
6114                   fidp->fid, fidp->flags);
6115         lock_ReleaseMutex(&fidp->mx);
6116         code = CM_ERROR_BADFDOP;
6117         goto done;
6118     }
6119     
6120     scp = fidp->scp;
6121     cm_HoldSCache(scp);
6122     lock_ReleaseMutex(&fidp->mx);
6123
6124     lock_ObtainMutex(&scp->mx);
6125     /* start by looking up the file's end */
6126     code = cm_SyncOp(scp, NULL, userp, &req, 0,
6127                       CM_SCACHESYNC_NEEDCALLBACK
6128                       | CM_SCACHESYNC_SETSTATUS
6129                       | CM_SCACHESYNC_GETSTATUS);
6130     if (code) 
6131         goto done;
6132         
6133     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
6134
6135     /* now we have the entry locked, look up the length */
6136     fileLength = scp->length;
6137     minLength = fileLength;
6138     if (LargeIntegerGreaterThan(minLength, scp->serverLength))
6139         minLength = scp->serverLength;
6140
6141     /* adjust file length if we extend past EOF */
6142     thyper.LowPart = count;
6143     thyper.HighPart = 0;
6144     thyper = LargeIntegerAdd(offset, thyper);   /* where write should end */
6145     if (LargeIntegerGreaterThan(thyper, fileLength)) {
6146         /* we'd write past EOF, so extend the file */
6147         scp->mask |= CM_SCACHEMASK_LENGTH;
6148         scp->length = thyper;
6149         filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
6150     } else
6151         filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
6152
6153     /* now, if the new position (thyper) and the old (offset) are in
6154      * different storeback windows, remember to store back the previous
6155      * storeback window when we're done with the write.
6156      */
6157     if ((thyper.LowPart & (-cm_chunkSize)) !=
6158          (offset.LowPart & (-cm_chunkSize))) {
6159         /* they're different */
6160         doWriteBack = 1;
6161         writeBackOffset.HighPart = offset.HighPart;
6162         writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
6163     }
6164         
6165     *writtenp = count;
6166
6167     /* now, copy the data one buffer at a time, until we've filled the
6168      * request packet */
6169     while (1) {
6170         /* if we've copied all the data requested, we're done */
6171         if (count <= 0) 
6172             break;
6173
6174         /* handle over quota or out of space */
6175         if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
6176             *writtenp = written;
6177             code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
6178             break;
6179         }
6180
6181         /* otherwise, load up a buffer of data */
6182         thyper.HighPart = offset.HighPart;
6183         thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6184         if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6185             /* wrong buffer */
6186             if (bufferp) {
6187                 lock_ReleaseMutex(&bufferp->mx);
6188                 buf_Release(bufferp);
6189                 bufferp = NULL;
6190             }   
6191             lock_ReleaseMutex(&scp->mx);
6192
6193             lock_ObtainRead(&scp->bufCreateLock);
6194             code = buf_Get(scp, &thyper, &bufferp);
6195             lock_ReleaseRead(&scp->bufCreateLock);
6196
6197             lock_ObtainMutex(&bufferp->mx);
6198             lock_ObtainMutex(&scp->mx);
6199             if (code) goto done;
6200
6201             bufferOffset = thyper;
6202
6203             /* now get the data in the cache */
6204             while (1) {
6205                 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6206                                   CM_SCACHESYNC_NEEDCALLBACK
6207                                   | CM_SCACHESYNC_WRITE
6208                                   | CM_SCACHESYNC_BUFLOCKED);
6209                 if (code) 
6210                     goto done;
6211
6212                 cm_SyncOpDone(scp, bufferp, 
6213                                CM_SCACHESYNC_NEEDCALLBACK 
6214                                | CM_SCACHESYNC_WRITE 
6215                                | CM_SCACHESYNC_BUFLOCKED);
6216
6217                 /* If we're overwriting the entire buffer, or
6218                  * if we're writing at or past EOF, mark the
6219                  * buffer as current so we don't call
6220                  * cm_GetBuffer.  This skips the fetch from the
6221                  * server in those cases where we're going to 
6222                  * obliterate all the data in the buffer anyway,
6223                  * or in those cases where there is no useful
6224                  * data at the server to start with.
6225                  *
6226                  * Use minLength instead of scp->length, since
6227                  * the latter has already been updated by this
6228                  * call.
6229                  */
6230                 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
6231                      || LargeIntegerEqualTo(offset, bufferp->offset)
6232                      && (count >= cm_data.buf_blockSize
6233                           || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
6234                                                                                ConvertLongToLargeInteger(count)),
6235                                                                minLength))) {
6236                     if (count < cm_data.buf_blockSize
6237                          && bufferp->dataVersion == -1)
6238                         memset(bufferp->datap, 0,
6239                                 cm_data.buf_blockSize);
6240                     bufferp->dataVersion = scp->dataVersion;
6241                 }
6242
6243                 if (cm_HaveBuffer(scp, bufferp, 1)) break;
6244
6245                 /* otherwise, load the buffer and try again */
6246                 lock_ReleaseMutex(&bufferp->mx);
6247                 code = cm_GetBuffer(scp, bufferp, NULL, userp,
6248                                      &req);
6249                 lock_ReleaseMutex(&scp->mx);
6250                 lock_ObtainMutex(&bufferp->mx);
6251                 lock_ObtainMutex(&scp->mx);
6252                 if (code) break;
6253             }
6254             if (code) {
6255                 lock_ReleaseMutex(&bufferp->mx);
6256                 buf_Release(bufferp);
6257                 bufferp = NULL;
6258                 goto done;
6259             }
6260         }       /* if (wrong buffer) ... */
6261
6262         /* now we have the right buffer loaded.  Copy out the
6263          * data from here to the user's buffer.
6264          */
6265         bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6266
6267         /* and figure out how many bytes we want from this buffer */
6268         nbytes = cm_data.buf_blockSize - bufIndex;      /* what remains in buffer */
6269         if (nbytes > count) 
6270             nbytes = count;     /* don't go past end of request */
6271
6272         /* now copy the data */
6273         memcpy(bufferp->datap + bufIndex, op, nbytes);
6274         buf_SetDirty(bufferp);
6275
6276         /* and record the last writer */
6277         if (bufferp->userp != userp) {
6278             cm_HoldUser(userp);
6279             if (bufferp->userp) 
6280                 cm_ReleaseUser(bufferp->userp);
6281             bufferp->userp = userp;
6282         }
6283
6284         /* adjust counters, pointers, etc. */
6285         op += nbytes;
6286         count -= nbytes;
6287         written += nbytes;
6288         thyper.LowPart = nbytes;
6289         thyper.HighPart = 0;
6290         offset = LargeIntegerAdd(thyper, offset);
6291     } /* while 1 */
6292
6293   done:
6294     lock_ReleaseMutex(&scp->mx);
6295
6296     if (bufferp) {
6297         lock_ReleaseMutex(&bufferp->mx);
6298         buf_Release(bufferp);
6299     }
6300
6301     lock_ObtainMutex(&fidp->mx);
6302     if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
6303          && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
6304         smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
6305                           fidp->NTopen_dscp, fidp->NTopen_pathp,
6306                           NULL, TRUE);
6307     }       
6308     lock_ReleaseMutex(&fidp->mx);
6309
6310     if (code == 0 && doWriteBack) {
6311         long code2;
6312         lock_ObtainMutex(&scp->mx);
6313         osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
6314                   fidp->fid);
6315         code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
6316         osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
6317                   fidp->fid, code2);
6318         lock_ReleaseMutex(&scp->mx);
6319         cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
6320                             writeBackOffset.HighPart, cm_chunkSize, 0, userp);
6321         /* cm_SyncOpDone is called at the completion of cm_BkgStore */
6322     }
6323
6324     cm_ReleaseSCache(scp);
6325
6326     osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
6327               fidp->fid, code, *writtenp);
6328     return code;
6329 }
6330
6331 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6332 {
6333     unsigned short fd;
6334     unsigned short count;
6335     osi_hyper_t offset;
6336     unsigned short hint;
6337     long written = 0, total_written = 0;
6338     unsigned pid;
6339     smb_fid_t *fidp;
6340     long code = 0;
6341     cm_user_t *userp;
6342     cm_attr_t truncAttr;        /* attribute struct used for truncating file */
6343     char *op;
6344     int inDataBlockCount;
6345
6346     fd = smb_GetSMBParm(inp, 0);
6347     count = smb_GetSMBParm(inp, 1);
6348     offset.HighPart = 0;        /* too bad */
6349     offset.LowPart = smb_GetSMBParmLong(inp, 2);
6350     hint = smb_GetSMBParm(inp, 4);
6351
6352     op = smb_GetSMBData(inp, NULL);
6353     op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
6354
6355     osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
6356              fd, offset.LowPart, count);
6357         
6358     fd = smb_ChainFID(fd, inp);
6359     fidp = smb_FindFID(vcp, fd, 0);
6360     if (!fidp) {
6361         osi_Log0(smb_logp, "smb_ReceiveCoreWrite fid not found");
6362         return CM_ERROR_BADFD;
6363     }
6364         
6365     lock_ObtainMutex(&fidp->mx);
6366     if (fidp->flags & SMB_FID_IOCTL) {
6367         lock_ReleaseMutex(&fidp->mx);
6368         code = smb_IoctlWrite(fidp, vcp, inp, outp);
6369         smb_ReleaseFID(fidp);
6370         osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
6371         return code;
6372     }
6373     lock_ReleaseMutex(&fidp->mx);
6374     userp = smb_GetUserFromVCP(vcp, inp);
6375
6376     {
6377         cm_key_t key;
6378         LARGE_INTEGER LOffset;
6379         LARGE_INTEGER LLength;
6380
6381         pid = ((smb_t *) inp)->pid;
6382         key = cm_GenerateKey(vcp->vcID, pid, fd);
6383
6384         LOffset.HighPart = offset.HighPart;
6385         LOffset.LowPart = offset.LowPart;
6386         LLength.HighPart = 0;
6387         LLength.LowPart = count;
6388
6389         lock_ObtainMutex(&fidp->scp->mx);
6390         code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6391         lock_ReleaseMutex(&fidp->scp->mx);
6392
6393         if (code) {
6394             osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
6395             goto done;
6396         }
6397     }
6398
6399     /* special case: 0 bytes transferred means truncate to this position */
6400     if (count == 0) {
6401         cm_req_t req;
6402
6403         osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
6404         
6405         cm_InitReq(&req);
6406
6407         truncAttr.mask = CM_ATTRMASK_LENGTH;
6408         truncAttr.length.LowPart = offset.LowPart;
6409         truncAttr.length.HighPart = 0;
6410         lock_ObtainMutex(&fidp->mx);
6411         code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
6412         fidp->flags |= SMB_FID_LENGTHSETDONE;
6413         lock_ReleaseMutex(&fidp->mx);
6414         smb_SetSMBParm(outp, 0, 0 /* count */);
6415         smb_SetSMBDataLength(outp, 0);
6416         goto done;
6417     }
6418
6419     /*
6420      * Work around bug in NT client
6421      *
6422      * When copying a file, the NT client should first copy the data,
6423      * then copy the last write time.  But sometimes the NT client does
6424      * these in the wrong order, so the data copies would inadvertently
6425      * cause the last write time to be overwritten.  We try to detect this,
6426      * and don't set client mod time if we think that would go against the
6427      * intention.
6428      */
6429     lock_ObtainMutex(&fidp->mx);
6430     if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6431         fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6432         fidp->scp->clientModTime = time(NULL);
6433     }
6434     lock_ReleaseMutex(&fidp->mx);
6435
6436     code = 0;
6437     while ( code == 0 && count > 0 ) {
6438         code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6439         if (code == 0 && written == 0)
6440             code = CM_ERROR_PARTIALWRITE;
6441
6442         offset = LargeIntegerAdd(offset,
6443                                  ConvertLongToLargeInteger(written));
6444         count -= written;
6445         total_written += written;
6446         written = 0;
6447     }
6448     
6449     osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
6450              total_written, code);
6451         
6452     /* set the packet data length to 3 bytes for the data block header,
6453      * plus the size of the data.
6454      */
6455     smb_SetSMBParm(outp, 0, total_written);
6456     smb_SetSMBParmLong(outp, 1, offset.LowPart);
6457     smb_SetSMBParm(outp, 3, hint);
6458     smb_SetSMBDataLength(outp, 0);
6459
6460   done:
6461     smb_ReleaseFID(fidp);
6462     cm_ReleaseUser(userp);
6463
6464     return code;
6465 }
6466
6467 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6468                           NCB *ncbp, raw_write_cont_t *rwcp)
6469 {
6470     unsigned short fd;
6471     smb_fid_t *fidp;
6472     cm_user_t *userp;
6473     char *rawBuf;
6474     long written = 0;
6475     long code = 0;
6476
6477     fd = smb_GetSMBParm(inp, 0);
6478     fidp = smb_FindFID(vcp, fd, 0);
6479
6480     osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
6481              rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
6482
6483     userp = smb_GetUserFromVCP(vcp, inp);
6484
6485     rawBuf = rwcp->buf;
6486     code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
6487                                                  &written);
6488     if (rwcp->writeMode & 0x1) {        /* synchronous */
6489         smb_t *op;
6490
6491         smb_FormatResponsePacket(vcp, inp, outp);
6492         op = (smb_t *) outp;
6493         op->com = 0x20;         /* SMB_COM_WRITE_COMPLETE */
6494         smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
6495         smb_SetSMBDataLength(outp,  0);
6496         smb_SendPacket(vcp, outp);
6497         smb_FreePacket(outp);
6498     }
6499     else {                              /* asynchronous */
6500         lock_ObtainMutex(&fidp->mx);
6501         fidp->raw_writers--;
6502         if (fidp->raw_writers == 0)
6503             thrd_SetEvent(fidp->raw_write_event);
6504         lock_ReleaseMutex(&fidp->mx);
6505     }
6506
6507     /* Give back raw buffer */
6508     lock_ObtainMutex(&smb_RawBufLock);
6509     *((char **)rawBuf) = smb_RawBufs;
6510     smb_RawBufs = rawBuf;
6511     lock_ReleaseMutex(&smb_RawBufLock);
6512
6513     smb_ReleaseFID(fidp);
6514     cm_ReleaseUser(userp);
6515 }
6516
6517 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6518 {
6519     return 0;
6520 }
6521
6522 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
6523 {
6524     osi_hyper_t offset;
6525     long count, written = 0, total_written = 0;
6526     long totalCount;
6527     unsigned short fd;
6528     smb_fid_t *fidp;
6529     long code = 0;
6530     cm_user_t *userp;
6531     char *op;
6532     unsigned short writeMode;
6533     char *rawBuf;
6534     fd = smb_GetSMBParm(inp, 0);
6535     totalCount = smb_GetSMBParm(inp, 1);
6536     count = smb_GetSMBParm(inp, 10);
6537     writeMode = smb_GetSMBParm(inp, 7);
6538
6539     op = (char *) inp->data;
6540     op += smb_GetSMBParm(inp, 11);
6541
6542     offset.HighPart = 0;
6543     offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6544
6545     if (*inp->wctp == 14) {
6546         /* we received a 64-bit file offset */
6547 #ifdef AFS_LARGEFILES
6548         offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
6549
6550         if (LargeIntegerLessThanZero(offset)) {
6551             osi_Log2(smb_logp,
6552                      "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
6553                      offset.HighPart, offset.LowPart);
6554             return CM_ERROR_BADSMB;
6555         }
6556 #else
6557         if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
6558             osi_Log0(smb_logp,
6559                      "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files");
6560             return CM_ERROR_BADSMB;
6561         }
6562
6563         offset.HighPart = 0;
6564 #endif
6565     } else {
6566         offset.HighPart = 0;    /* 32-bit file offset */
6567     }
6568     
6569     osi_Log4(smb_logp,
6570              "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
6571              fd, offset.HighPart, offset.LowPart, count);
6572     osi_Log1(smb_logp,
6573              "               WriteRaw WriteMode 0x%x",
6574              writeMode);
6575         
6576     fd = smb_ChainFID(fd, inp);
6577     fidp = smb_FindFID(vcp, fd, 0);
6578     if (!fidp) {
6579         return CM_ERROR_BADFD;
6580     }
6581
6582     {
6583         unsigned pid;
6584         cm_key_t key;
6585         LARGE_INTEGER LOffset;
6586         LARGE_INTEGER LLength;
6587
6588         pid = ((smb_t *) inp)->pid;
6589         key = cm_GenerateKey(vcp->vcID, pid, fd);
6590
6591         LOffset.HighPart = offset.HighPart;
6592         LOffset.LowPart = offset.LowPart;
6593         LLength.HighPart = 0;
6594         LLength.LowPart = count;
6595
6596         lock_ObtainMutex(&fidp->scp->mx);
6597         code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6598         lock_ReleaseMutex(&fidp->scp->mx);
6599
6600         if (code) {
6601             smb_ReleaseFID(fidp);
6602             return code;
6603         }
6604     }
6605         
6606     userp = smb_GetUserFromVCP(vcp, inp);
6607
6608     /*
6609      * Work around bug in NT client
6610      *
6611      * When copying a file, the NT client should first copy the data,
6612      * then copy the last write time.  But sometimes the NT client does
6613      * these in the wrong order, so the data copies would inadvertently
6614      * cause the last write time to be overwritten.  We try to detect this,
6615      * and don't set client mod time if we think that would go against the
6616      * intention.
6617      */
6618     lock_ObtainMutex(&fidp->mx);
6619     if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
6620         fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6621         fidp->scp->clientModTime = time(NULL);
6622     }
6623     lock_ReleaseMutex(&fidp->mx);
6624
6625     code = 0;
6626     while ( code == 0 && count > 0 ) {
6627         code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6628         if (code == 0 && written == 0)
6629             code = CM_ERROR_PARTIALWRITE;
6630
6631         offset = LargeIntegerAdd(offset,
6632                                  ConvertLongToLargeInteger(written));
6633
6634         count -= written;
6635         total_written += written;
6636         written = 0;
6637     }
6638
6639     /* Get a raw buffer */
6640     if (code == 0) {
6641         rawBuf = NULL;
6642         lock_ObtainMutex(&smb_RawBufLock);
6643         if (smb_RawBufs) {
6644             /* Get a raw buf, from head of list */
6645             rawBuf = smb_RawBufs;
6646             smb_RawBufs = *(char **)smb_RawBufs;
6647         }
6648         else
6649             code = CM_ERROR_USESTD;
6650                 
6651         lock_ReleaseMutex(&smb_RawBufLock);
6652     }
6653
6654     /* Don't allow a premature Close */
6655     if (code == 0 && (writeMode & 1) == 0) {
6656         lock_ObtainMutex(&fidp->mx);
6657         fidp->raw_writers++;
6658         thrd_ResetEvent(fidp->raw_write_event);
6659         lock_ReleaseMutex(&fidp->mx);
6660     }
6661
6662     smb_ReleaseFID(fidp);
6663     cm_ReleaseUser(userp);
6664
6665     if (code) {
6666         smb_SetSMBParm(outp, 0, total_written);
6667         smb_SetSMBDataLength(outp, 0);
6668         ((smb_t *)outp)->com = 0x20;    /* SMB_COM_WRITE_COMPLETE */
6669         rwcp->code = code;
6670         return code;
6671     }
6672
6673     offset = LargeIntegerAdd(offset,
6674                              ConvertLongToLargeInteger(count));
6675
6676     rwcp->code = 0;
6677     rwcp->buf = rawBuf;
6678     rwcp->offset.HighPart = offset.HighPart;
6679     rwcp->offset.LowPart = offset.LowPart;
6680     rwcp->count = totalCount - count;
6681     rwcp->writeMode = writeMode;
6682     rwcp->alreadyWritten = total_written;
6683
6684     /* set the packet data length to 3 bytes for the data block header,
6685      * plus the size of the data.
6686      */
6687     smb_SetSMBParm(outp, 0, 0xffff);
6688     smb_SetSMBDataLength(outp, 0);
6689
6690     return 0;
6691 }
6692
6693 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6694 {
6695     osi_hyper_t offset;
6696     long count, finalCount;
6697     unsigned short fd;
6698     unsigned pid;
6699     smb_fid_t *fidp;
6700     long code = 0;
6701     cm_user_t *userp;
6702     char *op;
6703         
6704     fd = smb_GetSMBParm(inp, 0);
6705     count = smb_GetSMBParm(inp, 1);
6706     offset.HighPart = 0;        /* too bad */
6707     offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6708         
6709     osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
6710              fd, offset.LowPart, count);
6711         
6712     fd = smb_ChainFID(fd, inp);
6713     fidp = smb_FindFID(vcp, fd, 0);
6714     if (!fidp)
6715         return CM_ERROR_BADFD;
6716         
6717     lock_ObtainMutex(&fidp->mx);
6718     if (fidp->flags & SMB_FID_IOCTL) {
6719         lock_ReleaseMutex(&fidp->mx);
6720         code = smb_IoctlRead(fidp, vcp, inp, outp);
6721         smb_ReleaseFID(fidp);
6722         return code;
6723     }
6724     lock_ReleaseMutex(&fidp->mx);
6725
6726     {
6727         LARGE_INTEGER LOffset, LLength;
6728         cm_key_t key;
6729
6730         pid = ((smb_t *) inp)->pid;
6731         key = cm_GenerateKey(vcp->vcID, pid, fd);
6732
6733         LOffset.HighPart = 0;
6734         LOffset.LowPart = offset.LowPart;
6735         LLength.HighPart = 0;
6736         LLength.LowPart = count;
6737         
6738         lock_ObtainMutex(&fidp->scp->mx);
6739         code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
6740         lock_ReleaseMutex(&fidp->scp->mx);
6741     }
6742     if (code) {
6743         smb_ReleaseFID(fidp);
6744         return code;
6745     }
6746         
6747     userp = smb_GetUserFromVCP(vcp, inp);
6748
6749     /* remember this for final results */
6750     smb_SetSMBParm(outp, 0, count);
6751     smb_SetSMBParm(outp, 1, 0);
6752     smb_SetSMBParm(outp, 2, 0);
6753     smb_SetSMBParm(outp, 3, 0);
6754     smb_SetSMBParm(outp, 4, 0);
6755
6756     /* set the packet data length to 3 bytes for the data block header,
6757      * plus the size of the data.
6758      */
6759     smb_SetSMBDataLength(outp, count+3);
6760         
6761     /* get op ptr after putting in the parms, since otherwise we don't
6762      * know where the data really is.
6763      */
6764     op = smb_GetSMBData(outp, NULL);
6765
6766     /* now emit the data block header: 1 byte of type and 2 bytes of length */
6767     *op++ = 1;  /* data block marker */
6768     *op++ = (unsigned char) (count & 0xff);
6769     *op++ = (unsigned char) ((count >> 8) & 0xff);
6770                 
6771     code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6772
6773     /* fix some things up */
6774     smb_SetSMBParm(outp, 0, finalCount);
6775     smb_SetSMBDataLength(outp, finalCount+3);
6776
6777     smb_ReleaseFID(fidp);
6778         
6779     cm_ReleaseUser(userp);
6780     return code;
6781 }
6782
6783 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6784 {
6785     char *pathp;
6786     long code = 0;
6787     cm_space_t *spacep;
6788     char *tp;
6789     cm_user_t *userp;
6790     cm_scache_t *dscp;                  /* dir we're dealing with */
6791     cm_scache_t *scp;                   /* file we're creating */
6792     cm_attr_t setAttr;
6793     int initialModeBits;
6794     char *lastNamep;
6795     int caseFold;
6796     char *tidPathp;
6797     cm_req_t req;
6798
6799     cm_InitReq(&req);
6800
6801     scp = NULL;
6802         
6803     /* compute initial mode bits based on read-only flag in attributes */
6804     initialModeBits = 0777;
6805         
6806     tp = smb_GetSMBData(inp, NULL);
6807     pathp = smb_ParseASCIIBlock(tp, &tp);
6808     if (smb_StoreAnsiFilenames)
6809         OemToChar(pathp,pathp);
6810
6811     if (strcmp(pathp, "\\") == 0)
6812         return CM_ERROR_EXISTS;
6813
6814     spacep = inp->spacep;
6815     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6816
6817     userp = smb_GetUserFromVCP(vcp, inp);
6818
6819     caseFold = CM_FLAG_CASEFOLD;
6820
6821     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6822     if (code) {
6823         cm_ReleaseUser(userp);
6824         return CM_ERROR_NOSUCHPATH;
6825     }
6826
6827     code = cm_NameI(cm_data.rootSCachep, spacep->data,
6828                     caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
6829                     userp, tidPathp, &req, &dscp);
6830
6831     if (code) {
6832         cm_ReleaseUser(userp);
6833         return code;
6834     }
6835         
6836 #ifdef DFS_SUPPORT
6837     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6838         cm_ReleaseSCache(dscp);
6839         cm_ReleaseUser(userp);
6840         if ( WANTS_DFS_PATHNAMES(inp) )
6841             return CM_ERROR_PATH_NOT_COVERED;
6842         else
6843             return CM_ERROR_BADSHARENAME;
6844     }
6845 #endif /* DFS_SUPPORT */
6846
6847     /* otherwise, scp points to the parent directory.  Do a lookup, and
6848      * fail if we find it.  Otherwise, we do the create.
6849      */
6850     if (!lastNamep) 
6851         lastNamep = pathp;
6852     else 
6853         lastNamep++;
6854     code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6855     if (scp) cm_ReleaseSCache(scp);
6856     if (code != CM_ERROR_NOSUCHFILE) {
6857         if (code == 0) code = CM_ERROR_EXISTS;
6858         cm_ReleaseSCache(dscp);
6859         cm_ReleaseUser(userp);
6860         return code;
6861     }
6862         
6863     setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6864     setAttr.clientModTime = time(NULL);
6865     code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
6866     if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6867         smb_NotifyChange(FILE_ACTION_ADDED,
6868                          FILE_NOTIFY_CHANGE_DIR_NAME,
6869                          dscp, lastNamep, NULL, TRUE);
6870         
6871     /* we don't need this any longer */
6872     cm_ReleaseSCache(dscp);
6873
6874     if (code) {
6875         /* something went wrong creating or truncating the file */
6876         cm_ReleaseUser(userp);
6877         return code;
6878     }
6879         
6880     /* otherwise we succeeded */
6881     smb_SetSMBDataLength(outp, 0);
6882     cm_ReleaseUser(userp);
6883
6884     return 0;
6885 }
6886
6887 BOOL smb_IsLegalFilename(char *filename)
6888 {
6889     /* 
6890      *  Find the longest substring of filename that does not contain
6891      *  any of the chars in illegalChars.  If that substring is less
6892      *  than the length of the whole string, then one or more of the
6893      *  illegal chars is in filename. 
6894      */
6895     if (strcspn(filename, illegalChars) < strlen(filename))
6896         return FALSE;
6897
6898     return TRUE;
6899 }        
6900
6901 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6902 {
6903     char *pathp;
6904     long code = 0;
6905     cm_space_t *spacep;
6906     char *tp;
6907     int excl;
6908     cm_user_t *userp;
6909     cm_scache_t *dscp;                  /* dir we're dealing with */
6910     cm_scache_t *scp;                   /* file we're creating */
6911     cm_attr_t setAttr;
6912     int initialModeBits;
6913     smb_fid_t *fidp;
6914     int attributes;
6915     char *lastNamep;
6916     int caseFold;
6917     afs_uint32 dosTime;
6918     char *tidPathp;
6919     cm_req_t req;
6920     int created = 0;                    /* the file was new */
6921
6922     cm_InitReq(&req);
6923
6924     scp = NULL;
6925     excl = (inp->inCom == 0x03)? 0 : 1;
6926         
6927     attributes = smb_GetSMBParm(inp, 0);
6928     dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6929         
6930     /* compute initial mode bits based on read-only flag in attributes */
6931     initialModeBits = 0666;
6932     if (attributes & SMB_ATTR_READONLY) 
6933         initialModeBits &= ~0222;
6934         
6935     tp = smb_GetSMBData(inp, NULL);
6936     pathp = smb_ParseASCIIBlock(tp, &tp);
6937     if (smb_StoreAnsiFilenames)
6938         OemToChar(pathp,pathp);
6939
6940     spacep = inp->spacep;
6941     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6942
6943     userp = smb_GetUserFromVCP(vcp, inp);
6944
6945     caseFold = CM_FLAG_CASEFOLD;
6946
6947     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6948     if (code) {
6949         cm_ReleaseUser(userp);
6950         return CM_ERROR_NOSUCHPATH;
6951     }
6952     code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
6953                     userp, tidPathp, &req, &dscp);
6954
6955     if (code) {
6956         cm_ReleaseUser(userp);
6957         return code;
6958     }
6959         
6960 #ifdef DFS_SUPPORT
6961     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6962         cm_ReleaseSCache(dscp);
6963         cm_ReleaseUser(userp);
6964         if ( WANTS_DFS_PATHNAMES(inp) )
6965             return CM_ERROR_PATH_NOT_COVERED;
6966         else
6967             return CM_ERROR_BADSHARENAME;
6968     }
6969 #endif /* DFS_SUPPORT */
6970
6971     /* otherwise, scp points to the parent directory.  Do a lookup, and
6972      * truncate the file if we find it, otherwise we create the file.
6973      */
6974     if (!lastNamep) 
6975         lastNamep = pathp;
6976     else 
6977         lastNamep++;
6978
6979     if (!smb_IsLegalFilename(lastNamep))
6980         return CM_ERROR_BADNTFILENAME;
6981
6982     osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
6983 #ifdef DEBUG_VERBOSE
6984     {
6985         char *hexp;
6986         hexp = osi_HexifyString( lastNamep );
6987         DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
6988         free(hexp);
6989     }
6990 #endif    
6991
6992     code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6993     if (code && code != CM_ERROR_NOSUCHFILE) {
6994         cm_ReleaseSCache(dscp);
6995         cm_ReleaseUser(userp);
6996         return code;
6997     }
6998         
6999     /* if we get here, if code is 0, the file exists and is represented by
7000      * scp.  Otherwise, we have to create it.
7001      */
7002     if (code == 0) {
7003         if (excl) {
7004             /* oops, file shouldn't be there */
7005             cm_ReleaseSCache(dscp);
7006             cm_ReleaseSCache(scp);
7007             cm_ReleaseUser(userp);
7008             return CM_ERROR_EXISTS;
7009         }
7010
7011         setAttr.mask = CM_ATTRMASK_LENGTH;
7012         setAttr.length.LowPart = 0;
7013         setAttr.length.HighPart = 0;
7014         code = cm_SetAttr(scp, &setAttr, userp, &req);
7015     }
7016     else {
7017         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7018         smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
7019         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7020                          &req);
7021         if (code == 0) {
7022             created = 1;
7023             if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7024                 smb_NotifyChange(FILE_ACTION_ADDED,     
7025                                  FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7026                                  dscp, lastNamep, NULL, TRUE);
7027         } else if (!excl && code == CM_ERROR_EXISTS) {
7028             /* not an exclusive create, and someone else tried
7029              * creating it already, then we open it anyway.  We
7030              * don't bother retrying after this, since if this next
7031              * fails, that means that the file was deleted after
7032              * we started this call.
7033              */
7034             code = cm_Lookup(dscp, lastNamep, caseFold, userp,
7035                              &req, &scp);
7036             if (code == 0) {
7037                 setAttr.mask = CM_ATTRMASK_LENGTH;
7038                 setAttr.length.LowPart = 0;
7039                 setAttr.length.HighPart = 0;
7040                 code = cm_SetAttr(scp, &setAttr, userp, &req);
7041             }
7042         }
7043     }
7044         
7045     /* we don't need this any longer */
7046     cm_ReleaseSCache(dscp);
7047
7048     if (code) {
7049         /* something went wrong creating or truncating the file */
7050         if (scp) cm_ReleaseSCache(scp);
7051         cm_ReleaseUser(userp);
7052         return code;
7053     }
7054
7055     /* make sure we only open files */
7056     if (scp->fileType != CM_SCACHETYPE_FILE) {
7057         cm_ReleaseSCache(scp);
7058         cm_ReleaseUser(userp);
7059         return CM_ERROR_ISDIR;
7060     }
7061
7062     /* now all we have to do is open the file itself */
7063     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7064     osi_assert(fidp);
7065         
7066     cm_HoldUser(userp);
7067
7068     lock_ObtainMutex(&fidp->mx);
7069     /* always create it open for read/write */
7070     fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
7071
7072     /* remember that the file was newly created */
7073     if (created)
7074         fidp->flags |= SMB_FID_CREATED;
7075
7076     osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
7077
7078     /* save a pointer to the vnode */
7079     fidp->scp = scp;
7080     lock_ObtainMutex(&scp->mx);
7081     scp->flags |= CM_SCACHEFLAG_SMB_FID;
7082     lock_ReleaseMutex(&scp->mx);
7083     
7084     /* and the user */
7085     fidp->userp = userp;
7086     lock_ReleaseMutex(&fidp->mx);
7087
7088     smb_SetSMBParm(outp, 0, fidp->fid);
7089     smb_SetSMBDataLength(outp, 0);
7090
7091     cm_Open(scp, 0, userp);
7092
7093     smb_ReleaseFID(fidp);
7094     cm_ReleaseUser(userp);
7095     /* leave scp held since we put it in fidp->scp */
7096     return 0;
7097 }
7098
7099 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7100 {
7101     long code = 0;
7102     osi_hyper_t new_offset;
7103     long offset;
7104     int whence;
7105     unsigned short fd;
7106     smb_fid_t *fidp;
7107     cm_scache_t *scp;
7108     cm_user_t *userp;
7109     cm_req_t req;
7110
7111     cm_InitReq(&req);
7112         
7113     fd = smb_GetSMBParm(inp, 0);
7114     whence = smb_GetSMBParm(inp, 1);
7115     offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7116         
7117     /* try to find the file descriptor */
7118     fd = smb_ChainFID(fd, inp);
7119     fidp = smb_FindFID(vcp, fd, 0);
7120
7121     if (!fidp)
7122         return CM_ERROR_BADFD;
7123     
7124     lock_ObtainMutex(&fidp->mx);
7125     if (fidp->flags & SMB_FID_IOCTL) {
7126         lock_ReleaseMutex(&fidp->mx);
7127         smb_ReleaseFID(fidp);
7128         return CM_ERROR_BADFD;
7129     }
7130     lock_ReleaseMutex(&fidp->mx);
7131         
7132     userp = smb_GetUserFromVCP(vcp, inp);
7133
7134     lock_ObtainMutex(&fidp->mx);
7135     scp = fidp->scp;
7136     cm_HoldSCache(scp);
7137     lock_ReleaseMutex(&fidp->mx);
7138     lock_ObtainMutex(&scp->mx);
7139     code = cm_SyncOp(scp, NULL, userp, &req, 0,
7140                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7141     if (code == 0) {
7142         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7143         if (whence == 1) {
7144             /* offset from current offset */
7145             new_offset = LargeIntegerAdd(fidp->offset,
7146                                          ConvertLongToLargeInteger(offset));
7147         }
7148         else if (whence == 2) {
7149             /* offset from current EOF */
7150             new_offset = LargeIntegerAdd(scp->length,
7151                                          ConvertLongToLargeInteger(offset));
7152         } else {
7153             new_offset = ConvertLongToLargeInteger(offset);
7154         }
7155
7156         fidp->offset = new_offset;
7157         smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
7158         smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
7159         smb_SetSMBDataLength(outp, 0);
7160     }
7161     lock_ReleaseMutex(&scp->mx);
7162     smb_ReleaseFID(fidp);
7163     cm_ReleaseSCache(scp);
7164     cm_ReleaseUser(userp);
7165     return code;
7166 }
7167
7168 /* dispatch all of the requests received in a packet.  Due to chaining, this may
7169  * be more than one request.
7170  */
7171 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7172                         NCB *ncbp, raw_write_cont_t *rwcp)
7173 {
7174     smb_dispatch_t *dp;
7175     smb_t *smbp;
7176     unsigned long code = 0;
7177     unsigned char *outWctp;
7178     int nparms;                 /* # of bytes of parameters */
7179     char tbuffer[200];
7180     int nbytes;                 /* bytes of data, excluding count */
7181     int temp;
7182     unsigned char *tp;
7183     unsigned short errCode;
7184     unsigned long NTStatus;
7185     int noSend;
7186     unsigned char errClass;
7187     unsigned int oldGen;
7188     DWORD oldTime, newTime;
7189
7190     /* get easy pointer to the data */
7191     smbp = (smb_t *) inp->data;
7192
7193     if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
7194         /* setup the basic parms for the initial request in the packet */
7195         inp->inCom = smbp->com;
7196         inp->wctp = &smbp->wct;
7197         inp->inCount = 0;
7198         inp->ncb_length = ncbp->ncb_length;
7199     }
7200     noSend = 0;
7201
7202     /* Sanity check */
7203     if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
7204         /* log it and discard it */
7205         LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT, 
7206                  __FILE__, __LINE__, ncbp->ncb_length);
7207         osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
7208         return;
7209     }
7210
7211     /* We are an ongoing op */
7212     thrd_Increment(&ongoingOps);
7213
7214     /* set up response packet for receiving output */
7215     if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
7216         smb_FormatResponsePacket(vcp, inp, outp);
7217     outWctp = outp->wctp;
7218
7219     /* Remember session generation number and time */
7220     oldGen = sessionGen;
7221     oldTime = GetTickCount();
7222
7223     while (inp->inCom != 0xff) {
7224         dp = &smb_dispatchTable[inp->inCom];
7225
7226         if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
7227             outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
7228             code = outp->resumeCode;
7229             goto resume;
7230         }
7231
7232         /* process each request in the packet; inCom, wctp and inCount
7233          * are already set up.
7234          */
7235         osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
7236                   ncbp->ncb_lsn);
7237
7238         /* now do the dispatch */
7239         /* start by formatting the response record a little, as a default */
7240         if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
7241             outWctp[0] = 2;
7242             outWctp[1] = 0xff;  /* no operation */
7243             outWctp[2] = 0;             /* padding */
7244             outWctp[3] = 0;
7245             outWctp[4] = 0;
7246         }
7247         else {
7248             /* not a chained request, this is a more reasonable default */
7249             outWctp[0] = 0;     /* wct of zero */
7250             outWctp[1] = 0;     /* and bcc (word) of zero */
7251             outWctp[2] = 0;
7252         }   
7253
7254         /* once set, stays set.  Doesn't matter, since we never chain
7255          * "no response" calls.
7256          */
7257         if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
7258             noSend = 1;
7259
7260         if (dp->procp) {
7261             /* we have a recognized operation */
7262
7263             if (inp->inCom == 0x1d)
7264                 /* Raw Write */
7265                 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
7266             else {
7267                 osi_Log4(smb_logp,"Dispatch %s vcp 0x%p lana %d lsn %d",myCrt_Dispatch(inp->inCom),vcp,vcp->lana,vcp->lsn);
7268                 code = (*(dp->procp)) (vcp, inp, outp);
7269                 osi_Log4(smb_logp,"Dispatch return  code 0x%x vcp 0x%p lana %d lsn %d",code,vcp,vcp->lana,vcp->lsn);
7270 #ifdef LOG_PACKET
7271                 if ( code == CM_ERROR_BADSMB ||
7272                      code == CM_ERROR_BADOP )
7273                 smb_LogPacket(inp);
7274 #endif /* LOG_PACKET */
7275             }   
7276
7277             if (oldGen != sessionGen) {
7278                 newTime = GetTickCount();
7279                 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION, 
7280                          newTime - oldTime, ncbp->ncb_length);
7281                 osi_Log2(smb_logp, "Pkt straddled session startup, "
7282                           "took %d ms, ncb length %d", newTime - oldTime, ncbp->ncb_length);
7283             }
7284         }
7285         else {
7286             /* bad opcode, fail the request, after displaying it */
7287             osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
7288 #ifdef LOG_PACKET
7289             smb_LogPacket(inp);
7290 #endif  /* LOG_PACKET */
7291
7292             if (showErrors) {
7293                 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
7294                 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
7295                                       MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
7296                 if (code == IDCANCEL) 
7297                     showErrors = 0;
7298             }
7299             code = CM_ERROR_BADOP;
7300         }
7301
7302         /* catastrophic failure:  log as much as possible */
7303         if (code == CM_ERROR_BADSMB) {
7304             LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID, 
7305                      ncbp->ncb_length);
7306 #ifdef LOG_PACKET
7307             smb_LogPacket(inp);
7308 #endif /* LOG_PACKET */
7309             osi_Log1(smb_logp, "Invalid SMB message, length %d",
7310                      ncbp->ncb_length);
7311
7312             code = CM_ERROR_INVAL;
7313         }
7314
7315         if (outp->flags & SMB_PACKETFLAG_NOSEND) {
7316             thrd_Decrement(&ongoingOps);
7317             return;
7318         }
7319
7320       resume:
7321         /* now, if we failed, turn the current response into an empty
7322          * one, and fill in the response packet's error code.
7323          */
7324         if (code) {
7325             if (vcp->flags & SMB_VCFLAG_STATUS32) {
7326                 smb_MapNTError(code, &NTStatus);
7327                 outWctp = outp->wctp;
7328                 smbp = (smb_t *) &outp->data;
7329                 if (code != CM_ERROR_PARTIALWRITE
7330                      && code != CM_ERROR_BUFFERTOOSMALL 
7331                      && code != CM_ERROR_GSSCONTINUE) {
7332                     /* nuke wct and bcc.  For a partial
7333                      * write or an in-process authentication handshake, 
7334                      * assume they're OK.
7335                      */
7336                     *outWctp++ = 0;
7337                     *outWctp++ = 0;
7338                     *outWctp++ = 0;
7339                 }
7340                 smbp->rcls = (unsigned char) (NTStatus & 0xff);
7341                 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
7342                 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
7343                 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
7344                 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7345                 break;
7346             }
7347             else {
7348                 smb_MapCoreError(code, vcp, &errCode, &errClass);
7349                 outWctp = outp->wctp;
7350                 smbp = (smb_t *) &outp->data;
7351                 if (code != CM_ERROR_PARTIALWRITE) {
7352                     /* nuke wct and bcc.  For a partial
7353                      * write, assume they're OK.
7354                      */
7355                     *outWctp++ = 0;
7356                     *outWctp++ = 0;
7357                     *outWctp++ = 0;
7358                 }
7359                 smbp->errLow = (unsigned char) (errCode & 0xff);
7360                 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
7361                 smbp->rcls = errClass;
7362                 break;
7363             }
7364         }       /* error occurred */
7365
7366         /* if we're here, we've finished one request.  Look to see if
7367          * this is a chained opcode.  If it is, setup things to process
7368          * the chained request, and setup the output buffer to hold the
7369          * chained response.  Start by finding the next input record.
7370          */
7371         if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
7372             break;              /* not a chained req */
7373         tp = inp->wctp;         /* points to start of last request */
7374         /* in a chained request, the first two
7375          * parm fields are required, and are
7376          * AndXCommand/AndXReserved and
7377          * AndXOffset. */
7378         if (tp[0] < 2) break;   
7379         if (tp[1] == 0xff) break;       /* no more chained opcodes */
7380         inp->inCom = tp[1];
7381         inp->wctp = inp->data + tp[3] + (tp[4] << 8);
7382         inp->inCount++;
7383
7384         /* and now append the next output request to the end of this
7385          * last request.  Begin by finding out where the last response
7386          * ends, since that's where we'll put our new response.
7387          */
7388         outWctp = outp->wctp;           /* ptr to out parameters */
7389         osi_assert (outWctp[0] >= 2);   /* need this for all chained requests */
7390         nparms = outWctp[0] << 1;
7391         tp = outWctp + nparms + 1;      /* now points to bcc field */
7392         nbytes = tp[0] + (tp[1] << 8);  /* # of data bytes */
7393         tp += 2 /* for the count itself */ + nbytes;
7394         /* tp now points to the new output record; go back and patch the
7395          * second parameter (off2) to point to the new record.
7396          */
7397         temp = (unsigned int)(tp - outp->data);
7398         outWctp[3] = (unsigned char) (temp & 0xff);
7399         outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
7400         outWctp[2] = 0; /* padding */
7401         outWctp[1] = inp->inCom;        /* next opcode */
7402
7403         /* finally, setup for the next iteration */
7404         outp->wctp = tp;
7405         outWctp = tp;
7406     }   /* while loop over all requests in the packet */
7407
7408     /* now send the output packet, and return */
7409     if (!noSend)
7410         smb_SendPacket(vcp, outp);
7411     thrd_Decrement(&ongoingOps);
7412
7413     return;
7414 }
7415
7416 /* Wait for Netbios() calls to return, and make the results available to server
7417  * threads.  Note that server threads can't wait on the NCBevents array
7418  * themselves, because NCB events are manual-reset, and the servers would race
7419  * each other to reset them.
7420  */
7421 void smb_ClientWaiter(void *parmp)
7422 {
7423     DWORD code;
7424     int   idx;
7425
7426     while (smbShutdownFlag == 0) {
7427         code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
7428                                                  FALSE, INFINITE);
7429         if (code == WAIT_OBJECT_0)
7430             continue;
7431
7432         /* error checking */
7433         if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7434         {
7435             int abandonIdx = code - WAIT_ABANDONED_0;
7436             osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7437         }
7438
7439         if (code == WAIT_IO_COMPLETION)
7440         {
7441             osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
7442             continue;
7443         }
7444         
7445         if (code == WAIT_TIMEOUT)
7446         {
7447             osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
7448         }
7449
7450         if (code == WAIT_FAILED)
7451         {
7452             osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
7453         }
7454
7455         idx = code - WAIT_OBJECT_0;
7456  
7457         /* check idx range! */
7458         if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
7459         {
7460             /* this is fatal - log as much as possible */
7461             osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
7462             osi_assert(0);
7463         }
7464         
7465         thrd_ResetEvent(NCBevents[idx]);
7466         thrd_SetEvent(NCBreturns[0][idx]);
7467     }
7468 }
7469
7470 /*
7471  * Try to have one NCBRECV request waiting for every live session.  Not more
7472  * than one, because if there is more than one, it's hard to handle Write Raw.
7473  */
7474 void smb_ServerWaiter(void *parmp)
7475 {
7476     DWORD code;
7477     int idx_session, idx_NCB;
7478     NCB *ncbp;
7479
7480     while (smbShutdownFlag == 0) {
7481         /* Get a session */
7482         code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
7483                                                  FALSE, INFINITE);
7484         if (code == WAIT_OBJECT_0)
7485             continue;
7486
7487         if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
7488         {
7489             int abandonIdx = code - WAIT_ABANDONED_0;
7490             osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7491         }
7492         
7493         if (code == WAIT_IO_COMPLETION)
7494         {
7495             osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
7496             continue;
7497         }
7498         
7499         if (code == WAIT_TIMEOUT)
7500         {
7501             osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
7502         }
7503         
7504         if (code == WAIT_FAILED)
7505         {
7506             osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
7507         }
7508         
7509         idx_session = code - WAIT_OBJECT_0;
7510
7511         /* check idx range! */
7512         if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
7513         {
7514             /* this is fatal - log as much as possible */
7515             osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
7516             osi_assert(0);
7517         }
7518
7519                 /* Get an NCB */
7520       NCBretry:
7521         code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
7522                                                  FALSE, INFINITE);
7523         if (code == WAIT_OBJECT_0) {
7524             if (smbShutdownFlag == 1) 
7525                 break;
7526             else
7527                 goto NCBretry;
7528         }
7529
7530         /* error checking */
7531         if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7532         {
7533             int abandonIdx = code - WAIT_ABANDONED_0;
7534             osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7535         }
7536         
7537         if (code == WAIT_IO_COMPLETION)
7538         {
7539             osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
7540             continue;
7541         }
7542         
7543         if (code == WAIT_TIMEOUT)
7544         {
7545             osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
7546         }
7547         
7548         if (code == WAIT_FAILED)
7549         {
7550             osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
7551         }
7552                 
7553         idx_NCB = code - WAIT_OBJECT_0;
7554
7555         /* check idx range! */
7556         if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
7557         {
7558             /* this is fatal - log as much as possible */
7559             osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
7560             osi_assert(0);
7561         }
7562
7563         /* Link them together */
7564         NCBsessions[idx_NCB] = idx_session;
7565
7566         /* Fire it up */
7567         ncbp = NCBs[idx_NCB];
7568         ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
7569         ncbp->ncb_command = NCBRECV | ASYNCH;
7570         ncbp->ncb_lana_num = lanas[idx_session];
7571         ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
7572         ncbp->ncb_event = NCBevents[idx_NCB];
7573         ncbp->ncb_length = SMB_PACKETSIZE;
7574         Netbios(ncbp);
7575     }
7576 }
7577
7578 /*
7579  * The top level loop for handling SMB request messages.  Each server thread
7580  * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
7581  * NCB and buffer for the incoming request are loaned to us.
7582  *
7583  * Write Raw trickery starts here.  When we get a Write Raw, we are supposed
7584  * to immediately send a request for the rest of the data.  This must come
7585  * before any other traffic for that session, so we delay setting the session
7586  * event until that data has come in.
7587  */
7588 void smb_Server(VOID *parmp)
7589 {
7590     INT_PTR myIdx = (INT_PTR) parmp;
7591     NCB *ncbp;
7592     NCB *outncbp;
7593     smb_packet_t *bufp;
7594     smb_packet_t *outbufp;
7595     DWORD code, rcode;
7596     int idx_NCB, idx_session;
7597     UCHAR rc;
7598     smb_vc_t *vcp = NULL;
7599     smb_t *smbp;
7600
7601     rx_StartClientThread();
7602
7603     outncbp = GetNCB();
7604     outbufp = GetPacket();
7605     outbufp->ncbp = outncbp;
7606
7607     while (1) {
7608         if (vcp) {
7609             smb_ReleaseVC(vcp);
7610             vcp = NULL;
7611         }
7612
7613         smb_ResetServerPriority();
7614
7615         code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
7616                                                  FALSE, INFINITE);
7617
7618         /* terminate silently if shutdown flag is set */
7619         if (code == WAIT_OBJECT_0) {
7620             if (smbShutdownFlag == 1) {
7621                 thrd_SetEvent(smb_ServerShutdown[myIdx]);
7622                 break;
7623             } else
7624                 continue;
7625         }
7626
7627         /* error checking */
7628         if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7629         {
7630             int abandonIdx = code - WAIT_ABANDONED_0;
7631             osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
7632         }
7633         
7634         if (code == WAIT_IO_COMPLETION)
7635         {
7636             osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
7637             continue;
7638         }
7639         
7640         if (code == WAIT_TIMEOUT)
7641         {
7642             osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
7643         }
7644         
7645         if (code == WAIT_FAILED)
7646         {
7647             osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
7648         }
7649
7650         idx_NCB = code - WAIT_OBJECT_0;
7651         
7652         /* check idx range! */
7653         if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
7654         {
7655             /* this is fatal - log as much as possible */
7656             osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
7657             osi_assert(0);
7658         }
7659
7660         ncbp = NCBs[idx_NCB];
7661         idx_session = NCBsessions[idx_NCB];
7662         rc = ncbp->ncb_retcode;
7663
7664         if (rc != NRC_PENDING && rc != NRC_GOODRET)
7665             osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
7666
7667         switch (rc) {
7668         case NRC_GOODRET: 
7669             vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7670             break;
7671
7672         case NRC_PENDING:
7673             /* Can this happen? Or is it just my UNIX paranoia? */
7674             osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
7675             continue;
7676
7677         case NRC_SNUMOUT:
7678         case NRC_SABORT:
7679             LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
7680             /* fallthrough */
7681         case NRC_SCLOSED:
7682             /* Client closed session */
7683             vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7684             if (vcp) {
7685                 lock_ObtainMutex(&vcp->mx);
7686                 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7687                     osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
7688                              vcp, vcp->usersp);
7689                     vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7690                     lock_ReleaseMutex(&vcp->mx);
7691                     lock_ObtainWrite(&smb_globalLock);
7692                     dead_sessions[vcp->session] = TRUE;
7693                     lock_ReleaseWrite(&smb_globalLock);
7694                     smb_CleanupDeadVC(vcp);
7695                     smb_ReleaseVC(vcp);
7696                     vcp = NULL;
7697                 } else {
7698                     lock_ReleaseMutex(&vcp->mx);
7699                 }
7700             }
7701             goto doneWithNCB;
7702
7703         case NRC_INCOMP:
7704             /* Treat as transient error */
7705             LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE, 
7706                      ncbp->ncb_length);
7707             osi_Log1(smb_logp,
7708                      "dispatch smb recv failed, message incomplete, ncb_length %d",
7709                      ncbp->ncb_length);
7710             osi_Log1(smb_logp,
7711                      "SMB message incomplete, "
7712                      "length %d", ncbp->ncb_length);
7713
7714             /*
7715              * We used to discard the packet.
7716              * Instead, try handling it normally.
7717              *
7718              continue;
7719              */
7720             vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7721             break;
7722
7723         default:
7724             /* A weird error code.  Log it, sleep, and continue. */
7725             vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7726             if (vcp) 
7727                 lock_ObtainMutex(&vcp->mx);
7728             if (vcp && vcp->errorCount++ > 3) {
7729                 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
7730                 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7731                     osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
7732                              vcp, vcp->usersp);
7733                     vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7734                     lock_ReleaseMutex(&vcp->mx);
7735                     lock_ObtainWrite(&smb_globalLock);
7736                     dead_sessions[vcp->session] = TRUE;
7737                     lock_ReleaseWrite(&smb_globalLock);
7738                     smb_CleanupDeadVC(vcp);
7739                     smb_ReleaseVC(vcp);
7740                     vcp = NULL;
7741                 } else {
7742                     lock_ReleaseMutex(&vcp->mx);
7743                 }
7744                 goto doneWithNCB;
7745             }
7746             else {
7747                 if (vcp)
7748                     lock_ReleaseMutex(&vcp->mx);
7749                 thrd_Sleep(1000);
7750                 thrd_SetEvent(SessionEvents[idx_session]);
7751             }
7752             continue;
7753         }
7754
7755         /* Success, so now dispatch on all the data in the packet */
7756
7757         smb_concurrentCalls++;
7758         if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
7759             smb_maxObsConcurrentCalls = smb_concurrentCalls;
7760
7761         /*
7762          * If at this point vcp is NULL (implies that packet was invalid)
7763          * then we are in big trouble. This means either :
7764          *   a) we have the wrong NCB.
7765          *   b) Netbios screwed up the call.
7766          *   c) The VC was already marked dead before we were able to
7767          *      process the call
7768          * Obviously this implies that 
7769          *   ( LSNs[idx_session] != ncbp->ncb_lsn ||
7770          *   lanas[idx_session] != ncbp->ncb_lana_num )
7771          * Either way, we can't do anything with this packet.
7772          * Log, sleep and resume.
7773          */
7774         if (!vcp) {
7775             LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
7776                      LSNs[idx_session],
7777                      lanas[idx_session],
7778                      ncbp->ncb_lsn,
7779                      ncbp->ncb_lana_num);
7780
7781             /* Also log in the trace log. */
7782             osi_Log4(smb_logp, "Server: VCP does not exist!"
7783                       "LSNs[idx_session]=[%d],"
7784                       "lanas[idx_session]=[%d],"
7785                       "ncbp->ncb_lsn=[%d],"
7786                       "ncbp->ncb_lana_num=[%d]",
7787                       LSNs[idx_session],
7788                       lanas[idx_session],
7789                       ncbp->ncb_lsn,
7790                       ncbp->ncb_lana_num);
7791
7792             /* thrd_Sleep(1000); Don't bother sleeping */
7793             thrd_SetEvent(SessionEvents[idx_session]);
7794             smb_concurrentCalls--;
7795             continue;
7796         }
7797
7798         smb_SetRequestStartTime();
7799
7800         vcp->errorCount = 0;
7801         bufp = (struct smb_packet *) ncbp->ncb_buffer;
7802         smbp = (smb_t *)bufp->data;
7803         outbufp->flags = 0;
7804
7805         __try
7806         {
7807             if (smbp->com == 0x1d) {
7808                 /* Special handling for Write Raw */
7809                 raw_write_cont_t rwc;
7810                 EVENT_HANDLE rwevent;
7811                 char eventName[MAX_PATH];
7812             
7813                 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
7814                 if (rwc.code == 0) {
7815                     rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
7816                     if ( GetLastError() == ERROR_ALREADY_EXISTS )
7817                         osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7818                     ncbp->ncb_command = NCBRECV | ASYNCH;
7819                     ncbp->ncb_lsn = (unsigned char) vcp->lsn;
7820                     ncbp->ncb_lana_num = vcp->lana;
7821                     ncbp->ncb_buffer = rwc.buf;
7822                     ncbp->ncb_length = 65535;
7823                     ncbp->ncb_event = rwevent;
7824                     Netbios(ncbp);
7825                     rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
7826                     thrd_CloseHandle(rwevent);
7827                 }
7828                 thrd_SetEvent(SessionEvents[idx_session]);
7829                 if (rwc.code == 0)
7830                     smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
7831             } 
7832             else if (smbp->com == 0xa0) {
7833                 /* 
7834                  * Serialize the handling for NT Transact 
7835                  * (defect 11626)
7836                  */
7837                 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7838                 thrd_SetEvent(SessionEvents[idx_session]);
7839             } else {
7840                 thrd_SetEvent(SessionEvents[idx_session]);
7841                 /* TODO: what else needs to be serialized? */
7842                 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7843             }
7844         }
7845         __except( smb_ServerExceptionFilter() ) {
7846         }
7847
7848         smb_concurrentCalls--;
7849
7850       doneWithNCB:
7851         thrd_SetEvent(NCBavails[idx_NCB]);
7852     }
7853     if (vcp)
7854         smb_ReleaseVC(vcp);
7855 }
7856
7857 /*
7858  * Exception filter for the server threads.  If an exception occurs in the
7859  * dispatch routines, which is where exceptions are most common, then do a
7860  * force trace and give control to upstream exception handlers. Useful for
7861  * debugging.
7862  */
7863 DWORD smb_ServerExceptionFilter(void) {
7864     /* While this is not the best time to do a trace, if it succeeds, then
7865      * we have a trace (assuming tracing was enabled). Otherwise, this should
7866      * throw a second exception.
7867      */
7868     LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
7869     afsd_ForceTrace(TRUE);
7870     buf_ForceTrace(TRUE);
7871     return EXCEPTION_CONTINUE_SEARCH;
7872 }       
7873
7874 /*
7875  * Create a new NCB and associated events, packet buffer, and "space" buffer.
7876  * If the number of server threads is M, and the number of live sessions is
7877  * N, then the number of NCB's in use at any time either waiting for, or
7878  * holding, received messages is M + N, so that is how many NCB's get created.
7879  */
7880 void InitNCBslot(int idx)
7881 {
7882     struct smb_packet *bufp;
7883     EVENT_HANDLE retHandle;
7884     int i;
7885     char eventName[MAX_PATH];
7886
7887     osi_assert( idx < (sizeof(NCBs) / sizeof(NCBs[0])) );
7888
7889     NCBs[idx] = GetNCB();
7890     sprintf(eventName,"NCBavails[%d]", idx);
7891     NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7892     if ( GetLastError() == ERROR_ALREADY_EXISTS )
7893         osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7894     sprintf(eventName,"NCBevents[%d]", idx);
7895     NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
7896     if ( GetLastError() == ERROR_ALREADY_EXISTS )
7897         osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7898     sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
7899     retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7900     if ( GetLastError() == ERROR_ALREADY_EXISTS )
7901         osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7902     for (i=0; i<smb_NumServerThreads; i++)
7903         NCBreturns[i][idx] = retHandle;
7904     bufp = GetPacket();
7905     bufp->spacep = cm_GetSpace();
7906     bufs[idx] = bufp;
7907 }
7908
7909 /* listen for new connections */
7910 void smb_Listener(void *parmp)
7911 {
7912     NCB *ncbp;
7913     long code = 0;
7914     long len;
7915     long i;
7916     int  session, thread;
7917     smb_vc_t *vcp = NULL;
7918     int flags = 0;
7919     char rname[NCBNAMSZ+1];
7920     char cname[MAX_COMPUTERNAME_LENGTH+1];
7921     int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
7922     INT_PTR lana = (INT_PTR) parmp;
7923
7924     ncbp = GetNCB();
7925
7926     /* retrieve computer name */
7927     GetComputerName(cname, &cnamelen);
7928     _strupr(cname);
7929
7930     while (smb_ListenerState == SMB_LISTENER_STARTED) {
7931         memset(ncbp, 0, sizeof(NCB));
7932         flags = 0;
7933
7934         ncbp->ncb_command = NCBLISTEN;
7935         ncbp->ncb_rto = 0;      /* No receive timeout */
7936         ncbp->ncb_sto = 0;      /* No send timeout */
7937
7938         /* pad out with spaces instead of null termination */
7939         len = (long)strlen(smb_localNamep);
7940         strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
7941         for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
7942         
7943         strcpy(ncbp->ncb_callname, "*");
7944         for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
7945         
7946         ncbp->ncb_lana_num = (UCHAR)lana;
7947
7948         code = Netbios(ncbp);
7949
7950         if (code == NRC_BRIDGE) {
7951             int lanaRemaining = 0;
7952
7953             if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1) {
7954                 ExitThread(1);
7955             }
7956
7957             osi_Log2(smb_logp,
7958                       "NCBLISTEN lana=%d failed with NRC_BRIDGE.  Listener thread exiting.",
7959                       ncbp->ncb_lana_num, code);
7960
7961             for (i = 0; i < lana_list.length; i++) {
7962                 if (lana_list.lana[i] == ncbp->ncb_lana_num) {
7963                     smb_StopListener(ncbp, lana_list.lana[i]);
7964                     lana_list.lana[i] = 255;
7965                 }
7966                 if (lana_list.lana[i] != 255)
7967                     lanaRemaining++;
7968             }
7969
7970             if (lanaRemaining == 0) {
7971                 smb_ListenerState = SMB_LISTENER_STOPPED;
7972                 smb_LANadapter = -1;
7973                 lana_list.length = 0;
7974             }
7975             FreeNCB(ncbp);
7976             return;
7977         } else if (code != 0) {
7978             char tbuffer[256];
7979
7980             /* terminate silently if shutdown flag is set */
7981             if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1) {
7982                 ExitThread(1);
7983             }
7984
7985             osi_Log2(smb_logp, 
7986                      "NCBLISTEN lana=%d failed with code %d",
7987                      ncbp->ncb_lana_num, code);
7988             osi_Log0(smb_logp, 
7989                      "Client exiting due to network failure. Please restart client.\n");
7990
7991             sprintf(tbuffer, 
7992                      "Client exiting due to network failure.  Please restart client.\n"
7993                      "NCBLISTEN lana=%d failed with code %d",
7994                      ncbp->ncb_lana_num, code);
7995             if (showErrors)
7996                 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
7997                                       MB_OK|MB_SERVICE_NOTIFICATION);
7998             osi_panic(tbuffer, __FILE__, __LINE__);
7999         }
8000
8001         /* check for remote conns */
8002         /* first get remote name and insert null terminator */
8003         memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
8004         for (i=NCBNAMSZ; i>0; i--) {
8005             if (rname[i-1] != ' ' && rname[i-1] != 0) {
8006                 rname[i] = 0;
8007                 break;
8008             }
8009         }
8010
8011         /* compare with local name */
8012         if (!isGateway)
8013             if (strncmp(rname, cname, NCBNAMSZ) != 0)
8014                 flags |= SMB_VCFLAG_REMOTECONN;
8015
8016         /* lock */
8017         lock_ObtainMutex(&smb_ListenerLock);
8018
8019         osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
8020         osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
8021
8022         /* now ncbp->ncb_lsn is the connection ID */
8023         vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
8024         if (vcp->session == 0) {
8025             /* New generation */
8026             osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
8027             sessionGen++;
8028
8029             /* Log session startup */
8030 #ifdef NOTSERVICE
8031             fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8032                     ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8033 #endif /* NOTSERVICE */
8034             osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8035                      ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8036
8037             if (reportSessionStartups) {
8038                 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8039             }
8040             
8041             lock_ObtainMutex(&vcp->mx);
8042             strcpy(vcp->rname, rname);
8043             vcp->flags |= flags;
8044             lock_ReleaseMutex(&vcp->mx);
8045
8046             /* Allocate slot in session arrays */
8047             /* Re-use dead session if possible, otherwise add one more */
8048             /* But don't look at session[0], it is reserved */
8049             lock_ObtainWrite(&smb_globalLock);
8050             for (session = 1; session < numSessions; session++) {
8051                 if (dead_sessions[session]) {
8052                     osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
8053                     dead_sessions[session] = FALSE;
8054                     break;
8055                 }
8056             }
8057             lock_ReleaseWrite(&smb_globalLock);
8058         } else {
8059             /* We are re-using an existing VC because the lsn and lana 
8060              * were re-used */
8061             session = vcp->session;
8062
8063             osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
8064
8065             /* Log session startup */
8066 #ifdef NOTSERVICE
8067             fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8068                     ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8069 #endif /* NOTSERVICE */
8070             osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8071                      ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8072
8073             if (reportSessionStartups) {
8074                 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8075             }
8076         }
8077
8078         if (session >= SESSION_MAX - 1  || numNCBs >= NCB_MAX - 1) {
8079             unsigned long code = CM_ERROR_ALLBUSY;
8080             smb_packet_t * outp = GetPacket();
8081             unsigned char *outWctp;
8082             smb_t *smbp;
8083             
8084             smb_FormatResponsePacket(vcp, NULL, outp);
8085             outp->ncbp = ncbp;
8086
8087             if (vcp->flags & SMB_VCFLAG_STATUS32) {
8088                 unsigned long NTStatus;
8089                 smb_MapNTError(code, &NTStatus);
8090                 outWctp = outp->wctp;
8091                 smbp = (smb_t *) &outp->data;
8092                 *outWctp++ = 0;
8093                 *outWctp++ = 0;
8094                 *outWctp++ = 0;
8095                 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8096                 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8097                 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8098                 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8099                 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8100             } else {
8101                 unsigned short errCode;
8102                 unsigned char errClass;
8103                 smb_MapCoreError(code, vcp, &errCode, &errClass);
8104                 outWctp = outp->wctp;
8105                 smbp = (smb_t *) &outp->data;
8106                 *outWctp++ = 0;
8107                 *outWctp++ = 0;
8108                 *outWctp++ = 0;
8109                 smbp->errLow = (unsigned char) (errCode & 0xff);
8110                 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8111                 smbp->rcls = errClass;
8112             }
8113             smb_SendPacket(vcp, outp);
8114             smb_FreePacket(outp);
8115
8116             lock_ObtainMutex(&vcp->mx);
8117             if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8118                 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8119                           vcp, vcp->usersp);
8120                 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8121                 lock_ReleaseMutex(&vcp->mx);
8122                 lock_ObtainWrite(&smb_globalLock);
8123                 dead_sessions[vcp->session] = TRUE;
8124                 lock_ReleaseWrite(&smb_globalLock);
8125                 smb_CleanupDeadVC(vcp);
8126             } else {
8127                 lock_ReleaseMutex(&vcp->mx);
8128             }
8129         } else {
8130             /* assert that we do not exceed the maximum number of sessions or NCBs.
8131              * we should probably want to wait for a session to be freed in case
8132              * we run out.
8133              */
8134             osi_assert(session < SESSION_MAX - 1);
8135             osi_assert(numNCBs < NCB_MAX - 1);   /* if we pass this test we can allocate one more */
8136
8137             lock_ObtainMutex(&vcp->mx);
8138             vcp->session   = session;
8139             lock_ReleaseMutex(&vcp->mx);
8140             lock_ObtainWrite(&smb_globalLock);
8141             LSNs[session]  = ncbp->ncb_lsn;
8142             lanas[session] = ncbp->ncb_lana_num;
8143             lock_ReleaseWrite(&smb_globalLock);
8144                 
8145             if (session == numSessions) {
8146                 /* Add new NCB for new session */
8147                 char eventName[MAX_PATH];
8148
8149                 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
8150
8151                 InitNCBslot(numNCBs);
8152                 lock_ObtainWrite(&smb_globalLock);
8153                 numNCBs++;
8154                 lock_ReleaseWrite(&smb_globalLock);
8155                 thrd_SetEvent(NCBavails[0]);
8156                 thrd_SetEvent(NCBevents[0]);
8157                 for (thread = 0; thread < smb_NumServerThreads; thread++)
8158                     thrd_SetEvent(NCBreturns[thread][0]);
8159                 /* Also add new session event */
8160                 sprintf(eventName, "SessionEvents[%d]", session);
8161                 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8162                 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8163                     osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8164                 lock_ObtainWrite(&smb_globalLock);
8165                 numSessions++;
8166                 lock_ReleaseWrite(&smb_globalLock);
8167                 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
8168                 thrd_SetEvent(SessionEvents[0]);
8169             } else {
8170                 thrd_SetEvent(SessionEvents[session]);
8171             }
8172         }
8173         smb_ReleaseVC(vcp);
8174
8175         /* unlock */
8176         lock_ReleaseMutex(&smb_ListenerLock);
8177     }   /* dispatch while loop */
8178
8179     FreeNCB(ncbp);
8180 }
8181
8182 /* initialize Netbios */
8183 int smb_NetbiosInit(void)
8184 {
8185     NCB *ncbp;
8186     int i, lana, code, l;
8187     char s[100];
8188     int delname_tried=0;
8189     int len;
8190     int lana_found = 0;
8191     lana_number_t lanaNum;
8192
8193     /* setup the NCB system */
8194     ncbp = GetNCB();
8195
8196     /* Call lanahelper to get Netbios name, lan adapter number and gateway flag */
8197     if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
8198         smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
8199
8200         if (smb_LANadapter != -1)
8201             afsi_log("LAN adapter number %d", smb_LANadapter);
8202         else
8203             afsi_log("LAN adapter number not determined");
8204
8205         if (isGateway)
8206             afsi_log("Set for gateway service");
8207
8208         afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
8209     } else {
8210         /* something went horribly wrong.  We can't proceed without a netbios name */
8211         char buf[128];
8212         StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
8213         osi_panic(buf, __FILE__, __LINE__);
8214     }
8215
8216     /* remember the name */
8217     len = (int)strlen(cm_NetbiosName);
8218     if (smb_localNamep)
8219         free(smb_localNamep);
8220     smb_localNamep = malloc(len+1);
8221     strcpy(smb_localNamep, cm_NetbiosName);
8222     afsi_log("smb_localNamep is >%s<", smb_localNamep);
8223
8224
8225     if (smb_LANadapter == -1) {
8226         ncbp->ncb_command = NCBENUM;
8227         ncbp->ncb_buffer = (PUCHAR)&lana_list;
8228         ncbp->ncb_length = sizeof(lana_list);
8229         code = Netbios(ncbp);
8230         if (code != 0) {
8231             afsi_log("Netbios NCBENUM error code %d", code);
8232             osi_panic(s, __FILE__, __LINE__);
8233         }
8234     }
8235     else {
8236         lana_list.length = 1;
8237         lana_list.lana[0] = smb_LANadapter;
8238     }
8239           
8240     for (i = 0; i < lana_list.length; i++) {
8241         /* reset the adaptor: in Win32, this is required for every process, and
8242          * acts as an init call, not as a real hardware reset.
8243          */
8244         ncbp->ncb_command = NCBRESET;
8245         ncbp->ncb_callname[0] = 100;
8246         ncbp->ncb_callname[2] = 100;
8247         ncbp->ncb_lana_num = lana_list.lana[i];
8248         code = Netbios(ncbp);
8249         if (code == 0) 
8250             code = ncbp->ncb_retcode;
8251         if (code != 0) {
8252             afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
8253             lana_list.lana[i] = 255;  /* invalid lana */
8254         } else {
8255             afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
8256         }
8257     }
8258
8259     /* and declare our name so we can receive connections */
8260     memset(ncbp, 0, sizeof(*ncbp));
8261     len=lstrlen(smb_localNamep);
8262     memset(smb_sharename,' ',NCBNAMSZ);
8263     memcpy(smb_sharename,smb_localNamep,len);
8264     afsi_log("lana_list.length %d", lana_list.length);
8265
8266     /* Keep the name so we can unregister it later */
8267     for (l = 0; l < lana_list.length; l++) {
8268         lana = lana_list.lana[l];
8269
8270         ncbp->ncb_command = NCBADDNAME;
8271         ncbp->ncb_lana_num = lana;
8272         memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8273         code = Netbios(ncbp);
8274           
8275         afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
8276                  lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
8277         {
8278             char name[NCBNAMSZ+1];
8279             name[NCBNAMSZ]=0;
8280             memcpy(name,ncbp->ncb_name,NCBNAMSZ);
8281             afsi_log("Netbios NCBADDNAME added new name >%s<",name);
8282         }
8283
8284         if (code == 0) 
8285             code = ncbp->ncb_retcode;
8286
8287         if (code == 0) {
8288             afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
8289         }
8290         else {
8291             afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8292             if (code == NRC_BRIDGE) {    /* invalid LANA num */
8293                 lana_list.lana[l] = 255;
8294                 continue;
8295             }
8296             else if (code == NRC_DUPNAME) {
8297                 afsi_log("Name already exists; try to delete it");
8298                 memset(ncbp, 0, sizeof(*ncbp));
8299                 ncbp->ncb_command = NCBDELNAME;
8300                 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8301                 ncbp->ncb_lana_num = lana;
8302                 code = Netbios(ncbp);
8303                 if (code == 0) 
8304                     code = ncbp->ncb_retcode;
8305                 else {
8306                     afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
8307                 }
8308                 if (code != 0 || delname_tried) {
8309                     lana_list.lana[l] = 255;
8310                 }
8311                 else if (code == 0) {
8312                     if (!delname_tried) {
8313                         lana--;
8314                         delname_tried = 1;
8315                         continue;
8316                     }
8317                 }
8318             }
8319             else {
8320                 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8321                 lana_list.lana[l] = 255;  /* invalid lana */
8322             }
8323         }
8324         if (code == 0) {
8325             lana_found = 1;   /* at least one worked */
8326         }
8327     }
8328
8329     osi_assert(lana_list.length >= 0);
8330     if (!lana_found) {
8331         afsi_log("No valid LANA numbers found!");
8332         lana_list.length = 0;
8333         smb_LANadapter = -1;
8334         smb_ListenerState = SMB_LISTENER_STOPPED;
8335     }
8336         
8337     /* we're done with the NCB now */
8338     FreeNCB(ncbp);
8339
8340     return (lana_list.length > 0 ? 1 : 0);
8341 }
8342
8343 void smb_StartListeners()
8344 {
8345     int i;
8346     int lpid;
8347     thread_t phandle;
8348
8349     if (smb_ListenerState == SMB_LISTENER_STARTED)
8350         return;
8351     
8352     smb_ListenerState = SMB_LISTENER_STARTED;
8353
8354     for (i = 0; i < lana_list.length; i++) {
8355         if (lana_list.lana[i] == 255) 
8356             continue;
8357         phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
8358                                (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
8359         osi_assert(phandle != NULL);
8360         thrd_CloseHandle(phandle);
8361     }
8362 }
8363
8364 void smb_RestartListeners()
8365 {
8366     if (!powerStateSuspended && smb_ListenerState == SMB_LISTENER_STOPPED) {
8367         if (smb_NetbiosInit())
8368             smb_StartListeners();
8369     }
8370 }
8371
8372 void smb_StopListener(NCB *ncbp, int lana)
8373 {
8374     long code;
8375
8376     memset(ncbp, 0, sizeof(*ncbp));
8377     ncbp->ncb_command = NCBDELNAME;
8378     ncbp->ncb_lana_num = lana;
8379     memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8380     code = Netbios(ncbp);
8381           
8382     afsi_log("Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
8383               lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
8384
8385     /* and then reset the LANA; this will cause the listener threads to exit */
8386     ncbp->ncb_command = NCBRESET;
8387     ncbp->ncb_callname[0] = 100;
8388     ncbp->ncb_callname[2] = 100;
8389     ncbp->ncb_lana_num = lana;
8390     code = Netbios(ncbp);
8391     if (code == 0) 
8392         code = ncbp->ncb_retcode;
8393     if (code != 0) {
8394         afsi_log("Netbios NCBRESET lana %d error code %d", lana, code);
8395     } else {
8396         afsi_log("Netbios NCBRESET lana %d succeeded", lana);
8397     }
8398 }
8399
8400 void smb_StopListeners(void)
8401 {
8402     NCB *ncbp;
8403     int lana, l;
8404
8405     if (smb_ListenerState == SMB_LISTENER_STOPPED)
8406         return;
8407
8408     smb_ListenerState = SMB_LISTENER_STOPPED;
8409
8410     ncbp = GetNCB();
8411
8412     /* Unregister the SMB name */
8413     for (l = 0; l < lana_list.length; l++) {
8414         lana = lana_list.lana[l];
8415
8416         if (lana != 255) {
8417             smb_StopListener(ncbp, lana);
8418
8419             /* mark the adapter invalid */
8420             lana_list.lana[l] = 255;  /* invalid lana */
8421         }
8422     }
8423
8424     /* force a re-evaluation of the network adapters */
8425     lana_list.length = 0;
8426     smb_LANadapter = -1;
8427     FreeNCB(ncbp);
8428     Sleep(1000);        /* give the listener threads a chance to exit */
8429 }
8430
8431 void smb_Init(osi_log_t *logp, int useV3,
8432               int nThreads
8433               , void *aMBfunc
8434   )
8435
8436 {
8437     thread_t phandle;
8438     int lpid;
8439     INT_PTR i;
8440     struct tm myTime;
8441     EVENT_HANDLE retHandle;
8442     char eventName[MAX_PATH];
8443
8444     smb_TlsRequestSlot = TlsAlloc();
8445
8446     smb_MBfunc = aMBfunc;
8447
8448     smb_useV3 = useV3;
8449
8450     /* Initialize smb_localZero */
8451     myTime.tm_isdst = -1;               /* compute whether on DST or not */
8452     myTime.tm_year = 70;
8453     myTime.tm_mon = 0;
8454     myTime.tm_mday = 1;
8455     myTime.tm_hour = 0;
8456     myTime.tm_min = 0;
8457     myTime.tm_sec = 0;
8458     smb_localZero = mktime(&myTime);
8459
8460 #ifndef USE_NUMERIC_TIME_CONV
8461     /* Initialize kludge-GMT */
8462     smb_CalculateNowTZ();
8463 #endif /* USE_NUMERIC_TIME_CONV */
8464 #ifdef AFS_FREELANCE_CLIENT
8465     /* Make sure the root.afs volume has the correct time */
8466     cm_noteLocalMountPointChange();
8467 #endif
8468
8469     /* initialize the remote debugging log */
8470     smb_logp = logp;
8471         
8472     /* and the global lock */
8473     lock_InitializeRWLock(&smb_globalLock, "smb global lock");
8474     lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
8475
8476     /* Raw I/O data structures */
8477     lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
8478
8479     lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
8480         
8481     /* 4 Raw I/O buffers */
8482     smb_RawBufs = calloc(65536,1);
8483     *((char **)smb_RawBufs) = NULL;
8484     for (i=0; i<3; i++) {
8485         char *rawBuf = calloc(65536,1);
8486         *((char **)rawBuf) = smb_RawBufs;
8487         smb_RawBufs = rawBuf;
8488     }
8489
8490     /* global free lists */
8491     smb_ncbFreeListp = NULL;
8492     smb_packetFreeListp = NULL;
8493
8494     smb_NetbiosInit();
8495
8496     /* Initialize listener and server structures */
8497     numVCs = 0;
8498     memset(dead_sessions, 0, sizeof(dead_sessions));
8499     sprintf(eventName, "SessionEvents[0]");
8500     SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8501     if ( GetLastError() == ERROR_ALREADY_EXISTS )
8502         afsi_log("Event Object Already Exists: %s", eventName);
8503     numSessions = 1;
8504     smb_NumServerThreads = nThreads;
8505     sprintf(eventName, "NCBavails[0]");
8506     NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8507     if ( GetLastError() == ERROR_ALREADY_EXISTS )
8508         afsi_log("Event Object Already Exists: %s", eventName);
8509     sprintf(eventName, "NCBevents[0]");
8510     NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8511     if ( GetLastError() == ERROR_ALREADY_EXISTS )
8512         afsi_log("Event Object Already Exists: %s", eventName);
8513     NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
8514     sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
8515     retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8516     if ( GetLastError() == ERROR_ALREADY_EXISTS )
8517         afsi_log("Event Object Already Exists: %s", eventName);
8518     for (i = 0; i < smb_NumServerThreads; i++) {
8519         NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
8520         NCBreturns[i][0] = retHandle;
8521     }
8522
8523     smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
8524     for (i = 0; i < smb_NumServerThreads; i++) {
8525         sprintf(eventName, "smb_ServerShutdown[%d]", i);
8526         smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8527         if ( GetLastError() == ERROR_ALREADY_EXISTS )
8528             afsi_log("Event Object Already Exists: %s", eventName);
8529         InitNCBslot((int)(i+1));
8530     }
8531     numNCBs = smb_NumServerThreads + 1;
8532
8533     /* Initialize dispatch table */
8534     memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
8535     /* Prepare the table for unknown operations */
8536     for(i=0; i<= SMB_NOPCODES; i++) {
8537         smb_dispatchTable[i].procp = smb_SendCoreBadOp;
8538     }
8539     /* Fill in the ones we do know */
8540     smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
8541     smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
8542     smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
8543     smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
8544     smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
8545     smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
8546     smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
8547     smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
8548     smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
8549     smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
8550     smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
8551     smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
8552     smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
8553     smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
8554     smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
8555     smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
8556     smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
8557     smb_dispatchTable[0x11].procp = smb_SendCoreBadOp;  /* process exit */
8558     smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
8559     smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
8560     /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
8561     smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8562     smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
8563     smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
8564     smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
8565     smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
8566     smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
8567     smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
8568     smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8569     smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
8570     smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8571     smb_dispatchTable[0x29].procp = smb_SendCoreBadOp;  /* copy file */
8572     smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
8573     /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
8574     smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8575     smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
8576     smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
8577     smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
8578     smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
8579     smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
8580     smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
8581     smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A;        /* both are same */
8582     smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8583     smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
8584     smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8585     smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
8586     smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
8587     smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
8588     smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
8589     smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
8590     smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
8591     smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
8592     smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
8593     smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
8594     smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
8595     smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
8596     smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
8597     smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
8598     smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
8599     smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
8600     smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
8601     smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
8602     smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
8603     smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
8604     smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
8605     smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8606     smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
8607     smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp;  /* Open Print File */
8608     smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp;  /* Write Print File */
8609     smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp;  /* Close Print File */
8610     smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp;  /* Get Print Queue */
8611     smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp;  /* Read Bulk */
8612     smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp;  /* Write Bulk */
8613     smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp;  /* Write Bulk Data */
8614
8615     /* setup tran 2 dispatch table */
8616     smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
8617     smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir;        /* FindFirst */
8618     smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir;        /* FindNext */
8619     smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
8620     smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
8621     smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
8622     smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
8623     smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
8624     smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
8625     smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
8626     smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
8627     smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
8628     smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
8629     smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
8630     smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
8631     smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
8632     smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
8633     smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
8634
8635     /* setup the rap dispatch table */
8636     memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
8637     smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
8638     smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
8639     smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
8640     smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
8641
8642     smb3_Init();
8643
8644     /* if we are doing SMB authentication we have register outselves as a logon process */
8645     if (smb_authType != SMB_AUTH_NONE) {
8646         NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
8647         LSA_STRING afsProcessName;
8648         LSA_OPERATIONAL_MODE dummy; /*junk*/
8649
8650         afsProcessName.Buffer = "OpenAFSClientDaemon";
8651         afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
8652         afsProcessName.MaximumLength = afsProcessName.Length + 1;
8653
8654         nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
8655
8656         if (nts == STATUS_SUCCESS) {
8657             LSA_STRING packageName;
8658             /* we are registered. Find out the security package id */
8659             packageName.Buffer = MSV1_0_PACKAGE_NAME;
8660             packageName.Length = (USHORT)strlen(packageName.Buffer);
8661             packageName.MaximumLength = packageName.Length + 1;
8662             nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
8663             if (nts == STATUS_SUCCESS) {
8664                 /* BEGIN 
8665                  * This code forces Windows to authenticate against the Logon Cache 
8666                  * first instead of attempting to authenticate against the Domain 
8667                  * Controller.  When the Windows logon cache is enabled this improves
8668                  * performance by removing the network access and works around a bug
8669                  * seen at sites which are using a MIT Kerberos principal to login
8670                  * to machines joined to a non-root domain in a multi-domain forest.
8671                  * MsV1_0SetProcessOption was added in Windows XP.
8672                  */
8673                 PVOID pResponse = NULL;
8674                 ULONG cbResponse = 0;
8675                 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
8676
8677                 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
8678                 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
8679                 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST; 
8680                 OptionsRequest.DisableOptions = FALSE;
8681
8682                 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
8683                                                     smb_lsaSecPackage,
8684                                                     &OptionsRequest,
8685                                                     sizeof(OptionsRequest),
8686                                                     &pResponse,
8687                                                     &cbResponse,
8688                                                     &ntsEx
8689                                                     );
8690
8691                 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
8692                     char message[256];
8693                     sprintf(message,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
8694                                        nts, ntsEx);
8695                     OutputDebugString(message);
8696                     afsi_log(message);
8697                 } else {
8698                     OutputDebugString("MsV1_0SetProcessOption success");
8699                     afsi_log("MsV1_0SetProcessOption success");
8700                 }
8701                 /* END - code from Larry */
8702
8703                 smb_lsaLogonOrigin.Buffer = "OpenAFS";
8704                 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
8705                 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
8706             } else {
8707                 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
8708
8709                 /* something went wrong. We report the error and revert back to no authentication
8710                 because we can't perform any auth requests without a successful lsa handle
8711                 or sec package id. */
8712                 afsi_log("Reverting to NO SMB AUTH");
8713                 smb_authType = SMB_AUTH_NONE;
8714             }
8715         } else {
8716             afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
8717
8718             /* something went wrong. We report the error and revert back to no authentication
8719             because we can't perform any auth requests without a successful lsa handle
8720             or sec package id. */
8721             afsi_log("Reverting to NO SMB AUTH");
8722             smb_authType = SMB_AUTH_NONE;
8723         }
8724
8725 #ifdef COMMENT
8726         /* Don't fallback to SMB_AUTH_NTLM.  Apparently, allowing SPNEGO to be used each
8727          * time prevents the failure of authentication when logged into Windows with an
8728          * external Kerberos principal mapped to a local account.
8729          */
8730         else if ( smb_authType == SMB_AUTH_EXTENDED) {
8731             /* Test to see if there is anything to negotiate.  If SPNEGO is not going to be used 
8732              * then the only option is NTLMSSP anyway; so just fallback. 
8733              */
8734             void * secBlob;
8735             int secBlobLength;
8736
8737             smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
8738             if (secBlobLength == 0) {
8739                 smb_authType = SMB_AUTH_NTLM;
8740                 afsi_log("Reverting to SMB AUTH NTLM");
8741             } else
8742                 free(secBlob);
8743         }
8744 #endif
8745     }
8746
8747     {
8748         DWORD bufsize;
8749         /* Now get ourselves a domain name. */
8750         /* For now we are using the local computer name as the domain name.
8751          * It is actually the domain for local logins, and we are acting as
8752          * a local SMB server. 
8753          */
8754         bufsize = sizeof(smb_ServerDomainName) - 1;
8755         GetComputerName(smb_ServerDomainName, &bufsize);
8756         smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
8757         afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
8758     }
8759
8760     /* Start listeners, waiters, servers, and daemons */
8761
8762     smb_StartListeners();
8763
8764     phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
8765                           NULL, 0, &lpid, "smb_ClientWaiter");
8766     osi_assert(phandle != NULL);
8767     thrd_CloseHandle(phandle);
8768
8769     phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
8770                           NULL, 0, &lpid, "smb_ServerWaiter");
8771     osi_assert(phandle != NULL);
8772     thrd_CloseHandle(phandle);
8773
8774     for (i=0; i<smb_NumServerThreads; i++) {
8775         phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
8776                               (void *) i, 0, &lpid, "smb_Server");
8777         osi_assert(phandle != NULL);
8778         thrd_CloseHandle(phandle);
8779     }
8780
8781     phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
8782                           NULL, 0, &lpid, "smb_Daemon");
8783     osi_assert(phandle != NULL);
8784     thrd_CloseHandle(phandle);
8785
8786     phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
8787                           NULL, 0, &lpid, "smb_WaitingLocksDaemon");
8788     osi_assert(phandle != NULL);
8789     thrd_CloseHandle(phandle);
8790
8791     return;
8792 }
8793
8794 void smb_Shutdown(void)
8795 {
8796     NCB *ncbp;
8797     long code = 0;
8798     int i;
8799     smb_vc_t *vcp;
8800
8801     /*fprintf(stderr, "Entering smb_Shutdown\n");*/
8802         
8803     /* setup the NCB system */
8804     ncbp = GetNCB();
8805
8806     /* Block new sessions by setting shutdown flag */
8807     smbShutdownFlag = 1;
8808
8809     /* Hang up all sessions */
8810     memset((char *)ncbp, 0, sizeof(NCB));
8811     for (i = 1; i < numSessions; i++)
8812     {
8813         if (dead_sessions[i])
8814             continue;
8815       
8816         /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8817         ncbp->ncb_command = NCBHANGUP;
8818         ncbp->ncb_lana_num = lanas[i];  /*smb_LANadapter;*/
8819         ncbp->ncb_lsn = (UCHAR)LSNs[i];
8820         code = Netbios(ncbp);
8821         /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8822         if (code == 0) code = ncbp->ncb_retcode;
8823         if (code != 0) {
8824             osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
8825             fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
8826         }
8827     }
8828
8829     /* Trigger the shutdown of all SMB threads */                                
8830     for (i = 0; i < smb_NumServerThreads; i++)                                   
8831         thrd_SetEvent(NCBreturns[i][0]);                                         
8832                                                                                  
8833     thrd_SetEvent(NCBevents[0]);                                                 
8834     thrd_SetEvent(SessionEvents[0]);                                             
8835     thrd_SetEvent(NCBavails[0]);                                                 
8836                                                                                  
8837     for (i = 0;i < smb_NumServerThreads; i++) {                                  
8838         DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500); 
8839         if (code == WAIT_OBJECT_0) {                                             
8840             continue;                                                            
8841         } else {                                                                 
8842             afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);      
8843             thrd_SetEvent(NCBreturns[i--][0]);                                   
8844         }                                                                        
8845     }                                                                            
8846
8847     /* Delete Netbios name */
8848     memset((char *)ncbp, 0, sizeof(NCB));
8849     for (i = 0; i < lana_list.length; i++) {
8850         if (lana_list.lana[i] == 255) continue;
8851         ncbp->ncb_command = NCBDELNAME;
8852         ncbp->ncb_lana_num = lana_list.lana[i];
8853         memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8854         code = Netbios(ncbp);
8855         if (code == 0) 
8856             code = ncbp->ncb_retcode;
8857         if (code != 0) {
8858             fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
8859                      ncbp->ncb_lana_num, code);
8860         }       
8861         fflush(stderr);
8862     }
8863
8864     /* Release the reference counts held by the VCs */
8865     lock_ObtainWrite(&smb_rctLock);
8866     for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) 
8867     {
8868         smb_fid_t *fidp;
8869         smb_tid_t *tidp;
8870      
8871         if (vcp->magic != SMB_VC_MAGIC)
8872             osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp", 
8873                        __FILE__, __LINE__);
8874
8875         for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8876         {
8877             if (fidp->scp != NULL) {
8878                 cm_scache_t * scp;
8879
8880                 lock_ObtainMutex(&fidp->mx);
8881                 if (fidp->scp != NULL) {
8882                     scp = fidp->scp;
8883                     fidp->scp = NULL;
8884                     lock_ObtainMutex(&scp->mx);
8885                     scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
8886                     lock_ReleaseMutex(&scp->mx);
8887                     osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
8888                     cm_ReleaseSCache(scp);
8889                 }
8890                 lock_ReleaseMutex(&fidp->mx);
8891             }
8892         }
8893
8894         for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
8895             if (tidp->vcp)
8896                 smb_ReleaseVCNoLock(tidp->vcp);
8897             if (tidp->userp) {
8898                 cm_user_t *userp = tidp->userp;
8899                 tidp->userp = NULL;
8900                 lock_ReleaseWrite(&smb_rctLock);
8901                 cm_ReleaseUser(userp);
8902                 lock_ObtainWrite(&smb_rctLock);
8903             }
8904         }
8905     }
8906     lock_ReleaseWrite(&smb_rctLock);
8907     FreeNCB(ncbp);
8908     TlsFree(smb_TlsRequestSlot);
8909 }
8910
8911 /* Get the UNC \\<servername>\<sharename> prefix. */
8912 char *smb_GetSharename()
8913 {
8914     char *name;
8915
8916     /* Make sure we have been properly initialized. */
8917     if (smb_localNamep == NULL)
8918         return NULL;
8919
8920     /* Allocate space for \\<servername>\<sharename>, plus the
8921      * terminator.
8922      */
8923     name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
8924     sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
8925     return name;
8926 }   
8927
8928
8929 #ifdef LOG_PACKET
8930 void smb_LogPacket(smb_packet_t *packet)
8931 {
8932     BYTE *vp, *cp;
8933     unsigned length, paramlen, datalen, i, j;
8934     char buf[81];
8935     char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
8936
8937     if (!packet) return;
8938
8939     osi_Log0(smb_logp, "*** SMB packet dump ***");
8940
8941     vp = (BYTE *) packet->data;
8942
8943     datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
8944     length = paramlen + 2 + datalen;
8945
8946
8947     for (i=0;i < length; i+=16)
8948     {
8949         memset( buf, ' ', 80 );
8950         buf[80] = 0;
8951
8952         itoa( i, buf, 16 );
8953
8954         buf[strlen(buf)] = ' ';
8955
8956         cp = (BYTE*) buf + 7;
8957
8958         for (j=0;j < 16 && (i+j)<length; j++)
8959         {
8960             *(cp++) = hex[vp[i+j] >> 4];
8961             *(cp++) = hex[vp[i+j] & 0xf];
8962             *(cp++) = ' ';
8963
8964             if (j==7)
8965             {
8966                 *(cp++) = '-';
8967                 *(cp++) = ' ';
8968             }
8969         }
8970
8971         for (j=0;j < 16 && (i+j)<length;j++)
8972         {
8973             *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
8974             if (j==7)
8975             {
8976                 *(cp++) = ' ';
8977                 *(cp++) = '-';
8978                 *(cp++) = ' ';
8979             }
8980         }
8981
8982         *cp = 0;
8983
8984         osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
8985     }
8986
8987     osi_Log0(smb_logp, "*** End SMB packet dump ***");
8988 }
8989 #endif /* LOG_PACKET */
8990
8991
8992 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
8993 {
8994     int zilch;
8995     char output[1024];
8996   
8997     smb_vc_t *vcp;
8998   
8999     if (lock)
9000         lock_ObtainRead(&smb_rctLock);
9001   
9002     sprintf(output, "begin dumping smb_vc_t\r\n");
9003     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9004
9005     for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) 
9006     {
9007         smb_fid_t *fidp;
9008       
9009         sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
9010                  cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9011         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9012       
9013         sprintf(output, "begin dumping smb_fid_t\r\n");
9014         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9015
9016         for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9017         {
9018             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", 
9019                      cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp, 
9020                      fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL", 
9021                      fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
9022             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9023         }
9024       
9025         sprintf(output, "done dumping smb_fid_t\r\n");
9026         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9027     }
9028
9029     sprintf(output, "done dumping smb_vc_t\r\n");
9030     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9031   
9032     sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
9033     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9034
9035     for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp) 
9036     {
9037         smb_fid_t *fidp;
9038       
9039         sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
9040                  cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9041         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9042       
9043         sprintf(output, "begin dumping smb_fid_t\r\n");
9044         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9045
9046         for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9047         {
9048             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", 
9049                      cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp, 
9050                      fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL", 
9051                      fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
9052             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9053         }
9054       
9055         sprintf(output, "done dumping smb_fid_t\r\n");
9056         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9057     }
9058
9059     sprintf(output, "done dumping DEAD smb_vc_t\r\n");
9060     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9061   
9062     if (lock)
9063         lock_ReleaseRead(&smb_rctLock);
9064     return 0;
9065 }