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