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