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