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