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