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