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