windows-afsd-dirop-20070830
[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) + 1;
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              code == CM_ERROR_BPLUS_NOMATCH) {
2503         NTStatus = 0xC000000FL; /* No such file */
2504     }
2505     else if (code == CM_ERROR_NOSUCHPATH) {
2506         NTStatus = 0xC000003AL; /* Object path not found */
2507     }           
2508     else if (code == CM_ERROR_TOOBIG) {
2509         NTStatus = 0xC000007BL; /* Invalid image format */
2510     }
2511     else if (code == CM_ERROR_INVAL) {
2512         NTStatus = 0xC000000DL; /* Invalid parameter */
2513     }
2514     else if (code == CM_ERROR_BADFD) {
2515         NTStatus = 0xC0000008L; /* Invalid handle */
2516     }
2517     else if (code == CM_ERROR_BADFDOP) {
2518         NTStatus = 0xC0000022L; /* Access denied */
2519     }
2520     else if (code == CM_ERROR_EXISTS) {
2521         NTStatus = 0xC0000035L; /* Object name collision */
2522     }
2523     else if (code == CM_ERROR_NOTEMPTY) {
2524         NTStatus = 0xC0000101L; /* Directory not empty */
2525     }   
2526     else if (code == CM_ERROR_CROSSDEVLINK) {
2527         NTStatus = 0xC00000D4L; /* Not same device */
2528     }
2529     else if (code == CM_ERROR_NOTDIR) {
2530         NTStatus = 0xC0000103L; /* Not a directory */
2531     }
2532     else if (code == CM_ERROR_ISDIR) {
2533         NTStatus = 0xC00000BAL; /* File is a directory */
2534     }
2535     else if (code == CM_ERROR_BADOP) {
2536 #ifdef COMMENT
2537         /* I have no idea where this comes from */
2538         NTStatus = 0xC09820FFL; /* SMB no support */
2539 #else
2540         NTStatus = 0xC00000BBL;     /* Not supported */
2541 #endif /* COMMENT */
2542     }
2543     else if (code == CM_ERROR_BADSHARENAME) {
2544         NTStatus = 0xC00000CCL; /* Bad network name */
2545     }
2546     else if (code == CM_ERROR_NOIPC) {
2547 #ifdef COMMENT
2548         NTStatus = 0xC0000022L; /* Access Denied */
2549 #else   
2550         NTStatus = 0xC000013DL; /* Remote Resources */
2551 #endif
2552     }
2553     else if (code == CM_ERROR_CLOCKSKEW) {
2554         NTStatus = 0xC0000133L; /* Time difference at DC */
2555     }
2556     else if (code == CM_ERROR_BADTID) {
2557         NTStatus = 0xC0982005L; /* SMB bad TID */
2558     }
2559     else if (code == CM_ERROR_USESTD) {
2560         NTStatus = 0xC09820FBL; /* SMB use standard */
2561     }
2562     else if (code == CM_ERROR_QUOTA) {
2563 #ifdef COMMENT
2564         NTStatus = 0xC0000044L; /* Quota exceeded */
2565 #else
2566         NTStatus = 0xC000007FL; /* Disk full */
2567 #endif
2568     }
2569     else if (code == CM_ERROR_SPACE) {
2570         NTStatus = 0xC000007FL; /* Disk full */
2571     }
2572     else if (code == CM_ERROR_ATSYS) {
2573         NTStatus = 0xC0000033L; /* Object name invalid */
2574     }
2575     else if (code == CM_ERROR_BADNTFILENAME) {
2576         NTStatus = 0xC0000033L; /* Object name invalid */
2577     }
2578     else if (code == CM_ERROR_WOULDBLOCK) {
2579         NTStatus = 0xC0000055L; /* Lock not granted */
2580     }
2581     else if (code == CM_ERROR_SHARING_VIOLATION) {
2582         NTStatus = 0xC0000043L; /* Sharing violation */
2583     }
2584     else if (code == CM_ERROR_LOCK_CONFLICT) {
2585         NTStatus = 0xC0000054L; /* Lock conflict */
2586     }
2587     else if (code == CM_ERROR_PARTIALWRITE) {
2588         NTStatus = 0xC000007FL; /* Disk full */
2589     }
2590     else if (code == CM_ERROR_BUFFERTOOSMALL) {
2591         NTStatus = 0xC0000023L; /* Buffer too small */
2592     }
2593     else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2594         NTStatus = 0xC0000035L; /* Object name collision */
2595     }   
2596     else if (code == CM_ERROR_BADPASSWORD) {
2597         NTStatus = 0xC000006DL; /* unknown username or bad password */
2598     }
2599     else if (code == CM_ERROR_BADLOGONTYPE) {
2600         NTStatus = 0xC000015BL; /* logon type not granted */
2601     }
2602     else if (code == CM_ERROR_GSSCONTINUE) {
2603         NTStatus = 0xC0000016L; /* more processing required */
2604     }
2605     else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2606 #ifdef COMMENT
2607         NTStatus = 0xC0000280L; /* reparse point not resolved */
2608 #else
2609         NTStatus = 0xC0000022L; /* Access Denied */
2610 #endif
2611     }
2612     else if (code == CM_ERROR_PATH_NOT_COVERED) {
2613         NTStatus = 0xC0000257L; /* Path Not Covered */
2614     } 
2615 #ifdef COMMENT
2616     else if (code == CM_ERROR_ALLBUSY) {
2617         NTStatus = 0xC00000BFL; /* Network Busy */
2618     } 
2619     else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
2620         NTStatus = 0xC0000350L; /* Remote Host Down */
2621     } 
2622 #else
2623     /* we do not want to be telling the SMB/CIFS client that
2624      * the AFS Client Service is busy or down.  
2625      */
2626     else if (code == CM_ERROR_ALLBUSY || 
2627              code == CM_ERROR_ALLOFFLINE ||
2628              code == CM_ERROR_ALLDOWN) {
2629         NTStatus = 0xC00000BEL; /* Bad Network Path */
2630     }
2631 #endif
2632     else if (code == RXKADUNKNOWNKEY) {
2633         NTStatus = 0xC0000322L; /* Bad Kerberos key */
2634     } 
2635     else if (code == CM_ERROR_BAD_LEVEL) {
2636         NTStatus = 0xC0000148L; /* Invalid Level */
2637     } else {
2638         NTStatus = 0xC0982001L; /* SMB non-specific error */
2639     }
2640
2641     *NTStatusp = NTStatus;
2642     osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2643 }       
2644
2645 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2646                       unsigned char *classp)
2647 {
2648     unsigned char class;
2649     unsigned short error;
2650
2651     /* map CM_ERROR_* errors to SMB errors */
2652     if (code == CM_ERROR_NOSUCHCELL) {
2653         class = 1;
2654         error = 3;      /* bad path */
2655     }
2656     else if (code == CM_ERROR_NOSUCHVOLUME) {
2657         class = 1;
2658         error = 3;      /* bad path */
2659     }
2660     else if (code == CM_ERROR_TIMEDOUT) {
2661         class = 2;
2662         error = 81;     /* server is paused */
2663     }
2664     else if (code == CM_ERROR_RETRY) {
2665         class = 2;      /* shouldn't happen */
2666         error = 1;
2667     }
2668     else if (code == CM_ERROR_NOACCESS) {
2669         class = 2;
2670         error = 4;      /* bad access */
2671     }
2672     else if (code == CM_ERROR_READONLY) {
2673         class = 3;
2674         error = 19;     /* read only */
2675     }
2676     else if (code == CM_ERROR_NOSUCHFILE ||
2677              code == CM_ERROR_BPLUS_NOMATCH) {
2678         class = 1;
2679         error = 2;      /* ENOENT! */
2680     }
2681     else if (code == CM_ERROR_NOSUCHPATH) {
2682         class = 1;
2683         error = 3;      /* Bad path */
2684     }
2685     else if (code == CM_ERROR_TOOBIG) {
2686         class = 1;
2687         error = 11;     /* bad format */
2688     }
2689     else if (code == CM_ERROR_INVAL) {
2690         class = 2;      /* server non-specific error code */
2691         error = 1;
2692     }
2693     else if (code == CM_ERROR_BADFD) {
2694         class = 1;
2695         error = 6;      /* invalid file handle */
2696     }
2697     else if (code == CM_ERROR_BADFDOP) {
2698         class = 1;      /* invalid op on FD */
2699         error = 5;
2700     }
2701     else if (code == CM_ERROR_EXISTS) {
2702         class = 1;
2703         error = 80;     /* file already exists */
2704     }
2705     else if (code == CM_ERROR_NOTEMPTY) {
2706         class = 1;
2707         error = 5;      /* delete directory not empty */
2708     }
2709     else if (code == CM_ERROR_CROSSDEVLINK) {
2710         class = 1;
2711         error = 17;     /* EXDEV */
2712     }
2713     else if (code == CM_ERROR_NOTDIR) {
2714         class = 1;      /* bad path */
2715         error = 3;
2716     }
2717     else if (code == CM_ERROR_ISDIR) {
2718         class = 1;      /* access denied; DOS doesn't have a good match */
2719         error = 5;
2720     }       
2721     else if (code == CM_ERROR_BADOP) {
2722         class = 2;
2723         error = 65535;
2724     }
2725     else if (code == CM_ERROR_BADSHARENAME) {
2726         class = 2;
2727         error = 6;
2728     }
2729     else if (code == CM_ERROR_NOIPC) {
2730         class = 2;
2731         error = 4; /* bad access */
2732     }
2733     else if (code == CM_ERROR_CLOCKSKEW) {
2734         class = 1;      /* invalid function */
2735         error = 1;
2736     }
2737     else if (code == CM_ERROR_BADTID) {
2738         class = 2;
2739         error = 5;
2740     }
2741     else if (code == CM_ERROR_USESTD) {
2742         class = 2;
2743         error = 251;
2744     }
2745     else if (code == CM_ERROR_REMOTECONN) {
2746         class = 2;
2747         error = 82;
2748     }
2749     else if (code == CM_ERROR_QUOTA) {
2750         if (vcp->flags & SMB_VCFLAG_USEV3) {
2751             class = 3;
2752             error = 39; /* disk full */
2753         }
2754         else {
2755             class = 1;
2756             error = 5;  /* access denied */
2757         }
2758     }
2759     else if (code == CM_ERROR_SPACE) {
2760         if (vcp->flags & SMB_VCFLAG_USEV3) {
2761             class = 3;
2762             error = 39; /* disk full */
2763         }
2764         else {
2765             class = 1;
2766             error = 5;  /* access denied */
2767         }
2768     }
2769     else if (code == CM_ERROR_PARTIALWRITE) {
2770         class = 3;
2771         error = 39;     /* disk full */
2772     }
2773     else if (code == CM_ERROR_ATSYS) {
2774         class = 1;
2775         error = 2;      /* ENOENT */
2776     }
2777     else if (code == CM_ERROR_WOULDBLOCK) {
2778         class = 1;
2779         error = 33;     /* lock conflict */
2780     }
2781     else if (code == CM_ERROR_LOCK_CONFLICT) {
2782         class = 1;
2783         error = 33;     /* lock conflict */
2784     }
2785     else if (code == CM_ERROR_SHARING_VIOLATION) {
2786         class = 1;
2787         error = 33;     /* lock conflict */
2788     }
2789     else if (code == CM_ERROR_NOFILES) {
2790         class = 1;
2791         error = 18;     /* no files in search */
2792     }
2793     else if (code == CM_ERROR_RENAME_IDENTICAL) {
2794         class = 1;
2795         error = 183;     /* Samba uses this */
2796     }
2797     else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2798         /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2799         class = 2;
2800         error = 2; /* bad password */
2801     }
2802     else if (code == CM_ERROR_PATH_NOT_COVERED) {
2803         class = 2;
2804         error = 3;     /* bad path */
2805     }
2806     else {
2807         class = 2;
2808         error = 1;
2809     }
2810
2811     *scodep = error;
2812     *classp = class;
2813     osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2814 }       
2815
2816 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2817 {
2818     osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2819     return CM_ERROR_BADOP;
2820 }
2821
2822 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2823 {
2824     unsigned short EchoCount, i;
2825     char *data, *outdata;
2826     int dataSize;
2827
2828     EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2829
2830     for (i=1; i<=EchoCount; i++) {
2831         data = smb_GetSMBData(inp, &dataSize);
2832         smb_SetSMBParm(outp, 0, i);
2833         smb_SetSMBDataLength(outp, dataSize);
2834         outdata = smb_GetSMBData(outp, NULL);
2835         memcpy(outdata, data, dataSize);
2836         smb_SendPacket(vcp, outp);
2837     }
2838
2839     return 0;
2840 }
2841
2842 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2843 {
2844     osi_hyper_t offset;
2845     long count, minCount, finalCount;
2846     unsigned short fd;
2847     unsigned pid;
2848     smb_fid_t *fidp;
2849     long code = 0;
2850     cm_user_t *userp = NULL;
2851     NCB *ncbp;
2852     int rc;
2853     char *rawBuf = NULL;
2854
2855     rawBuf = NULL;
2856     finalCount = 0;
2857
2858     fd = smb_GetSMBParm(inp, 0);
2859     count = smb_GetSMBParm(inp, 3);
2860     minCount = smb_GetSMBParm(inp, 4);
2861     offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2862
2863     if (*inp->wctp == 10) {
2864         /* we were sent a request with 64-bit file offsets */
2865 #ifdef AFS_LARGEFILES
2866         offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
2867
2868         if (LargeIntegerLessThanZero(offset)) {
2869             osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
2870             goto send1;
2871         }
2872 #else
2873         if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
2874             osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset.  Dropping request.");
2875             goto send1;
2876         } else {
2877             offset.HighPart = 0;
2878         }
2879 #endif
2880     } else {
2881         /* we were sent a request with 32-bit file offsets */
2882         offset.HighPart = 0;
2883     }
2884
2885     osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
2886              fd, offset.HighPart, offset.LowPart, count);
2887
2888     fidp = smb_FindFID(vcp, fd, 0);
2889     if (!fidp)
2890         goto send1;
2891
2892     pid = ((smb_t *) inp)->pid;
2893     {
2894         LARGE_INTEGER LOffset, LLength;
2895         cm_key_t key;
2896
2897         key = cm_GenerateKey(vcp->vcID, pid, fd);
2898
2899         LOffset.HighPart = offset.HighPart;
2900         LOffset.LowPart = offset.LowPart;
2901         LLength.HighPart = 0;
2902         LLength.LowPart = count;
2903
2904         lock_ObtainMutex(&fidp->scp->mx);
2905         code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
2906         lock_ReleaseMutex(&fidp->scp->mx);
2907     }    
2908     if (code) {
2909         goto send1a;
2910     }
2911
2912     lock_ObtainMutex(&smb_RawBufLock);
2913     if (smb_RawBufs) {
2914         /* Get a raw buf, from head of list */
2915         rawBuf = smb_RawBufs;
2916         smb_RawBufs = *(char **)smb_RawBufs;
2917     }
2918     lock_ReleaseMutex(&smb_RawBufLock);
2919     if (!rawBuf)
2920         goto send1a;
2921
2922     lock_ObtainMutex(&fidp->mx);
2923     if (fidp->flags & SMB_FID_IOCTL)
2924     {
2925         lock_ReleaseMutex(&fidp->mx);
2926         rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2927         if (rawBuf) {
2928             /* Give back raw buffer */
2929             lock_ObtainMutex(&smb_RawBufLock);
2930             *((char **) rawBuf) = smb_RawBufs;
2931             
2932             smb_RawBufs = rawBuf;
2933             lock_ReleaseMutex(&smb_RawBufLock);
2934         }
2935
2936         smb_ReleaseFID(fidp);
2937         return rc;
2938     }
2939     lock_ReleaseMutex(&fidp->mx);
2940
2941     userp = smb_GetUserFromVCP(vcp, inp);
2942
2943     code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2944
2945     if (code != 0)
2946         goto send;
2947
2948   send:
2949     cm_ReleaseUser(userp);
2950
2951   send1a:
2952     smb_ReleaseFID(fidp);
2953
2954   send1:
2955     ncbp = outp->ncbp;
2956     memset((char *)ncbp, 0, sizeof(NCB));
2957
2958     ncbp->ncb_length = (unsigned short) finalCount;
2959     ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2960     ncbp->ncb_lana_num = vcp->lana;
2961     ncbp->ncb_command = NCBSEND;
2962     ncbp->ncb_buffer = rawBuf;
2963
2964     code = Netbios(ncbp);
2965     if (code != 0)
2966         osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2967
2968     if (rawBuf) {
2969         /* Give back raw buffer */
2970         lock_ObtainMutex(&smb_RawBufLock);
2971         *((char **) rawBuf) = smb_RawBufs;
2972
2973         smb_RawBufs = rawBuf;
2974         lock_ReleaseMutex(&smb_RawBufLock);
2975     }
2976
2977     return 0;
2978 }
2979
2980 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2981 {
2982     osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
2983                          ongoingOps - 1);
2984     return 0;
2985 }
2986
2987 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2988 {
2989     osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
2990                          ongoingOps - 1);
2991     return 0;
2992 }
2993
2994 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2995 {
2996     char *namep;
2997     char *datap;
2998     int coreProtoIndex;
2999     int v3ProtoIndex;
3000     int NTProtoIndex;
3001     int VistaProtoIndex;
3002     int protoIndex;                             /* index we're using */
3003     int namex;
3004     int dbytes;
3005     int entryLength;
3006     int tcounter;
3007     char protocol_array[10][1024];  /* protocol signature of the client */
3008     int caps;                       /* capabilities */
3009     time_t unixTime;
3010     afs_uint32 dosTime;
3011     TIME_ZONE_INFORMATION tzi;
3012
3013     osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3014                          ongoingOps - 1);
3015
3016     namep = smb_GetSMBData(inp, &dbytes);
3017     namex = 0;
3018     tcounter = 0;
3019     coreProtoIndex = -1;                /* not found */
3020     v3ProtoIndex = -1;
3021     NTProtoIndex = -1;
3022     VistaProtoIndex = -1;
3023     while(namex < dbytes) {
3024         osi_Log1(smb_logp, "Protocol %s",
3025                   osi_LogSaveString(smb_logp, namep+1));
3026         strcpy(protocol_array[tcounter], namep+1);
3027
3028         /* namep points at the first protocol, or really, a 0x02
3029          * byte preceding the null-terminated ASCII name.
3030          */
3031         if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3032             coreProtoIndex = tcounter;
3033         }       
3034         else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3035             v3ProtoIndex = tcounter;
3036         }
3037         else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3038             NTProtoIndex = tcounter;
3039         }
3040         else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3041             VistaProtoIndex = tcounter;
3042         }
3043
3044         /* compute size of protocol entry */
3045         entryLength = (int)strlen(namep+1);
3046         entryLength += 2;       /* 0x02 bytes and null termination */
3047
3048         /* advance over this protocol entry */
3049         namex += entryLength;
3050         namep += entryLength;
3051         tcounter++;             /* which proto entry we're looking at */
3052     }
3053
3054     lock_ObtainMutex(&vcp->mx);
3055 #if 0
3056     if (VistaProtoIndex != -1) {
3057         protoIndex = VistaProtoIndex;
3058         vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3059     } else 
3060 #endif  
3061         if (NTProtoIndex != -1) {
3062         protoIndex = NTProtoIndex;
3063         vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3064     }
3065     else if (v3ProtoIndex != -1) {
3066         protoIndex = v3ProtoIndex;
3067         vcp->flags |= SMB_VCFLAG_USEV3;
3068     }   
3069     else if (coreProtoIndex != -1) {
3070         protoIndex = coreProtoIndex;
3071         vcp->flags |= SMB_VCFLAG_USECORE;
3072     }   
3073     else protoIndex = -1;
3074     lock_ReleaseMutex(&vcp->mx);
3075
3076     if (protoIndex == -1)
3077         return CM_ERROR_INVAL;
3078     else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3079         smb_SetSMBParm(outp, 0, protoIndex);
3080         if (smb_authType != SMB_AUTH_NONE) {
3081             smb_SetSMBParmByte(outp, 1,
3082                                NEGOTIATE_SECURITY_USER_LEVEL |
3083                                NEGOTIATE_SECURITY_CHALLENGE_RESPONSE);  /* user level security, challenge response */
3084         } else {
3085             smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3086         }
3087         smb_SetSMBParm(outp, 1, smb_maxMpxRequests);    /* max multiplexed requests */
3088         smb_SetSMBParm(outp, 2, smb_maxVCPerServer);    /* max VCs per consumer/server connection */
3089         smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE);    /* xmit buffer size */
3090         smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE);    /* raw buffer size */
3091         /* The session key is not a well documented field however most clients
3092          * will echo back the session key to the server.  Currently we are using
3093          * the same value for all sessions.  We should generate a random value
3094          * and store it into the vcp 
3095          */
3096         smb_SetSMBParm(outp, 7, 1);     /* next 2: session key */
3097         smb_SetSMBParm(outp, 8, 1);
3098         /* 
3099          * Tried changing the capabilities to support for W2K - defect 117695
3100          * Maybe something else needs to be changed here?
3101          */
3102         /*
3103         if (isWindows2000) 
3104         smb_SetSMBParmLong(outp, 9, 0x43fd);
3105         else 
3106         smb_SetSMBParmLong(outp, 9, 0x251);
3107         */
3108         /* Capabilities: *
3109          * 32-bit error codes *
3110          * and NT Find *
3111          * and NT SMB's *
3112          * and raw mode 
3113          * and DFS */
3114         caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3115 #ifdef DFS_SUPPORT
3116                NTNEGOTIATE_CAPABILITY_DFS |
3117 #endif
3118 #ifdef AFS_LARGEFILES
3119                NTNEGOTIATE_CAPABILITY_LARGEFILES |
3120 #endif
3121                NTNEGOTIATE_CAPABILITY_NTFIND |
3122                NTNEGOTIATE_CAPABILITY_RAWMODE |
3123                NTNEGOTIATE_CAPABILITY_NTSMB;
3124
3125         if ( smb_authType == SMB_AUTH_EXTENDED )
3126             caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3127
3128         smb_SetSMBParmLong(outp, 9, caps);
3129         time(&unixTime);
3130         smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3131         smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3132         smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3133
3134         GetTimeZoneInformation(&tzi);
3135         smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias);    /* server tzone */
3136
3137         if (smb_authType == SMB_AUTH_NTLM) {
3138             smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3139             smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3140             /* paste in encryption key */
3141             datap = smb_GetSMBData(outp, NULL);
3142             memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3143             /* and the faux domain name */
3144             strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
3145         } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3146             void * secBlob;
3147             int secBlobLength;
3148
3149             smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3150
3151             smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3152
3153             smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3154                         
3155             datap = smb_GetSMBData(outp, NULL);
3156             memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3157
3158             if (secBlob) {
3159                 datap += sizeof(smb_ServerGUID);
3160                 memcpy(datap, secBlob, secBlobLength);
3161                 free(secBlob);
3162             }
3163         } else {
3164             smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3165             smb_SetSMBDataLength(outp, 0);   /* Perhaps we should specify 8 bytes anyway */
3166         }
3167     }
3168     else if (v3ProtoIndex != -1) {
3169         smb_SetSMBParm(outp, 0, protoIndex);
3170
3171         /* NOTE: Extended authentication cannot be negotiated with v3
3172          * therefore we fail over to NTLM 
3173          */
3174         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3175             smb_SetSMBParm(outp, 1,
3176                            NEGOTIATE_SECURITY_USER_LEVEL |
3177                            NEGOTIATE_SECURITY_CHALLENGE_RESPONSE);      /* user level security, challenge response */
3178         } else {
3179             smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3180         }
3181         smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3182         smb_SetSMBParm(outp, 3, smb_maxMpxRequests);    /* max multiplexed requests */
3183         smb_SetSMBParm(outp, 4, smb_maxVCPerServer);    /* max VCs per consumer/server connection */
3184         smb_SetSMBParm(outp, 5, 0);     /* no support of block mode for read or write */
3185         smb_SetSMBParm(outp, 6, 1);     /* next 2: session key */
3186         smb_SetSMBParm(outp, 7, 1);
3187         time(&unixTime);
3188         smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3189         smb_SetSMBParm(outp, 8, LOWORD(dosTime));       /* server time */
3190         smb_SetSMBParm(outp, 9, HIWORD(dosTime));       /* server date */
3191
3192         GetTimeZoneInformation(&tzi);
3193         smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias);    /* server tzone */
3194
3195         /* NOTE: Extended authentication cannot be negotiated with v3
3196          * therefore we fail over to NTLM 
3197          */
3198         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3199             smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH);  /* encryption key length */
3200             smb_SetSMBParm(outp, 12, 0);        /* resvd */
3201             smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);   /* perhaps should specify 8 bytes anyway */
3202             datap = smb_GetSMBData(outp, NULL);
3203             /* paste in a new encryption key */
3204             memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3205             /* and the faux domain name */
3206             strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
3207         } else {
3208             smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3209             smb_SetSMBParm(outp, 12, 0); /* resvd */
3210             smb_SetSMBDataLength(outp, 0);
3211         }
3212     }
3213     else if (coreProtoIndex != -1) {     /* not really supported anymore */
3214         smb_SetSMBParm(outp, 0, protoIndex);
3215         smb_SetSMBDataLength(outp, 0);
3216     }
3217     return 0;
3218 }
3219
3220 void smb_CheckVCs(void)
3221 {
3222     smb_vc_t * vcp, *nextp;
3223     smb_packet_t * outp = GetPacket();
3224     smb_t *smbp;
3225             
3226     lock_ObtainWrite(&smb_rctLock);
3227     for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp ) 
3228     {
3229         if (vcp->magic != SMB_VC_MAGIC)
3230             osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp", 
3231                        __FILE__, __LINE__);
3232
3233         nextp = vcp->nextp;
3234
3235         if (vcp->flags & SMB_VCFLAG_ALREADYDEAD)
3236             continue;
3237
3238         smb_HoldVCNoLock(vcp);
3239         if (nextp)
3240             smb_HoldVCNoLock(nextp);
3241         smb_FormatResponsePacket(vcp, NULL, outp);
3242         smbp = (smb_t *)outp;
3243         outp->inCom = smbp->com = 0x2b /* Echo */;
3244         smbp->tid = 0xFFFF;
3245         smbp->pid = 0;
3246         smbp->uid = 0;
3247         smbp->mid = 0;
3248         smbp->res[0] = 0;
3249         smbp->res[1] = 0;
3250
3251         smb_SetSMBParm(outp, 0, 0);
3252         smb_SetSMBDataLength(outp, 0);
3253         lock_ReleaseWrite(&smb_rctLock);
3254
3255         smb_SendPacket(vcp, outp);
3256
3257         lock_ObtainWrite(&smb_rctLock);
3258         smb_ReleaseVCNoLock(vcp);
3259         if (nextp)
3260             smb_ReleaseVCNoLock(nextp);
3261     }
3262     lock_ReleaseWrite(&smb_rctLock);
3263     smb_FreePacket(outp);
3264 }
3265
3266 void smb_Daemon(void *parmp)
3267 {
3268     afs_uint32 count = 0;
3269     smb_username_t    **unpp;
3270     time_t              now;
3271
3272     while(smbShutdownFlag == 0) {
3273         count++;
3274         thrd_Sleep(10000);
3275
3276         if (smbShutdownFlag == 1)
3277             break;
3278         
3279         if ((count % 72) == 0)  {       /* every five minutes */
3280             struct tm myTime;
3281             time_t old_localZero = smb_localZero;
3282                  
3283             /* Initialize smb_localZero */
3284             myTime.tm_isdst = -1;               /* compute whether on DST or not */
3285             myTime.tm_year = 70;
3286             myTime.tm_mon = 0;
3287             myTime.tm_mday = 1;
3288             myTime.tm_hour = 0;
3289             myTime.tm_min = 0;
3290             myTime.tm_sec = 0;
3291             smb_localZero = mktime(&myTime);
3292
3293 #ifndef USE_NUMERIC_TIME_CONV
3294             smb_CalculateNowTZ();
3295 #endif /* USE_NUMERIC_TIME_CONV */
3296 #ifdef AFS_FREELANCE
3297             if ( smb_localZero != old_localZero )
3298                 cm_noteLocalMountPointChange();
3299 #endif
3300
3301             smb_CheckVCs();
3302         }
3303
3304         /* GC smb_username_t objects that will no longer be used */
3305         now = osi_Time();
3306         lock_ObtainWrite(&smb_rctLock);
3307         for ( unpp=&usernamesp; *unpp; ) {
3308             int delete = 0;
3309             smb_username_t *unp;
3310
3311             lock_ObtainMutex(&(*unpp)->mx);
3312             if ( (*unpp)->refCount > 0 || 
3313                  ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) || 
3314                  !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
3315                 ;
3316             else if (!smb_LogoffTokenTransfer ||
3317                      ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
3318                 delete = 1;
3319             lock_ReleaseMutex(&(*unpp)->mx);
3320
3321             if (delete) {
3322                 cm_user_t * userp;
3323
3324                 unp = *unpp;    
3325                 *unpp = unp->nextp;
3326                 unp->nextp = NULL;
3327                 lock_FinalizeMutex(&unp->mx);
3328                 userp = unp->userp;
3329                 free(unp->name);
3330                 free(unp->machine);
3331                 free(unp);
3332                 if (userp) {
3333                     lock_ReleaseWrite(&smb_rctLock);
3334                     cm_ReleaseUser(userp);
3335                     lock_ObtainWrite(&smb_rctLock);
3336                 }
3337             } else {
3338                 unpp = &(*unpp)->nextp;
3339             }
3340         }
3341         lock_ReleaseWrite(&smb_rctLock);
3342
3343         /* XXX GC dir search entries */
3344     }
3345 }
3346
3347 void smb_WaitingLocksDaemon()
3348 {
3349     smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3350     smb_waitingLock_t *wl, *wlNext;
3351     int first;
3352     smb_vc_t *vcp;
3353     smb_packet_t *inp, *outp;
3354     NCB *ncbp;
3355     long code = 0;
3356
3357     while (smbShutdownFlag == 0) {
3358         lock_ObtainWrite(&smb_globalLock);
3359         nwlRequest = smb_allWaitingLocks;
3360         if (nwlRequest == NULL) {
3361             osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
3362             thrd_Sleep(1000);
3363             continue;
3364         } else {
3365             first = 1;
3366             osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
3367         }
3368
3369         do {
3370             if (first)
3371                 first = 0;
3372             else
3373                 lock_ObtainWrite(&smb_globalLock);
3374
3375             osi_Log1(smb_logp, "    Checking waiting lock request %p", nwlRequest);
3376
3377             wlRequest = nwlRequest;
3378             nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3379             lock_ReleaseWrite(&smb_globalLock);
3380
3381             code = 0;
3382
3383             for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3384                 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3385                     continue;
3386
3387                 osi_assert(wl->state != SMB_WAITINGLOCKSTATE_ERROR);
3388                 
3389                 /* wl->state is either _DONE or _WAITING.  _ERROR
3390                    would no longer be on the queue. */
3391                 code = cm_RetryLock( wl->lockp,
3392                                      !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3393
3394                 if (code == 0) {
3395                     wl->state = SMB_WAITINGLOCKSTATE_DONE;
3396                 } else if (code != CM_ERROR_WOULDBLOCK) {
3397                     wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3398                     break;
3399                 }
3400             }
3401
3402             if (code == CM_ERROR_WOULDBLOCK) {
3403
3404                 /* no progress */
3405                 if (wlRequest->timeRemaining != 0xffffffff
3406                      && (wlRequest->timeRemaining -= 1000) < 0)
3407                     goto endWait;
3408
3409                 continue;
3410             }
3411
3412           endWait:
3413
3414             if (code != 0) {
3415                 cm_scache_t * scp;
3416                 cm_req_t req;
3417
3418                 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
3419                          wlRequest);
3420
3421                 scp = wlRequest->scp;
3422                 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
3423
3424                 cm_InitReq(&req);
3425
3426                 lock_ObtainMutex(&scp->mx);
3427
3428                 for (wl = wlRequest->locks; wl; wl = wlNext) {
3429                     wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3430                     
3431                     cm_Unlock(scp, wlRequest->lockType, wl->LOffset, 
3432                               wl->LLength, wl->key, NULL, &req);
3433
3434                     osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3435
3436                     free(wl);
3437                 }
3438                 
3439                 lock_ReleaseMutex(&scp->mx);
3440
3441             } else {
3442
3443                 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
3444                          wlRequest);
3445
3446                 for (wl = wlRequest->locks; wl; wl = wlNext) {
3447                     wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3448                     osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3449                     free(wl);
3450                 }
3451             }
3452
3453             vcp = wlRequest->vcp;
3454             inp = wlRequest->inp;
3455             outp = wlRequest->outp;
3456             ncbp = GetNCB();
3457             ncbp->ncb_length = inp->ncb_length;
3458             inp->spacep = cm_GetSpace();
3459
3460             /* Remove waitingLock from list */
3461             lock_ObtainWrite(&smb_globalLock);
3462             osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3463                          &wlRequest->q);
3464             lock_ReleaseWrite(&smb_globalLock);
3465
3466             /* Resume packet processing */
3467             if (code == 0)
3468                 smb_SetSMBDataLength(outp, 0);
3469             outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3470             outp->resumeCode = code;
3471             outp->ncbp = ncbp;
3472             smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3473
3474             /* Clean up */
3475             cm_FreeSpace(inp->spacep);
3476             smb_FreePacket(inp);
3477             smb_FreePacket(outp);
3478             smb_ReleaseVC(vcp);
3479             cm_ReleaseSCache(wlRequest->scp);
3480             FreeNCB(ncbp);
3481             free(wlRequest);
3482         } while (nwlRequest && smbShutdownFlag == 0);
3483         thrd_Sleep(1000);
3484     }
3485 }
3486
3487 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3488 {
3489     osi_Log0(smb_logp, "SMB receive get disk attributes");
3490
3491     smb_SetSMBParm(outp, 0, 32000);
3492     smb_SetSMBParm(outp, 1, 64);
3493     smb_SetSMBParm(outp, 2, 1024);
3494     smb_SetSMBParm(outp, 3, 30000);
3495     smb_SetSMBParm(outp, 4, 0);
3496     smb_SetSMBDataLength(outp, 0);
3497     return 0;
3498 }
3499
3500 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3501 {
3502     smb_tid_t *tidp;
3503     smb_user_t *uidp;
3504     unsigned short newTid;
3505     char shareName[256];
3506     char *sharePath;
3507     int shareFound;
3508     char *tp;
3509     char *pathp;
3510     char *passwordp;
3511     cm_user_t *userp;
3512
3513     osi_Log0(smb_logp, "SMB receive tree connect");
3514
3515     /* parse input parameters */
3516     tp = smb_GetSMBData(inp, NULL);
3517     pathp = smb_ParseASCIIBlock(tp, &tp);
3518     if (smb_StoreAnsiFilenames)
3519         OemToChar(pathp,pathp);
3520     passwordp = smb_ParseASCIIBlock(tp, &tp);
3521     tp = strrchr(pathp, '\\');
3522     if (!tp)
3523         return CM_ERROR_BADSMB;
3524     strcpy(shareName, tp+1);
3525
3526     lock_ObtainMutex(&vcp->mx);
3527     newTid = vcp->tidCounter++;
3528     lock_ReleaseMutex(&vcp->mx);
3529
3530     tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3531     uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3532     userp = smb_GetUserFromUID(uidp);
3533     shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3534     if (uidp)
3535         smb_ReleaseUID(uidp);
3536     if (!shareFound) {
3537         smb_ReleaseTID(tidp);
3538         return CM_ERROR_BADSHARENAME;
3539     }
3540     lock_ObtainMutex(&tidp->mx);
3541     tidp->userp = userp;
3542     tidp->pathname = sharePath;
3543     lock_ReleaseMutex(&tidp->mx);
3544     smb_ReleaseTID(tidp);
3545
3546     smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3547     smb_SetSMBParm(rsp, 1, newTid);
3548     smb_SetSMBDataLength(rsp, 0);
3549
3550     osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3551     return 0;
3552 }
3553
3554 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3555 {
3556     int tlen;
3557
3558     if (*inp++ != 0x1) return NULL;
3559     tlen = inp[0] + (inp[1]<<8);
3560     inp += 2;           /* skip length field */
3561         
3562     if (chainpp) {
3563         *chainpp = inp + tlen;
3564     }   
3565
3566     if (lengthp) *lengthp = tlen;
3567         
3568     return inp;
3569 }
3570
3571 /* set maskp to the mask part of the incoming path.
3572  * Mask is 11 bytes long (8.3 with the dot elided).
3573  * Returns true if succeeds with a valid name, otherwise it does
3574  * its best, but returns false.
3575  */
3576 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3577 {
3578     char *tp;
3579     char *up;
3580     int i;
3581     int tc;
3582     int valid8Dot3;
3583
3584     /* starts off valid */
3585     valid8Dot3 = 1;
3586
3587     /* mask starts out all blanks */
3588     memset(maskp, ' ', 11);
3589
3590     /* find last backslash, or use whole thing if there is none */
3591     tp = strrchr(pathp, '\\');
3592     if (!tp) tp = pathp;
3593     else tp++;  /* skip slash */
3594         
3595     up = maskp;
3596
3597     /* names starting with a dot are illegal */
3598     if (*tp == '.') valid8Dot3 = 0;
3599
3600     for(i=0;; i++) {
3601         tc = *tp++;
3602         if (tc == 0) return valid8Dot3;
3603         if (tc == '.' || tc == '"') break;
3604         if (i < 8) *up++ = tc;
3605         else valid8Dot3 = 0;
3606     }
3607         
3608     /* if we get here, tp point after the dot */
3609     up = maskp+8;       /* ext goes here */
3610     for(i=0;;i++) {
3611         tc = *tp++;
3612         if (tc == 0) 
3613             return valid8Dot3;
3614
3615         /* too many dots */
3616         if (tc == '.' || tc == '"') 
3617             valid8Dot3 = 0;
3618
3619         /* copy extension if not too long */
3620         if (i < 3) 
3621             *up++ = tc;
3622         else 
3623             valid8Dot3 = 0;
3624     }   
3625
3626     /* unreachable */
3627 }
3628
3629 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3630 {
3631     char umask[11];
3632     int valid;
3633     int i;
3634     char tc1;
3635     char tc2;
3636     char *tp1;
3637     char *tp2;
3638
3639     /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3640
3641     valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3642     if (!valid) 
3643         return 0;
3644  
3645     /* otherwise, we have a valid 8.3 name; see if we have a match,
3646      * treating '?' as a wildcard in maskp (but not in the file name).
3647      */
3648     tp1 = umask;        /* real name, in mask format */
3649     tp2 = maskp;        /* mask, in mask format */
3650     for(i=0; i<11; i++) {
3651         tc1 = *tp1++;   /* char from real name */
3652         tc2 = *tp2++;   /* char from mask */
3653         tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3654         tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3655         if (tc1 == tc2) 
3656             continue;
3657         if (tc2 == '?' && tc1 != ' ') 
3658             continue;
3659         if (tc2 == '>') 
3660             continue;
3661         return 0;
3662     }
3663
3664     /* we got a match */
3665     return 1;
3666 }
3667
3668 char *smb_FindMask(char *pathp)
3669 {
3670     char *tp;
3671         
3672     tp = strrchr(pathp, '\\');  /* find last slash */
3673
3674     if (tp) 
3675         return tp+1;    /* skip the slash */
3676     else 
3677         return pathp;   /* no slash, return the entire path */
3678 }       
3679
3680 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3681 {
3682     unsigned char *pathp;
3683     unsigned char *tp;
3684     unsigned char mask[11];
3685     unsigned char *statBlockp;
3686     unsigned char initStatBlock[21];
3687     int statLen;
3688         
3689     osi_Log0(smb_logp, "SMB receive search volume");
3690
3691     /* pull pathname and stat block out of request */
3692     tp = smb_GetSMBData(inp, NULL);
3693     pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3694     osi_assert(pathp != NULL);
3695     if (smb_StoreAnsiFilenames)
3696         OemToChar(pathp,pathp);
3697     statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3698     osi_assert(statBlockp != NULL);
3699     if (statLen == 0) {
3700         statBlockp = initStatBlock;
3701         statBlockp[0] = 8;
3702     }
3703         
3704     /* for returning to caller */
3705     smb_Get8Dot3MaskFromPath(mask, pathp);
3706
3707     smb_SetSMBParm(outp, 0, 1);         /* we're returning one entry */
3708     tp = smb_GetSMBData(outp, NULL);
3709     *tp++ = 5;
3710     *tp++ = 43; /* bytes in a dir entry */
3711     *tp++ = 0;  /* high byte in counter */
3712
3713     /* now marshall the dir entry, starting with the search status */
3714     *tp++ = statBlockp[0];              /* Reserved */
3715     memcpy(tp, mask, 11); tp += 11;     /* FileName */
3716
3717     /* now pass back server use info, with 1st byte non-zero */
3718     *tp++ = 1;
3719     memset(tp, 0, 4); tp += 4;  /* reserved for server use */
3720
3721     memcpy(tp, statBlockp+17, 4); tp += 4;      /* reserved for consumer */
3722
3723     *tp++ = 0x8;                /* attribute: volume */
3724
3725     /* copy out time */
3726     *tp++ = 0;
3727     *tp++ = 0;
3728
3729     /* copy out date */
3730     *tp++ = 18;
3731     *tp++ = 178;
3732
3733     /* 4 byte file size */
3734   &nbs