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