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