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