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