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