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