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