windows-afsd-notification-20071104
[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;
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)
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             osi_assertx(nts == STATUS_SUCCESS, "LsaCallAuthenticationPackage failed"); /* this had better work! */
859
860             memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
861             LsaFreeReturnBuffer(lsaResp);
862         }
863         else
864             memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
865
866         if (numVCs >= CM_SESSION_RESERVED) {
867             numVCs = 0;
868             osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
869         }
870     }
871     lock_ReleaseWrite(&smb_rctLock);
872         lock_ReleaseWrite(&smb_globalLock);
873     return vcp;
874 }
875
876 int smb_IsStarMask(char *maskp)
877 {
878     int i;
879     char tc;
880         
881     for(i=0; i<11; i++) {
882         tc = *maskp++;
883         if (tc == '?' || tc == '*' || tc == '>')
884             return 1;
885     }   
886     return 0;
887 }
888
889 void smb_ReleaseVCInternal(smb_vc_t *vcp)
890 {
891     smb_vc_t **vcpp;
892     smb_vc_t * avcp;
893
894     vcp->refCount--;
895
896     if (vcp->refCount == 0) {
897       if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
898         /* remove VCP from smb_deadVCsp */
899         for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
900           if (*vcpp == vcp) {
901             *vcpp = vcp->nextp;
902             break;
903           }
904         } 
905         lock_FinalizeMutex(&vcp->mx);
906         memset(vcp,0,sizeof(smb_vc_t));
907         free(vcp);
908       } else {
909         for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
910           if (avcp == vcp)
911             break;
912         }
913         osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
914                  avcp?"not ":"",vcp, vcp->refCount);
915 #ifdef DEBUG
916         GenerateMiniDump(NULL);
917 #endif
918         /* This is a wrong.  However, I suspect that there is an undercount
919          * and I don't want to release 1.4.1 in a state that will allow
920          * smb_vc_t objects to be deallocated while still in the
921          * smb_allVCsp list.  The list is supposed to keep a reference
922          * to the smb_vc_t.  Put it back.
923          */
924         vcp->refCount++;
925       }
926     }
927 }
928
929 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
930 {
931     osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
932     smb_ReleaseVCInternal(vcp);
933 }       
934
935 void smb_ReleaseVC(smb_vc_t *vcp)
936 {
937     lock_ObtainWrite(&smb_rctLock);
938     osi_Log2(smb_logp,"smb_ReleaseVC       vcp %x ref %d",vcp, vcp->refCount);
939     smb_ReleaseVCInternal(vcp);
940     lock_ReleaseWrite(&smb_rctLock);
941 }       
942
943 void smb_HoldVCNoLock(smb_vc_t *vcp)
944 {
945     vcp->refCount++;
946     osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
947 }       
948
949 void smb_HoldVC(smb_vc_t *vcp)
950 {
951     lock_ObtainWrite(&smb_rctLock);
952     vcp->refCount++;
953     osi_Log2(smb_logp,"smb_HoldVC       vcp %x ref %d",vcp, vcp->refCount);
954     lock_ReleaseWrite(&smb_rctLock);
955 }       
956
957 void smb_CleanupDeadVC(smb_vc_t *vcp)
958 {
959     smb_fid_t *fidpIter;
960     smb_fid_t *fidpNext;
961     unsigned short fid;
962     smb_tid_t *tidpIter;
963     smb_tid_t *tidpNext;
964     unsigned short tid;
965     smb_user_t *uidpIter;
966     smb_user_t *uidpNext;
967     smb_vc_t **vcpp;
968
969
970     lock_ObtainMutex(&vcp->mx);
971     if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
972         lock_ReleaseMutex(&vcp->mx);
973         osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
974         return;
975     }
976     vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
977     lock_ReleaseMutex(&vcp->mx);
978     osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
979
980     lock_ObtainWrite(&smb_rctLock);
981     /* remove VCP from smb_allVCsp */
982     for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
983         if ((*vcpp)->magic != SMB_VC_MAGIC)
984             osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp", 
985                        __FILE__, __LINE__);
986         if (*vcpp == vcp) {
987             *vcpp = vcp->nextp;
988             vcp->nextp = smb_deadVCsp;
989             smb_deadVCsp = vcp;
990             /* Hold onto the reference until we are done with this function */
991             break;
992         }
993     }
994
995     for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
996         fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
997
998         if (fidpIter->delete)
999             continue;
1000
1001         fid = fidpIter->fid;
1002         osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1003
1004         smb_HoldFIDNoLock(fidpIter);
1005         lock_ReleaseWrite(&smb_rctLock);
1006
1007         smb_CloseFID(vcp, fidpIter, NULL, 0);
1008         smb_ReleaseFID(fidpIter);
1009
1010         lock_ObtainWrite(&smb_rctLock);
1011         fidpNext = vcp->fidsp;
1012     }
1013
1014     for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1015         tidpNext = tidpIter->nextp;
1016         if (tidpIter->delete)
1017             continue;
1018         tidpIter->delete = 1;
1019
1020         tid = tidpIter->tid;
1021         osi_Log2(smb_logp, "  Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1022
1023         smb_HoldTIDNoLock(tidpIter);
1024         lock_ReleaseWrite(&smb_rctLock);
1025
1026         smb_ReleaseTID(tidpIter);
1027
1028         lock_ObtainWrite(&smb_rctLock);
1029         tidpNext = vcp->tidsp;
1030     }
1031
1032     for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1033         uidpNext = uidpIter->nextp;
1034         if (uidpIter->delete)
1035             continue;
1036         uidpIter->delete = 1;
1037
1038         /* do not add an additional reference count for the smb_user_t
1039          * as the smb_vc_t already is holding a reference */
1040         lock_ReleaseWrite(&smb_rctLock);
1041
1042         smb_ReleaseUID(uidpIter);
1043
1044         lock_ObtainWrite(&smb_rctLock);
1045         uidpNext = vcp->usersp;
1046     }
1047
1048     /* The vcp is now on the deadVCsp list.  We intentionally drop the
1049      * reference so that the refcount can reach 0 and we can delete it */
1050     smb_ReleaseVCNoLock(vcp);
1051     
1052     lock_ReleaseWrite(&smb_rctLock);
1053     osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1054 }
1055
1056 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1057 {
1058     smb_tid_t *tidp;
1059
1060     lock_ObtainWrite(&smb_rctLock);
1061   retry:
1062     for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1063         if (tidp->refCount == 0 && tidp->delete) {
1064             tidp->refCount++;
1065             lock_ReleaseWrite(&smb_rctLock);
1066             smb_ReleaseTID(tidp);
1067             lock_ObtainWrite(&smb_rctLock);
1068             goto retry;
1069         }
1070
1071         if (tid == tidp->tid) {
1072             tidp->refCount++;
1073             break;
1074         }       
1075     }
1076     if (!tidp && (flags & SMB_FLAG_CREATE)) {
1077         tidp = malloc(sizeof(*tidp));
1078         memset(tidp, 0, sizeof(*tidp));
1079         tidp->nextp = vcp->tidsp;
1080         tidp->refCount = 1;
1081         tidp->vcp = vcp;
1082         smb_HoldVCNoLock(vcp);
1083         vcp->tidsp = tidp;
1084         lock_InitializeMutex(&tidp->mx, "tid_t mutex");
1085         tidp->tid = tid;
1086     }
1087     lock_ReleaseWrite(&smb_rctLock);
1088     return tidp;
1089 }               
1090
1091 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1092 {
1093     tidp->refCount++;
1094 }
1095
1096 void smb_ReleaseTID(smb_tid_t *tidp)
1097 {
1098     smb_tid_t *tp;
1099     smb_tid_t **ltpp;
1100     cm_user_t *userp;
1101
1102     userp = NULL;
1103     lock_ObtainWrite(&smb_rctLock);
1104     osi_assertx(tidp->refCount-- > 0, "smb_tid_t refCount 0");
1105     if (tidp->refCount == 0 && (tidp->delete)) {
1106         ltpp = &tidp->vcp->tidsp;
1107         for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1108             if (tp == tidp) 
1109                 break;
1110         }
1111         osi_assertx(tp != NULL, "null smb_tid_t");
1112         *ltpp = tp->nextp;
1113         lock_FinalizeMutex(&tidp->mx);
1114         userp = tidp->userp;    /* remember to drop ref later */
1115         tidp->userp = NULL;
1116         smb_ReleaseVCNoLock(tidp->vcp);
1117         tidp->vcp = NULL;
1118     }
1119     lock_ReleaseWrite(&smb_rctLock);
1120     if (userp)
1121         cm_ReleaseUser(userp);
1122 }               
1123
1124 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1125 {
1126     smb_user_t *uidp = NULL;
1127
1128     lock_ObtainWrite(&smb_rctLock);
1129     for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1130         if (uid == uidp->userID) {
1131             uidp->refCount++;
1132             osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%s]",
1133                      vcp, uidp->userID, 
1134                      osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
1135             break;
1136         }
1137     }
1138     if (!uidp && (flags & SMB_FLAG_CREATE)) {
1139         uidp = malloc(sizeof(*uidp));
1140         memset(uidp, 0, sizeof(*uidp));
1141         uidp->nextp = vcp->usersp;
1142         uidp->refCount = 2; /* one for the vcp and one for the caller */
1143         uidp->vcp = vcp;
1144         smb_HoldVCNoLock(vcp);
1145         vcp->usersp = uidp;
1146         lock_InitializeMutex(&uidp->mx, "user_t mutex");
1147         uidp->userID = uid;
1148         osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%s]",
1149                  vcp, uidp->userID, 
1150                  osi_LogSaveString(smb_logp,uidp->unp ? uidp->unp->name : ""));
1151     }
1152     lock_ReleaseWrite(&smb_rctLock);
1153     return uidp;
1154 }               
1155
1156 smb_username_t *smb_FindUserByName(char *usern, char *machine, afs_uint32 flags)
1157 {
1158     smb_username_t *unp= NULL;
1159
1160     lock_ObtainWrite(&smb_rctLock);
1161     for(unp = usernamesp; unp; unp = unp->nextp) {
1162         if (stricmp(unp->name, usern) == 0 &&
1163              stricmp(unp->machine, machine) == 0) {
1164             unp->refCount++;
1165             break;
1166         }
1167     }
1168     if (!unp && (flags & SMB_FLAG_CREATE)) {
1169         unp = malloc(sizeof(*unp));
1170         memset(unp, 0, sizeof(*unp));
1171         unp->refCount = 1;
1172         unp->nextp = usernamesp;
1173         unp->name = strdup(usern);
1174         unp->machine = strdup(machine);
1175         usernamesp = unp;
1176         lock_InitializeMutex(&unp->mx, "username_t mutex");
1177         if (flags & SMB_FLAG_AFSLOGON)
1178             unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1179     }
1180
1181     lock_ReleaseWrite(&smb_rctLock);
1182     return unp;
1183 }       
1184
1185 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
1186 {
1187     smb_user_t *uidp= NULL;
1188
1189     lock_ObtainWrite(&smb_rctLock);
1190     for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1191         if (!uidp->unp) 
1192             continue;
1193         if (stricmp(uidp->unp->name, usern) == 0) {
1194             uidp->refCount++;
1195             osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%s]",
1196                      vcp,uidp->userID,osi_LogSaveString(smb_logp,usern));
1197             break;
1198         } else
1199             continue;
1200     }           
1201     lock_ReleaseWrite(&smb_rctLock);
1202     return uidp;
1203 }       
1204
1205 void smb_ReleaseUsername(smb_username_t *unp)
1206 {
1207     smb_username_t *up;
1208     smb_username_t **lupp;
1209     cm_user_t *userp = NULL;
1210     time_t      now = osi_Time();
1211
1212     lock_ObtainWrite(&smb_rctLock);
1213     osi_assertx(unp->refCount-- > 0, "smb_username_t refCount 0");
1214     if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1215         (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1216         lupp = &usernamesp;
1217         for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1218             if (up == unp) 
1219                 break;
1220         }
1221         osi_assertx(up != NULL, "null smb_username_t");
1222         *lupp = up->nextp;
1223         up->nextp = NULL;                       /* do not remove this */
1224         lock_FinalizeMutex(&unp->mx);
1225         userp = unp->userp;
1226         free(unp->name);
1227         free(unp->machine);
1228         free(unp);
1229     }           
1230     lock_ReleaseWrite(&smb_rctLock);
1231
1232     if (userp) {
1233         cm_ReleaseUser(userp);
1234     }   
1235 }       
1236
1237 void smb_HoldUIDNoLock(smb_user_t *uidp)
1238 {
1239     uidp->refCount++;
1240 }
1241
1242 void smb_ReleaseUID(smb_user_t *uidp)
1243 {
1244     smb_user_t *up;
1245     smb_user_t **lupp;
1246     smb_username_t *unp = NULL;
1247
1248     lock_ObtainWrite(&smb_rctLock);
1249     osi_assertx(uidp->refCount-- > 0, "smb_user_t refCount 0");
1250     if (uidp->refCount == 0) {
1251         lupp = &uidp->vcp->usersp;
1252         for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1253             if (up == uidp) 
1254                 break;
1255         }
1256         osi_assertx(up != NULL, "null smb_user_t");
1257         *lupp = up->nextp;
1258         lock_FinalizeMutex(&uidp->mx);
1259         unp = uidp->unp;
1260         smb_ReleaseVCNoLock(uidp->vcp);
1261         uidp->vcp = NULL;
1262         free(uidp);
1263     }           
1264     lock_ReleaseWrite(&smb_rctLock);
1265
1266     if (unp) {
1267         if (unp->userp)
1268             cm_ReleaseUserVCRef(unp->userp);
1269         smb_ReleaseUsername(unp);
1270     }
1271 }       
1272
1273 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1274 {
1275     cm_user_t *up = NULL;
1276
1277     if (!uidp)
1278         return NULL;
1279     
1280     lock_ObtainMutex(&uidp->mx);
1281     if (uidp->unp) {
1282         up = uidp->unp->userp;
1283         cm_HoldUser(up);
1284     }
1285     lock_ReleaseMutex(&uidp->mx);
1286
1287     return up;
1288 }
1289
1290
1291 /* retrieve a held reference to a user structure corresponding to an incoming
1292  * request.
1293  * corresponding release function is cm_ReleaseUser.
1294  */
1295 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1296 {
1297     smb_user_t *uidp;
1298     cm_user_t *up = NULL;
1299     smb_t *smbp;
1300
1301     smbp = (smb_t *) inp;
1302     uidp = smb_FindUID(vcp, smbp->uid, 0);
1303     if (!uidp)
1304         return NULL;
1305     
1306     up = smb_GetUserFromUID(uidp);
1307
1308     smb_ReleaseUID(uidp);
1309     return up;
1310 }
1311
1312 /*
1313  * Return a pointer to a pathname extracted from a TID structure.  The
1314  * TID structure is not held; assume it won't go away.
1315  */
1316 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1317 {
1318     smb_tid_t *tidp;
1319     long code = 0;
1320
1321     tidp = smb_FindTID(vcp, tid, 0);
1322     if (!tidp) {
1323         *treepath = NULL;
1324     } else {
1325         if (tidp->flags & SMB_TIDFLAG_IPC) {
1326             code = CM_ERROR_TIDIPC;
1327             /* tidp->pathname would be NULL, but that's fine */
1328         }
1329         *treepath = tidp->pathname;
1330         smb_ReleaseTID(tidp);
1331     }
1332     return code;
1333 }
1334
1335 /* check to see if we have a chained fid, that is, a fid that comes from an
1336  * OpenAndX message that ran earlier in this packet.  In this case, the fid
1337  * field in a read, for example, request, isn't set, since the value is
1338  * supposed to be inherited from the openAndX call.
1339  */
1340 int smb_ChainFID(int fid, smb_packet_t *inp)
1341 {
1342     if (inp->fid == 0 || inp->inCount == 0) 
1343         return fid;
1344     else 
1345         return inp->fid;
1346 }
1347
1348 /* are we a priv'd user?  What does this mean on NT? */
1349 int smb_SUser(cm_user_t *userp)
1350 {
1351     return 1;
1352 }
1353
1354 /* find a file ID.  If we pass in 0 we select an unused File ID.
1355  * If the SMB_FLAG_CREATE flag is set, we allocate a new  
1356  * smb_fid_t data structure if desired File ID cannot be found.
1357  */
1358 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1359 {
1360     smb_fid_t *fidp;
1361     int newFid = 0;
1362         
1363     if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1364         return NULL;
1365
1366     lock_ObtainWrite(&smb_rctLock);
1367     /* figure out if we need to allocate a new file ID */
1368     if (fid == 0) {
1369         newFid = 1;
1370         fid = vcp->fidCounter;
1371     }
1372
1373   retry:
1374     for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1375         if (fidp->refCount == 0 && fidp->delete) {
1376             fidp->refCount++;
1377             lock_ReleaseWrite(&smb_rctLock);
1378             smb_ReleaseFID(fidp);
1379             lock_ObtainWrite(&smb_rctLock);
1380             goto retry;
1381         }
1382         if (fid == fidp->fid) {
1383             if (newFid) {
1384                 fid++;
1385                 if (fid == 0xFFFF) {
1386                     osi_Log1(smb_logp,
1387                              "New FID number wraps on vcp 0x%x", vcp);
1388                     fid = 1;
1389                 }
1390                 goto retry;
1391             }
1392             fidp->refCount++;
1393             break;
1394         }
1395     }
1396
1397     if (!fidp && (flags & SMB_FLAG_CREATE)) {
1398         char eventName[MAX_PATH];
1399         EVENT_HANDLE event;
1400         sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1401         event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1402         if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1403             osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1404             thrd_CloseHandle(event);
1405             fid++;
1406             if (fid == 0xFFFF) {
1407                 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1408                 fid = 1;
1409             }
1410             goto retry;
1411         }
1412
1413         fidp = malloc(sizeof(*fidp));
1414         memset(fidp, 0, sizeof(*fidp));
1415         osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1416         fidp->refCount = 1;
1417         fidp->vcp = vcp;
1418         smb_HoldVCNoLock(vcp);
1419         lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1420         fidp->fid = fid;
1421         fidp->curr_chunk = fidp->prev_chunk = -2;
1422         fidp->raw_write_event = event;
1423         if (newFid) {
1424             vcp->fidCounter = fid+1;
1425             if (vcp->fidCounter == 0xFFFF) {
1426                 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1427                          vcp);
1428                 vcp->fidCounter = 1;
1429             }
1430         }
1431     }
1432
1433     lock_ReleaseWrite(&smb_rctLock);
1434     return fidp;
1435 }
1436
1437 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1438 {
1439     smb_fid_t *fidp = NULL;
1440     int newFid = 0;
1441         
1442     if (!scp)
1443         return NULL;
1444
1445     lock_ObtainWrite(&smb_rctLock);
1446     for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1447         if (scp == fidp->scp) {
1448             fidp->refCount++;
1449             break;
1450         }
1451     }
1452     lock_ReleaseWrite(&smb_rctLock);
1453     return fidp;
1454 }
1455
1456 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1457 {
1458     fidp->refCount++;
1459 }
1460
1461
1462 /* smb_ReleaseFID cannot be called while an cm_scache_t mutex lock is held */
1463 /* the sm_fid_t->mx and smb_rctLock must not be held */
1464 void smb_ReleaseFID(smb_fid_t *fidp)
1465 {
1466     cm_scache_t *scp = NULL;
1467     cm_user_t *userp = NULL;
1468     smb_vc_t *vcp = NULL;
1469     smb_ioctl_t *ioctlp;
1470
1471     lock_ObtainMutex(&fidp->mx);
1472     lock_ObtainWrite(&smb_rctLock);
1473     osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
1474     if (fidp->refCount == 0 && (fidp->delete)) {
1475         vcp = fidp->vcp;
1476         fidp->vcp = NULL;
1477         scp = fidp->scp;    /* release after lock is released */
1478         if (scp) {
1479             lock_ObtainMutex(&scp->mx);
1480             scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1481             lock_ReleaseMutex(&scp->mx);
1482             osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1483             fidp->scp = NULL;
1484         }
1485         userp = fidp->userp;
1486         fidp->userp = NULL;
1487
1488         if (vcp->fidsp) 
1489             osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1490         thrd_CloseHandle(fidp->raw_write_event);
1491
1492         /* and see if there is ioctl stuff to free */
1493         ioctlp = fidp->ioctlp;
1494         if (ioctlp) {
1495             if (ioctlp->prefix)
1496                 cm_FreeSpace(ioctlp->prefix);
1497             if (ioctlp->inAllocp)
1498                 free(ioctlp->inAllocp);
1499             if (ioctlp->outAllocp)
1500                 free(ioctlp->outAllocp);
1501             free(ioctlp);
1502         }       
1503         lock_ReleaseMutex(&fidp->mx);
1504         lock_FinalizeMutex(&fidp->mx);
1505         free(fidp);
1506
1507         if (vcp)
1508             smb_ReleaseVCNoLock(vcp);
1509     } else {
1510         lock_ReleaseMutex(&fidp->mx);
1511     }
1512     lock_ReleaseWrite(&smb_rctLock);
1513
1514     /* now release the scache structure */
1515     if (scp) 
1516         cm_ReleaseSCache(scp);
1517
1518     if (userp)
1519         cm_ReleaseUser(userp);
1520 }       
1521
1522 /*
1523  * Case-insensitive search for one string in another;
1524  * used to find variable names in submount pathnames.
1525  */
1526 static char *smb_stristr(char *str1, char *str2)
1527 {
1528     char *cursor;
1529
1530     for (cursor = str1; *cursor; cursor++)
1531         if (stricmp(cursor, str2) == 0)
1532             return cursor;
1533
1534     return NULL;
1535 }
1536
1537 /*
1538  * Substitute a variable value for its name in a submount pathname.  Variable
1539  * name has been identified by smb_stristr() and is in substr.  Variable name
1540  * length (plus one) is in substr_size.  Variable value is in newstr.
1541  */
1542 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1543                       char *newstr)
1544 {
1545     char temp[1024];
1546
1547     strcpy(temp, substr + substr_size - 1);
1548     strcpy(substr, newstr);
1549     strcat(str1, temp);
1550 }       
1551
1552 char VNUserName[] = "%USERNAME%";
1553 char VNLCUserName[] = "%LCUSERNAME%";
1554 char VNComputerName[] = "%COMPUTERNAME%";
1555 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1556
1557
1558 typedef struct smb_findShare_rock {
1559     char * shareName;
1560     char * match;
1561     int matchType;
1562 } smb_findShare_rock_t;
1563
1564 #define SMB_FINDSHARE_EXACT_MATCH 1
1565 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1566
1567 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1568                        osi_hyper_t *offp)
1569 {
1570     int matchType = 0;
1571     smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1572     if (!strnicmp(dep->name, vrock->shareName, 12)) {
1573         if(!stricmp(dep->name, vrock->shareName))
1574             matchType = SMB_FINDSHARE_EXACT_MATCH;
1575         else
1576             matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1577         if(vrock->match) free(vrock->match);
1578         vrock->match = strdup(dep->name);
1579         vrock->matchType = matchType;
1580
1581         if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1582             return CM_ERROR_STOPNOW;
1583     }
1584     return 0;
1585 }
1586
1587
1588 /* find a shareName in the table of submounts */
1589 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1590         char **pathNamep)
1591 {
1592     DWORD len;
1593     char pathName[1024];
1594     char *var;
1595     char temp[1024];
1596     DWORD sizeTemp;
1597     char *p, *q;
1598     HKEY parmKey;
1599     DWORD code;
1600     DWORD allSubmount = 1;
1601
1602     /* if allSubmounts == 0, only return the //mountRoot/all share 
1603      * if in fact it has been been created in the subMounts table.  
1604      * This is to allow sites that want to restrict access to the 
1605      * world to do so.
1606      */
1607     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1608                          0, KEY_QUERY_VALUE, &parmKey);
1609     if (code == ERROR_SUCCESS) {
1610         len = sizeof(allSubmount);
1611         code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1612                                 (BYTE *) &allSubmount, &len);
1613         if (code != ERROR_SUCCESS) {
1614             allSubmount = 1;
1615         }
1616         RegCloseKey (parmKey);
1617     }
1618
1619     if (allSubmount && _stricmp(shareName, "all") == 0) {
1620         *pathNamep = NULL;
1621         return 1;
1622     }
1623
1624     /* In case, the all share is disabled we need to still be able
1625      * to handle ioctl requests 
1626      */
1627     if (_stricmp(shareName, "ioctl$") == 0) {
1628         *pathNamep = strdup("/.__ioctl__");
1629         return 1;
1630     }
1631
1632     if (_stricmp(shareName, "IPC$") == 0 ||
1633         _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1634         _stricmp(shareName, "DESKTOP.INI") == 0
1635          ) {
1636         *pathNamep = NULL;
1637         return 0;
1638     }
1639
1640     /* Check for volume references
1641      * 
1642      * They look like <cell>{%,#}<volume>
1643      */
1644     if (strchr(shareName, '%') != NULL ||
1645         strchr(shareName, '#') != NULL) {
1646         char pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
1647                                 /* make room for '/@vol:' + mountchar + NULL terminator*/
1648
1649         osi_Log1(smb_logp, "smb_FindShare found volume reference [%s]",
1650                  osi_LogSaveString(smb_logp, shareName));
1651
1652         snprintf(pathstr, sizeof(pathstr)/sizeof(char),
1653                  "/" CM_PREFIX_VOL "%s", shareName);
1654         pathstr[sizeof(pathstr)/sizeof(char) - 1] = '\0';
1655         len = strlen(pathstr) + 1;
1656
1657         *pathNamep = malloc(len);
1658         if (*pathNamep) {
1659             strcpy(*pathNamep, pathstr);
1660             strlwr(*pathNamep);
1661             osi_Log1(smb_logp, "   returning pathname [%s]",
1662                      osi_LogSaveString(smb_logp, *pathNamep));
1663
1664             return 1;
1665         } else {
1666             return 0;
1667         }
1668     }
1669
1670     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1671                          0, KEY_QUERY_VALUE, &parmKey);
1672     if (code == ERROR_SUCCESS) {
1673         len = sizeof(pathName);
1674         code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1675                                 (BYTE *) pathName, &len);
1676         if (code != ERROR_SUCCESS)
1677             len = 0;
1678         RegCloseKey (parmKey);
1679     } else {
1680         len = 0;
1681     }   
1682     if (len != 0 && len != sizeof(pathName) - 1) {
1683         /* We can accept either unix or PC style AFS pathnames.  Convert
1684          * Unix-style to PC style here for internal use. 
1685          */
1686         p = pathName;
1687         if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1688             p += strlen(cm_mountRoot);  /* skip mount path */
1689         q = p;
1690         while (*q) {
1691             if (*q == '/') *q = '\\';    /* change to \ */
1692             q++;
1693         }
1694
1695         while (1)
1696         {
1697             if (var = smb_stristr(p, VNUserName)) {
1698                 if (uidp && uidp->unp)
1699                     smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1700                 else
1701                     smb_subst(p, var, sizeof(VNUserName)," ");
1702             }
1703             else if (var = smb_stristr(p, VNLCUserName)) 
1704             {
1705                 if (uidp && uidp->unp)
1706                     strcpy(temp, uidp->unp->name);
1707                 else 
1708                     strcpy(temp, " ");
1709                 _strlwr(temp);
1710                 smb_subst(p, var, sizeof(VNLCUserName), temp);
1711             }
1712             else if (var = smb_stristr(p, VNComputerName)) 
1713             {
1714                 sizeTemp = sizeof(temp);
1715                 GetComputerName((LPTSTR)temp, &sizeTemp);
1716                 smb_subst(p, var, sizeof(VNComputerName), temp);
1717             }
1718             else if (var = smb_stristr(p, VNLCComputerName)) 
1719             {
1720                 sizeTemp = sizeof(temp);
1721                 GetComputerName((LPTSTR)temp, &sizeTemp);
1722                 _strlwr(temp);
1723                 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1724             }
1725             else     
1726                 break;
1727         }
1728         *pathNamep = strdup(p);
1729         return 1;
1730     } 
1731     else
1732     {
1733         /* First lookup shareName in root.afs */
1734         cm_req_t req;
1735         smb_findShare_rock_t vrock;
1736         osi_hyper_t thyper;
1737         char * p = shareName; 
1738         int rw = 0;
1739
1740         /*  attempt to locate a partial match in root.afs.  This is because
1741             when using the ANSI RAP calls, the share name is limited to 13 chars
1742             and hence is truncated. Of course we prefer exact matches. */
1743         cm_InitReq(&req);
1744         thyper.HighPart = 0;
1745         thyper.LowPart = 0;
1746
1747         vrock.shareName = shareName;
1748         vrock.match = NULL;
1749         vrock.matchType = 0;
1750
1751         cm_HoldSCache(cm_data.rootSCachep);
1752         code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1753             (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1754         cm_ReleaseSCache(cm_data.rootSCachep);
1755
1756         if (vrock.matchType) {
1757             sprintf(pathName,"/%s/",vrock.match);
1758             *pathNamep = strdup(strlwr(pathName));
1759             free(vrock.match);
1760             return 1;
1761         }
1762
1763         /* if we get here, there was no match for the share in root.afs */
1764         /* so try to create  \\<netbiosName>\<cellname>  */
1765         if ( *p == '.' ) {
1766             p++;
1767             rw = 1;
1768         }
1769         /* Get the full name for this cell */
1770         code = cm_SearchCellFile(p, temp, 0, 0);
1771 #ifdef AFS_AFSDB_ENV
1772         if (code && cm_dnsEnabled) {
1773             int ttl;
1774             code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1775         }
1776 #endif
1777         /* construct the path */
1778         if (code == 0) {     
1779             sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1780             *pathNamep = strdup(strlwr(pathName));
1781             return 1;
1782         }
1783     }
1784     /* failure */
1785     *pathNamep = NULL;
1786     return 0;
1787 }
1788
1789 /* Client-side offline caching policy types */
1790 #define CSC_POLICY_MANUAL 0
1791 #define CSC_POLICY_DOCUMENTS 1
1792 #define CSC_POLICY_PROGRAMS 2
1793 #define CSC_POLICY_DISABLE 3
1794
1795 int smb_FindShareCSCPolicy(char *shareName)
1796 {
1797     DWORD len;
1798     char policy[1024];
1799     DWORD dwType;
1800     HKEY hkCSCPolicy;
1801     int  retval = CSC_POLICY_MANUAL;
1802
1803     RegCreateKeyEx( HKEY_LOCAL_MACHINE, 
1804                     AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1805                     0, 
1806                     "AFS", 
1807                     REG_OPTION_NON_VOLATILE,
1808                     KEY_READ,
1809                     NULL, 
1810                     &hkCSCPolicy,
1811                     NULL );
1812
1813     len = sizeof(policy);
1814     if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1815          len == 0) {
1816         retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1817     }
1818     else if (stricmp(policy, "documents") == 0)
1819     {
1820         retval = CSC_POLICY_DOCUMENTS;
1821     }
1822     else if (stricmp(policy, "programs") == 0)
1823     {
1824         retval = CSC_POLICY_PROGRAMS;
1825     }
1826     else if (stricmp(policy, "disable") == 0)
1827     {
1828         retval = CSC_POLICY_DISABLE;
1829     }
1830         
1831     RegCloseKey(hkCSCPolicy);
1832     return retval;
1833 }
1834
1835 /* find a dir search structure by cookie value, and return it held.
1836  * Must be called with smb_globalLock held.
1837  */
1838 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
1839 {
1840     smb_dirSearch_t *dsp;
1841         
1842     for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1843         if (dsp->cookie == cookie) {
1844             if (dsp != smb_firstDirSearchp) {
1845                 /* move to head of LRU queue, too, if we're not already there */
1846                 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1847                     smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
1848                 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1849                 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1850                 if (!smb_lastDirSearchp)
1851                     smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1852             }
1853             lock_ObtainMutex(&dsp->mx);
1854             dsp->refCount++;
1855             lock_ReleaseMutex(&dsp->mx);
1856             break;
1857         }
1858     }
1859
1860     if (dsp == NULL) {
1861         osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
1862         for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1863             osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
1864         }
1865     }
1866     return dsp;
1867 }       
1868
1869 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1870 {
1871     lock_ObtainWrite(&smb_globalLock);
1872     lock_ObtainMutex(&dsp->mx);
1873     osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p", 
1874               dsp->cookie, dsp, dsp->scp);
1875     dsp->flags |= SMB_DIRSEARCH_DELETE;
1876     if (dsp->scp != NULL) {
1877         lock_ObtainMutex(&dsp->scp->mx);
1878         if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1879             dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1880             dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1881             dsp->scp->bulkStatProgress = hzero;
1882         }       
1883         lock_ReleaseMutex(&dsp->scp->mx);
1884     }   
1885     lock_ReleaseMutex(&dsp->mx);
1886     lock_ReleaseWrite(&smb_globalLock);
1887 }               
1888
1889 /* Must be called with the smb_globalLock held */
1890 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
1891 {
1892     cm_scache_t *scp = NULL;
1893
1894     lock_ObtainMutex(&dsp->mx);
1895     osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
1896     if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1897         if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1898             smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1899         osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1900         lock_ReleaseMutex(&dsp->mx);
1901         lock_FinalizeMutex(&dsp->mx);
1902         scp = dsp->scp;
1903         osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p", 
1904                  dsp->cookie, dsp, scp);
1905         free(dsp);
1906     } else {
1907         lock_ReleaseMutex(&dsp->mx);
1908     }
1909     /* do this now to avoid spurious locking hierarchy creation */
1910     if (scp) 
1911         cm_ReleaseSCache(scp);
1912 }       
1913
1914 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1915 {
1916     lock_ObtainWrite(&smb_globalLock);
1917     smb_ReleaseDirSearchNoLock(dsp);
1918     lock_ReleaseWrite(&smb_globalLock);
1919 }       
1920
1921 /* find a dir search structure by cookie value, and return it held */
1922 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1923 {
1924     smb_dirSearch_t *dsp;
1925
1926     lock_ObtainWrite(&smb_globalLock);
1927     dsp = smb_FindDirSearchNoLock(cookie);
1928     lock_ReleaseWrite(&smb_globalLock);
1929     return dsp;
1930 }
1931
1932 /* GC some dir search entries, in the address space expected by the specific protocol.
1933  * Must be called with smb_globalLock held; release the lock temporarily.
1934  */
1935 #define SMB_DIRSEARCH_GCMAX     10      /* how many at once */
1936 void smb_GCDirSearches(int isV3)
1937 {
1938     smb_dirSearch_t *prevp;
1939     smb_dirSearch_t *tp;
1940     smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1941     int victimCount;
1942     int i;
1943         
1944     victimCount = 0;    /* how many have we got so far */
1945     for (tp = smb_lastDirSearchp; tp; tp=prevp) {
1946         /* we'll move tp from queue, so
1947          * do this early.
1948          */
1949         prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);  
1950         /* if no one is using this guy, and we're either in the new protocol,
1951          * or we're in the old one and this is a small enough ID to be useful
1952          * to the old protocol, GC this guy.
1953          */
1954         if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1955             /* hold and delete */
1956             lock_ObtainMutex(&tp->mx);
1957             tp->flags |= SMB_DIRSEARCH_DELETE;
1958             lock_ReleaseMutex(&tp->mx);
1959             victimsp[victimCount++] = tp;
1960             tp->refCount++;
1961         }
1962
1963         /* don't do more than this */
1964         if (victimCount >= SMB_DIRSEARCH_GCMAX) 
1965             break;
1966     }
1967         
1968     /* now release them */
1969     for (i = 0; i < victimCount; i++) {
1970         smb_ReleaseDirSearchNoLock(victimsp[i]);
1971     }
1972 }
1973
1974 /* function for allocating a dir search entry.  We need these to remember enough context
1975  * since we don't get passed the path from call to call during a directory search.
1976  *
1977  * Returns a held dir search structure, and bumps the reference count on the vnode,
1978  * since it saves a pointer to the vnode.
1979  */
1980 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1981 {
1982     smb_dirSearch_t *dsp;
1983     int counter;
1984     int maxAllowed;
1985     int start;
1986     int wrapped = 0;
1987
1988     lock_ObtainWrite(&smb_globalLock);
1989     counter = 0;
1990
1991     /* what's the biggest ID allowed in this version of the protocol */
1992     /* TODO: do we really want a non v3 dir search request to wrap
1993        smb_dirSearchCounter? */
1994     maxAllowed = isV3 ? 65535 : 255;
1995     if (smb_dirSearchCounter > maxAllowed)
1996         smb_dirSearchCounter = 1;
1997
1998     start = smb_dirSearchCounter;
1999
2000     while (1) {
2001         /* twice so we have enough tries to find guys we GC after one pass;
2002          * 10 extra is just in case I mis-counted.
2003          */
2004         if (++counter > 2*maxAllowed+10) 
2005             osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2006
2007         if (smb_dirSearchCounter > maxAllowed) {        
2008             smb_dirSearchCounter = 1;
2009         }
2010         if (smb_dirSearchCounter == start) {
2011             if (wrapped)
2012                 smb_GCDirSearches(isV3);
2013             wrapped++;
2014         }
2015         dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2016         if (dsp) {
2017             /* don't need to watch for refcount zero and deleted, since
2018             * we haven't dropped the global lock.
2019             */
2020             lock_ObtainMutex(&dsp->mx);
2021             dsp->refCount--;
2022             lock_ReleaseMutex(&dsp->mx);
2023             ++smb_dirSearchCounter;
2024             continue;
2025         }       
2026
2027         dsp = malloc(sizeof(*dsp));
2028         memset(dsp, 0, sizeof(*dsp));
2029         dsp->cookie = smb_dirSearchCounter;
2030         ++smb_dirSearchCounter;
2031         dsp->refCount = 1;
2032         lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
2033         dsp->lastTime = osi_Time();
2034         osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2035         if (!smb_lastDirSearchp) 
2036             smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2037     
2038         osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p", 
2039                  dsp->cookie, dsp);
2040         break;
2041     }   
2042     lock_ReleaseWrite(&smb_globalLock);
2043     return dsp;
2044 }
2045
2046 static smb_packet_t *GetPacket(void)
2047 {
2048     smb_packet_t *tbp;
2049
2050     lock_ObtainWrite(&smb_globalLock);
2051     tbp = smb_packetFreeListp;
2052     if (tbp) 
2053         smb_packetFreeListp = tbp->nextp;
2054     lock_ReleaseWrite(&smb_globalLock);
2055     if (!tbp) {
2056         tbp = calloc(65540,1);
2057         tbp->magic = SMB_PACKETMAGIC;
2058         tbp->ncbp = NULL;
2059         tbp->vcp = NULL;
2060         tbp->resumeCode = 0;
2061         tbp->inCount = 0;
2062         tbp->fid = 0;
2063         tbp->wctp = NULL;
2064         tbp->inCom = 0;
2065         tbp->oddByte = 0;
2066         tbp->ncb_length = 0;
2067         tbp->flags = 0;
2068         tbp->spacep = NULL;
2069         
2070     }
2071     osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2072
2073     return tbp;
2074 }
2075
2076 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2077 {
2078     smb_packet_t *tbp;
2079     tbp = GetPacket();
2080     memcpy(tbp, pkt, sizeof(smb_packet_t));
2081     tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2082     if (tbp->vcp)
2083         smb_HoldVC(tbp->vcp);
2084     return tbp;
2085 }
2086
2087 static NCB *GetNCB(void)
2088 {
2089     smb_ncb_t *tbp;
2090     NCB *ncbp;
2091
2092     lock_ObtainWrite(&smb_globalLock);
2093     tbp = smb_ncbFreeListp;
2094     if (tbp) 
2095         smb_ncbFreeListp = tbp->nextp;
2096     lock_ReleaseWrite(&smb_globalLock);
2097     if (!tbp) {
2098         tbp = calloc(sizeof(*tbp),1);
2099         tbp->magic = SMB_NCBMAGIC;
2100     }
2101         
2102     osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2103
2104     memset(&tbp->ncb, 0, sizeof(NCB));
2105     ncbp = &tbp->ncb;
2106     return ncbp;
2107 }
2108
2109 void smb_FreePacket(smb_packet_t *tbp)
2110 {
2111     smb_vc_t * vcp = NULL;
2112     osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2113         
2114     lock_ObtainWrite(&smb_globalLock);
2115     tbp->nextp = smb_packetFreeListp;
2116     smb_packetFreeListp = tbp;
2117     tbp->magic = SMB_PACKETMAGIC;
2118     tbp->ncbp = NULL;
2119     vcp = tbp->vcp;
2120     tbp->vcp = NULL;
2121     tbp->resumeCode = 0;
2122     tbp->inCount = 0;
2123     tbp->fid = 0;
2124     tbp->wctp = NULL;
2125     tbp->inCom = 0;
2126     tbp->oddByte = 0;
2127     tbp->ncb_length = 0;
2128     tbp->flags = 0;
2129     lock_ReleaseWrite(&smb_globalLock);
2130
2131     if (vcp)
2132         smb_ReleaseVC(vcp);
2133 }
2134
2135 static void FreeNCB(NCB *bufferp)
2136 {
2137     smb_ncb_t *tbp;
2138         
2139     tbp = (smb_ncb_t *) bufferp;
2140     osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2141         
2142     lock_ObtainWrite(&smb_globalLock);
2143     tbp->nextp = smb_ncbFreeListp;
2144     smb_ncbFreeListp = tbp;
2145     lock_ReleaseWrite(&smb_globalLock);
2146 }
2147
2148 /* get a ptr to the data part of a packet, and its count */
2149 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2150 {
2151     int parmBytes;
2152     int dataBytes;
2153     unsigned char *afterParmsp;
2154
2155     parmBytes = *smbp->wctp << 1;
2156     afterParmsp = smbp->wctp + parmBytes + 1;
2157         
2158     dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2159     if (nbytesp) *nbytesp = dataBytes;
2160         
2161     /* don't forget to skip the data byte count, since it follows
2162      * the parameters; that's where the "2" comes from below.
2163      */
2164     return (unsigned char *) (afterParmsp + 2);
2165 }
2166
2167 /* must set all the returned parameters before playing around with the
2168  * data region, since the data region is located past the end of the
2169  * variable number of parameters.
2170  */
2171 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2172 {
2173     unsigned char *afterParmsp;
2174
2175     afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2176         
2177     *afterParmsp++ = dsize & 0xff;
2178     *afterParmsp = (dsize>>8) & 0xff;
2179 }       
2180
2181 /* return the parm'th parameter in the smbp packet */
2182 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2183 {
2184     int parmCount;
2185     unsigned char *parmDatap;
2186
2187     parmCount = *smbp->wctp;
2188
2189     if (parm >= parmCount) {
2190         char s[100];
2191
2192         sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2193                 parm, parmCount, smbp->ncb_length);
2194         osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2195                  parm, parmCount, smbp->ncb_length);
2196         LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM, 
2197                  __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2198         osi_panic(s, __FILE__, __LINE__);
2199     }
2200     parmDatap = smbp->wctp + (2*parm) + 1;
2201         
2202     return parmDatap[0] + (parmDatap[1] << 8);
2203 }
2204
2205 /* return the parm'th parameter in the smbp packet */
2206 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2207 {
2208     int parmCount;
2209     unsigned char *parmDatap;
2210
2211     parmCount = *smbp->wctp;
2212
2213     if (parm >= parmCount) {
2214         char s[100];
2215
2216         sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2217                 parm, parmCount, smbp->ncb_length);
2218         osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2219                  parm, parmCount, smbp->ncb_length);
2220         LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM, 
2221                  __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2222         osi_panic(s, __FILE__, __LINE__);
2223     }
2224     parmDatap = smbp->wctp + (2*parm) + 1;
2225         
2226     return parmDatap[0];
2227 }
2228
2229 /* return the parm'th parameter in the smbp packet */
2230 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2231 {
2232     int parmCount;
2233     unsigned char *parmDatap;
2234
2235     parmCount = *smbp->wctp;
2236
2237     if (parm + 1 >= parmCount) {
2238         char s[100];
2239
2240         sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2241                 parm, parmCount, smbp->ncb_length);
2242         osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2243                  parm, parmCount, smbp->ncb_length);
2244         LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM, 
2245                  __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2246         osi_panic(s, __FILE__, __LINE__);
2247     }
2248     parmDatap = smbp->wctp + (2*parm) + 1;
2249         
2250     return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2251 }
2252
2253 /* return the parm'th parameter in the smbp packet */
2254 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2255 {
2256     int parmCount;
2257     unsigned char *parmDatap;
2258
2259     parmCount = *smbp->wctp;
2260
2261     if (parm * 2 + offset >= parmCount * 2) {
2262         char s[100];
2263
2264         sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2265                 parm, offset, parmCount, smbp->ncb_length);
2266         LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET, 
2267                  __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2268         osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2269                 parm, offset, parmCount, smbp->ncb_length);
2270         osi_panic(s, __FILE__, __LINE__);
2271     }
2272     parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2273         
2274     return parmDatap[0] + (parmDatap[1] << 8);
2275 }
2276
2277 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2278 {
2279     char *parmDatap;
2280
2281     /* make sure we have enough slots */
2282     if (*smbp->wctp <= slot) 
2283         *smbp->wctp = slot+1;
2284         
2285     parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2286     *parmDatap++ = parmValue & 0xff;
2287     *parmDatap = (parmValue>>8) & 0xff;
2288 }       
2289
2290 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2291 {
2292     char *parmDatap;
2293
2294     /* make sure we have enough slots */
2295     if (*smbp->wctp <= slot) 
2296         *smbp->wctp = slot+2;
2297
2298     parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2299     *parmDatap++ = parmValue & 0xff;
2300     *parmDatap++ = (parmValue>>8) & 0xff;
2301     *parmDatap++ = (parmValue>>16) & 0xff;
2302     *parmDatap   = (parmValue>>24) & 0xff;
2303 }
2304
2305 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2306 {
2307     char *parmDatap;
2308     int i;
2309
2310     /* make sure we have enough slots */
2311     if (*smbp->wctp <= slot) 
2312         *smbp->wctp = slot+4;
2313
2314     parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2315     for (i=0; i<8; i++)
2316         *parmDatap++ = *parmValuep++;
2317 }       
2318
2319 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2320 {
2321     char *parmDatap;
2322
2323     /* make sure we have enough slots */
2324     if (*smbp->wctp <= slot) {
2325         if (smbp->oddByte) {
2326             smbp->oddByte = 0;
2327             *smbp->wctp = slot+1;
2328         } else
2329             smbp->oddByte = 1;
2330     }
2331
2332     parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2333     *parmDatap++ = parmValue & 0xff;
2334 }
2335
2336 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2337 {
2338     char *lastSlashp;
2339         
2340     lastSlashp = strrchr(inPathp, '\\');
2341     if (lastComponentp)
2342         *lastComponentp = lastSlashp;
2343     if (lastSlashp) {
2344         while (1) {
2345             if (inPathp == lastSlashp) 
2346                 break;
2347             *outPathp++ = *inPathp++;
2348         }
2349         *outPathp++ = 0;
2350     }
2351     else {
2352         *outPathp++ = 0;
2353     }
2354 }
2355
2356 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2357 {
2358     if (*inp++ != 0x4) 
2359         return NULL;
2360     if (chainpp) {
2361         *chainpp = inp + strlen(inp) + 1;       /* skip over null-terminated string */
2362     }
2363     return inp;
2364 }
2365
2366 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2367 {
2368     int tlen;
2369
2370     if (*inp++ != 0x5) 
2371         return NULL;
2372     tlen = inp[0] + (inp[1]<<8);
2373     inp += 2;           /* skip length field */
2374
2375     if (chainpp) {
2376         *chainpp = inp + tlen;
2377     }
2378         
2379     if (lengthp) 
2380         *lengthp = tlen;
2381         
2382     return inp;
2383 }       
2384
2385 /* format a packet as a response */
2386 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2387 {
2388     smb_t *outp;
2389     smb_t *inSmbp;
2390
2391     outp = (smb_t *) op;
2392         
2393     /* zero the basic structure through the smb_wct field, and zero the data
2394      * size field, assuming that wct stays zero; otherwise, you have to 
2395      * explicitly set the data size field, too.
2396      */
2397     inSmbp = (smb_t *) inp;
2398     memset(outp, 0, sizeof(smb_t)+2);
2399     outp->id[0] = 0xff;
2400     outp->id[1] = 'S';
2401     outp->id[2] = 'M';
2402     outp->id[3] = 'B';
2403     if (inp) {
2404         outp->com = inSmbp->com;
2405         outp->tid = inSmbp->tid;
2406         outp->pid = inSmbp->pid;
2407         outp->uid = inSmbp->uid;
2408         outp->mid = inSmbp->mid;
2409         outp->res[0] = inSmbp->res[0];
2410         outp->res[1] = inSmbp->res[1];
2411         op->inCom = inSmbp->com;
2412     }
2413     outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
2414 #ifdef SEND_CANONICAL_PATHNAMES
2415     outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
2416 #endif
2417     outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2418
2419     /* copy fields in generic packet area */
2420     op->wctp = &outp->wct;
2421 }       
2422
2423 /* send a (probably response) packet; vcp tells us to whom to send it.
2424  * we compute the length by looking at wct and bcc fields.
2425  */
2426 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2427 {
2428     NCB *ncbp;
2429     int extra;
2430     long code = 0;
2431     unsigned char *tp;
2432     int localNCB = 0;
2433         
2434     ncbp = inp->ncbp;
2435     if (ncbp == NULL) {
2436         ncbp = GetNCB();
2437         localNCB = 1;
2438     }
2439  
2440     memset((char *)ncbp, 0, sizeof(NCB));
2441
2442     extra = 2 * (*inp->wctp);   /* space used by parms, in bytes */
2443     tp = inp->wctp + 1+ extra;  /* points to count of data bytes */
2444     extra += tp[0] + (tp[1]<<8);
2445     extra += (unsigned int)(inp->wctp - inp->data);     /* distance to last wct field */
2446     extra += 3;                 /* wct and length fields */
2447         
2448     ncbp->ncb_length = extra;   /* bytes to send */
2449     ncbp->ncb_lsn = (unsigned char) vcp->lsn;   /* vc to use */
2450     ncbp->ncb_lana_num = vcp->lana;
2451     ncbp->ncb_command = NCBSEND;        /* op means send data */
2452     ncbp->ncb_buffer = (char *) inp;/* packet */
2453     code = Netbios(ncbp);
2454         
2455     if (code != 0) {
2456         const char * s = ncb_error_string(code);
2457         osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2458         LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
2459
2460         lock_ObtainMutex(&vcp->mx);
2461         if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
2462             osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
2463                       vcp, vcp->usersp);
2464             vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2465             lock_ReleaseMutex(&vcp->mx);
2466             lock_ObtainWrite(&smb_globalLock);
2467             dead_sessions[vcp->session] = TRUE;
2468             lock_ReleaseWrite(&smb_globalLock);
2469             smb_CleanupDeadVC(vcp);
2470         } else {
2471             lock_ReleaseMutex(&vcp->mx);
2472         }
2473     }
2474
2475     if (localNCB)
2476         FreeNCB(ncbp);
2477 }
2478
2479 void smb_MapNTError(long code, unsigned long *NTStatusp)
2480 {
2481     unsigned long NTStatus;
2482
2483     /* map CM_ERROR_* errors to NT 32-bit status codes */
2484     /* NT Status codes are listed in ntstatus.h not winerror.h */
2485     if (code == CM_ERROR_NOSUCHCELL) {
2486         NTStatus = 0xC000000FL; /* No such file */
2487     }
2488     else if (code == CM_ERROR_NOSUCHVOLUME) {
2489         NTStatus = 0xC000000FL; /* No such file */
2490     }
2491     else if (code == CM_ERROR_TIMEDOUT) {
2492 #ifdef COMMENT
2493         NTStatus = 0xC00000CFL; /* Sharing Paused */
2494 #else
2495         NTStatus = 0x00000102L; /* Timeout */
2496 #endif
2497     }
2498     else if (code == CM_ERROR_RETRY) {
2499         NTStatus = 0xC000022DL; /* Retry */
2500     }
2501     else if (code == CM_ERROR_NOACCESS) {
2502         NTStatus = 0xC0000022L; /* Access denied */
2503     }
2504     else if (code == CM_ERROR_READONLY) {
2505         NTStatus = 0xC00000A2L; /* Write protected */
2506     }
2507     else if (code == CM_ERROR_NOSUCHFILE ||
2508              code == CM_ERROR_BPLUS_NOMATCH) {
2509         NTStatus = 0xC000000FL; /* No such file */
2510     }
2511     else if (code == CM_ERROR_NOSUCHPATH) {
2512         NTStatus = 0xC000003AL; /* Object path not found */
2513     }           
2514     else if (code == CM_ERROR_TOOBIG) {
2515         NTStatus = 0xC000007BL; /* Invalid image format */
2516     }
2517     else if (code == CM_ERROR_INVAL) {
2518         NTStatus = 0xC000000DL; /* Invalid parameter */
2519     }
2520     else if (code == CM_ERROR_BADFD) {
2521         NTStatus = 0xC0000008L; /* Invalid handle */
2522     }
2523     else if (code == CM_ERROR_BADFDOP) {
2524         NTStatus = 0xC0000022L; /* Access denied */
2525     }
2526     else if (code == CM_ERROR_EXISTS) {
2527         NTStatus = 0xC0000035L; /* Object name collision */
2528     }
2529     else if (code == CM_ERROR_NOTEMPTY) {
2530         NTStatus = 0xC0000101L; /* Directory not empty */
2531     }   
2532     else if (code == CM_ERROR_CROSSDEVLINK) {
2533         NTStatus = 0xC00000D4L; /* Not same device */
2534     }
2535     else if (code == CM_ERROR_NOTDIR) {
2536         NTStatus = 0xC0000103L; /* Not a directory */
2537     }
2538     else if (code == CM_ERROR_ISDIR) {
2539         NTStatus = 0xC00000BAL; /* File is a directory */
2540     }
2541     else if (code == CM_ERROR_BADOP) {
2542 #ifdef COMMENT
2543         /* I have no idea where this comes from */
2544         NTStatus = 0xC09820FFL; /* SMB no support */
2545 #else
2546         NTStatus = 0xC00000BBL;     /* Not supported */
2547 #endif /* COMMENT */
2548     }
2549     else if (code == CM_ERROR_BADSHARENAME) {
2550         NTStatus = 0xC00000CCL; /* Bad network name */
2551     }
2552     else if (code == CM_ERROR_NOIPC) {
2553 #ifdef COMMENT
2554         NTStatus = 0xC0000022L; /* Access Denied */
2555 #else   
2556         NTStatus = 0xC000013DL; /* Remote Resources */
2557 #endif
2558     }
2559     else if (code == CM_ERROR_CLOCKSKEW) {
2560         NTStatus = 0xC0000133L; /* Time difference at DC */
2561     }
2562     else if (code == CM_ERROR_BADTID) {
2563         NTStatus = 0xC0982005L; /* SMB bad TID */
2564     }
2565     else if (code == CM_ERROR_USESTD) {
2566         NTStatus = 0xC09820FBL; /* SMB use standard */
2567     }
2568     else if (code == CM_ERROR_QUOTA) {
2569 #ifdef COMMENT
2570         NTStatus = 0xC0000044L; /* Quota exceeded */
2571 #else
2572         NTStatus = 0xC000007FL; /* Disk full */
2573 #endif
2574     }
2575     else if (code == CM_ERROR_SPACE) {
2576         NTStatus = 0xC000007FL; /* Disk full */
2577     }
2578     else if (code == CM_ERROR_ATSYS) {
2579         NTStatus = 0xC0000033L; /* Object name invalid */
2580     }
2581     else if (code == CM_ERROR_BADNTFILENAME) {
2582         NTStatus = 0xC0000033L; /* Object name invalid */
2583     }
2584     else if (code == CM_ERROR_WOULDBLOCK) {
2585         NTStatus = 0xC0000055L; /* Lock not granted */
2586     }
2587     else if (code == CM_ERROR_SHARING_VIOLATION) {
2588         NTStatus = 0xC0000043L; /* Sharing violation */
2589     }
2590     else if (code == CM_ERROR_LOCK_CONFLICT) {
2591         NTStatus = 0xC0000054L; /* Lock conflict */
2592     }
2593     else if (code == CM_ERROR_PARTIALWRITE) {
2594         NTStatus = 0xC000007FL; /* Disk full */
2595     }
2596     else if (code == CM_ERROR_BUFFERTOOSMALL) {
2597         NTStatus = 0xC0000023L; /* Buffer too small */
2598     }
2599     else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2600         NTStatus = 0xC0000035L; /* Object name collision */
2601     }   
2602     else if (code == CM_ERROR_BADPASSWORD) {
2603         NTStatus = 0xC000006DL; /* unknown username or bad password */
2604     }
2605     else if (code == CM_ERROR_BADLOGONTYPE) {
2606         NTStatus = 0xC000015BL; /* logon type not granted */
2607     }
2608     else if (code == CM_ERROR_GSSCONTINUE) {
2609         NTStatus = 0xC0000016L; /* more processing required */
2610     }
2611     else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2612 #ifdef COMMENT
2613         NTStatus = 0xC0000280L; /* reparse point not resolved */
2614 #else
2615         NTStatus = 0xC0000022L; /* Access Denied */
2616 #endif
2617     }
2618     else if (code == CM_ERROR_PATH_NOT_COVERED) {
2619         NTStatus = 0xC0000257L; /* Path Not Covered */
2620     } 
2621 #ifdef COMMENT
2622     else if (code == CM_ERROR_ALLBUSY) {
2623         NTStatus = 0xC00000BFL; /* Network Busy */
2624     } 
2625     else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
2626         NTStatus = 0xC0000350L; /* Remote Host Down */
2627     } 
2628 #else
2629     /* we do not want to be telling the SMB/CIFS client that
2630      * the AFS Client Service is busy or down.  
2631      */
2632     else if (code == CM_ERROR_ALLBUSY || 
2633              code == CM_ERROR_ALLOFFLINE ||
2634              code == CM_ERROR_ALLDOWN) {
2635         NTStatus = 0xC00000BEL; /* Bad Network Path */
2636     }
2637 #endif
2638     else if (code == RXKADUNKNOWNKEY) {
2639         NTStatus = 0xC0000322L; /* Bad Kerberos key */
2640     } 
2641     else if (code == CM_ERROR_BAD_LEVEL) {
2642         NTStatus = 0xC0000148L; /* Invalid Level */
2643     } else {
2644         NTStatus = 0xC0982001L; /* SMB non-specific error */
2645     }
2646
2647     *NTStatusp = NTStatus;
2648     osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2649 }       
2650
2651 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2652                       unsigned char *classp)
2653 {
2654     unsigned char class;
2655     unsigned short error;
2656
2657     /* map CM_ERROR_* errors to SMB errors */
2658     if (code == CM_ERROR_NOSUCHCELL) {
2659         class = 1;
2660         error = 3;      /* bad path */
2661     }
2662     else if (code == CM_ERROR_NOSUCHVOLUME) {
2663         class = 1;
2664         error = 3;      /* bad path */
2665     }
2666     else if (code == CM_ERROR_TIMEDOUT) {
2667         class = 2;
2668         error = 81;     /* server is paused */
2669     }
2670     else if (code == CM_ERROR_RETRY) {
2671         class = 2;      /* shouldn't happen */
2672         error = 1;
2673     }
2674     else if (code == CM_ERROR_NOACCESS) {
2675         class = 2;
2676         error = 4;      /* bad access */
2677     }
2678     else if (code == CM_ERROR_READONLY) {
2679         class = 3;
2680         error = 19;     /* read only */
2681     }
2682     else if (code == CM_ERROR_NOSUCHFILE ||
2683              code == CM_ERROR_BPLUS_NOMATCH) {
2684         class = 1;
2685         error = 2;      /* ENOENT! */
2686     }
2687     else if (code == CM_ERROR_NOSUCHPATH) {
2688         class = 1;
2689         error = 3;      /* Bad path */
2690     }
2691     else if (code == CM_ERROR_TOOBIG) {
2692         class = 1;
2693         error = 11;     /* bad format */
2694     }
2695     else if (code == CM_ERROR_INVAL) {
2696         class = 2;      /* server non-specific error code */
2697         error = 1;
2698     }
2699     else if (code == CM_ERROR_BADFD) {
2700         class = 1;
2701         error = 6;      /* invalid file handle */
2702     }
2703     else if (code == CM_ERROR_BADFDOP) {
2704         class = 1;      /* invalid op on FD */
2705         error = 5;
2706     }
2707     else if (code == CM_ERROR_EXISTS) {
2708         class = 1;
2709         error = 80;     /* file already exists */
2710     }
2711     else if (code == CM_ERROR_NOTEMPTY) {
2712         class = 1;
2713         error = 5;      /* delete directory not empty */
2714     }
2715     else if (code == CM_ERROR_CROSSDEVLINK) {
2716         class = 1;
2717         error = 17;     /* EXDEV */
2718     }
2719     else if (code == CM_ERROR_NOTDIR) {
2720         class = 1;      /* bad path */
2721         error = 3;
2722     }
2723     else if (code == CM_ERROR_ISDIR) {
2724         class = 1;      /* access denied; DOS doesn't have a good match */
2725         error = 5;
2726     }       
2727     else if (code == CM_ERROR_BADOP) {
2728         class = 2;
2729         error = 65535;
2730     }
2731     else if (code == CM_ERROR_BADSHARENAME) {
2732         class = 2;
2733         error = 6;
2734     }
2735     else if (code == CM_ERROR_NOIPC) {
2736         class = 2;
2737         error = 4; /* bad access */
2738     }
2739     else if (code == CM_ERROR_CLOCKSKEW) {
2740         class = 1;      /* invalid function */
2741         error = 1;
2742     }
2743     else if (code == CM_ERROR_BADTID) {
2744         class = 2;
2745         error = 5;
2746     }
2747     else if (code == CM_ERROR_USESTD) {
2748         class = 2;
2749         error = 251;
2750     }
2751     else if (code == CM_ERROR_REMOTECONN) {
2752         class = 2;
2753         error = 82;
2754     }
2755     else if (code == CM_ERROR_QUOTA) {
2756         if (vcp->flags & SMB_VCFLAG_USEV3) {
2757             class = 3;
2758             error = 39; /* disk full */
2759         }
2760         else {
2761             class = 1;
2762             error = 5;  /* access denied */
2763         }
2764     }
2765     else if (code == CM_ERROR_SPACE) {
2766         if (vcp->flags & SMB_VCFLAG_USEV3) {
2767             class = 3;
2768             error = 39; /* disk full */
2769         }
2770         else {
2771             class = 1;
2772             error = 5;  /* access denied */
2773         }
2774     }
2775     else if (code == CM_ERROR_PARTIALWRITE) {
2776         class = 3;
2777         error = 39;     /* disk full */
2778     }
2779     else if (code == CM_ERROR_ATSYS) {
2780         class = 1;
2781         error = 2;      /* ENOENT */
2782     }
2783     else if (code == CM_ERROR_WOULDBLOCK) {
2784         class = 1;
2785         error = 33;     /* lock conflict */
2786     }
2787     else if (code == CM_ERROR_LOCK_CONFLICT) {
2788         class = 1;
2789         error = 33;     /* lock conflict */
2790     }
2791     else if (code == CM_ERROR_SHARING_VIOLATION) {
2792         class = 1;
2793         error = 33;     /* lock conflict */
2794     }
2795     else if (code == CM_ERROR_NOFILES) {
2796         class = 1;
2797         error = 18;     /* no files in search */
2798     }
2799     else if (code == CM_ERROR_RENAME_IDENTICAL) {
2800         class = 1;
2801         error = 183;     /* Samba uses this */
2802     }
2803     else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2804         /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2805         class = 2;
2806         error = 2; /* bad password */
2807     }
2808     else if (code == CM_ERROR_PATH_NOT_COVERED) {
2809         class = 2;
2810         error = 3;     /* bad path */
2811     }
2812     else {
2813         class = 2;
2814         error = 1;
2815     }
2816
2817     *scodep = error;
2818     *classp = class;
2819     osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2820 }       
2821
2822 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2823 {
2824     osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2825     return CM_ERROR_BADOP;
2826 }
2827
2828 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2829 {
2830     unsigned short EchoCount, i;
2831     char *data, *outdata;
2832     int dataSize;
2833
2834     EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2835
2836     for (i=1; i<=EchoCount; i++) {
2837         data = smb_GetSMBData(inp, &dataSize);
2838         smb_SetSMBParm(outp, 0, i);
2839         smb_SetSMBDataLength(outp, dataSize);
2840         outdata = smb_GetSMBData(outp, NULL);
2841         memcpy(outdata, data, dataSize);
2842         smb_SendPacket(vcp, outp);
2843     }
2844
2845     return 0;
2846 }
2847
2848 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2849 {
2850     osi_hyper_t offset;
2851     long count, minCount, finalCount;
2852     unsigned short fd;
2853     unsigned pid;
2854     smb_fid_t *fidp;
2855     long code = 0;
2856     cm_user_t *userp = NULL;
2857     NCB *ncbp;
2858     int rc;
2859     char *rawBuf = NULL;
2860
2861     rawBuf = NULL;
2862     finalCount = 0;
2863
2864     fd = smb_GetSMBParm(inp, 0);
2865     count = smb_GetSMBParm(inp, 3);
2866     minCount = smb_GetSMBParm(inp, 4);
2867     offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2868
2869     if (*inp->wctp == 10) {
2870         /* we were sent a request with 64-bit file offsets */
2871 #ifdef AFS_LARGEFILES
2872         offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
2873
2874         if (LargeIntegerLessThanZero(offset)) {
2875             osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
2876             goto send1;
2877         }
2878 #else
2879         if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
2880             osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset.  Dropping request.");
2881             goto send1;
2882         } else {
2883             offset.HighPart = 0;
2884         }
2885 #endif
2886     } else {
2887         /* we were sent a request with 32-bit file offsets */
2888         offset.HighPart = 0;
2889     }
2890
2891     osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
2892              fd, offset.HighPart, offset.LowPart, count);
2893
2894     fidp = smb_FindFID(vcp, fd, 0);
2895     if (!fidp)
2896         goto send1;
2897
2898     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
2899         smb_CloseFID(vcp, fidp, NULL, 0);
2900         code = CM_ERROR_NOSUCHFILE;
2901         goto send1a;
2902     }
2903
2904
2905     pid = ((smb_t *) inp)->pid;
2906     {
2907         LARGE_INTEGER LOffset, LLength;
2908         cm_key_t key;
2909
2910         key = cm_GenerateKey(vcp->vcID, pid, fd);
2911
2912         LOffset.HighPart = offset.HighPart;
2913         LOffset.LowPart = offset.LowPart;
2914         LLength.HighPart = 0;
2915         LLength.LowPart = count;
2916
2917         lock_ObtainMutex(&fidp->scp->mx);
2918         code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
2919         lock_ReleaseMutex(&fidp->scp->mx);
2920     }    
2921     if (code) {
2922         goto send1a;
2923     }
2924
2925     lock_ObtainMutex(&smb_RawBufLock);
2926     if (smb_RawBufs) {
2927         /* Get a raw buf, from head of list */
2928         rawBuf = smb_RawBufs;
2929         smb_RawBufs = *(char **)smb_RawBufs;
2930     }
2931     lock_ReleaseMutex(&smb_RawBufLock);
2932     if (!rawBuf)
2933         goto send1a;
2934
2935     lock_ObtainMutex(&fidp->mx);
2936     if (fidp->flags & SMB_FID_IOCTL)
2937     {
2938         lock_ReleaseMutex(&fidp->mx);
2939         rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2940         if (rawBuf) {
2941             /* Give back raw buffer */
2942             lock_ObtainMutex(&smb_RawBufLock);
2943             *((char **) rawBuf) = smb_RawBufs;
2944             
2945             smb_RawBufs = rawBuf;
2946             lock_ReleaseMutex(&smb_RawBufLock);
2947         }
2948
2949         smb_ReleaseFID(fidp);
2950         return rc;
2951     }
2952     lock_ReleaseMutex(&fidp->mx);
2953
2954     userp = smb_GetUserFromVCP(vcp, inp);
2955
2956     code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2957
2958     if (code != 0)
2959         goto send;
2960
2961   send:
2962     cm_ReleaseUser(userp);
2963
2964   send1a:
2965     smb_ReleaseFID(fidp);
2966
2967   send1:
2968     ncbp = outp->ncbp;
2969     memset((char *)ncbp, 0, sizeof(NCB));
2970
2971     ncbp->ncb_length = (unsigned short) finalCount;
2972     ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2973     ncbp->ncb_lana_num = vcp->lana;
2974     ncbp->ncb_command = NCBSEND;
2975     ncbp->ncb_buffer = rawBuf;
2976
2977     code = Netbios(ncbp);
2978     if (code != 0)
2979         osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2980
2981     if (rawBuf) {
2982         /* Give back raw buffer */
2983         lock_ObtainMutex(&smb_RawBufLock);
2984         *((char **) rawBuf) = smb_RawBufs;
2985
2986         smb_RawBufs = rawBuf;
2987         lock_ReleaseMutex(&smb_RawBufLock);
2988     }
2989
2990     return 0;
2991 }
2992
2993 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2994 {
2995     osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
2996                          ongoingOps - 1);
2997     return 0;
2998 }
2999
3000 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3001 {
3002     osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3003                          ongoingOps - 1);
3004     return 0;
3005 }
3006
3007 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3008 {
3009     char *namep;
3010     char *datap;
3011     int coreProtoIndex;
3012     int v3ProtoIndex;
3013     int NTProtoIndex;
3014     int VistaProtoIndex;
3015     int protoIndex;                             /* index we're using */
3016     int namex;
3017     int dbytes;
3018     int entryLength;
3019     int tcounter;
3020     char protocol_array[10][1024];  /* protocol signature of the client */
3021     int caps;                       /* capabilities */
3022     time_t unixTime;
3023     afs_uint32 dosTime;
3024     TIME_ZONE_INFORMATION tzi;
3025
3026     osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3027                          ongoingOps - 1);
3028
3029     namep = smb_GetSMBData(inp, &dbytes);
3030     namex = 0;
3031     tcounter = 0;
3032     coreProtoIndex = -1;                /* not found */
3033     v3ProtoIndex = -1;
3034     NTProtoIndex = -1;
3035     VistaProtoIndex = -1;
3036     while(namex < dbytes) {
3037         osi_Log1(smb_logp, "Protocol %s",
3038                   osi_LogSaveString(smb_logp, namep+1));
3039         strcpy(protocol_array[tcounter], namep+1);
3040
3041         /* namep points at the first protocol, or really, a 0x02
3042          * byte preceding the null-terminated ASCII name.
3043          */
3044         if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3045             coreProtoIndex = tcounter;
3046         }       
3047         else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3048             v3ProtoIndex = tcounter;
3049         }
3050         else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3051             NTProtoIndex = tcounter;
3052         }
3053         else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3054             VistaProtoIndex = tcounter;
3055         }
3056
3057         /* compute size of protocol entry */
3058         entryLength = (int)strlen(namep+1);
3059         entryLength += 2;       /* 0x02 bytes and null termination */
3060
3061         /* advance over this protocol entry */
3062         namex += entryLength;
3063         namep += entryLength;
3064         tcounter++;             /* which proto entry we're looking at */
3065     }
3066
3067     lock_ObtainMutex(&vcp->mx);
3068 #if 0
3069     if (VistaProtoIndex != -1) {
3070         protoIndex = VistaProtoIndex;
3071         vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3072     } else 
3073 #endif  
3074         if (NTProtoIndex != -1) {
3075         protoIndex = NTProtoIndex;
3076         vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3077     }
3078     else if (v3ProtoIndex != -1) {
3079         protoIndex = v3ProtoIndex;
3080         vcp->flags |= SMB_VCFLAG_USEV3;
3081     }   
3082     else if (coreProtoIndex != -1) {
3083         protoIndex = coreProtoIndex;
3084         vcp->flags |= SMB_VCFLAG_USECORE;
3085     }   
3086     else protoIndex = -1;
3087     lock_ReleaseMutex(&vcp->mx);
3088
3089     if (protoIndex == -1)
3090         return CM_ERROR_INVAL;
3091     else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3092         smb_SetSMBParm(outp, 0, protoIndex);
3093         if (smb_authType != SMB_AUTH_NONE) {
3094             smb_SetSMBParmByte(outp, 1,
3095                                NEGOTIATE_SECURITY_USER_LEVEL |
3096                                NEGOTIATE_SECURITY_CHALLENGE_RESPONSE);  /* user level security, challenge response */
3097         } else {
3098             smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3099         }
3100         smb_SetSMBParm(outp, 1, smb_maxMpxRequests);    /* max multiplexed requests */
3101         smb_SetSMBParm(outp, 2, smb_maxVCPerServer);    /* max VCs per consumer/server connection */
3102         smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE);    /* xmit buffer size */
3103         smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE);    /* raw buffer size */
3104         /* The session key is not a well documented field however most clients
3105          * will echo back the session key to the server.  Currently we are using
3106          * the same value for all sessions.  We should generate a random value
3107          * and store it into the vcp 
3108          */
3109         smb_SetSMBParm(outp, 7, 1);     /* next 2: session key */
3110         smb_SetSMBParm(outp, 8, 1);
3111         /* 
3112          * Tried changing the capabilities to support for W2K - defect 117695
3113          * Maybe something else needs to be changed here?
3114          */
3115         /*
3116         if (isWindows2000) 
3117         smb_SetSMBParmLong(outp, 9, 0x43fd);
3118         else 
3119         smb_SetSMBParmLong(outp, 9, 0x251);
3120         */
3121         /* Capabilities: *
3122          * 32-bit error codes *
3123          * and NT Find *
3124          * and NT SMB's *
3125          * and raw mode 
3126          * and DFS */
3127         caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3128 #ifdef DFS_SUPPORT
3129                NTNEGOTIATE_CAPABILITY_DFS |
3130 #endif
3131 #ifdef AFS_LARGEFILES
3132                NTNEGOTIATE_CAPABILITY_LARGEFILES |
3133 #endif
3134                NTNEGOTIATE_CAPABILITY_NTFIND |
3135                NTNEGOTIATE_CAPABILITY_RAWMODE |
3136                NTNEGOTIATE_CAPABILITY_NTSMB;
3137
3138         if ( smb_authType == SMB_AUTH_EXTENDED )
3139             caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3140
3141         smb_SetSMBParmLong(outp, 9, caps);
3142         time(&unixTime);
3143         smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3144         smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3145         smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3146
3147         GetTimeZoneInformation(&tzi);
3148         smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias);    /* server tzone */
3149
3150         if (smb_authType == SMB_AUTH_NTLM) {
3151             smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3152             smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3153             /* paste in encryption key */
3154             datap = smb_GetSMBData(outp, NULL);
3155             memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3156             /* and the faux domain name */
3157             strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
3158         } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3159             void * secBlob;
3160             int secBlobLength;
3161
3162             smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3163
3164             smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3165
3166             smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3167                         
3168             datap = smb_GetSMBData(outp, NULL);
3169             memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3170
3171             if (secBlob) {
3172                 datap += sizeof(smb_ServerGUID);
3173                 memcpy(datap, secBlob, secBlobLength);
3174                 free(secBlob);
3175             }
3176         } else {
3177             smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3178             smb_SetSMBDataLength(outp, 0);   /* Perhaps we should specify 8 bytes anyway */
3179         }
3180     }
3181     else if (v3ProtoIndex != -1) {
3182         smb_SetSMBParm(outp, 0, protoIndex);
3183
3184         /* NOTE: Extended authentication cannot be negotiated with v3
3185          * therefore we fail over to NTLM 
3186          */
3187         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3188             smb_SetSMBParm(outp, 1,
3189                            NEGOTIATE_SECURITY_USER_LEVEL |
3190                            NEGOTIATE_SECURITY_CHALLENGE_RESPONSE);      /* user level security, challenge response */
3191         } else {
3192             smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3193         }
3194         smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3195         smb_SetSMBParm(outp, 3, smb_maxMpxRequests);    /* max multiplexed requests */
3196         smb_SetSMBParm(outp, 4, smb_maxVCPerServer);    /* max VCs per consumer/server connection */
3197         smb_SetSMBParm(outp, 5, 0);     /* no support of block mode for read or write */
3198         smb_SetSMBParm(outp, 6, 1);     /* next 2: session key */
3199         smb_SetSMBParm(outp, 7, 1);
3200         time(&unixTime);
3201         smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3202         smb_SetSMBParm(outp, 8, LOWORD(dosTime));       /* server time */
3203         smb_SetSMBParm(outp, 9, HIWORD(dosTime));       /* server date */
3204
3205         GetTimeZoneInformation(&tzi);
3206         smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias);    /* server tzone */
3207
3208         /* NOTE: Extended authentication cannot be negotiated with v3
3209          * therefore we fail over to NTLM 
3210          */
3211         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3212             smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH);  /* encryption key length */
3213             smb_SetSMBParm(outp, 12, 0);        /* resvd */
3214             smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);   /* perhaps should specify 8 bytes anyway */
3215             datap = smb_GetSMBData(outp, NULL);
3216             /* paste in a new encryption key */
3217             memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3218             /* and the faux domain name */
3219             strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
3220         } else {
3221             smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3222             smb_SetSMBParm(outp, 12, 0); /* resvd */
3223             smb_SetSMBDataLength(outp, 0);
3224         }
3225     }
3226     else if (coreProtoIndex != -1) {     /* not really supported anymore */
3227         smb_SetSMBParm(outp, 0, protoIndex);
3228         smb_SetSMBDataLength(outp, 0);
3229     }
3230     return 0;
3231 }
3232
3233 void smb_CheckVCs(void)
3234 {
3235     smb_vc_t * vcp, *nextp;
3236     smb_packet_t * outp = GetPacket();
3237     smb_t *smbp;
3238             
3239     lock_ObtainWrite(&smb_rctLock);
3240     for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp ) 
3241     {
3242         if (vcp->magic != SMB_VC_MAGIC)
3243             osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp", 
3244                        __FILE__, __LINE__);
3245
3246         nextp = vcp->nextp;
3247
3248         if (vcp->flags & SMB_VCFLAG_ALREADYDEAD)
3249             continue;
3250
3251         smb_HoldVCNoLock(vcp);
3252         if (nextp)
3253             smb_HoldVCNoLock(nextp);
3254         smb_FormatResponsePacket(vcp, NULL, outp);
3255         smbp = (smb_t *)outp;
3256         outp->inCom = smbp->com = 0x2b /* Echo */;
3257         smbp->tid = 0xFFFF;
3258         smbp->pid = 0;
3259         smbp->uid = 0;
3260         smbp->mid = 0;
3261         smbp->res[0] = 0;
3262         smbp->res[1] = 0;
3263
3264         smb_SetSMBParm(outp, 0, 0);
3265         smb_SetSMBDataLength(outp, 0);
3266         lock_ReleaseWrite(&smb_rctLock);
3267
3268         smb_SendPacket(vcp, outp);
3269
3270         lock_ObtainWrite(&smb_rctLock);
3271         smb_ReleaseVCNoLock(vcp);
3272         if (nextp)
3273             smb_ReleaseVCNoLock(nextp);
3274     }
3275     lock_ReleaseWrite(&smb_rctLock);
3276     smb_FreePacket(outp);
3277 }
3278
3279 void smb_Daemon(void *parmp)
3280 {
3281     afs_uint32 count = 0;
3282     smb_username_t    **unpp;
3283     time_t              now;
3284
3285     while(smbShutdownFlag == 0) {
3286         count++;
3287         thrd_Sleep(10000);
3288
3289         if (smbShutdownFlag == 1)
3290             break;
3291         
3292         if ((count % 72) == 0)  {       /* every five minutes */
3293             struct tm myTime;
3294             time_t old_localZero = smb_localZero;
3295                  
3296             /* Initialize smb_localZero */
3297             myTime.tm_isdst = -1;               /* compute whether on DST or not */
3298             myTime.tm_year = 70;
3299             myTime.tm_mon = 0;
3300             myTime.tm_mday = 1;
3301             myTime.tm_hour = 0;
3302             myTime.tm_min = 0;
3303             myTime.tm_sec = 0;
3304             smb_localZero = mktime(&myTime);
3305
3306 #ifndef USE_NUMERIC_TIME_CONV
3307             smb_CalculateNowTZ();
3308 #endif /* USE_NUMERIC_TIME_CONV */
3309 #ifdef AFS_FREELANCE
3310             if ( smb_localZero != old_localZero )
3311                 cm_noteLocalMountPointChange();
3312 #endif
3313
3314             smb_CheckVCs();
3315         }
3316
3317         /* GC smb_username_t objects that will no longer be used */
3318         now = osi_Time();
3319         lock_ObtainWrite(&smb_rctLock);
3320         for ( unpp=&usernamesp; *unpp; ) {
3321             int delete = 0;
3322             smb_username_t *unp;
3323
3324             lock_ObtainMutex(&(*unpp)->mx);
3325             if ( (*unpp)->refCount > 0 || 
3326                  ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) || 
3327                  !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
3328                 ;
3329             else if (!smb_LogoffTokenTransfer ||
3330                      ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
3331                 delete = 1;
3332             lock_ReleaseMutex(&(*unpp)->mx);
3333
3334             if (delete) {
3335                 cm_user_t * userp;
3336
3337                 unp = *unpp;    
3338                 *unpp = unp->nextp;
3339                 unp->nextp = NULL;
3340                 lock_FinalizeMutex(&unp->mx);
3341                 userp = unp->userp;
3342                 free(unp->name);
3343                 free(unp->machine);
3344                 free(unp);
3345                 if (userp) {
3346                     lock_ReleaseWrite(&smb_rctLock);
3347                     cm_ReleaseUser(userp);
3348                     lock_ObtainWrite(&smb_rctLock);
3349                 }
3350             } else {
3351                 unpp = &(*unpp)->nextp;
3352             }
3353         }
3354         lock_ReleaseWrite(&smb_rctLock);
3355
3356         /* XXX GC dir search entries */
3357     }
3358 }
3359
3360 void smb_WaitingLocksDaemon()
3361 {
3362     smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3363     smb_waitingLock_t *wl, *wlNext;
3364     int first;
3365     smb_vc_t *vcp;
3366     smb_packet_t *inp, *outp;
3367     NCB *ncbp;
3368     long code = 0;
3369
3370     while (smbShutdownFlag == 0) {
3371         lock_ObtainWrite(&smb_globalLock);
3372         nwlRequest = smb_allWaitingLocks;
3373         if (nwlRequest == NULL) {
3374             osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
3375             thrd_Sleep(1000);
3376             continue;
3377         } else {
3378             first = 1;
3379             osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
3380         }
3381
3382         do {
3383             if (first)
3384                 first = 0;
3385             else
3386                 lock_ObtainWrite(&smb_globalLock);
3387
3388             osi_Log1(smb_logp, "    Checking waiting lock request %p", nwlRequest);
3389
3390             wlRequest = nwlRequest;
3391             nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3392             lock_ReleaseWrite(&smb_globalLock);
3393
3394             code = 0;
3395
3396             for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3397                 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3398                     continue;
3399
3400                 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
3401                 
3402                 /* wl->state is either _DONE or _WAITING.  _ERROR
3403                    would no longer be on the queue. */
3404                 code = cm_RetryLock( wl->lockp,
3405                                      !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3406
3407                 if (code == 0) {
3408                     wl->state = SMB_WAITINGLOCKSTATE_DONE;
3409                 } else if (code != CM_ERROR_WOULDBLOCK) {
3410                     wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3411                     break;
3412                 }
3413             }
3414
3415             if (code == CM_ERROR_WOULDBLOCK) {
3416
3417                 /* no progress */
3418                 if (wlRequest->timeRemaining != 0xffffffff
3419                      && (wlRequest->timeRemaining -= 1000) < 0)
3420                     goto endWait;
3421
3422                 continue;
3423             }
3424
3425           endWait:
3426
3427             if (code != 0) {
3428                 cm_scache_t * scp;
3429                 cm_req_t req;
3430
3431                 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
3432                          wlRequest);
3433
3434                 scp = wlRequest->scp;
3435                 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
3436
3437                 cm_InitReq(&req);
3438
3439                 lock_ObtainMutex(&scp->mx);
3440
3441                 for (wl = wlRequest->locks; wl; wl = wlNext) {
3442                     wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3443                     
3444                     cm_Unlock(scp, wlRequest->lockType, wl->LOffset, 
3445                               wl->LLength, wl->key, NULL, &req);
3446
3447                     osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3448
3449                     free(wl);
3450                 }
3451                 
3452                 lock_ReleaseMutex(&scp->mx);
3453
3454             } else {
3455
3456                 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
3457                          wlRequest);
3458
3459                 for (wl = wlRequest->locks; wl; wl = wlNext) {
3460                     wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3461                     osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3462                     free(wl);
3463                 }
3464             }
3465
3466             vcp = wlRequest->vcp;
3467             inp = wlRequest->inp;
3468             outp = wlRequest->outp;
3469             ncbp = GetNCB();
3470             ncbp->ncb_length = inp->ncb_length;
3471             inp->spacep = cm_GetSpace();
3472
3473             /* Remove waitingLock from list */
3474             lock_ObtainWrite(&smb_globalLock);
3475             osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3476                          &wlRequest->q);
3477             lock_ReleaseWrite(&smb_globalLock);
3478
3479             /* Resume packet processing */
3480             if (code == 0)
3481                 smb_SetSMBDataLength(outp, 0);
3482             outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3483             outp->resumeCode = code;
3484             outp->ncbp = ncbp;
3485             smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3486
3487             /* Clean up */
3488             cm_FreeSpace(inp->spacep);
3489             smb_FreePacket(inp);
3490             smb_FreePacket(outp);
3491             smb_ReleaseVC(vcp);
3492             cm_ReleaseSCache(wlRequest->scp);
3493             FreeNCB(ncbp);
3494             free(wlRequest);
3495         } while (nwlRequest && smbShutdownFlag == 0);
3496         thrd_Sleep(1000);
3497     }
3498 }
3499
3500 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3501 {
3502     osi_Log0(smb_logp, "SMB receive get disk attributes");
3503
3504     smb_SetSMBParm(outp, 0, 32000);
3505     smb_SetSMBParm(outp, 1, 64);
3506     smb_SetSMBParm(outp, 2, 1024);
3507     smb_SetSMBParm(outp, 3, 30000);
3508     smb_SetSMBParm(outp, 4, 0);
3509     smb_SetSMBDataLength(outp, 0);
3510     return 0;
3511 }
3512
3513 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3514 {
3515     smb_tid_t *tidp;
3516     smb_user_t *uidp;
3517     unsigned short newTid;
3518     char shareName[AFSPATHMAX];
3519     char *sharePath;
3520     int shareFound;
3521     char *tp;
3522     char *pathp;
3523     char *passwordp;
3524     cm_user_t *userp;
3525
3526     osi_Log0(smb_logp, "SMB receive tree connect");
3527
3528     /* parse input parameters */
3529     tp = smb_GetSMBData(inp, NULL);
3530     pathp = smb_ParseASCIIBlock(tp, &tp);
3531     if (smb_StoreAnsiFilenames)
3532         OemToChar(pathp,pathp);
3533     passwordp = smb_ParseASCIIBlock(tp, &tp);
3534     tp = strrchr(pathp, '\\');
3535     if (!tp)
3536         return CM_ERROR_BADSMB;
3537     strcpy(shareName, tp+1);
3538
3539     lock_ObtainMutex(&vcp->mx);
3540     newTid = vcp->tidCounter++;
3541     lock_ReleaseMutex(&vcp->mx);
3542
3543     tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3544     uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3545     userp = smb_GetUserFromUID(uidp);
3546     shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3547     if (uidp)
3548         smb_ReleaseUID(uidp);
3549     if (!shareFound) {
3550         smb_ReleaseTID(tidp);
3551         return CM_ERROR_BADSHARENAME;
3552     }
3553     lock_ObtainMutex(&tidp->mx);
3554     tidp->userp = userp;
3555     tidp->pathname = sharePath;
3556     lock_ReleaseMutex(&tidp->mx);
3557     smb_ReleaseTID(tidp);
3558
3559     smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3560     smb_SetSMBParm(rsp, 1, newTid);
3561     smb_SetSMBDataLength(rsp, 0);
3562
3563     osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3564     return 0;
3565 }
3566
3567 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3568 {
3569     int tlen;
3570
3571     if (*inp++ != 0x1) return NULL;
3572     tlen = inp[0] + (inp[1]<<8);
3573     inp += 2;           /* skip length field */
3574         
3575     if (chainpp) {
3576         *chainpp = inp + tlen;
3577     }   
3578
3579     if (lengthp) *lengthp = tlen;
3580         
3581     return inp;
3582 }
3583
3584 /* set maskp to the mask part of the incoming path.
3585  * Mask is 11 bytes long (8.3 with the dot elided).
3586  * Returns true if succeeds with a valid name, otherwise it does
3587  * its best, but returns false.
3588  */
3589 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3590 {
3591     char *tp;
3592     char *up;
3593     int i;
3594     int tc;
3595     int valid8Dot3;
3596
3597     /* starts off valid */
3598     valid8Dot3 = 1;
3599
3600     /* mask starts out all blanks */
3601     memset(maskp, ' ', 11);
3602
3603     /* find last backslash, or use whole thing if there is none */
3604     tp = strrchr(pathp, '\\');
3605     if (!tp) tp = pathp;
3606     else tp++;  /* skip slash */
3607         
3608     up = maskp;
3609
3610     /* names starting with a dot are illegal */
3611     if (*tp == '.') valid8Dot3 = 0;
3612
3613     for(i=0;; i++) {
3614         tc = *tp++;
3615         if (tc == 0) return valid8Dot3;
3616         if (tc == '.' || tc == '"') break;
3617         if (i < 8) *up++ = tc;
3618         else valid8Dot3 = 0;
3619     }
3620         
3621     /* if we get here, tp point after the dot */
3622     up = maskp+8;       /* ext goes here */
3623     for(i=0;;i++) {
3624         tc = *tp++;
3625         if (tc == 0) 
3626             return valid8Dot3;
3627
3628         /* too many dots */
3629         if (tc == '.' || tc == '"') 
3630             valid8Dot3 = 0;
3631
3632         /* copy extension if not too long */
3633         if (i < 3) 
3634             *up++ = tc;
3635         else 
3636             valid8Dot3 = 0;
3637     }   
3638
3639     /* unreachable */
3640 }
3641
3642 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3643 {
3644     char umask[11];
3645     int valid;
3646     int i;
3647     char tc1;
3648     char tc2;
3649     char *tp1;
3650     char *tp2;
3651
3652     /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3653
3654     valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3655     if (!valid) 
3656         return 0;
3657  
3658     /* otherwise, we have a valid 8.3 name; see if we have a match,
3659      * treating '?' as a wildcard in maskp (but not in the file name).
3660      */
3661     tp1 = umask;        /* real name, in mask format */
3662     tp2 = maskp;        /* mask, in mask format */
3663     for(i=0; i<11; i++) {
3664         tc1 = *tp1++;   /* char from real name */
3665         tc2 = *tp2++;   /* char from mask */
3666         tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3667         tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3668         if (tc1 == tc2) 
3669             continue;
3670         if (tc2 == '?' && tc1 != ' ') 
3671             continue;
3672         if (tc2 == '>') 
3673             continue;
3674         return 0;
3675     }
3676
3677     /* we got a match */
3678     return 1;
3679 }
3680
3681 char *smb_FindMask(char *pathp)
3682 {
3683     char *tp;
3684         
3685     tp = strrchr(pathp, '\\');  /* find last slash */
3686
3687     if (tp) 
3688         return tp+1;    /* skip the slash */
3689     else 
3690         return pathp;   /* no slash, return the entire path */
3691 }       
3692
3693 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3694 {
3695     unsigned char *pathp;
3696     unsigned char *tp;
3697     unsigned char mask[11];
3698     unsigned char *statBlockp;
3699     unsigned char initStatBlock[21];
3700     int statLen;
3701         
3702     osi_Log0(smb_logp, "SMB receive search volume");
3703
3704     /* pull pathname and stat block out of request */
3705     tp = smb_GetSMBData(inp, NULL);
3706     pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3707     osi_assertx(pathp != NULL, "null path");
3708     if (smb_StoreAnsiFilenames)
3709         OemToChar(pathp,pathp);
3710     statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3711     osi_assertx(statBlockp != NULL, "null statBlock");
3712     if (statLen == 0) {
3713         statBlockp = initStatBlock;
3714         statBlockp[0] = 8;
3715     }
3716         
3717     /* for returning to caller */
3718     smb_Get8Dot3MaskFromPath(mask, pathp);
3719
3720     smb_SetSMBParm(outp, 0, 1);         /* we're returning one entry */
3721     tp = smb_GetSMBData(outp, NULL);
3722     *tp++ = 5;
3723     *tp++ = 43; /* bytes in a dir entry */
3724     *tp++ = 0;  /* high byte in counter */
3725
3726     /* now marshall the dir entry, starting with the search status */
3727     *tp++ = statBlockp[0];              /* Reserved */
3728     memcpy(tp, mask, 11); tp += 11;     /* FileName */
3729
3730     /* now pass back server use info, with 1st byte non-zero */
3731     *tp++ = 1;