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