windows-mountpoint-is-directory-20070622
[openafs.git] / src / WINNT / afsd / smb.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afs/param.h>
11 #include <afs/stds.h>
12
13 #include <windows.h>
14 #include <ntstatus.h>
15 #include <stddef.h>
16 #include <stdlib.h>
17 #include <malloc.h>
18 #include <string.h>
19 #include <stdio.h>
20 #include <time.h>
21
22 #include "afsd.h"
23 #include <osi.h>
24 #include <rx\rx.h>
25 #include <rx/rx_prototypes.h>
26 #include <WINNT\afsreg.h>
27
28 #include "smb.h"
29 #include "lanahelper.h"
30
31 /* These characters are illegal in Windows filenames */
32 static char *illegalChars = "\\/:*?\"<>|";
33
34 static int smbShutdownFlag = 0;
35 static int smb_ListenerState = SMB_LISTENER_UNINITIALIZED;
36
37 int smb_LogoffTokenTransfer;
38 time_t smb_LogoffTransferTimeout;
39
40 int smb_StoreAnsiFilenames = 0;
41
42 DWORD last_msg_time = 0;
43
44 long ongoingOps = 0;
45
46 unsigned int sessionGen = 0;
47
48 extern void afsi_log(char *pattern, ...);
49 extern HANDLE afsi_file;
50 extern int powerStateSuspended;
51
52 osi_hyper_t hzero = {0, 0};
53 osi_hyper_t hones = {0xFFFFFFFF, -1};
54
55 osi_log_t *  smb_logp;
56 osi_rwlock_t smb_globalLock;
57 osi_rwlock_t smb_rctLock;
58 osi_mutex_t  smb_ListenerLock;
59  
60 char smb_LANadapter;
61 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
62
63 BOOL isGateway = FALSE;
64
65 /* for debugging */
66 long smb_maxObsConcurrentCalls=0;
67 long smb_concurrentCalls=0;
68
69 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
70
71 smb_packet_t *smb_packetFreeListp;
72 smb_ncb_t *smb_ncbFreeListp;
73
74 int smb_NumServerThreads;
75
76 int numNCBs, numSessions, numVCs;
77
78 int smb_maxVCPerServer;
79 int smb_maxMpxRequests;
80
81 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
82 HANDLE smb_lsaHandle;
83 ULONG smb_lsaSecPackage;
84 LSA_STRING smb_lsaLogonOrigin;
85
86 #define NCB_MAX MAXIMUM_WAIT_OBJECTS
87 EVENT_HANDLE NCBavails[NCB_MAX], NCBevents[NCB_MAX];
88 EVENT_HANDLE **NCBreturns;
89 EVENT_HANDLE **NCBShutdown;
90 EVENT_HANDLE *smb_ServerShutdown;
91 DWORD NCBsessions[NCB_MAX];
92 NCB *NCBs[NCB_MAX];
93 struct smb_packet *bufs[NCB_MAX];
94
95 #define SESSION_MAX MAXIMUM_WAIT_OBJECTS - 4
96 EVENT_HANDLE SessionEvents[SESSION_MAX];
97 unsigned short LSNs[SESSION_MAX];
98 int lanas[SESSION_MAX];
99 BOOL dead_sessions[SESSION_MAX];
100 LANA_ENUM lana_list;
101
102 /* for raw I/O */
103 osi_mutex_t smb_RawBufLock;
104 char *smb_RawBufs;
105
106 #define SMB_MASKFLAG_TILDE 1
107 #define SMB_MASKFLAG_CASEFOLD 2
108
109 #define RAWTIMEOUT INFINITE
110
111 /* for raw write */
112 typedef struct raw_write_cont {
113         long code;
114         osi_hyper_t offset;
115         long count;
116         char *buf;
117         int writeMode;
118         long alreadyWritten;
119 } raw_write_cont_t;
120
121 /* dir search stuff */
122 long smb_dirSearchCounter = 1;
123 smb_dirSearch_t *smb_firstDirSearchp;
124 smb_dirSearch_t *smb_lastDirSearchp;
125
126 /* hide dot files? */
127 int smb_hideDotFiles;
128
129 /* global state about V3 protocols */
130 int smb_useV3;          /* try to negotiate V3 */
131
132 static showErrors = 0;
133 /* MessageBox or something like it */
134 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
135
136 /* GMT time info:
137  * Time in Unix format of midnight, 1/1/1970 local time.
138  * When added to dosUTime, gives Unix (AFS) time.
139  */
140 time_t smb_localZero = 0;
141
142 #define USE_NUMERIC_TIME_CONV 1
143
144 #ifndef USE_NUMERIC_TIME_CONV
145 /* Time difference for converting to kludge-GMT */
146 afs_uint32 smb_NowTZ;
147 #endif /* USE_NUMERIC_TIME_CONV */
148
149 char *smb_localNamep = NULL;
150
151 smb_vc_t *smb_allVCsp;
152 smb_vc_t *smb_deadVCsp;
153
154 smb_username_t *usernamesp = NULL;
155
156 smb_waitingLockRequest_t *smb_allWaitingLocks;
157
158 DWORD smb_TlsRequestSlot = -1;
159
160 /* forward decl */
161 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
162                         NCB *ncbp, raw_write_cont_t *rwcp);
163 int smb_NetbiosInit(void);
164
165 #ifdef LOG_PACKET
166 void smb_LogPacket(smb_packet_t *packet);
167 #endif /* LOG_PACKET */
168
169 char smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = ""; /* domain name */
170 int smb_ServerDomainNameLength = 0;
171 char smb_ServerOS[] = "Windows 5.0"; /* Faux OS String */
172 int smb_ServerOSLength = sizeof(smb_ServerOS);
173 char smb_ServerLanManager[] = "Windows 2000 LAN Manager"; /* Faux LAN Manager string */
174 int smb_ServerLanManagerLength = sizeof(smb_ServerLanManager);
175
176 /* Faux server GUID. This is never checked. */
177 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
178
179 void smb_ResetServerPriority()
180 {
181     void * p = TlsGetValue(smb_TlsRequestSlot);
182     if (p) {
183         free(p);
184         TlsSetValue(smb_TlsRequestSlot, NULL);
185         SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
186     }
187 }
188
189 void smb_SetRequestStartTime()
190 {
191     time_t * tp = TlsGetValue(smb_TlsRequestSlot);
192     if (!tp)
193         tp = malloc(sizeof(time_t));
194     if (tp) {
195         *tp = osi_Time();
196
197         if (!TlsSetValue(smb_TlsRequestSlot, tp))
198             free(tp);
199     }   
200 }
201
202 void smb_UpdateServerPriority()
203 {       
204     time_t *tp = TlsGetValue(smb_TlsRequestSlot);
205
206     if (tp) {
207         time_t now = osi_Time();
208
209         /* Give one priority boost for each 15 seconds */
210         SetThreadPriority(GetCurrentThread(), (now - *tp) / 15);
211     }
212 }
213
214
215 const char * ncb_error_string(int code)
216 {
217     const char * s;
218     switch ( code ) {
219     case 0x01: s = "llegal buffer length";                      break; 
220     case 0x03: s = "illegal command";                           break; 
221     case 0x05: s = "command timed out";                         break; 
222     case 0x06: s = "message incomplete, issue another command"; break; 
223     case 0x07: s = "illegal buffer address";                    break; 
224     case 0x08: s = "session number out of range";               break; 
225     case 0x09: s = "no resource available";                     break; 
226     case 0x0a: s = "session closed";                            break; 
227     case 0x0b: s = "command cancelled";                         break; 
228     case 0x0d: s = "duplicate name";                            break; 
229     case 0x0e: s = "name table full";                           break; 
230     case 0x0f: s = "no deletions, name has active sessions";    break; 
231     case 0x11: s = "local session table full";                  break; 
232     case 0x12: s = "remote session table full";                 break; 
233     case 0x13: s = "illegal name number";                       break; 
234     case 0x14: s = "no callname";                               break; 
235     case 0x15: s = "cannot put * in NCB_NAME";                  break; 
236     case 0x16: s = "name in use on remote adapter";             break; 
237     case 0x17: s = "name deleted";                              break; 
238     case 0x18: s = "session ended abnormally";                  break; 
239     case 0x19: s = "name conflict detected";                    break; 
240     case 0x21: s = "interface busy, IRET before retrying";      break; 
241     case 0x22: s = "too many commands outstanding, retry later";break;
242     case 0x23: s = "ncb_lana_num field invalid";                break; 
243     case 0x24: s = "command completed while cancel occurring "; break; 
244     case 0x26: s = "command not valid to cancel";               break; 
245     case 0x30: s = "name defined by anther local process";      break; 
246     case 0x34: s = "environment undefined. RESET required";     break; 
247     case 0x35: s = "required OS resources exhausted";           break; 
248     case 0x36: s = "max number of applications exceeded";       break; 
249     case 0x37: s = "no saps available for netbios";             break; 
250     case 0x38: s = "requested resources are not available";     break; 
251     case 0x39: s = "invalid ncb address or length > segment";   break; 
252     case 0x3B: s = "invalid NCB DDID";                          break; 
253     case 0x3C: s = "lock of user area failed";                  break; 
254     case 0x3f: s = "NETBIOS not loaded";                        break; 
255     case 0x40: s = "system error";                              break;                 
256     default:   s = "unknown error";
257     }
258     return s;
259 }
260
261
262 char * myCrt_Dispatch(int i)
263 {
264     switch (i)
265     {
266     case 0x00:
267         return "(00)ReceiveCoreMakeDir";
268     case 0x01:
269         return "(01)ReceiveCoreRemoveDir";
270     case 0x02:
271         return "(02)ReceiveCoreOpen";
272     case 0x03:
273         return "(03)ReceiveCoreCreate";
274     case 0x04:
275         return "(04)ReceiveCoreClose";
276     case 0x05:
277         return "(05)ReceiveCoreFlush";
278     case 0x06:
279         return "(06)ReceiveCoreUnlink";
280     case 0x07:
281         return "(07)ReceiveCoreRename";
282     case 0x08:
283         return "(08)ReceiveCoreGetFileAttributes";
284     case 0x09:
285         return "(09)ReceiveCoreSetFileAttributes";
286     case 0x0a:
287         return "(0a)ReceiveCoreRead";
288     case 0x0b:
289         return "(0b)ReceiveCoreWrite";
290     case 0x0c:
291         return "(0c)ReceiveCoreLockRecord";
292     case 0x0d:
293         return "(0d)ReceiveCoreUnlockRecord";
294     case 0x0e:
295         return "(0e)SendCoreBadOp";
296     case 0x0f:
297         return "(0f)ReceiveCoreCreate";
298     case 0x10:
299         return "(10)ReceiveCoreCheckPath";
300     case 0x11:
301         return "(11)SendCoreBadOp";
302     case 0x12:
303         return "(12)ReceiveCoreSeek";
304     case 0x1a:
305         return "(1a)ReceiveCoreReadRaw";
306     case 0x1d:
307         return "(1d)ReceiveCoreWriteRawDummy";
308     case 0x22:
309         return "(22)ReceiveV3SetAttributes";
310     case 0x23:
311         return "(23)ReceiveV3GetAttributes";
312     case 0x24:
313         return "(24)ReceiveV3LockingX";
314     case 0x25:
315         return "(25)ReceiveV3Trans";
316     case 0x26:
317         return "(26)ReceiveV3Trans[aux]";
318     case 0x29:
319         return "(29)SendCoreBadOp";
320     case 0x2b:
321         return "(2b)ReceiveCoreEcho";
322     case 0x2d:
323         return "(2d)ReceiveV3OpenX";
324     case 0x2e:
325         return "(2e)ReceiveV3ReadX";
326     case 0x2f:
327         return "(2f)ReceiveV3WriteX";
328     case 0x32:
329         return "(32)ReceiveV3Tran2A";
330     case 0x33:
331         return "(33)ReceiveV3Tran2A[aux]";
332     case 0x34:
333         return "(34)ReceiveV3FindClose";
334     case 0x35:
335         return "(35)ReceiveV3FindNotifyClose";
336     case 0x70:
337         return "(70)ReceiveCoreTreeConnect";
338     case 0x71:
339         return "(71)ReceiveCoreTreeDisconnect";
340     case 0x72:
341         return "(72)ReceiveNegotiate";
342     case 0x73:
343         return "(73)ReceiveV3SessionSetupX";
344     case 0x74:
345         return "(74)ReceiveV3UserLogoffX";
346     case 0x75:
347         return "(75)ReceiveV3TreeConnectX";
348     case 0x80:
349         return "(80)ReceiveCoreGetDiskAttributes";
350     case 0x81:
351         return "(81)ReceiveCoreSearchDir";
352     case 0x82:
353         return "(82)Find";
354     case 0x83:
355         return "(83)FindUnique";
356     case 0x84:
357         return "(84)FindClose";
358     case 0xA0:
359         return "(A0)ReceiveNTTransact";
360     case 0xA2:
361         return "(A2)ReceiveNTCreateX";
362     case 0xA4:
363         return "(A4)ReceiveNTCancel";
364     case 0xA5:
365         return "(A5)ReceiveNTRename";
366     case 0xc0:
367         return "(C0)OpenPrintFile";
368     case 0xc1:
369         return "(C1)WritePrintFile";
370     case 0xc2:
371         return "(C2)ClosePrintFile";
372     case 0xc3:
373         return "(C3)GetPrintQueue";
374     case 0xd8:
375         return "(D8)ReadBulk";
376     case 0xd9:
377         return "(D9)WriteBulk";
378     case 0xda:
379         return "(DA)WriteBulkData";
380     default:
381         return "unknown SMB op";
382     }
383 }       
384
385 char * myCrt_2Dispatch(int i)
386 {
387     switch (i)
388     {
389     default:
390         return "unknown SMB op-2";
391     case 0:
392         return "S(00)CreateFile_ReceiveTran2Open";
393     case 1:
394         return "S(01)FindFirst_ReceiveTran2SearchDir";
395     case 2:
396         return "S(02)FindNext_ReceiveTran2SearchDir";   /* FindNext */
397     case 3:
398         return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
399     case 4:
400         return "S(04)SetFileSystem_ReceiveTran2SetFSInfo";
401     case 5:
402         return "S(05)QueryPathInfo_ReceiveTran2QPathInfo";
403     case 6:
404         return "S(06)SetPathInfo_ReceiveTran2SetPathInfo";
405     case 7:
406         return "S(07)QueryFileInfo_ReceiveTran2QFileInfo";
407     case 8:
408         return "S(08)SetFileInfo_ReceiveTran2SetFileInfo";
409     case 9:
410         return "S(09)_ReceiveTran2FSCTL";
411     case 10:
412         return "S(0a)_ReceiveTran2IOCTL";
413     case 11:
414         return "S(0b)_ReceiveTran2FindNotifyFirst";
415     case 12:
416         return "S(0c)_ReceiveTran2FindNotifyNext";
417     case 13:
418         return "S(0d)_ReceiveTran2CreateDirectory";
419     case 14:
420         return "S(0e)_ReceiveTran2SessionSetup";
421     case 15:
422         return "S(0f)_QueryFileSystemInformationFid";
423     case 16:
424         return "S(10)_ReceiveTran2GetDfsReferral";
425     case 17:
426         return "S(11)_ReceiveTran2ReportDfsInconsistency";
427     }
428 }       
429
430 char * myCrt_RapDispatch(int i)
431 {
432     switch(i)
433     {
434     default:
435         return "unknown RAP OP";
436     case 0:
437         return "RAP(0)NetShareEnum";
438     case 1:
439         return "RAP(1)NetShareGetInfo";
440     case 13:
441         return "RAP(13)NetServerGetInfo";
442     case 63:
443         return "RAP(63)NetWkStaGetInfo";
444     }
445 }       
446
447 /* scache must be locked */
448 unsigned int smb_Attributes(cm_scache_t *scp)
449 {
450     unsigned int attrs;
451
452     if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
453          scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
454          scp->fileType == CM_SCACHETYPE_INVALID)
455     {
456         attrs = SMB_ATTR_DIRECTORY;
457 #ifdef SPECIAL_FOLDERS
458         attrs |= SMB_ATTR_SYSTEM;               /* FILE_ATTRIBUTE_SYSTEM */
459 #endif /* SPECIAL_FOLDERS */
460     } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
461         attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
462     } else
463         attrs = 0;
464
465     /*
466      * We used to mark a file RO if it was in an RO volume, but that
467      * turns out to be impolitic in NT.  See defect 10007.
468      */
469 #ifdef notdef
470     if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
471         attrs |= SMB_ATTR_READONLY;     /* turn on read-only flag */
472 #else
473     if ((scp->unixModeBits & 0222) == 0)
474         attrs |= SMB_ATTR_READONLY;     /* turn on read-only flag */
475 #endif
476
477     return attrs;
478 }
479
480 /* Check if the named file/dir is a dotfile/dotdir */
481 /* String pointed to by lastComp can have leading slashes, but otherwise should have
482    no other patch components */
483 unsigned int smb_IsDotFile(char *lastComp) {
484     char *s;
485     if(lastComp) {
486         /* skip over slashes */
487         for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
488     }
489     else
490         return 0;
491
492     /* nulls, curdir and parent dir doesn't count */
493     if (!*s) 
494         return 0;
495     if (*s == '.') {
496         if (!*(s + 1)) 
497             return 0;
498         if(*(s+1) == '.' && !*(s + 2)) 
499             return 0;
500         return 1;
501     }
502     return 0;
503 }
504
505 static int ExtractBits(WORD bits, short start, short len)
506 {
507     int end;
508     WORD num;
509
510     end = start + len;
511         
512     num = bits << (16 - end);
513     num = num >> ((16 - end) + start);
514
515     return (int)num;
516 }
517
518 void ShowUnixTime(char *FuncName, time_t unixTime)
519 {
520     FILETIME ft;
521     WORD wDate, wTime;
522
523     smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
524
525     if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
526         osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
527     else {
528         int day, month, year, sec, min, hour;
529         char msg[256];
530
531         day = ExtractBits(wDate, 0, 5);
532         month = ExtractBits(wDate, 5, 4);
533         year = ExtractBits(wDate, 9, 7) + 1980;
534
535         sec = ExtractBits(wTime, 0, 5);
536         min = ExtractBits(wTime, 5, 6);
537         hour = ExtractBits(wTime, 11, 5);
538
539         sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
540         osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
541     }
542 }       
543
544 /* Determine if we are observing daylight savings time */
545 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
546 {
547     TIME_ZONE_INFORMATION timeZoneInformation;
548     SYSTEMTIME utc, local, localDST;
549
550     /* Get the time zone info. NT uses this to calc if we are in DST. */
551     GetTimeZoneInformation(&timeZoneInformation);
552
553     /* Return the daylight bias */
554     *pDstBias = timeZoneInformation.DaylightBias;
555
556     /* Return the bias */
557     *pBias = timeZoneInformation.Bias;
558
559     /* Now determine if DST is being observed */
560
561     /* Get the UTC (GMT) time */
562     GetSystemTime(&utc);
563
564     /* Convert UTC time to local time using the time zone info.  If we are
565        observing DST, the calculated local time will include this. 
566      */
567     SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
568
569     /* Set the daylight bias to 0.  The daylight bias is the amount of change
570      * in time that we use for daylight savings time.  By setting this to 0
571      * we cause there to be no change in time during daylight savings time. 
572      */
573     timeZoneInformation.DaylightBias = 0;
574
575     /* Convert the utc time to local time again, but this time without any
576        adjustment for daylight savings time. 
577        */
578     SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
579
580     /* If the two times are different, then it means that the localDST that
581        we calculated includes the daylight bias, and therefore we are
582        observing daylight savings time.
583      */
584     *pDST = localDST.wHour != local.wHour;
585 }       
586  
587
588 void CompensateForSmbClientLastWriteTimeBugs(afs_uint32 *pLastWriteTime)
589 {
590     BOOL dst;       /* Will be TRUE if observing DST */
591     LONG dstBias;   /* Offset from local time if observing DST */
592     LONG bias;      /* Offset from GMT for local time */
593
594     /*
595      * This function will adjust the last write time to compensate
596      * for two bugs in the smb client:
597      *
598      *    1) During Daylight Savings Time, the LastWriteTime is ahead
599      *       in time by the DaylightBias (ignoring the sign - the
600      *       DaylightBias is always stored as a negative number).  If
601      *       the DaylightBias is -60, then the LastWriteTime will be
602      *       ahead by 60 minutes.
603      *
604      *    2) If the local time zone is a positive offset from GMT, then
605      *       the LastWriteTime will be the correct local time plus the
606      *       Bias (ignoring the sign - a positive offset from GMT is
607      *       always stored as a negative Bias).  If the Bias is -120,
608      *       then the LastWriteTime will be ahead by 120 minutes.
609      *
610      *    These bugs can occur at the same time.
611      */
612
613     GetTimeZoneInfo(&dst, &dstBias, &bias);
614
615     /* First adjust for DST */
616     if (dst)
617         *pLastWriteTime -= (-dstBias * 60);     /* Convert dstBias to seconds */
618
619     /* Now adjust for a positive offset from GMT (a negative bias). */
620     if (bias < 0)
621         *pLastWriteTime -= (-bias * 60);        /* Convert bias to seconds */
622 }                       
623
624 #ifndef USE_NUMERIC_TIME_CONV
625 /*
626  * Calculate the difference (in seconds) between local time and GMT.
627  * This enables us to convert file times to kludge-GMT.
628  */
629 static void
630 smb_CalculateNowTZ()
631 {
632     time_t t;
633     struct tm gmt_tm, local_tm;
634     int days, hours, minutes, seconds;
635
636     t = time(NULL);
637     gmt_tm = *(gmtime(&t));
638     local_tm = *(localtime(&t));
639
640     days = local_tm.tm_yday - gmt_tm.tm_yday;
641     hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour;
642     minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min; 
643     seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
644
645     smb_NowTZ = seconds;
646 }
647 #endif /* USE_NUMERIC_TIME_CONV */
648
649 #ifdef USE_NUMERIC_TIME_CONV
650 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
651 {
652     // Note that LONGLONG is a 64-bit value
653     LONGLONG ll;
654
655     ll = Int32x32To64(unixTime, 10000000) + 116444736000000000;
656     largeTimep->dwLowDateTime = (DWORD)(ll & 0xFFFFFFFF);
657     largeTimep->dwHighDateTime = (DWORD)(ll >> 32);
658 }
659 #else
660 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
661 {
662     struct tm *ltp;
663     SYSTEMTIME stm;
664     struct tm localJunk;
665     time_t ersatz_unixTime;
666
667     /*
668      * Must use kludge-GMT instead of real GMT.
669      * kludge-GMT is computed by adding time zone difference to localtime.
670      *
671      * real GMT would be:
672      * ltp = gmtime(&unixTime);
673      */
674     ersatz_unixTime = unixTime - smb_NowTZ;
675     ltp = localtime(&ersatz_unixTime);
676
677     /* if we fail, make up something */
678     if (!ltp) {
679         ltp = &localJunk;
680         localJunk.tm_year = 89 - 20;
681         localJunk.tm_mon = 4;
682         localJunk.tm_mday = 12;
683         localJunk.tm_hour = 0;
684         localJunk.tm_min = 0;
685         localJunk.tm_sec = 0;
686     }
687
688     stm.wYear = ltp->tm_year + 1900;
689     stm.wMonth = ltp->tm_mon + 1;
690     stm.wDayOfWeek = ltp->tm_wday;
691     stm.wDay = ltp->tm_mday;
692     stm.wHour = ltp->tm_hour;
693     stm.wMinute = ltp->tm_min;
694     stm.wSecond = ltp->tm_sec;
695     stm.wMilliseconds = 0;
696
697     SystemTimeToFileTime(&stm, largeTimep);
698 }
699 #endif /* USE_NUMERIC_TIME_CONV */
700
701 #ifdef USE_NUMERIC_TIME_CONV
702 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
703 {
704     // Note that LONGLONG is a 64-bit value
705     LONGLONG ll;
706
707     ll = largeTimep->dwHighDateTime;
708     ll <<= 32;
709     ll += largeTimep->dwLowDateTime;
710
711     ll -= 116444736000000000;
712     ll /= 10000000;
713
714     *unixTimep = (DWORD)ll;
715 }
716 #else /* USE_NUMERIC_TIME_CONV */
717 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
718 {
719     SYSTEMTIME stm;
720     struct tm lt;
721     long save_timezone;
722
723     FileTimeToSystemTime(largeTimep, &stm);
724
725     lt.tm_year = stm.wYear - 1900;
726     lt.tm_mon = stm.wMonth - 1;
727     lt.tm_wday = stm.wDayOfWeek;
728     lt.tm_mday = stm.wDay;
729     lt.tm_hour = stm.wHour;
730     lt.tm_min = stm.wMinute;
731     lt.tm_sec = stm.wSecond;
732     lt.tm_isdst = -1;
733
734     save_timezone = _timezone;
735     _timezone += smb_NowTZ;
736     *unixTimep = mktime(&lt);
737     _timezone = save_timezone;
738 }       
739 #endif /* USE_NUMERIC_TIME_CONV */
740
741 void smb_SearchTimeFromUnixTime(afs_uint32 *searchTimep, time_t unixTime)
742 {
743     struct tm *ltp;
744     int dosDate;
745     int dosTime;
746     struct tm localJunk;
747     time_t t = unixTime;
748
749     ltp = localtime(&t);
750
751     /* if we fail, make up something */
752     if (!ltp) {
753         ltp = &localJunk;
754         localJunk.tm_year = 89 - 20;
755         localJunk.tm_mon = 4;
756         localJunk.tm_mday = 12;
757         localJunk.tm_hour = 0;
758         localJunk.tm_min = 0;
759         localJunk.tm_sec = 0;
760     }   
761
762     dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
763     dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
764     *searchTimep = (dosDate<<16) | dosTime;
765 }       
766
767 void smb_UnixTimeFromSearchTime(time_t *unixTimep, afs_uint32 searchTime)
768 {
769     unsigned short dosDate;
770     unsigned short dosTime;
771     struct tm localTm;
772         
773     dosDate = (unsigned short) (searchTime & 0xffff);
774     dosTime = (unsigned short) ((searchTime >> 16) & 0xffff);
775
776     localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
777     localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1;        /* January is 0 in localTm */
778     localTm.tm_mday = (dosDate) & 0x1f;
779     localTm.tm_hour = (dosTime>>11) & 0x1f;
780     localTm.tm_min = (dosTime >> 5) & 0x3f;
781     localTm.tm_sec = (dosTime & 0x1f) * 2;
782     localTm.tm_isdst = -1;                              /* compute whether DST in effect */
783
784     *unixTimep = mktime(&localTm);
785 }
786
787 void smb_DosUTimeFromUnixTime(afs_uint32 *dosUTimep, time_t unixTime)
788 {
789     time_t diff_t = unixTime - smb_localZero;
790 #if defined(DEBUG) && !defined(_USE_32BIT_TIME_T)
791     osi_assert(diff_t < _UI32_MAX);
792 #endif
793     *dosUTimep = (afs_uint32)diff_t;
794 }
795
796 void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
797 {
798     *unixTimep = dosTime + smb_localZero;
799 }
800
801 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
802 {
803     smb_vc_t *vcp;
804
805         lock_ObtainWrite(&smb_globalLock);      /* for numVCs */
806     lock_ObtainWrite(&smb_rctLock);
807     for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
808         if (vcp->magic != SMB_VC_MAGIC)
809             osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp", 
810                        __FILE__, __LINE__);
811
812         if (lsn == vcp->lsn && lana == vcp->lana &&
813             !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
814             smb_HoldVCNoLock(vcp);
815             break;
816         }
817     }
818     if (!vcp && (flags & SMB_FLAG_CREATE)) {
819         vcp = malloc(sizeof(*vcp));
820         memset(vcp, 0, sizeof(*vcp));
821         vcp->vcID = ++numVCs;
822         vcp->magic = SMB_VC_MAGIC;
823         vcp->refCount = 2;      /* smb_allVCsp and caller */
824         vcp->tidCounter = 1;
825         vcp->fidCounter = 1;
826         vcp->uidCounter = 1;    /* UID 0 is reserved for blank user */
827         vcp->nextp = smb_allVCsp;
828         smb_allVCsp = vcp;
829         lock_InitializeMutex(&vcp->mx, "vc_t mutex");
830         vcp->lsn = lsn;
831         vcp->lana = lana;
832         vcp->secCtx = NULL;
833
834         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
835             /* We must obtain a challenge for extended auth 
836              * in case the client negotiates smb v3 
837              */
838             NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
839             MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
840             PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp;
841             ULONG lsaRespSize = 0;
842
843             lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
844
845             nts = LsaCallAuthenticationPackage( smb_lsaHandle,
846                                                 smb_lsaSecPackage,
847                                                 &lsaReq,
848                                                 sizeof(lsaReq),
849                                                 &lsaResp,
850                                                 &lsaRespSize,
851                                                 &ntsEx);
852             if (nts != STATUS_SUCCESS)
853                 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
854                          nts, ntsEx, sizeof(lsaReq), lsaRespSize);
855             osi_assert(nts == STATUS_SUCCESS); /* this had better work! */
856
857             memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
858             LsaFreeReturnBuffer(lsaResp);
859         }
860         else
861             memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
862
863         if (numVCs >= CM_SESSION_RESERVED) {
864             numVCs = 0;
865             osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
866         }
867     }
868     lock_ReleaseWrite(&smb_rctLock);
869         lock_ReleaseWrite(&smb_globalLock);
870     return vcp;
871 }
872
873 int smb_IsStarMask(char *maskp)
874 {
875     int i;
876     char tc;
877         
878     for(i=0; i<11; i++) {
879         tc = *maskp++;
880         if (tc == '?' || tc == '*' || tc == '>')
881             return 1;
882     }   
883     return 0;
884 }
885
886 void smb_ReleaseVCInternal(smb_vc_t *vcp)
887 {
888     smb_vc_t **vcpp;
889     smb_vc_t * avcp;
890
891     vcp->refCount--;
892
893     if (vcp->refCount == 0) {
894       if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
895         /* remove VCP from smb_deadVCsp */
896         for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
897           if (*vcpp == vcp) {
898             *vcpp = vcp->nextp;
899             break;
900           }
901         } 
902         lock_FinalizeMutex(&vcp->mx);
903         memset(vcp,0,sizeof(smb_vc_t));
904         free(vcp);
905       } else {
906         for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
907           if (avcp == vcp)
908             break;
909         }
910         osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
911                  avcp?"not ":"",vcp, vcp->refCount);
912 #ifdef DEBUG
913         GenerateMiniDump(NULL);
914 #endif
915         /* This is a wrong.  However, I suspect that there is an undercount
916          * and I don't want to release 1.4.1 in a state that will allow
917          * smb_vc_t objects to be deallocated while still in the
918          * smb_allVCsp list.  The list is supposed to keep a reference
919          * to the smb_vc_t.  Put it back.
920          */
921         vcp->refCount++;
922       }
923     }
924 }
925
926 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
927 {
928     osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
929     smb_ReleaseVCInternal(vcp);
930 }       
931
932 void smb_ReleaseVC(smb_vc_t *vcp)
933 {
934     lock_ObtainWrite(&smb_rctLock);
935     osi_Log2(smb_logp,"smb_ReleaseVC       vcp %x ref %d",vcp, vcp->refCount);
936     smb_ReleaseVCInternal(vcp);
937     lock_ReleaseWrite(&smb_rctLock);
938 }       
939
940 void smb_HoldVCNoLock(smb_vc_t *vcp)
941 {
942     vcp->refCount++;
943     osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
944 }       
945
946 void smb_HoldVC(smb_vc_t *vcp)
947 {
948     lock_ObtainWrite(&smb_rctLock);
949     vcp->refCount++;
950     osi_Log2(smb_logp,"smb_HoldVC       vcp %x ref %d",vcp, vcp->refCount);
951     lock_ReleaseWrite(&smb_rctLock);
952 }       
953
954 void smb_CleanupDeadVC(smb_vc_t *vcp)
955 {
956     smb_fid_t *fidpIter;
957     smb_fid_t *fidpNext;
958     unsigned short fid;
959     smb_tid_t *tidpIter;
960     smb_tid_t *tidpNext;
961     unsigned short tid;
962     smb_user_t *uidpIter;
963     smb_user_t *uidpNext;
964     smb_vc_t **vcpp;
965
966
967     lock_ObtainMutex(&vcp->mx);
968     if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
969         lock_ReleaseMutex(&vcp->mx);
970         osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
971         return;
972     }
973     vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
974     lock_ReleaseMutex(&vcp->mx);
975     osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
976
977     lock_ObtainWrite(&smb_rctLock);
978     /* remove VCP from smb_allVCsp */
979     for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
980         if ((*vcpp)->magic != SMB_VC_MAGIC)
981             osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp", 
982                        __FILE__, __LINE__);
983         if (*vcpp == vcp) {
984             *vcpp = vcp->nextp;
985             vcp->nextp = smb_deadVCsp;
986             smb_deadVCsp = vcp;
987             /* Hold onto the reference until we are done with this function */
988             break;
989         }
990     }
991
992     for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
993         fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
994
995         if (fidpIter->delete)
996             continue;
997
998         fid = fidpIter->fid;
999         osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1000
1001         smb_HoldFIDNoLock(fidpIter);
1002         lock_ReleaseWrite(&smb_rctLock);
1003
1004         smb_CloseFID(vcp, fidpIter, NULL, 0);
1005         smb_ReleaseFID(fidpIter);
1006
1007         lock_ObtainWrite(&smb_rctLock);
1008         fidpNext = vcp->fidsp;
1009     }
1010
1011     for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1012         tidpNext = tidpIter->nextp;
1013         if (tidpIter->delete)
1014             continue;
1015         tidpIter->delete = 1;
1016
1017         tid = tidpIter->tid;
1018         osi_Log2(smb_logp, "  Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1019
1020         smb_HoldTIDNoLock(tidpIter);
1021         lock_ReleaseWrite(&smb_rctLock);
1022
1023         smb_ReleaseTID(tidpIter);
1024
1025         lock_ObtainWrite(&smb_rctLock);
1026         tidpNext = vcp->tidsp;
1027     }
1028
1029     for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1030         uidpNext = uidpIter->nextp;
1031         if (uidpIter->delete)
1032             continue;
1033         uidpIter->delete = 1;
1034
1035         /* do not add an additional reference count for the smb_user_t
1036          * as the smb_vc_t already is holding a reference */
1037         lock_ReleaseWrite(&smb_rctLock);
1038
1039         smb_ReleaseUID(uidpIter);
1040
1041         lock_ObtainWrite(&smb_rctLock);
1042         uidpNext = vcp->usersp;
1043     }
1044
1045     /* The vcp is now on the deadVCsp list.  We intentionally drop the
1046      * reference so that the refcount can reach 0 and we can delete it */
1047     smb_ReleaseVCNoLock(vcp);
1048     
1049     lock_ReleaseWrite(&smb_rctLock);
1050     osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1051 }
1052
1053 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1054 {
1055     smb_tid_t *tidp;
1056
1057     lock_ObtainWrite(&smb_rctLock);
1058   retry:
1059     for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1060         if (tidp->refCount == 0 && tidp->delete) {
1061             tidp->refCount++;
1062             lock_ReleaseWrite(&smb_rctLock);
1063             smb_ReleaseTID(tidp);
1064             lock_ObtainWrite(&smb_rctLock);
1065             goto retry;
1066         }
1067
1068         if (tid == tidp->tid) {
1069             tidp->refCount++;
1070             break;
1071         }       
1072     }
1073     if (!tidp && (flags & SMB_FLAG_CREATE)) {
1074         tidp = malloc(sizeof(*tidp));
1075         memset(tidp, 0, sizeof(*tidp));
1076         tidp->nextp = vcp->tidsp;
1077         tidp->refCount = 1;
1078         tidp->vcp = vcp;
1079         smb_HoldVCNoLock(vcp);
1080         vcp->tidsp = tidp;
1081         lock_InitializeMutex(&tidp->mx, "tid_t mutex");
1082         tidp->tid = tid;
1083     }
1084     lock_ReleaseWrite(&smb_rctLock);
1085     return tidp;
1086 }               
1087
1088 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1089 {
1090     tidp->refCount++;
1091 }
1092
1093 void smb_ReleaseTID(smb_tid_t *tidp)
1094 {
1095     smb_tid_t *tp;
1096     smb_tid_t **ltpp;
1097     cm_user_t *userp;
1098
1099     userp = NULL;
1100     lock_ObtainWrite(&smb_rctLock);
1101     osi_assert(tidp->refCount-- > 0);
1102     if (tidp->refCount == 0 && (tidp->delete)) {
1103         ltpp = &tidp->vcp->tidsp;
1104         for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1105             if (tp == tidp) 
1106                 break;
1107         }
1108         osi_assert(tp != NULL);
1109         *ltpp = tp->nextp;
1110         lock_FinalizeMutex(&tidp->mx);
1111         userp = tidp->userp;    /* remember to drop ref later */
1112         tidp->userp = NULL;
1113         smb_ReleaseVCNoLock(tidp->vcp);
1114         tidp->vcp = NULL;
1115     }
1116     lock_ReleaseWrite(&smb_rctLock);
1117     if (userp)
1118         cm_ReleaseUser(userp);
1119 }               
1120
1121 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1122 {
1123     smb_user_t *uidp = NULL;
1124
1125     lock_ObtainWrite(&smb_rctLock);
1126     for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1127         if (uid == uidp->userID) {
1128             uidp->refCount++;
1129             osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%s]",
1130                      vcp, uidp->userID, 
1131                      osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
1132             break;
1133         }
1134     }
1135     if (!uidp && (flags & SMB_FLAG_CREATE)) {
1136         uidp = malloc(sizeof(*uidp));
1137         memset(uidp, 0, sizeof(*uidp));
1138         uidp->nextp = vcp->usersp;
1139         uidp->refCount = 2; /* one for the vcp and one for the caller */
1140         uidp->vcp = vcp;
1141         smb_HoldVCNoLock(vcp);
1142         vcp->usersp = uidp;
1143         lock_InitializeMutex(&uidp->mx, "user_t mutex");
1144         uidp->userID = uid;
1145         osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%s]",
1146                  vcp, uidp->userID, 
1147                  osi_LogSaveString(smb_logp,uidp->unp ? uidp->unp->name : ""));
1148     }
1149     lock_ReleaseWrite(&smb_rctLock);
1150     return uidp;
1151 }               
1152
1153 smb_username_t *smb_FindUserByName(char *usern, char *machine, afs_uint32 flags)
1154 {
1155     smb_username_t *unp= NULL;
1156
1157     lock_ObtainWrite(&smb_rctLock);
1158     for(unp = usernamesp; unp; unp = unp->nextp) {
1159         if (stricmp(unp->name, usern) == 0 &&
1160              stricmp(unp->machine, machine) == 0) {
1161             unp->refCount++;
1162             break;
1163         }
1164     }
1165     if (!unp && (flags & SMB_FLAG_CREATE)) {
1166         unp = malloc(sizeof(*unp));
1167         memset(unp, 0, sizeof(*unp));
1168         unp->refCount = 1;
1169         unp->nextp = usernamesp;
1170         unp->name = strdup(usern);
1171         unp->machine = strdup(machine);
1172         usernamesp = unp;
1173         lock_InitializeMutex(&unp->mx, "username_t mutex");
1174         if (flags & SMB_FLAG_AFSLOGON)
1175             unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1176     }
1177
1178     lock_ReleaseWrite(&smb_rctLock);
1179     return unp;
1180 }       
1181
1182 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
1183 {
1184     smb_user_t *uidp= NULL;
1185
1186     lock_ObtainWrite(&smb_rctLock);
1187     for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1188         if (!uidp->unp) 
1189             continue;
1190         if (stricmp(uidp->unp->name, usern) == 0) {
1191             uidp->refCount++;
1192             osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%s]",
1193                      vcp,uidp->userID,osi_LogSaveString(smb_logp,usern));
1194             break;
1195         } else
1196             continue;
1197     }           
1198     lock_ReleaseWrite(&smb_rctLock);
1199     return uidp;
1200 }       
1201
1202 void smb_ReleaseUsername(smb_username_t *unp)
1203 {
1204     smb_username_t *up;
1205     smb_username_t **lupp;
1206     cm_user_t *userp = NULL;
1207     time_t      now = osi_Time();
1208
1209     lock_ObtainWrite(&smb_rctLock);
1210     osi_assert(unp->refCount-- > 0);
1211     if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1212         (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1213         lupp = &usernamesp;
1214         for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1215             if (up == unp) 
1216                 break;
1217         }
1218         osi_assert(up != NULL);
1219         *lupp = up->nextp;
1220         up->nextp = NULL;                       /* do not remove this */
1221         lock_FinalizeMutex(&unp->mx);
1222         userp = unp->userp;
1223         free(unp->name);
1224         free(unp->machine);
1225         free(unp);
1226     }           
1227     lock_ReleaseWrite(&smb_rctLock);
1228
1229     if (userp) {
1230         cm_ReleaseUser(userp);
1231     }   
1232 }       
1233
1234 void smb_HoldUIDNoLock(smb_user_t *uidp)
1235 {
1236     uidp->refCount++;
1237 }
1238
1239 void smb_ReleaseUID(smb_user_t *uidp)
1240 {
1241     smb_user_t *up;
1242     smb_user_t **lupp;
1243     smb_username_t *unp = NULL;
1244
1245     lock_ObtainWrite(&smb_rctLock);
1246     osi_assert(uidp->refCount-- > 0);
1247     if (uidp->refCount == 0) {
1248         lupp = &uidp->vcp->usersp;
1249         for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1250             if (up == uidp) 
1251                 break;
1252         }
1253         osi_assert(up != NULL);
1254         *lupp = up->nextp;
1255         lock_FinalizeMutex(&uidp->mx);
1256         unp = uidp->unp;
1257         smb_ReleaseVCNoLock(uidp->vcp);
1258         uidp->vcp = NULL;
1259         free(uidp);
1260     }           
1261     lock_ReleaseWrite(&smb_rctLock);
1262
1263     if (unp) {
1264         if (unp->userp)
1265             cm_ReleaseUserVCRef(unp->userp);
1266         smb_ReleaseUsername(unp);
1267     }
1268 }       
1269
1270 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1271 {
1272     cm_user_t *up = NULL;
1273
1274     if (!uidp)
1275         return NULL;
1276     
1277     lock_ObtainMutex(&uidp->mx);
1278     if (uidp->unp) {
1279         up = uidp->unp->userp;
1280         cm_HoldUser(up);
1281     }
1282     lock_ReleaseMutex(&uidp->mx);
1283
1284     return up;
1285 }
1286
1287
1288 /* retrieve a held reference to a user structure corresponding to an incoming
1289  * request.
1290  * corresponding release function is cm_ReleaseUser.
1291  */
1292 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1293 {
1294     smb_user_t *uidp;
1295     cm_user_t *up = NULL;
1296     smb_t *smbp;
1297
1298     smbp = (smb_t *) inp;
1299     uidp = smb_FindUID(vcp, smbp->uid, 0);
1300     if (!uidp)
1301         return NULL;
1302     
1303     up = smb_GetUserFromUID(uidp);
1304
1305     smb_ReleaseUID(uidp);
1306     return up;
1307 }
1308
1309 /*
1310  * Return a pointer to a pathname extracted from a TID structure.  The
1311  * TID structure is not held; assume it won't go away.
1312  */
1313 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1314 {
1315     smb_tid_t *tidp;
1316     long code = 0;
1317
1318     tidp = smb_FindTID(vcp, tid, 0);
1319     if (!tidp) {
1320         *treepath = NULL;
1321     } else {
1322         if (tidp->flags & SMB_TIDFLAG_IPC) {
1323             code = CM_ERROR_TIDIPC;
1324             /* tidp->pathname would be NULL, but that's fine */
1325         }
1326         *treepath = tidp->pathname;
1327         smb_ReleaseTID(tidp);
1328     }
1329     return code;
1330 }
1331
1332 /* check to see if we have a chained fid, that is, a fid that comes from an
1333  * OpenAndX message that ran earlier in this packet.  In this case, the fid
1334  * field in a read, for example, request, isn't set, since the value is
1335  * supposed to be inherited from the openAndX call.
1336  */
1337 int smb_ChainFID(int fid, smb_packet_t *inp)
1338 {
1339     if (inp->fid == 0 || inp->inCount == 0) 
1340         return fid;
1341     else 
1342         return inp->fid;
1343 }
1344
1345 /* are we a priv'd user?  What does this mean on NT? */
1346 int smb_SUser(cm_user_t *userp)
1347 {
1348     return 1;
1349 }
1350
1351 /* find a file ID.  If we pass in 0 we select an unused File ID.
1352  * If the SMB_FLAG_CREATE flag is set, we allocate a new  
1353  * smb_fid_t data structure if desired File ID cannot be found.
1354  */
1355 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1356 {
1357     smb_fid_t *fidp;
1358     int newFid = 0;
1359         
1360     if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1361         return NULL;
1362
1363     lock_ObtainWrite(&smb_rctLock);
1364     /* figure out if we need to allocate a new file ID */
1365     if (fid == 0) {
1366         newFid = 1;
1367         fid = vcp->fidCounter;
1368     }
1369
1370   retry:
1371     for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1372         if (fidp->refCount == 0 && fidp->delete) {
1373             fidp->refCount++;
1374             lock_ReleaseWrite(&smb_rctLock);
1375             smb_ReleaseFID(fidp);
1376             lock_ObtainWrite(&smb_rctLock);
1377             goto retry;
1378         }
1379         if (fid == fidp->fid) {
1380             if (newFid) {
1381                 fid++;
1382                 if (fid == 0xFFFF) {
1383                     osi_Log1(smb_logp,
1384                              "New FID number wraps on vcp 0x%x", vcp);
1385                     fid = 1;
1386                 }
1387                 goto retry;
1388             }
1389             fidp->refCount++;
1390             break;
1391         }
1392     }
1393
1394     if (!fidp && (flags & SMB_FLAG_CREATE)) {
1395         char eventName[MAX_PATH];
1396         EVENT_HANDLE event;
1397         sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1398         event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1399         if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1400             osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1401             thrd_CloseHandle(event);
1402             fid++;
1403             if (fid == 0xFFFF) {
1404                 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1405                 fid = 1;
1406             }
1407             goto retry;
1408         }
1409
1410         fidp = malloc(sizeof(*fidp));
1411         memset(fidp, 0, sizeof(*fidp));
1412         osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1413         fidp->refCount = 1;
1414         fidp->vcp = vcp;
1415         smb_HoldVCNoLock(vcp);
1416         lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1417         fidp->fid = fid;
1418         fidp->curr_chunk = fidp->prev_chunk = -2;
1419         fidp->raw_write_event = event;
1420         if (newFid) {
1421             vcp->fidCounter = fid+1;
1422             if (vcp->fidCounter == 0xFFFF) {
1423                 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1424                          vcp);
1425                 vcp->fidCounter = 1;
1426             }
1427         }
1428     }
1429
1430     lock_ReleaseWrite(&smb_rctLock);
1431     return fidp;
1432 }
1433
1434 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1435 {
1436     smb_fid_t *fidp = NULL;
1437     int newFid = 0;
1438         
1439     if (!scp)
1440         return NULL;
1441
1442     lock_ObtainWrite(&smb_rctLock);
1443     for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1444         if (scp == fidp->scp) {
1445             fidp->refCount++;
1446             break;
1447         }
1448     }
1449     lock_ReleaseWrite(&smb_rctLock);
1450     return fidp;
1451 }
1452
1453 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1454 {
1455     fidp->refCount++;
1456 }
1457
1458
1459 /* smb_ReleaseFID cannot be called while an cm_scache_t mutex lock is held */
1460 /* the sm_fid_t->mx and smb_rctLock must not be held */
1461 void smb_ReleaseFID(smb_fid_t *fidp)
1462 {
1463     cm_scache_t *scp = NULL;
1464     cm_user_t *userp = NULL;
1465     smb_vc_t *vcp = NULL;
1466     smb_ioctl_t *ioctlp;
1467
1468     lock_ObtainMutex(&fidp->mx);
1469     lock_ObtainWrite(&smb_rctLock);
1470     osi_assert(fidp->refCount-- > 0);
1471     if (fidp->refCount == 0 && (fidp->delete)) {
1472         vcp = fidp->vcp;
1473         fidp->vcp = NULL;
1474         scp = fidp->scp;    /* release after lock is released */
1475         if (scp) {
1476             lock_ObtainMutex(&scp->mx);
1477             scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1478             lock_ReleaseMutex(&scp->mx);
1479             osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1480             fidp->scp = NULL;
1481         }
1482         userp = fidp->userp;
1483         fidp->userp = NULL;
1484
1485         if (vcp->fidsp) 
1486             osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1487         thrd_CloseHandle(fidp->raw_write_event);
1488
1489         /* and see if there is ioctl stuff to free */
1490         ioctlp = fidp->ioctlp;
1491         if (ioctlp) {
1492             if (ioctlp->prefix)
1493                 cm_FreeSpace(ioctlp->prefix);
1494             if (ioctlp->inAllocp)
1495                 free(ioctlp->inAllocp);
1496             if (ioctlp->outAllocp)
1497                 free(ioctlp->outAllocp);
1498             free(ioctlp);
1499         }       
1500         lock_ReleaseMutex(&fidp->mx);
1501         lock_FinalizeMutex(&fidp->mx);
1502         free(fidp);
1503
1504         if (vcp)
1505             smb_ReleaseVCNoLock(vcp);
1506     } else {
1507         lock_ReleaseMutex(&fidp->mx);
1508     }
1509     lock_ReleaseWrite(&smb_rctLock);
1510
1511     /* now release the scache structure */
1512     if (scp) 
1513         cm_ReleaseSCache(scp);
1514
1515     if (userp)
1516         cm_ReleaseUser(userp);
1517 }       
1518
1519 /*
1520  * Case-insensitive search for one string in another;
1521  * used to find variable names in submount pathnames.
1522  */
1523 static char *smb_stristr(char *str1, char *str2)
1524 {
1525     char *cursor;
1526
1527     for (cursor = str1; *cursor; cursor++)
1528         if (stricmp(cursor, str2) == 0)
1529             return cursor;
1530
1531     return NULL;
1532 }
1533
1534 /*
1535  * Substitute a variable value for its name in a submount pathname.  Variable
1536  * name has been identified by smb_stristr() and is in substr.  Variable name
1537  * length (plus one) is in substr_size.  Variable value is in newstr.
1538  */
1539 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1540                       char *newstr)
1541 {
1542     char temp[1024];
1543
1544     strcpy(temp, substr + substr_size - 1);
1545     strcpy(substr, newstr);
1546     strcat(str1, temp);
1547 }       
1548
1549 char VNUserName[] = "%USERNAME%";
1550 char VNLCUserName[] = "%LCUSERNAME%";
1551 char VNComputerName[] = "%COMPUTERNAME%";
1552 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1553
1554
1555 typedef struct smb_findShare_rock {
1556     char * shareName;
1557     char * match;
1558     int matchType;
1559 } smb_findShare_rock_t;
1560
1561 #define SMB_FINDSHARE_EXACT_MATCH 1
1562 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1563
1564 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1565                        osi_hyper_t *offp)
1566 {
1567     int matchType = 0;
1568     smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1569     if (!strnicmp(dep->name, vrock->shareName, 12)) {
1570         if(!stricmp(dep->name, vrock->shareName))
1571             matchType = SMB_FINDSHARE_EXACT_MATCH;
1572         else
1573             matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1574         if(vrock->match) free(vrock->match);
1575         vrock->match = strdup(dep->name);
1576         vrock->matchType = matchType;
1577
1578         if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1579             return CM_ERROR_STOPNOW;
1580     }
1581     return 0;
1582 }
1583
1584
1585 /* find a shareName in the table of submounts */
1586 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1587         char **pathNamep)
1588 {
1589     DWORD len;
1590     char pathName[1024];
1591     char *var;
1592     char temp[1024];
1593     DWORD sizeTemp;
1594     char *p, *q;
1595     HKEY parmKey;
1596     DWORD code;
1597     DWORD allSubmount = 1;
1598
1599     /* if allSubmounts == 0, only return the //mountRoot/all share 
1600      * if in fact it has been been created in the subMounts table.  
1601      * This is to allow sites that want to restrict access to the 
1602      * world to do so.
1603      */
1604     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1605                          0, KEY_QUERY_VALUE, &parmKey);
1606     if (code == ERROR_SUCCESS) {
1607         len = sizeof(allSubmount);
1608         code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1609                                 (BYTE *) &allSubmount, &len);
1610         if (code != ERROR_SUCCESS) {
1611             allSubmount = 1;
1612         }
1613         RegCloseKey (parmKey);
1614     }
1615
1616     if (allSubmount && _stricmp(shareName, "all") == 0) {
1617         *pathNamep = NULL;
1618         return 1;
1619     }
1620
1621     /* In case, the all share is disabled we need to still be able
1622      * to handle ioctl requests 
1623      */
1624     if (_stricmp(shareName, "ioctl$") == 0) {
1625         *pathNamep = strdup("/.__ioctl__");
1626         return 1;
1627     }
1628
1629     if (_stricmp(shareName, "IPC$") == 0 ||
1630         _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1631         _stricmp(shareName, "DESKTOP.INI") == 0
1632          ) {
1633         *pathNamep = NULL;
1634         return 0;
1635     }
1636
1637     /* Check for volume references
1638      * 
1639      * They look like <cell>{%,#}<volume>
1640      */
1641     if (strchr(shareName, '%') != NULL ||
1642         strchr(shareName, '#') != NULL) {
1643         char pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
1644                                 /* make room for '/@vol:' + mountchar + NULL terminator*/
1645
1646         osi_Log1(smb_logp, "smb_FindShare found volume reference [%s]",
1647                  osi_LogSaveString(smb_logp, shareName));
1648
1649         snprintf(pathstr, sizeof(pathstr)/sizeof(char),
1650                  "/" CM_PREFIX_VOL "%s", shareName);
1651         pathstr[sizeof(pathstr)/sizeof(char) - 1] = '\0';
1652         len = strlen(pathstr);
1653
1654         *pathNamep = malloc(len);
1655         if (*pathNamep) {
1656             strcpy(*pathNamep, pathstr);
1657             strlwr(*pathNamep);
1658             osi_Log1(smb_logp, "   returning pathname [%s]",
1659                      osi_LogSaveString(smb_logp, *pathNamep));
1660
1661             return 1;
1662         } else {
1663             return 0;
1664         }
1665     }
1666
1667     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1668                          0, KEY_QUERY_VALUE, &parmKey);
1669     if (code == ERROR_SUCCESS) {
1670         len = sizeof(pathName);
1671         code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1672                                 (BYTE *) pathName, &len);
1673         if (code != ERROR_SUCCESS)
1674             len = 0;
1675         RegCloseKey (parmKey);
1676     } else {
1677         len = 0;
1678     }   
1679     if (len != 0 && len != sizeof(pathName) - 1) {
1680         /* We can accept either unix or PC style AFS pathnames.  Convert
1681          * Unix-style to PC style here for internal use. 
1682          */
1683         p = pathName;
1684         if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1685             p += strlen(cm_mountRoot);  /* skip mount path */
1686         q = p;
1687         while (*q) {
1688             if (*q == '/') *q = '\\';    /* change to \ */
1689             q++;
1690         }
1691
1692         while (1)
1693         {
1694             if (var = smb_stristr(p, VNUserName)) {
1695                 if (uidp && uidp->unp)
1696                     smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1697                 else
1698                     smb_subst(p, var, sizeof(VNUserName)," ");
1699             }
1700             else if (var = smb_stristr(p, VNLCUserName)) 
1701             {
1702                 if (uidp && uidp->unp)
1703                     strcpy(temp, uidp->unp->name);
1704                 else 
1705                     strcpy(temp, " ");
1706                 _strlwr(temp);
1707                 smb_subst(p, var, sizeof(VNLCUserName), temp);
1708             }
1709             else if (var = smb_stristr(p, VNComputerName)) 
1710             {
1711                 sizeTemp = sizeof(temp);
1712                 GetComputerName((LPTSTR)temp, &sizeTemp);
1713                 smb_subst(p, var, sizeof(VNComputerName), temp);
1714             }
1715             else if (var = smb_stristr(p, VNLCComputerName)) 
1716             {
1717                 sizeTemp = sizeof(temp);
1718                 GetComputerName((LPTSTR)temp, &sizeTemp);
1719                 _strlwr(temp);
1720                 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1721             }
1722             else     
1723                 break;
1724         }
1725         *pathNamep = strdup(p);
1726         return 1;
1727     } 
1728     else
1729     {
1730         /* First lookup shareName in root.afs */
1731         cm_req_t req;
1732         smb_findShare_rock_t vrock;
1733         osi_hyper_t thyper;
1734         char * p = shareName; 
1735         int rw = 0;
1736
1737         /*  attempt to locate a partial match in root.afs.  This is because
1738             when using the ANSI RAP calls, the share name is limited to 13 chars
1739             and hence is truncated. Of course we prefer exact matches. */
1740         cm_InitReq(&req);
1741         thyper.HighPart = 0;
1742         thyper.LowPart = 0;
1743
1744         vrock.shareName = shareName;
1745         vrock.match = NULL;
1746         vrock.matchType = 0;
1747
1748         cm_HoldSCache(cm_data.rootSCachep);
1749         code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1750             (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1751         cm_ReleaseSCache(cm_data.rootSCachep);
1752
1753         if (vrock.matchType) {
1754             sprintf(pathName,"/%s/",vrock.match);
1755             *pathNamep = strdup(strlwr(pathName));
1756             free(vrock.match);
1757             return 1;
1758         }
1759
1760         /* if we get here, there was no match for the share in root.afs */
1761         /* so try to create  \\<netbiosName>\<cellname>  */
1762         if ( *p == '.' ) {
1763             p++;
1764             rw = 1;
1765         }
1766         /* Get the full name for this cell */
1767         code = cm_SearchCellFile(p, temp, 0, 0);
1768 #ifdef AFS_AFSDB_ENV
1769         if (code && cm_dnsEnabled) {
1770             int ttl;
1771             code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1772         }
1773 #endif
1774         /* construct the path */
1775         if (code == 0) {     
1776             sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1777             *pathNamep = strdup(strlwr(pathName));
1778             return 1;
1779         }
1780     }
1781     /* failure */
1782     *pathNamep = NULL;
1783     return 0;
1784 }
1785
1786 /* Client-side offline caching policy types */
1787 #define CSC_POLICY_MANUAL 0
1788 #define CSC_POLICY_DOCUMENTS 1
1789 #define CSC_POLICY_PROGRAMS 2
1790 #define CSC_POLICY_DISABLE 3
1791
1792 int smb_FindShareCSCPolicy(char *shareName)
1793 {
1794     DWORD len;
1795     char policy[1024];
1796     DWORD dwType;
1797     HKEY hkCSCPolicy;
1798     int  retval = CSC_POLICY_MANUAL;
1799
1800     RegCreateKeyEx( HKEY_LOCAL_MACHINE, 
1801                     AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1802                     0, 
1803                     "AFS", 
1804                     REG_OPTION_NON_VOLATILE,
1805                     KEY_READ,
1806                     NULL, 
1807                     &hkCSCPolicy,
1808                     NULL );
1809
1810     len = sizeof(policy);
1811     if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1812          len == 0) {
1813         retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1814     }
1815     else if (stricmp(policy, "documents") == 0)
1816     {
1817         retval = CSC_POLICY_DOCUMENTS;
1818     }
1819     else if (stricmp(policy, "programs") == 0)
1820     {
1821         retval = CSC_POLICY_PROGRAMS;
1822     }
1823     else if (stricmp(policy, "disable") == 0)
1824     {
1825         retval = CSC_POLICY_DISABLE;
1826     }
1827         
1828     RegCloseKey(hkCSCPolicy);
1829     return retval;
1830 }
1831
1832 /* find a dir search structure by cookie value, and return it held.
1833  * Must be called with smb_globalLock held.
1834  */
1835 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
1836 {
1837     smb_dirSearch_t *dsp;
1838         
1839     for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1840         if (dsp->cookie == cookie) {
1841             if (dsp != smb_firstDirSearchp) {
1842                 /* move to head of LRU queue, too, if we're not already there */
1843                 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1844                     smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
1845                 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1846                 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1847                 if (!smb_lastDirSearchp)
1848                     smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1849             }
1850             lock_ObtainMutex(&dsp->mx);
1851             dsp->refCount++;
1852             lock_ReleaseMutex(&dsp->mx);
1853             break;
1854         }
1855     }
1856
1857     if (dsp == NULL) {
1858         osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
1859         for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1860             osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
1861         }
1862     }
1863     return dsp;
1864 }       
1865
1866 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1867 {
1868     lock_ObtainWrite(&smb_globalLock);
1869     lock_ObtainMutex(&dsp->mx);
1870     osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p", 
1871               dsp->cookie, dsp, dsp->scp);
1872     dsp->flags |= SMB_DIRSEARCH_DELETE;
1873     if (dsp->scp != NULL) {
1874         lock_ObtainMutex(&dsp->scp->mx);
1875         if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1876             dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1877             dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1878             dsp->scp->bulkStatProgress = hzero;
1879         }       
1880         lock_ReleaseMutex(&dsp->scp->mx);
1881     }   
1882     lock_ReleaseMutex(&dsp->mx);
1883     lock_ReleaseWrite(&smb_globalLock);
1884 }               
1885
1886 /* Must be called with the smb_globalLock held */
1887 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
1888 {
1889     cm_scache_t *scp = NULL;
1890
1891     lock_ObtainMutex(&dsp->mx);
1892     osi_assert(dsp->refCount-- > 0);
1893     if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1894         if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1895             smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1896         osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1897         lock_ReleaseMutex(&dsp->mx);
1898         lock_FinalizeMutex(&dsp->mx);
1899         scp = dsp->scp;
1900         osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p", 
1901                  dsp->cookie, dsp, scp);
1902         free(dsp);
1903     } else {
1904         lock_ReleaseMutex(&dsp->mx);
1905     }
1906     /* do this now to avoid spurious locking hierarchy creation */
1907     if (scp) 
1908         cm_ReleaseSCache(scp);
1909 }       
1910
1911 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1912 {
1913     lock_ObtainWrite(&smb_globalLock);
1914     smb_ReleaseDirSearchNoLock(dsp);
1915     lock_ReleaseWrite(&smb_globalLock);
1916 }       
1917
1918 /* find a dir search structure by cookie value, and return it held */
1919 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1920 {
1921     smb_dirSearch_t *dsp;
1922
1923     lock_ObtainWrite(&smb_globalLock);
1924     dsp = smb_FindDirSearchNoLock(cookie);
1925     lock_ReleaseWrite(&smb_globalLock);
1926     return dsp;
1927 }
1928
1929 /* GC some dir search entries, in the address space expected by the specific protocol.
1930  * Must be called with smb_globalLock held; release the lock temporarily.
1931  */
1932 #define SMB_DIRSEARCH_GCMAX     10      /* how many at once */
1933 void smb_GCDirSearches(int isV3)
1934 {
1935     smb_dirSearch_t *prevp;
1936     smb_dirSearch_t *tp;
1937     smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1938     int victimCount;
1939     int i;
1940         
1941     victimCount = 0;    /* how many have we got so far */
1942     for (tp = smb_lastDirSearchp; tp; tp=prevp) {
1943         /* we'll move tp from queue, so
1944          * do this early.
1945          */
1946         prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);  
1947         /* if no one is using this guy, and we're either in the new protocol,
1948          * or we're in the old one and this is a small enough ID to be useful
1949          * to the old protocol, GC this guy.
1950          */
1951         if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1952             /* hold and delete */
1953             lock_ObtainMutex(&tp->mx);
1954             tp->flags |= SMB_DIRSEARCH_DELETE;
1955             lock_ReleaseMutex(&tp->mx);
1956             victimsp[victimCount++] = tp;
1957             tp->refCount++;
1958         }
1959
1960         /* don't do more than this */
1961         if (victimCount >= SMB_DIRSEARCH_GCMAX) 
1962             break;
1963     }
1964         
1965     /* now release them */
1966     for (i = 0; i < victimCount; i++) {
1967         smb_ReleaseDirSearchNoLock(victimsp[i]);
1968     }
1969 }
1970
1971 /* function for allocating a dir search entry.  We need these to remember enough context
1972  * since we don't get passed the path from call to call during a directory search.
1973  *
1974  * Returns a held dir search structure, and bumps the reference count on the vnode,
1975  * since it saves a pointer to the vnode.
1976  */
1977 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1978 {
1979     smb_dirSearch_t *dsp;
1980     int counter;
1981     int maxAllowed;
1982     int start;
1983     int wrapped = 0;
1984
1985     lock_ObtainWrite(&smb_globalLock);
1986     counter = 0;
1987
1988     /* what's the biggest ID allowed in this version of the protocol */
1989     /* TODO: do we really want a non v3 dir search request to wrap
1990        smb_dirSearchCounter? */
1991     maxAllowed = isV3 ? 65535 : 255;
1992     if (smb_dirSearchCounter > maxAllowed)
1993         smb_dirSearchCounter = 1;
1994
1995     start = smb_dirSearchCounter;
1996
1997     while (1) {
1998         /* twice so we have enough tries to find guys we GC after one pass;
1999          * 10 extra is just in case I mis-counted.
2000          */
2001         if (++counter > 2*maxAllowed+10) 
2002             osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2003
2004         if (smb_dirSearchCounter > maxAllowed) {        
2005             smb_dirSearchCounter = 1;
2006         }
2007         if (smb_dirSearchCounter == start) {
2008             if (wrapped)
2009                 smb_GCDirSearches(isV3);
2010             wrapped++;
2011         }
2012         dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2013         if (dsp) {
2014             /* don't need to watch for refcount zero and deleted, since
2015             * we haven't dropped the global lock.
2016             */
2017             lock_ObtainMutex(&dsp->mx);
2018             dsp->refCount--;
2019             lock_ReleaseMutex(&dsp->mx);
2020             ++smb_dirSearchCounter;
2021             continue;
2022         }       
2023
2024         dsp = malloc(sizeof(*dsp));
2025         memset(dsp, 0, sizeof(*dsp));
2026         dsp->cookie = smb_dirSearchCounter;
2027         ++smb_dirSearchCounter;
2028         dsp->refCount = 1;
2029         lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
2030         dsp->lastTime = osi_Time();
2031         osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2032         if (!smb_lastDirSearchp) 
2033             smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2034     
2035         osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p", 
2036                  dsp->cookie, dsp);
2037         break;
2038     }   
2039     lock_ReleaseWrite(&smb_globalLock);
2040     return dsp;
2041 }
2042
2043 static smb_packet_t *GetPacket(void)
2044 {
2045     smb_packet_t *tbp;
2046
2047     lock_ObtainWrite(&smb_globalLock);
2048     tbp = smb_packetFreeListp;
2049     if (tbp) 
2050         smb_packetFreeListp = tbp->nextp;
2051     lock_ReleaseWrite(&smb_globalLock);
2052     if (!tbp) {
2053         tbp = calloc(65540,1);
2054         tbp->magic = SMB_PACKETMAGIC;
2055         tbp->ncbp = NULL;
2056         tbp->vcp = NULL;
2057         tbp->resumeCode = 0;
2058         tbp->inCount = 0;
2059         tbp->fid = 0;
2060         tbp->wctp = NULL;
2061         tbp->inCom = 0;
2062         tbp->oddByte = 0;
2063         tbp->ncb_length = 0;
2064         tbp->flags = 0;
2065         tbp->spacep = NULL;
2066         
2067     }
2068     osi_assert(tbp->magic == SMB_PACKETMAGIC);
2069
2070     return tbp;
2071 }
2072
2073 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2074 {
2075     smb_packet_t *tbp;
2076     tbp = GetPacket();
2077     memcpy(tbp, pkt, sizeof(smb_packet_t));
2078     tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2079     if (tbp->vcp)
2080         smb_HoldVC(tbp->vcp);
2081     return tbp;
2082 }
2083
2084 static NCB *GetNCB(void)
2085 {
2086     smb_ncb_t *tbp;
2087     NCB *ncbp;
2088
2089     lock_ObtainWrite(&smb_globalLock);
2090     tbp = smb_ncbFreeListp;
2091     if (tbp) 
2092         smb_ncbFreeListp = tbp->nextp;
2093     lock_ReleaseWrite(&smb_globalLock);
2094     if (!tbp) {
2095         tbp = calloc(sizeof(*tbp),1);
2096         tbp->magic = SMB_NCBMAGIC;
2097     }
2098         
2099     osi_assert(tbp->magic == SMB_NCBMAGIC);
2100
2101     memset(&tbp->ncb, 0, sizeof(NCB));
2102     ncbp = &tbp->ncb;
2103     return ncbp;
2104 }
2105
2106 void smb_FreePacket(smb_packet_t *tbp)
2107 {
2108     smb_vc_t * vcp = NULL;
2109     osi_assert(tbp->magic == SMB_PACKETMAGIC);
2110         
2111     lock_ObtainWrite(&smb_globalLock);
2112     tbp->nextp = smb_packetFreeListp;
2113     smb_packetFreeListp = tbp;
2114     tbp->magic = SMB_PACKETMAGIC;
2115     tbp->ncbp = NULL;
2116     vcp = tbp->vcp;
2117     tbp->vcp = NULL;
2118     tbp->resumeCode = 0;
2119     tbp->inCount = 0;
2120     tbp->fid = 0;
2121     tbp->wctp = NULL;
2122     tbp->inCom = 0;
2123     tbp->oddByte = 0;
2124     tbp->ncb_length = 0;
2125     tbp->flags = 0;
2126     lock_ReleaseWrite(&smb_globalLock);
2127
2128     if (vcp)
2129         smb_ReleaseVC(vcp);
2130 }
2131
2132 static void FreeNCB(NCB *bufferp)
2133 {
2134     smb_ncb_t *tbp;
2135         
2136     tbp = (smb_ncb_t *) bufferp;
2137     osi_assert(tbp->magic == SMB_NCBMAGIC);
2138         
2139     lock_ObtainWrite(&smb_globalLock);
2140     tbp->nextp = smb_ncbFreeListp;
2141     smb_ncbFreeListp = tbp;
2142     lock_ReleaseWrite(&smb_globalLock);
2143 }
2144
2145 /* get a ptr to the data part of a packet, and its count */
2146 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2147 {
2148     int parmBytes;
2149     int dataBytes;
2150     unsigned char *afterParmsp;
2151
2152     parmBytes = *smbp->wctp << 1;
2153     afterParmsp = smbp->wctp + parmBytes + 1;
2154         
2155     dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2156     if (nbytesp) *nbytesp = dataBytes;
2157         
2158     /* don't forget to skip the data byte count, since it follows
2159      * the parameters; that's where the "2" comes from below.
2160      */
2161     return (unsigned char *) (afterParmsp + 2);
2162 }
2163
2164 /* must set all the returned parameters before playing around with the
2165  * data region, since the data region is located past the end of the
2166  * variable number of parameters.
2167  */
2168 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2169 {
2170     unsigned char *afterParmsp;
2171
2172     afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2173         
2174     *afterParmsp++ = dsize & 0xff;
2175     *afterParmsp = (dsize>>8) & 0xff;
2176 }       
2177
2178 /* return the parm'th parameter in the smbp packet */
2179 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2180 {
2181     int parmCount;
2182     unsigned char *parmDatap;
2183
2184     parmCount = *smbp->wctp;
2185
2186     if (parm >= parmCount) {
2187         char s[100];
2188
2189         sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2190                 parm, parmCount, smbp->ncb_length);
2191         osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2192                  parm, parmCount, smbp->ncb_length);
2193         LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM, 
2194                  __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2195         osi_panic(s, __FILE__, __LINE__);
2196     }
2197     parmDatap = smbp->wctp + (2*parm) + 1;
2198         
2199     return parmDatap[0] + (parmDatap[1] << 8);
2200 }
2201
2202 /* return the parm'th parameter in the smbp packet */
2203 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2204 {
2205     int parmCount;
2206     unsigned char *parmDatap;
2207
2208     parmCount = *smbp->wctp;
2209
2210     if (parm >= parmCount) {
2211         char s[100];
2212
2213         sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2214                 parm, parmCount, smbp->ncb_length);
2215         osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2216                  parm, parmCount, smbp->ncb_length);
2217         LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM, 
2218                  __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2219         osi_panic(s, __FILE__, __LINE__);
2220     }
2221     parmDatap = smbp->wctp + (2*parm) + 1;
2222         
2223     return parmDatap[0];
2224 }
2225
2226 /* return the parm'th parameter in the smbp packet */
2227 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2228 {
2229     int parmCount;
2230     unsigned char *parmDatap;
2231
2232     parmCount = *smbp->wctp;
2233
2234     if (parm + 1 >= parmCount) {
2235         char s[100];
2236
2237         sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2238                 parm, parmCount, smbp->ncb_length);
2239         osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2240                  parm, parmCount, smbp->ncb_length);
2241         LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM, 
2242                  __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2243         osi_panic(s, __FILE__, __LINE__);
2244     }
2245     parmDatap = smbp->wctp + (2*parm) + 1;
2246         
2247     return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2248 }
2249
2250 /* return the parm'th parameter in the smbp packet */
2251 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2252 {
2253     int parmCount;
2254     unsigned char *parmDatap;
2255
2256     parmCount = *smbp->wctp;
2257
2258     if (parm * 2 + offset >= parmCount * 2) {
2259         char s[100];
2260
2261         sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2262                 parm, offset, parmCount, smbp->ncb_length);
2263         LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET, 
2264                  __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2265         osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2266                 parm, offset, parmCount, smbp->ncb_length);
2267         osi_panic(s, __FILE__, __LINE__);
2268     }
2269     parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2270         
2271     return parmDatap[0] + (parmDatap[1] << 8);
2272 }
2273
2274 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2275 {
2276     char *parmDatap;
2277
2278     /* make sure we have enough slots */
2279     if (*smbp->wctp <= slot) 
2280         *smbp->wctp = slot+1;
2281         
2282     parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2283     *parmDatap++ = parmValue & 0xff;
2284     *parmDatap = (parmValue>>8) & 0xff;
2285 }       
2286
2287 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2288 {
2289     char *parmDatap;
2290
2291     /* make sure we have enough slots */
2292     if (*smbp->wctp <= slot) 
2293         *smbp->wctp = slot+2;
2294
2295     parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2296     *parmDatap++ = parmValue & 0xff;
2297     *parmDatap++ = (parmValue>>8) & 0xff;
2298     *parmDatap++ = (parmValue>>16) & 0xff;
2299     *parmDatap   = (parmValue>>24) & 0xff;
2300 }
2301
2302 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2303 {
2304     char *parmDatap;
2305     int i;
2306
2307     /* make sure we have enough slots */
2308     if (*smbp->wctp <= slot) 
2309         *smbp->wctp = slot+4;
2310
2311     parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2312     for (i=0; i<8; i++)
2313         *parmDatap++ = *parmValuep++;
2314 }       
2315
2316 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2317 {
2318     char *parmDatap;
2319
2320     /* make sure we have enough slots */
2321     if (*smbp->wctp <= slot) {
2322         if (smbp->oddByte) {
2323             smbp->oddByte = 0;
2324             *smbp->wctp = slot+1;
2325         } else
2326             smbp->oddByte = 1;
2327     }
2328
2329     parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2330     *parmDatap++ = parmValue & 0xff;
2331 }
2332
2333 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2334 {
2335     char *lastSlashp;
2336         
2337     lastSlashp = strrchr(inPathp, '\\');
2338     if (lastComponentp)
2339         *lastComponentp = lastSlashp;
2340     if (lastSlashp) {
2341         while (1) {
2342             if (inPathp == lastSlashp) 
2343                 break;
2344             *outPathp++ = *inPathp++;
2345         }
2346         *outPathp++ = 0;
2347     }
2348     else {
2349         *outPathp++ = 0;
2350     }
2351 }
2352
2353 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2354 {
2355     if (*inp++ != 0x4) 
2356         return NULL;
2357     if (chainpp) {
2358         *chainpp = inp + strlen(inp) + 1;       /* skip over null-terminated string */
2359     }
2360     return inp;
2361 }
2362
2363 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2364 {
2365     int tlen;
2366
2367     if (*inp++ != 0x5) 
2368         return NULL;
2369     tlen = inp[0] + (inp[1]<<8);
2370     inp += 2;           /* skip length field */
2371
2372     if (chainpp) {
2373         *chainpp = inp + tlen;
2374     }
2375         
2376     if (lengthp) 
2377         *lengthp = tlen;
2378         
2379     return inp;
2380 }       
2381
2382 /* format a packet as a response */
2383 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2384 {
2385     smb_t *outp;
2386     smb_t *inSmbp;
2387
2388     outp = (smb_t *) op;
2389         
2390     /* zero the basic structure through the smb_wct field, and zero the data
2391      * size field, assuming that wct stays zero; otherwise, you have to 
2392      * explicitly set the data size field, too.
2393      */
2394     inSmbp = (smb_t *) inp;
2395     memset(outp, 0, sizeof(smb_t)+2);
2396     outp->id[0] = 0xff;
2397     outp->id[1] = 'S';
2398     outp->id[2] = 'M';
2399     outp->id[3] = 'B';
2400     if (inp) {
2401         outp->com = inSmbp->com;
2402         outp->tid = inSmbp->tid;
2403         outp->pid = inSmbp->pid;
2404         outp->uid = inSmbp->uid;
2405         outp->mid = inSmbp->mid;
2406         outp->res[0] = inSmbp->res[0];
2407         outp->res[1] = inSmbp->res[1];
2408         op->inCom = inSmbp->com;
2409     }
2410     outp->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
2411     outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2412
2413     /* copy fields in generic packet area */
2414     op->wctp = &outp->wct;
2415 }       
2416
2417 /* send a (probably response) packet; vcp tells us to whom to send it.
2418  * we compute the length by looking at wct and bcc fields.
2419  */
2420 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2421 {
2422     NCB *ncbp;
2423     int extra;
2424     long code = 0;
2425     unsigned char *tp;
2426     int localNCB = 0;
2427         
2428     ncbp = inp->ncbp;
2429     if (ncbp == NULL) {
2430         ncbp = GetNCB();
2431         localNCB = 1;
2432     }
2433  
2434     memset((char *)ncbp, 0, sizeof(NCB));
2435
2436     extra = 2 * (*inp->wctp);   /* space used by parms, in bytes */
2437     tp = inp->wctp + 1+ extra;  /* points to count of data bytes */
2438     extra += tp[0] + (tp[1]<<8);
2439     extra += (unsigned int)(inp->wctp - inp->data);     /* distance to last wct field */
2440     extra += 3;                 /* wct and length fields */
2441         
2442     ncbp->ncb_length = extra;   /* bytes to send */
2443     ncbp->ncb_lsn = (unsigned char) vcp->lsn;   /* vc to use */
2444     ncbp->ncb_lana_num = vcp->lana;
2445     ncbp->ncb_command = NCBSEND;        /* op means send data */
2446     ncbp->ncb_buffer = (char *) inp;/* packet */
2447     code = Netbios(ncbp);
2448         
2449     if (code != 0) {
2450         const char * s = ncb_error_string(code);
2451         osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2452         LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
2453
2454         lock_ObtainMutex(&vcp->mx);
2455         if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
2456             osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
2457                       vcp, vcp->usersp);
2458             vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2459             lock_ReleaseMutex(&vcp->mx);
2460             lock_ObtainWrite(&smb_globalLock);
2461             dead_sessions[vcp->session] = TRUE;
2462             lock_ReleaseWrite(&smb_globalLock);
2463             smb_CleanupDeadVC(vcp);
2464         } else {
2465             lock_ReleaseMutex(&vcp->mx);
2466         }
2467     }
2468
2469     if (localNCB)
2470         FreeNCB(ncbp);
2471 }
2472
2473 void smb_MapNTError(long code, unsigned long *NTStatusp)
2474 {
2475     unsigned long NTStatus;
2476
2477     /* map CM_ERROR_* errors to NT 32-bit status codes */
2478     /* NT Status codes are listed in ntstatus.h not winerror.h */
2479     if (code == CM_ERROR_NOSUCHCELL) {
2480         NTStatus = 0xC000000FL; /* No such file */
2481     }
2482     else if (code == CM_ERROR_NOSUCHVOLUME) {
2483         NTStatus = 0xC000000FL; /* No such file */
2484     }
2485     else if (code == CM_ERROR_TIMEDOUT) {
2486 #ifdef COMMENT
2487         NTStatus = 0xC00000CFL; /* Sharing Paused */
2488 #else
2489         NTStatus = 0x00000102L; /* Timeout */
2490 #endif
2491     }
2492     else if (code == CM_ERROR_RETRY) {
2493         NTStatus = 0xC000022DL; /* Retry */
2494     }
2495     else if (code == CM_ERROR_NOACCESS) {
2496         NTStatus = 0xC0000022L; /* Access denied */
2497     }
2498     else if (code == CM_ERROR_READONLY) {
2499         NTStatus = 0xC00000A2L; /* Write protected */
2500     }
2501     else if (code == CM_ERROR_NOSUCHFILE) {
2502         NTStatus = 0xC000000FL; /* No such file */
2503     }
2504     else if (code == CM_ERROR_NOSUCHPATH) {
2505         NTStatus = 0xC000003AL; /* Object path not found */
2506     }           
2507     else if (code == CM_ERROR_TOOBIG) {
2508         NTStatus = 0xC000007BL; /* Invalid image format */
2509     }
2510     else if (code == CM_ERROR_INVAL) {
2511         NTStatus = 0xC000000DL; /* Invalid parameter */
2512     }
2513     else if (code == CM_ERROR_BADFD) {
2514         NTStatus = 0xC0000008L; /* Invalid handle */
2515     }
2516     else if (code == CM_ERROR_BADFDOP) {
2517         NTStatus = 0xC0000022L; /* Access denied */
2518     }
2519     else if (code == CM_ERROR_EXISTS) {
2520         NTStatus = 0xC0000035L; /* Object name collision */
2521     }
2522     else if (code == CM_ERROR_NOTEMPTY) {
2523         NTStatus = 0xC0000101L; /* Directory not empty */
2524     }   
2525     else if (code == CM_ERROR_CROSSDEVLINK) {
2526         NTStatus = 0xC00000D4L; /* Not same device */
2527     }
2528     else if (code == CM_ERROR_NOTDIR) {
2529         NTStatus = 0xC0000103L; /* Not a directory */
2530     }
2531     else if (code == CM_ERROR_ISDIR) {
2532         NTStatus = 0xC00000BAL; /* File is a directory */
2533     }
2534     else if (code == CM_ERROR_BADOP) {
2535 #ifdef COMMENT
2536         /* I have no idea where this comes from */
2537         NTStatus = 0xC09820FFL; /* SMB no support */
2538 #else
2539         NTStatus = 0xC00000BBL;     /* Not supported */
2540 #endif /* COMMENT */
2541     }
2542     else if (code == CM_ERROR_BADSHARENAME) {
2543         NTStatus = 0xC00000CCL; /* Bad network name */
2544     }
2545     else if (code == CM_ERROR_NOIPC) {
2546 #ifdef COMMENT
2547         NTStatus = 0xC0000022L; /* Access Denied */
2548 #else   
2549         NTStatus = 0xC000013DL; /* Remote Resources */
2550 #endif
2551     }
2552     else if (code == CM_ERROR_CLOCKSKEW) {
2553         NTStatus = 0xC0000133L; /* Time difference at DC */
2554     }
2555     else if (code == CM_ERROR_BADTID) {
2556         NTStatus = 0xC0982005L; /* SMB bad TID */
2557     }
2558     else if (code == CM_ERROR_USESTD) {
2559         NTStatus = 0xC09820FBL; /* SMB use standard */
2560     }
2561     else if (code == CM_ERROR_QUOTA) {
2562 #ifdef COMMENT
2563         NTStatus = 0xC0000044L; /* Quota exceeded */
2564 #else
2565         NTStatus = 0xC000007FL; /* Disk full */
2566 #endif
2567     }
2568     else if (code == CM_ERROR_SPACE) {
2569         NTStatus = 0xC000007FL; /* Disk full */
2570     }
2571     else if (code == CM_ERROR_ATSYS) {
2572         NTStatus = 0xC0000033L; /* Object name invalid */
2573     }
2574     else if (code == CM_ERROR_BADNTFILENAME) {
2575         NTStatus = 0xC0000033L; /* Object name invalid */
2576     }
2577     else if (code == CM_ERROR_WOULDBLOCK) {
2578         NTStatus = 0xC0000055L; /* Lock not granted */
2579     }
2580     else if (code == CM_ERROR_SHARING_VIOLATION) {
2581         NTStatus = 0xC0000043L; /* Sharing violation */
2582     }
2583     else if (code == CM_ERROR_LOCK_CONFLICT) {
2584         NTStatus = 0xC0000054L; /* Lock conflict */
2585     }
2586     else if (code == CM_ERROR_PARTIALWRITE) {
2587         NTStatus = 0xC000007FL; /* Disk full */
2588     }
2589     else if (code == CM_ERROR_BUFFERTOOSMALL) {
2590         NTStatus = 0xC0000023L; /* Buffer too small */
2591     }
2592     else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2593         NTStatus = 0xC0000035L; /* Object name collision */
2594     }   
2595     else if (code == CM_ERROR_BADPASSWORD) {
2596         NTStatus = 0xC000006DL; /* unknown username or bad password */
2597     }
2598     else if (code == CM_ERROR_BADLOGONTYPE) {
2599         NTStatus = 0xC000015BL; /* logon type not granted */
2600     }
2601     else if (code == CM_ERROR_GSSCONTINUE) {
2602         NTStatus = 0xC0000016L; /* more processing required */
2603     }
2604     else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2605 #ifdef COMMENT
2606         NTStatus = 0xC0000280L; /* reparse point not resolved */
2607 #else
2608         NTStatus = 0xC0000022L; /* Access Denied */
2609 #endif
2610     }
2611     else if (code == CM_ERROR_PATH_NOT_COVERED) {
2612         NTStatus = 0xC0000257L; /* Path Not Covered */
2613     } 
2614 #ifdef COMMENT
2615     else if (code == CM_ERROR_ALLBUSY) {
2616         NTStatus = 0xC00000BFL; /* Network Busy */
2617     } 
2618     else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
2619         NTStatus = 0xC0000350L; /* Remote Host Down */
2620     } 
2621 #else
2622     /* we do not want to be telling the SMB/CIFS client that
2623      * the AFS Client Service is busy or down.  
2624      */
2625     else if (code == CM_ERROR_ALLBUSY || 
2626              code == CM_ERROR_ALLOFFLINE ||
2627              code == CM_ERROR_ALLDOWN) {
2628         NTStatus = 0xC00000BEL; /* Bad Network Path */
2629     }
2630 #endif
2631     else if (code == RXKADUNKNOWNKEY) {
2632         NTStatus = 0xC0000322L; /* Bad Kerberos key */
2633     } 
2634     else if (code == CM_ERROR_BAD_LEVEL) {
2635         NTStatus = 0xC0000148L; /* Invalid Level */
2636     } else {
2637         NTStatus = 0xC0982001L; /* SMB non-specific error */
2638     }
2639
2640     *NTStatusp = NTStatus;
2641     osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2642 }       
2643
2644 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2645                       unsigned char *classp)
2646 {
2647     unsigned char class;
2648     unsigned short error;
2649
2650     /* map CM_ERROR_* errors to SMB errors */
2651     if (code == CM_ERROR_NOSUCHCELL) {
2652         class = 1;
2653         error = 3;      /* bad path */
2654     }
2655     else if (code == CM_ERROR_NOSUCHVOLUME) {
2656         class = 1;
2657         error = 3;      /* bad path */
2658     }
2659     else if (code == CM_ERROR_TIMEDOUT) {
2660         class = 2;
2661         error = 81;     /* server is paused */
2662     }
2663     else if (code == CM_ERROR_RETRY) {
2664         class = 2;      /* shouldn't happen */
2665         error = 1;
2666     }
2667     else if (code == CM_ERROR_NOACCESS) {
2668         class = 2;
2669         error = 4;      /* bad access */
2670     }
2671     else if (code == CM_ERROR_READONLY) {
2672         class = 3;
2673         error = 19;     /* read only */
2674     }
2675     else if (code == CM_ERROR_NOSUCHFILE) {
2676         class = 1;
2677         error = 2;      /* ENOENT! */
2678     }
2679     else if (code == CM_ERROR_NOSUCHPATH) {
2680         class = 1;
2681         error = 3;      /* Bad path */
2682     }
2683     else if (code == CM_ERROR_TOOBIG) {
2684         class = 1;
2685         error = 11;     /* bad format */
2686     }
2687     else if (code == CM_ERROR_INVAL) {
2688         class = 2;      /* server non-specific error code */
2689         error = 1;
2690     }
2691     else if (code == CM_ERROR_BADFD) {
2692         class = 1;
2693         error = 6;      /* invalid file handle */
2694     }
2695     else if (code == CM_ERROR_BADFDOP) {
2696         class = 1;      /* invalid op on FD */
2697         error = 5;
2698     }
2699     else if (code == CM_ERROR_EXISTS) {
2700         class = 1;
2701         error = 80;     /* file already exists */
2702     }
2703     else if (code == CM_ERROR_NOTEMPTY) {
2704         class = 1;
2705         error = 5;      /* delete directory not empty */
2706     }
2707     else if (code == CM_ERROR_CROSSDEVLINK) {
2708         class = 1;
2709         error = 17;     /* EXDEV */
2710     }
2711     else if (code == CM_ERROR_NOTDIR) {
2712         class = 1;      /* bad path */
2713         error = 3;
2714     }
2715     else if (code == CM_ERROR_ISDIR) {
2716         class = 1;      /* access denied; DOS doesn't have a good match */
2717         error = 5;
2718     }       
2719     else if (code == CM_ERROR_BADOP) {
2720         class = 2;
2721         error = 65535;
2722     }
2723     else if (code == CM_ERROR_BADSHARENAME) {
2724         class = 2;
2725         error = 6;
2726     }
2727     else if (code == CM_ERROR_NOIPC) {
2728         class = 2;
2729         error = 4; /* bad access */
2730     }
2731     else if (code == CM_ERROR_CLOCKSKEW) {
2732         class = 1;      /* invalid function */
2733         error = 1;
2734     }
2735     else if (code == CM_ERROR_BADTID) {
2736         class = 2;
2737         error = 5;
2738     }
2739     else if (code == CM_ERROR_USESTD) {
2740         class = 2;
2741         error = 251;
2742     }
2743     else if (code == CM_ERROR_REMOTECONN) {
2744         class = 2;
2745         error = 82;
2746     }
2747     else if (code == CM_ERROR_QUOTA) {
2748         if (vcp->flags & SMB_VCFLAG_USEV3) {
2749             class = 3;
2750             error = 39; /* disk full */
2751         }
2752         else {
2753             class = 1;
2754             error = 5;  /* access denied */
2755         }
2756     }
2757     else if (code == CM_ERROR_SPACE) {
2758         if (vcp->flags & SMB_VCFLAG_USEV3) {
2759             class = 3;
2760             error = 39; /* disk full */
2761         }
2762         else {
2763             class = 1;
2764             error = 5;  /* access denied */
2765         }
2766     }
2767     else if (code == CM_ERROR_PARTIALWRITE) {
2768         class = 3;
2769         error = 39;     /* disk full */
2770     }
2771     else if (code == CM_ERROR_ATSYS) {
2772         class = 1;
2773         error = 2;      /* ENOENT */
2774     }
2775     else if (code == CM_ERROR_WOULDBLOCK) {
2776         class = 1;
2777         error = 33;     /* lock conflict */
2778     }
2779     else if (code == CM_ERROR_LOCK_CONFLICT) {
2780         class = 1;
2781         error = 33;     /* lock conflict */
2782     }
2783     else if (code == CM_ERROR_SHARING_VIOLATION) {
2784         class = 1;
2785         error = 33;     /* lock conflict */
2786     }
2787     else if (code == CM_ERROR_NOFILES) {
2788         class = 1;
2789         error = 18;     /* no files in search */
2790     }
2791     else if (code == CM_ERROR_RENAME_IDENTICAL) {
2792         class = 1;
2793         error = 183;     /* Samba uses this */
2794     }
2795     else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2796         /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2797         class = 2;
2798         error = 2; /* bad password */
2799     }
2800     else if (code == CM_ERROR_PATH_NOT_COVERED) {
2801         class = 2;
2802         error = 3;     /* bad path */
2803     }
2804     else {
2805         class = 2;
2806         error = 1;
2807     }
2808
2809     *scodep = error;
2810     *classp = class;
2811     osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2812 }       
2813
2814 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2815 {
2816     osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2817     return CM_ERROR_BADOP;
2818 }
2819
2820 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2821 {
2822     unsigned short EchoCount, i;
2823     char *data, *outdata;
2824     int dataSize;
2825
2826     EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2827
2828     for (i=1; i<=EchoCount; i++) {
2829         data = smb_GetSMBData(inp, &dataSize);
2830         smb_SetSMBParm(outp, 0, i);
2831         smb_SetSMBDataLength(outp, dataSize);
2832         outdata = smb_GetSMBData(outp, NULL);
2833         memcpy(outdata, data, dataSize);
2834         smb_SendPacket(vcp, outp);
2835     }
2836
2837     return 0;
2838 }
2839
2840 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2841 {
2842     osi_hyper_t offset;
2843     long count, minCount, finalCount;
2844     unsigned short fd;
2845     unsigned pid;
2846     smb_fid_t *fidp;
2847     long code = 0;
2848     cm_user_t *userp = NULL;
2849     NCB *ncbp;
2850     int rc;
2851     char *rawBuf = NULL;
2852
2853     rawBuf = NULL;
2854     finalCount = 0;
2855
2856     fd = smb_GetSMBParm(inp, 0);
2857     count = smb_GetSMBParm(inp, 3);
2858     minCount = smb_GetSMBParm(inp, 4);
2859     offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2860
2861     if (*inp->wctp == 10) {
2862         /* we were sent a request with 64-bit file offsets */
2863 #ifdef AFS_LARGEFILES
2864         offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
2865
2866         if (LargeIntegerLessThanZero(offset)) {
2867             osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
2868             goto send1;
2869         }
2870 #else
2871         if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
2872             osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset.  Dropping request.");
2873             goto send1;
2874         } else {
2875             offset.HighPart = 0;
2876         }
2877 #endif
2878     } else {
2879         /* we were sent a request with 32-bit file offsets */
2880         offset.HighPart = 0;
2881     }
2882
2883     osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
2884              fd, offset.HighPart, offset.LowPart, count);
2885
2886     fidp = smb_FindFID(vcp, fd, 0);
2887     if (!fidp)
2888         goto send1;
2889
2890     pid = ((smb_t *) inp)->pid;
2891     {
2892         LARGE_INTEGER LOffset, LLength;
2893         cm_key_t key;
2894
2895         key = cm_GenerateKey(vcp->vcID, pid, fd);
2896
2897         LOffset.HighPart = offset.HighPart;
2898         LOffset.LowPart = offset.LowPart;
2899         LLength.HighPart = 0;
2900         LLength.LowPart = count;
2901
2902         lock_ObtainMutex(&fidp->scp->mx);
2903         code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
2904         lock_ReleaseMutex(&fidp->scp->mx);
2905     }    
2906     if (code) {
2907         goto send1a;
2908     }
2909
2910     lock_ObtainMutex(&smb_RawBufLock);
2911     if (smb_RawBufs) {
2912         /* Get a raw buf, from head of list */
2913         rawBuf = smb_RawBufs;
2914         smb_RawBufs = *(char **)smb_RawBufs;
2915     }
2916     lock_ReleaseMutex(&smb_RawBufLock);
2917     if (!rawBuf)
2918         goto send1a;
2919
2920     lock_ObtainMutex(&fidp->mx);
2921     if (fidp->flags & SMB_FID_IOCTL)
2922     {
2923         lock_ReleaseMutex(&fidp->mx);
2924         rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2925         if (rawBuf) {
2926             /* Give back raw buffer */
2927             lock_ObtainMutex(&smb_RawBufLock);
2928             *((char **) rawBuf) = smb_RawBufs;
2929             
2930             smb_RawBufs = rawBuf;
2931             lock_ReleaseMutex(&smb_RawBufLock);
2932         }
2933
2934         smb_ReleaseFID(fidp);
2935         return rc;
2936     }
2937     lock_ReleaseMutex(&fidp->mx);
2938
2939     userp = smb_GetUserFromVCP(vcp, inp);
2940
2941     code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2942
2943     if (code != 0)
2944         goto send;
2945
2946   send:
2947     cm_ReleaseUser(userp);
2948
2949   send1a:
2950     smb_ReleaseFID(fidp);
2951
2952   send1:
2953     ncbp = outp->ncbp;
2954     memset((char *)ncbp, 0, sizeof(NCB));
2955
2956     ncbp->ncb_length = (unsigned short) finalCount;
2957     ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2958     ncbp->ncb_lana_num = vcp->lana;
2959     ncbp->ncb_command = NCBSEND;
2960     ncbp->ncb_buffer = rawBuf;
2961
2962     code = Netbios(ncbp);
2963     if (code != 0)
2964         osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2965
2966     if (rawBuf) {
2967         /* Give back raw buffer */
2968         lock_ObtainMutex(&smb_RawBufLock);
2969         *((char **) rawBuf) = smb_RawBufs;
2970
2971         smb_RawBufs = rawBuf;
2972         lock_ReleaseMutex(&smb_RawBufLock);
2973     }
2974
2975     return 0;
2976 }
2977
2978 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2979 {
2980     osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
2981                          ongoingOps - 1);
2982     return 0;
2983 }
2984
2985 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2986 {
2987     osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
2988                          ongoingOps - 1);
2989     return 0;
2990 }
2991
2992 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2993 {
2994     char *namep;
2995     char *datap;
2996     int coreProtoIndex;
2997     int v3ProtoIndex;
2998     int NTProtoIndex;
2999     int VistaProtoIndex;
3000     int protoIndex;                             /* index we're using */
3001     int namex;
3002     int dbytes;
3003     int entryLength;
3004     int tcounter;
3005     char protocol_array[10][1024];  /* protocol signature of the client */
3006     int caps;                       /* capabilities */
3007     time_t unixTime;
3008     afs_uint32 dosTime;
3009     TIME_ZONE_INFORMATION tzi;
3010
3011     osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3012                          ongoingOps - 1);
3013
3014     namep = smb_GetSMBData(inp, &dbytes);
3015     namex = 0;
3016     tcounter = 0;
3017     coreProtoIndex = -1;                /* not found */
3018     v3ProtoIndex = -1;
3019     NTProtoIndex = -1;
3020     VistaProtoIndex = -1;
3021     while(namex < dbytes) {
3022         osi_Log1(smb_logp, "Protocol %s",
3023                   osi_LogSaveString(smb_logp, namep+1));
3024         strcpy(protocol_array[tcounter], namep+1);
3025
3026         /* namep points at the first protocol, or really, a 0x02
3027          * byte preceding the null-terminated ASCII name.
3028          */
3029         if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3030             coreProtoIndex = tcounter;
3031         }       
3032         else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3033             v3ProtoIndex = tcounter;
3034         }
3035         else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3036             NTProtoIndex = tcounter;
3037         }
3038         else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3039             VistaProtoIndex = tcounter;
3040         }
3041
3042         /* compute size of protocol entry */
3043         entryLength = (int)strlen(namep+1);
3044         entryLength += 2;       /* 0x02 bytes and null termination */
3045
3046         /* advance over this protocol entry */
3047         namex += entryLength;
3048         namep += entryLength;
3049         tcounter++;             /* which proto entry we're looking at */
3050     }
3051
3052     lock_ObtainMutex(&vcp->mx);
3053 #if 0
3054     if (VistaProtoIndex != -1) {
3055         protoIndex = VistaProtoIndex;
3056         vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3057     } else 
3058 #endif  
3059         if (NTProtoIndex != -1) {
3060         protoIndex = NTProtoIndex;
3061         vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3062     }
3063     else if (v3ProtoIndex != -1) {
3064         protoIndex = v3ProtoIndex;
3065         vcp->flags |= SMB_VCFLAG_USEV3;
3066     }   
3067     else if (coreProtoIndex != -1) {
3068         protoIndex = coreProtoIndex;
3069         vcp->flags |= SMB_VCFLAG_USECORE;
3070     }   
3071     else protoIndex = -1;
3072     lock_ReleaseMutex(&vcp->mx);
3073
3074     if (protoIndex == -1)
3075         return CM_ERROR_INVAL;
3076     else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3077         smb_SetSMBParm(outp, 0, protoIndex);
3078         if (smb_authType != SMB_AUTH_NONE) {
3079             smb_SetSMBParmByte(outp, 1,
3080                                NEGOTIATE_SECURITY_USER_LEVEL |
3081                                NEGOTIATE_SECURITY_CHALLENGE_RESPONSE);  /* user level security, challenge response */
3082         } else {
3083             smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3084         }
3085         smb_SetSMBParm(outp, 1, smb_maxMpxRequests);    /* max multiplexed requests */
3086         smb_SetSMBParm(outp, 2, smb_maxVCPerServer);    /* max VCs per consumer/server connection */
3087         smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE);    /* xmit buffer size */
3088         smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE);    /* raw buffer size */
3089         /* The session key is not a well documented field however most clients
3090          * will echo back the session key to the server.  Currently we are using
3091          * the same value for all sessions.  We should generate a random value
3092          * and store it into the vcp 
3093          */
3094         smb_SetSMBParm(outp, 7, 1);     /* next 2: session key */
3095         smb_SetSMBParm(outp, 8, 1);
3096         /* 
3097          * Tried changing the capabilities to support for W2K - defect 117695
3098          * Maybe something else needs to be changed here?
3099          */
3100         /*
3101         if (isWindows2000) 
3102         smb_SetSMBParmLong(outp, 9, 0x43fd);
3103         else 
3104         smb_SetSMBParmLong(outp, 9, 0x251);
3105         */
3106         /* Capabilities: *
3107          * 32-bit error codes *
3108          * and NT Find *
3109          * and NT SMB's *
3110          * and raw mode 
3111          * and DFS */
3112         caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3113 #ifdef DFS_SUPPORT
3114                NTNEGOTIATE_CAPABILITY_DFS |
3115 #endif
3116 #ifdef AFS_LARGEFILES
3117                NTNEGOTIATE_CAPABILITY_LARGEFILES |
3118 #endif
3119                NTNEGOTIATE_CAPABILITY_NTFIND |
3120                NTNEGOTIATE_CAPABILITY_RAWMODE |
3121                NTNEGOTIATE_CAPABILITY_NTSMB;
3122
3123         if ( smb_authType == SMB_AUTH_EXTENDED )
3124             caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3125
3126         smb_SetSMBParmLong(outp, 9, caps);
3127         time(&unixTime);
3128         smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3129         smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3130         smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3131
3132         GetTimeZoneInformation(&tzi);
3133         smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias);    /* server tzone */
3134
3135         if (smb_authType == SMB_AUTH_NTLM) {
3136             smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3137             smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3138             /* paste in encryption key */
3139             datap = smb_GetSMBData(outp, NULL);
3140             memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3141             /* and the faux domain name */
3142             strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
3143         } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3144             void * secBlob;
3145             int secBlobLength;
3146
3147             smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3148
3149             smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3150
3151             smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3152                         
3153             datap = smb_GetSMBData(outp, NULL);
3154             memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3155
3156             if (secBlob) {
3157                 datap += sizeof(smb_ServerGUID);
3158                 memcpy(datap, secBlob, secBlobLength);
3159                 free(secBlob);
3160             }
3161         } else {
3162             smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3163             smb_SetSMBDataLength(outp, 0);   /* Perhaps we should specify 8 bytes anyway */
3164         }
3165     }
3166     else if (v3ProtoIndex != -1) {
3167         smb_SetSMBParm(outp, 0, protoIndex);
3168
3169         /* NOTE: Extended authentication cannot be negotiated with v3
3170          * therefore we fail over to NTLM 
3171          */
3172         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3173             smb_SetSMBParm(outp, 1,
3174                            NEGOTIATE_SECURITY_USER_LEVEL |
3175                            NEGOTIATE_SECURITY_CHALLENGE_RESPONSE);      /* user level security, challenge response */
3176         } else {
3177             smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3178         }
3179         smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3180         smb_SetSMBParm(outp, 3, smb_maxMpxRequests);    /* max multiplexed requests */
3181         smb_SetSMBParm(outp, 4, smb_maxVCPerServer);    /* max VCs per consumer/server connection */
3182         smb_SetSMBParm(outp, 5, 0);     /* no support of block mode for read or write */
3183         smb_SetSMBParm(outp, 6, 1);     /* next 2: session key */
3184         smb_SetSMBParm(outp, 7, 1);
3185         time(&unixTime);
3186         smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3187         smb_SetSMBParm(outp, 8, LOWORD(dosTime));       /* server time */
3188         smb_SetSMBParm(outp, 9, HIWORD(dosTime));       /* server date */
3189
3190         GetTimeZoneInformation(&tzi);
3191         smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias);    /* server tzone */
3192
3193         /* NOTE: Extended authentication cannot be negotiated with v3
3194          * therefore we fail over to NTLM 
3195          */
3196         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3197             smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH);  /* encryption key length */
3198             smb_SetSMBParm(outp, 12, 0);        /* resvd */
3199             smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);   /* perhaps should specify 8 bytes anyway */
3200             datap = smb_GetSMBData(outp, NULL);
3201             /* paste in a new encryption key */
3202             memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3203             /* and the faux domain name */
3204             strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
3205         } else {
3206             smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3207             smb_SetSMBParm(outp, 12, 0); /* resvd */
3208             smb_SetSMBDataLength(outp, 0);
3209         }
3210     }
3211     else if (coreProtoIndex != -1) {     /* not really supported anymore */
3212         smb_SetSMBParm(outp, 0, protoIndex);
3213         smb_SetSMBDataLength(outp, 0);
3214     }
3215     return 0;
3216 }
3217
3218 void smb_CheckVCs(void)
3219 {
3220     smb_vc_t * vcp, *nextp;
3221     smb_packet_t * outp = GetPacket();
3222     smb_t *smbp;
3223             
3224     lock_ObtainWrite(&smb_rctLock);
3225     for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp ) 
3226     {
3227         if (vcp->magic != SMB_VC_MAGIC)
3228             osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp", 
3229                        __FILE__, __LINE__);
3230
3231         nextp = vcp->nextp;
3232
3233         if (vcp->flags & SMB_VCFLAG_ALREADYDEAD)
3234             continue;
3235
3236         smb_HoldVCNoLock(vcp);
3237         if (nextp)
3238             smb_HoldVCNoLock(nextp);
3239         smb_FormatResponsePacket(vcp, NULL, outp);
3240         smbp = (smb_t *)outp;
3241         outp->inCom = smbp->com = 0x2b /* Echo */;
3242         smbp->tid = 0xFFFF;
3243         smbp->pid = 0;
3244         smbp->uid = 0;
3245         smbp->mid = 0;
3246         smbp->res[0] = 0;
3247         smbp->res[1] = 0;
3248
3249         smb_SetSMBParm(outp, 0, 0);
3250         smb_SetSMBDataLength(outp, 0);
3251         lock_ReleaseWrite(&smb_rctLock);
3252
3253         smb_SendPacket(vcp, outp);
3254
3255         lock_ObtainWrite(&smb_rctLock);
3256         smb_ReleaseVCNoLock(vcp);
3257         if (nextp)
3258             smb_ReleaseVCNoLock(nextp);
3259     }
3260     lock_ReleaseWrite(&smb_rctLock);
3261     smb_FreePacket(outp);
3262 }
3263
3264 void smb_Daemon(void *parmp)
3265 {
3266     afs_uint32 count = 0;
3267     smb_username_t    **unpp;
3268     time_t              now;
3269
3270     while(smbShutdownFlag == 0) {
3271         count++;
3272         thrd_Sleep(10000);
3273
3274         if (smbShutdownFlag == 1)
3275             break;
3276         
3277         if ((count % 72) == 0)  {       /* every five minutes */
3278             struct tm myTime;
3279             time_t old_localZero = smb_localZero;
3280                  
3281             /* Initialize smb_localZero */
3282             myTime.tm_isdst = -1;               /* compute whether on DST or not */
3283             myTime.tm_year = 70;
3284             myTime.tm_mon = 0;
3285             myTime.tm_mday = 1;
3286             myTime.tm_hour = 0;
3287             myTime.tm_min = 0;
3288             myTime.tm_sec = 0;
3289             smb_localZero = mktime(&myTime);
3290
3291 #ifndef USE_NUMERIC_TIME_CONV
3292             smb_CalculateNowTZ();
3293 #endif /* USE_NUMERIC_TIME_CONV */
3294 #ifdef AFS_FREELANCE
3295             if ( smb_localZero != old_localZero )
3296                 cm_noteLocalMountPointChange();
3297 #endif
3298
3299             smb_CheckVCs();
3300         }
3301
3302         /* GC smb_username_t objects that will no longer be used */
3303         now = osi_Time();
3304         lock_ObtainWrite(&smb_rctLock);
3305         for ( unpp=&usernamesp; *unpp; ) {
3306             int delete = 0;
3307             smb_username_t *unp;
3308
3309             lock_ObtainMutex(&(*unpp)->mx);
3310             if ( (*unpp)->refCount > 0 || 
3311                  ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) || 
3312                  !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
3313                 ;
3314             else if (!smb_LogoffTokenTransfer ||
3315                      ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
3316                 delete = 1;
3317             lock_ReleaseMutex(&(*unpp)->mx);
3318
3319             if (delete) {
3320                 cm_user_t * userp;
3321
3322                 unp = *unpp;    
3323                 *unpp = unp->nextp;
3324                 unp->nextp = NULL;
3325                 lock_FinalizeMutex(&unp->mx);
3326                 userp = unp->userp;
3327                 free(unp->name);
3328                 free(unp->machine);
3329                 free(unp);
3330                 if (userp) {
3331                     lock_ReleaseWrite(&smb_rctLock);
3332                     cm_ReleaseUser(userp);
3333                     lock_ObtainWrite(&smb_rctLock);
3334                 }
3335             } else {
3336                 unpp = &(*unpp)->nextp;
3337             }
3338         }
3339         lock_ReleaseWrite(&smb_rctLock);
3340
3341         /* XXX GC dir search entries */
3342     }
3343 }
3344
3345 void smb_WaitingLocksDaemon()
3346 {
3347     smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3348     smb_waitingLock_t *wl, *wlNext;
3349     int first;
3350     smb_vc_t *vcp;
3351     smb_packet_t *inp, *outp;
3352     NCB *ncbp;
3353     long code = 0;
3354
3355     while (smbShutdownFlag == 0) {
3356         lock_ObtainWrite(&smb_globalLock);
3357         nwlRequest = smb_allWaitingLocks;
3358         if (nwlRequest == NULL) {
3359             osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
3360             thrd_Sleep(1000);
3361             continue;
3362         } else {
3363             first = 1;
3364             osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
3365         }
3366
3367         do {
3368             if (first)
3369                 first = 0;
3370             else
3371                 lock_ObtainWrite(&smb_globalLock);
3372
3373             osi_Log1(smb_logp, "    Checking waiting lock request %p", nwlRequest);
3374
3375             wlRequest = nwlRequest;
3376             nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3377             lock_ReleaseWrite(&smb_globalLock);
3378
3379             code = 0;
3380
3381             for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3382                 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3383                     continue;
3384
3385                 osi_assert(wl->state != SMB_WAITINGLOCKSTATE_ERROR);
3386                 
3387                 /* wl->state is either _DONE or _WAITING.  _ERROR
3388                    would no longer be on the queue. */
3389                 code = cm_RetryLock( wl->lockp,
3390                                      !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3391
3392                 if (code == 0) {
3393                     wl->state = SMB_WAITINGLOCKSTATE_DONE;
3394                 } else if (code != CM_ERROR_WOULDBLOCK) {
3395                     wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3396                     break;
3397                 }
3398             }
3399
3400             if (code == CM_ERROR_WOULDBLOCK) {
3401
3402                 /* no progress */
3403                 if (wlRequest->timeRemaining != 0xffffffff
3404                      && (wlRequest->timeRemaining -= 1000) < 0)
3405                     goto endWait;
3406
3407                 continue;
3408             }
3409
3410           endWait:
3411
3412             if (code != 0) {
3413                 cm_scache_t * scp;
3414                 cm_req_t req;
3415
3416                 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
3417                          wlRequest);
3418
3419                 scp = wlRequest->scp;
3420                 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
3421
3422                 cm_InitReq(&req);
3423
3424                 lock_ObtainMutex(&scp->mx);
3425
3426                 for (wl = wlRequest->locks; wl; wl = wlNext) {
3427                     wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3428                     
3429                     cm_Unlock(scp, wlRequest->lockType, wl->LOffset, 
3430                               wl->LLength, wl->key, NULL, &req);
3431
3432                     osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3433
3434                     free(wl);
3435                 }
3436                 
3437                 lock_ReleaseMutex(&scp->mx);
3438
3439             } else {
3440
3441                 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
3442                          wlRequest);
3443
3444                 for (wl = wlRequest->locks; wl; wl = wlNext) {
3445                     wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3446                     osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3447                     free(wl);
3448                 }
3449             }
3450
3451             vcp = wlRequest->vcp;
3452             inp = wlRequest->inp;
3453             outp = wlRequest->outp;
3454             ncbp = GetNCB();
3455             ncbp->ncb_length = inp->ncb_length;
3456             inp->spacep = cm_GetSpace();
3457
3458             /* Remove waitingLock from list */
3459             lock_ObtainWrite(&smb_globalLock);
3460             osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3461                          &wlRequest->q);
3462             lock_ReleaseWrite(&smb_globalLock);
3463
3464             /* Resume packet processing */
3465             if (code == 0)
3466                 smb_SetSMBDataLength(outp, 0);
3467             outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3468             outp->resumeCode = code;
3469             outp->ncbp = ncbp;
3470             smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3471
3472             /* Clean up */
3473             cm_FreeSpace(inp->spacep);
3474             smb_FreePacket(inp);
3475             smb_FreePacket(outp);
3476             smb_ReleaseVC(vcp);
3477             cm_ReleaseSCache(wlRequest->scp);
3478             FreeNCB(ncbp);
3479             free(wlRequest);
3480         } while (nwlRequest && smbShutdownFlag == 0);
3481         thrd_Sleep(1000);
3482     }
3483 }
3484
3485 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3486 {
3487     osi_Log0(smb_logp, "SMB receive get disk attributes");
3488
3489     smb_SetSMBParm(outp, 0, 32000);
3490     smb_SetSMBParm(outp, 1, 64);
3491     smb_SetSMBParm(outp, 2, 1024);
3492     smb_SetSMBParm(outp, 3, 30000);
3493     smb_SetSMBParm(outp, 4, 0);
3494     smb_SetSMBDataLength(outp, 0);
3495     return 0;
3496 }
3497
3498 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3499 {
3500     smb_tid_t *tidp;
3501     smb_user_t *uidp;
3502     unsigned short newTid;
3503     char shareName[256];
3504     char *sharePath;
3505     int shareFound;
3506     char *tp;
3507     char *pathp;
3508     char *passwordp;
3509     cm_user_t *userp;
3510
3511     osi_Log0(smb_logp, "SMB receive tree connect");
3512
3513     /* parse input parameters */
3514     tp = smb_GetSMBData(inp, NULL);
3515     pathp = smb_ParseASCIIBlock(tp, &tp);
3516     if (smb_StoreAnsiFilenames)
3517         OemToChar(pathp,pathp);
3518     passwordp = smb_ParseASCIIBlock(tp, &tp);
3519     tp = strrchr(pathp, '\\');
3520     if (!tp)
3521         return CM_ERROR_BADSMB;
3522     strcpy(shareName, tp+1);
3523
3524     lock_ObtainMutex(&vcp->mx);
3525     newTid = vcp->tidCounter++;
3526     lock_ReleaseMutex(&vcp->mx);
3527
3528     tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3529     uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3530     userp = smb_GetUserFromUID(uidp);
3531     shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3532     if (uidp)
3533         smb_ReleaseUID(uidp);
3534     if (!shareFound) {
3535         smb_ReleaseTID(tidp);
3536         return CM_ERROR_BADSHARENAME;
3537     }
3538     lock_ObtainMutex(&tidp->mx);
3539     tidp->userp = userp;
3540     tidp->pathname = sharePath;
3541     lock_ReleaseMutex(&tidp->mx);
3542     smb_ReleaseTID(tidp);
3543
3544     smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3545     smb_SetSMBParm(rsp, 1, newTid);
3546     smb_SetSMBDataLength(rsp, 0);
3547
3548     osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3549     return 0;
3550 }
3551
3552 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3553 {
3554     int tlen;
3555
3556     if (*inp++ != 0x1) return NULL;
3557     tlen = inp[0] + (inp[1]<<8);
3558     inp += 2;           /* skip length field */
3559         
3560     if (chainpp) {
3561         *chainpp = inp + tlen;
3562     }   
3563
3564     if (lengthp) *lengthp = tlen;
3565         
3566     return inp;
3567 }
3568
3569 /* set maskp to the mask part of the incoming path.
3570  * Mask is 11 bytes long (8.3 with the dot elided).
3571  * Returns true if succeeds with a valid name, otherwise it does
3572  * its best, but returns false.
3573  */
3574 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3575 {
3576     char *tp;
3577     char *up;
3578     int i;
3579     int tc;
3580     int valid8Dot3;
3581
3582     /* starts off valid */
3583     valid8Dot3 = 1;
3584
3585     /* mask starts out all blanks */
3586     memset(maskp, ' ', 11);
3587
3588     /* find last backslash, or use whole thing if there is none */
3589     tp = strrchr(pathp, '\\');
3590     if (!tp) tp = pathp;
3591     else tp++;  /* skip slash */
3592         
3593     up = maskp;
3594
3595     /* names starting with a dot are illegal */
3596     if (*tp == '.') valid8Dot3 = 0;
3597
3598     for(i=0;; i++) {
3599         tc = *tp++;
3600         if (tc == 0) return valid8Dot3;
3601         if (tc == '.' || tc == '"') break;
3602         if (i < 8) *up++ = tc;
3603         else valid8Dot3 = 0;
3604     }
3605         
3606     /* if we get here, tp point after the dot */
3607     up = maskp+8;       /* ext goes here */
3608     for(i=0;;i++) {
3609         tc = *tp++;
3610         if (tc == 0) 
3611             return valid8Dot3;
3612
3613         /* too many dots */
3614         if (tc == '.' || tc == '"') 
3615             valid8Dot3 = 0;
3616
3617         /* copy extension if not too long */
3618         if (i < 3) 
3619             *up++ = tc;
3620         else 
3621             valid8Dot3 = 0;
3622     }   
3623
3624     /* unreachable */
3625 }
3626
3627 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3628 {
3629     char umask[11];
3630     int valid;
3631     int i;
3632     char tc1;
3633     char tc2;
3634     char *tp1;
3635     char *tp2;
3636
3637     /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3638
3639     valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3640     if (!valid) 
3641         return 0;
3642  
3643     /* otherwise, we have a valid 8.3 name; see if we have a match,
3644      * treating '?' as a wildcard in maskp (but not in the file name).
3645      */
3646     tp1 = umask;        /* real name, in mask format */
3647     tp2 = maskp;        /* mask, in mask format */
3648     for(i=0; i<11; i++) {
3649         tc1 = *tp1++;   /* char from real name */
3650         tc2 = *tp2++;   /* char from mask */
3651         tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3652         tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3653         if (tc1 == tc2) 
3654             continue;
3655         if (tc2 == '?' && tc1 != ' ') 
3656             continue;
3657         if (tc2 == '>') 
3658             continue;
3659         return 0;
3660     }
3661
3662     /* we got a match */
3663     return 1;
3664 }
3665
3666 char *smb_FindMask(char *pathp)
3667 {
3668     char *tp;
3669         
3670     tp = strrchr(pathp, '\\');  /* find last slash */
3671
3672     if (tp) 
3673         return tp+1;    /* skip the slash */
3674     else 
3675         return pathp;   /* no slash, return the entire path */
3676 }       
3677
3678 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3679 {
3680     unsigned char *pathp;
3681     unsigned char *tp;
3682     unsigned char mask[11];
3683     unsigned char *statBlockp;
3684     unsigned char initStatBlock[21];
3685     int statLen;
3686         
3687     osi_Log0(smb_logp, "SMB receive search volume");
3688
3689     /* pull pathname and stat block out of request */
3690     tp = smb_GetSMBData(inp, NULL);
3691     pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3692     osi_assert(pathp != NULL);
3693     if (smb_StoreAnsiFilenames)
3694         OemToChar(pathp,pathp);
3695     statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3696     osi_assert(statBlockp != NULL);
3697     if (statLen == 0) {
3698         statBlockp = initStatBlock;
3699         statBlockp[0] = 8;
3700     }
3701         
3702     /* for returning to caller */
3703     smb_Get8Dot3MaskFromPath(mask, pathp);
3704
3705     smb_SetSMBParm(outp, 0, 1);         /* we're returning one entry */
3706     tp = smb_GetSMBData(outp, NULL);
3707     *tp++ = 5;
3708     *tp++ = 43; /* bytes in a dir entry */
3709     *tp++ = 0;  /* high byte in counter */
3710
3711     /* now marshall the dir entry, starting with the search status */
3712     *tp++ = statBlockp[0];              /* Reserved */
3713     memcpy(tp, mask, 11); tp += 11;     /* FileName */
3714
3715     /* now pass back server use info, with 1st byte non-zero */
3716     *tp++ = 1;
3717     memset(tp, 0, 4); tp += 4;  /* reserved for server use */
3718
3719     memcpy(tp, statBlockp+17, 4); tp += 4;      /* reserved for consumer */
3720
3721     *tp++ = 0x8;                /* attribute: volume */
3722
3723     /* copy out time */
3724     *tp++ = 0;
3725     *tp++ = 0;
3726
3727     /* copy out date */
3728     *tp++ = 18;
3729     *tp++ = 178;
3730
3731     /* 4 byte file size */
3732     *tp++ = 0;
3733     *tp++ = 0;
3734     *tp++ = 0;