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