e7151ae10a6ec629d4ca173b7704e87b6671a756
[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 & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
486         attrs |= SMB_ATTR_READONLY;     /* turn on read-only flag */
487 #else
488     if ((scp->unixModeBits & 0222) == 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 && !(flags & SMB_FLAG_CREATE))
1422         return NULL;
1423
1424     lock_ObtainWrite(&smb_rctLock);
1425     /* figure out if we need to allocate a new file ID */
1426     if (fid == 0) {
1427         newFid = 1;
1428         fid = vcp->fidCounter;
1429     }
1430
1431   retry:
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             goto retry;
1439         }
1440         if (fid == fidp->fid) {
1441             if (newFid) {
1442                 fid++;
1443                 if (fid == 0xFFFF) {
1444                     osi_Log1(smb_logp,
1445                              "New FID number wraps on vcp 0x%x", vcp);
1446                     fid = 1;
1447                 }
1448                 goto retry;
1449             }
1450             fidp->refCount++;
1451             break;
1452         }
1453     }
1454
1455     if (!fidp && (flags & SMB_FLAG_CREATE)) {
1456         char eventName[MAX_PATH];
1457         EVENT_HANDLE event;
1458         sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1459         event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1460         if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1461             osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1462             thrd_CloseHandle(event);
1463             fid++;
1464             if (fid == 0xFFFF) {
1465                 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1466                 fid = 1;
1467             }
1468             goto retry;
1469         }
1470
1471         fidp = malloc(sizeof(*fidp));
1472         memset(fidp, 0, sizeof(*fidp));
1473         osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1474         fidp->refCount = 1;
1475         fidp->vcp = vcp;
1476         smb_HoldVCNoLock(vcp);
1477         lock_InitializeMutex(&fidp->mx, "fid_t mutex", LOCK_HIERARCHY_SMB_FID);
1478         fidp->fid = fid;
1479         fidp->curr_chunk = fidp->prev_chunk = -2;
1480         fidp->raw_write_event = event;
1481         if (newFid) {
1482             vcp->fidCounter = fid+1;
1483             if (vcp->fidCounter == 0xFFFF) {
1484                 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1485                          vcp);
1486                 vcp->fidCounter = 1;
1487             }
1488         }
1489     }
1490
1491 #ifdef DEBUG_SMB_REFCOUNT
1492     if (fidp) {
1493         afsi_log("%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1494         osi_Log4(smb_logp,"%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1495     }
1496 #endif
1497     lock_ReleaseWrite(&smb_rctLock);
1498     return fidp;
1499 }
1500
1501
1502 /* Must not be called with scp->rw held because smb_ReleaseFID might be called */
1503 #ifdef DEBUG_SMB_REFCOUNT
1504 smb_fid_t *smb_FindFIDByScacheDbg(smb_vc_t *vcp, cm_scache_t * scp, char *file, long line)
1505 #else
1506 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1507 #endif
1508 {
1509     smb_fid_t *fidp = NULL, *nextp = NULL;
1510         
1511     if (!scp)
1512         return NULL;
1513
1514     /* 
1515      * If the fidp->scp changes out from under us then
1516      * we must not grab a refCount.  It means the *fidp
1517      * was processed by smb_CloseFID() and the *fidp is 
1518      * no longer valid for use.
1519      */
1520     lock_ObtainWrite(&smb_rctLock);
1521         for(fidp = vcp->fidsp, (fidp ? fidp->refCount++ : 0); fidp; fidp = nextp, nextp = NULL) {
1522         nextp = (smb_fid_t *) osi_QNext(&fidp->q);
1523         if (nextp)
1524             nextp->refCount++;
1525
1526         if (scp == fidp->scp) {
1527             lock_ReleaseWrite(&smb_rctLock);
1528             lock_ObtainMutex(&fidp->mx);
1529             lock_ObtainWrite(&smb_rctLock);
1530             if (scp == fidp->scp) {
1531                 lock_ReleaseMutex(&fidp->mx);
1532                 break;
1533             }
1534             lock_ReleaseMutex(&fidp->mx);
1535         }
1536
1537         if (fidp->refCount > 1) {
1538             fidp->refCount--;
1539         } else {
1540             lock_ReleaseWrite(&smb_rctLock);
1541             smb_ReleaseFID(fidp);
1542             lock_ObtainWrite(&smb_rctLock);
1543         }
1544     }
1545
1546     if (nextp) {
1547         if (nextp->refCount > 1) {
1548             nextp->refCount--;
1549         } else {
1550             lock_ReleaseWrite(&smb_rctLock);
1551             smb_ReleaseFID(nextp);
1552             lock_ObtainWrite(&smb_rctLock);
1553         }
1554     }
1555
1556 #ifdef DEBUG_SMB_REFCOUNT
1557     if (fidp) {
1558         afsi_log("%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1559         osi_Log4(smb_logp,"%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1560       }
1561 #endif
1562     lock_ReleaseWrite(&smb_rctLock);
1563     return (fidp);
1564 }
1565
1566 #ifdef DEBUG_SMB_REFCOUNT
1567 void smb_HoldFIDNoLockDbg(smb_fid_t *fidp, char *file, long line)
1568 #else
1569 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1570 #endif
1571 {
1572     lock_AssertWrite(&smb_rctLock);
1573     fidp->refCount++;
1574 #ifdef DEBUG_SMB_REFCOUNT
1575     afsi_log("%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1576     osi_Log4(smb_logp,"%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1577 #endif
1578 }
1579
1580
1581 /* smb_ReleaseFID cannot be called while a cm_scache_t rwlock is held */
1582 /* the smb_fid_t->mx and smb_rctLock must not be held */
1583 #ifdef DEBUG_SMB_REFCOUNT
1584 void smb_ReleaseFIDDbg(smb_fid_t *fidp, char *file, long line)
1585 #else
1586 void smb_ReleaseFID(smb_fid_t *fidp)
1587 #endif
1588 {
1589     cm_scache_t *scp = NULL;
1590     cm_user_t *userp = NULL;
1591     smb_vc_t *vcp = NULL;
1592     smb_ioctl_t *ioctlp;
1593
1594     lock_ObtainMutex(&fidp->mx);
1595     lock_ObtainWrite(&smb_rctLock);
1596     osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
1597 #ifdef DEBUG_SMB_REFCOUNT
1598     afsi_log("%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1599     osi_Log5(smb_logp,"%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1600 #endif
1601     if (fidp->refCount == 0) {
1602         if (fidp->deleteOk) {
1603             vcp = fidp->vcp;
1604             fidp->vcp = NULL;
1605             scp = fidp->scp;    /* release after lock is released */
1606             if (scp) {
1607                 lock_ObtainWrite(&scp->rw);
1608                 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1609                 lock_ReleaseWrite(&scp->rw);
1610                 osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1611                 fidp->scp = NULL;
1612             }
1613             userp = fidp->userp;
1614             fidp->userp = NULL;
1615
1616             if (vcp->fidsp) 
1617                 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1618             thrd_CloseHandle(fidp->raw_write_event);
1619
1620             /* and see if there is ioctl stuff to free */
1621             ioctlp = fidp->ioctlp;
1622             if (ioctlp) {
1623                 if (ioctlp->prefix)
1624                 cm_FreeSpace(ioctlp->prefix);
1625                 if (ioctlp->ioctl.inAllocp)
1626                     free(ioctlp->ioctl.inAllocp);
1627                 if (ioctlp->ioctl.outAllocp)
1628                     free(ioctlp->ioctl.outAllocp);
1629                 free(ioctlp);
1630             }
1631
1632             smb_CleanupRPCFid(fidp);
1633
1634             lock_ReleaseMutex(&fidp->mx);
1635             lock_FinalizeMutex(&fidp->mx);
1636             free(fidp);
1637             fidp = NULL;
1638
1639             if (vcp)
1640                 smb_ReleaseVCNoLock(vcp);
1641         }
1642     }
1643     if (fidp)
1644         lock_ReleaseMutex(&fidp->mx);
1645
1646     lock_ReleaseWrite(&smb_rctLock);
1647
1648     /* now release the scache structure */
1649     if (scp) 
1650         cm_ReleaseSCache(scp);
1651
1652     if (userp)
1653         cm_ReleaseUser(userp);
1654 }       
1655
1656 /*
1657  * Case-insensitive search for one string in another;
1658  * used to find variable names in submount pathnames.
1659  */
1660 static clientchar_t *smb_stristr(clientchar_t *str1, clientchar_t *str2)
1661 {
1662     clientchar_t *cursor;
1663
1664     for (cursor = str1; *cursor; cursor++)
1665         if (cm_ClientStrCmpI(cursor, str2) == 0)
1666             return cursor;
1667
1668     return NULL;
1669 }
1670
1671 /*
1672  * Substitute a variable value for its name in a submount pathname.  Variable
1673  * name has been identified by smb_stristr() and is in substr.  Variable name
1674  * length (plus one) is in substr_size.  Variable value is in newstr.
1675  */
1676 static void smb_subst(clientchar_t *str1, int cchstr1, clientchar_t *substr,
1677                       unsigned int substr_size, clientchar_t *newstr)
1678 {
1679     clientchar_t temp[1024];
1680
1681     cm_ClientStrCpy(temp, lengthof(temp), substr + substr_size - 1);
1682     cm_ClientStrCpy(substr, cchstr1 - (substr - str1), newstr);
1683     cm_ClientStrCat(str1, cchstr1, temp);
1684 }
1685
1686 clientchar_t VNUserName[] = _C("%USERNAME%");
1687 clientchar_t VNLCUserName[] = _C("%LCUSERNAME%");
1688 clientchar_t VNComputerName[] = _C("%COMPUTERNAME%");
1689 clientchar_t VNLCComputerName[] = _C("%LCCOMPUTERNAME%");
1690
1691 typedef struct smb_findShare_rock {
1692     clientchar_t * shareName;
1693     clientchar_t * match;
1694     int matchType;
1695 } smb_findShare_rock_t;
1696
1697 #define SMB_FINDSHARE_EXACT_MATCH 1
1698 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1699
1700 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1701                        osi_hyper_t *offp)
1702 {
1703     int matchType = 0;
1704     smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1705     normchar_t normName[MAX_PATH];
1706
1707     if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(normName[0])) == 0) {
1708         osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
1709                  osi_LogSaveString(smb_logp, dep->name));
1710         return 0;
1711     }
1712
1713     if (!cm_ClientStrCmpNI(normName, vrock->shareName, 12)) {
1714         if(!cm_ClientStrCmpI(normName, vrock->shareName))
1715             matchType = SMB_FINDSHARE_EXACT_MATCH;
1716         else
1717             matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1718         if(vrock->match) 
1719             free(vrock->match);
1720         vrock->match = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
1721         vrock->matchType = matchType;
1722
1723         if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1724             return CM_ERROR_STOPNOW;
1725     }
1726     return 0;
1727 }
1728
1729
1730 /* find a shareName in the table of submounts */
1731 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp,
1732                   clientchar_t *shareName,
1733                   clientchar_t **pathNamep)
1734 {
1735     DWORD cblen;
1736     DWORD cchlen;
1737     clientchar_t pathName[1024];
1738     clientchar_t *var;
1739     DWORD sizeTemp;
1740     clientchar_t *p, *q;
1741     fschar_t *cellname = NULL;
1742     HKEY parmKey;
1743     DWORD code;
1744     DWORD allSubmount = 1;
1745
1746     /* if allSubmounts == 0, only return the //mountRoot/all share 
1747      * if in fact it has been been created in the subMounts table.  
1748      * This is to allow sites that want to restrict access to the 
1749      * world to do so.
1750      */
1751     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1752                         0, KEY_QUERY_VALUE, &parmKey);
1753     if (code == ERROR_SUCCESS) {
1754         cblen = sizeof(allSubmount);
1755         code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1756                                (BYTE *) &allSubmount, &cblen);
1757         if (code != ERROR_SUCCESS) {
1758             allSubmount = 1;
1759         }
1760         RegCloseKey (parmKey);
1761     }
1762
1763     if (allSubmount && cm_ClientStrCmpI(shareName, _C("all")) == 0) {
1764         *pathNamep = NULL;
1765         return 1;
1766     }
1767
1768     /* In case, the all share is disabled we need to still be able
1769      * to handle ioctl requests 
1770      */
1771     if (cm_ClientStrCmpI(shareName, _C("ioctl$")) == 0) {
1772         *pathNamep = cm_ClientStrDup(_C("/.__ioctl__"));
1773         return 1;
1774     }
1775
1776     if (MSRPC_IsWellKnownService(shareName) ||
1777         cm_ClientStrCmpIA(shareName, _C(SMB_IOCTL_FILENAME_NOSLASH)) == 0 ||
1778         cm_ClientStrCmpIA(shareName, _C("DESKTOP.INI")) == 0
1779         ) {
1780         *pathNamep = NULL;
1781         return 0;
1782     }
1783
1784     /* Check for volume references
1785      * 
1786      * They look like <cell>{%,#}<volume>
1787      */
1788     if (cm_ClientStrChr(shareName, '%') != NULL ||
1789         cm_ClientStrChr(shareName, '#') != NULL) {
1790         clientchar_t pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
1791         /* make room for '/@vol:' + mountchar + NULL terminator*/
1792
1793         osi_Log1(smb_logp, "smb_FindShare found volume reference [%S]",
1794                  osi_LogSaveClientString(smb_logp, shareName));
1795
1796         cm_ClientStrPrintfN(pathstr, lengthof(pathstr),
1797                             _C("/") _C(CM_PREFIX_VOL) _C("%s"), shareName);
1798         cchlen = (DWORD)(cm_ClientStrLen(pathstr) + 1);
1799
1800         *pathNamep = malloc(cchlen * sizeof(clientchar_t));
1801         if (*pathNamep) {
1802             cm_ClientStrCpy(*pathNamep, cchlen, pathstr);
1803             cm_ClientStrLwr(*pathNamep);
1804             osi_Log1(smb_logp, "   returning pathname [%S]",
1805                      osi_LogSaveClientString(smb_logp, *pathNamep));
1806
1807             return 1;
1808         } else {
1809             return 0;
1810         }
1811     }
1812
1813     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1814                         0, KEY_QUERY_VALUE, &parmKey);
1815     if (code == ERROR_SUCCESS) {
1816         cblen = sizeof(pathName);
1817         code = RegQueryValueExW(parmKey, shareName, NULL, NULL,
1818                                 (BYTE *) pathName, &cblen);
1819         if (code != ERROR_SUCCESS)
1820             cblen = 0;
1821         RegCloseKey (parmKey);
1822     } else {
1823         cblen = 0;
1824     }
1825     cchlen = cblen / sizeof(clientchar_t);
1826     if (cchlen != 0 && cchlen != lengthof(pathName) - 1) {
1827         /* We can accept either unix or PC style AFS pathnames.  Convert
1828          * Unix-style to PC style here for internal use. 
1829          */
1830         p = pathName;
1831         cchlen = lengthof(pathName);
1832
1833         /* within this code block, we maintain, cchlen = writeable
1834            buffer length of p */
1835
1836         if (cm_ClientStrCmpN(p, cm_mountRootC, cm_mountRootCLen) == 0) {
1837             p += cm_mountRootCLen;  /* skip mount path */
1838             cchlen -= (DWORD)(p - pathName);
1839         }
1840
1841         q = p;
1842         while (*q) {
1843             if (*q == _C('/')) *q = _C('\\');    /* change to \ */
1844             q++;
1845         }
1846
1847         while (1)
1848         {
1849             clientchar_t temp[1024];
1850
1851             if (var = smb_stristr(p, VNUserName)) {
1852                 if (uidp && uidp->unp)
1853                     smb_subst(p, cchlen, var, lengthof(VNUserName),uidp->unp->name);
1854                 else
1855                     smb_subst(p, cchlen, var, lengthof(VNUserName), _C(" "));
1856             }
1857             else if (var = smb_stristr(p, VNLCUserName)) 
1858             {
1859                 if (uidp && uidp->unp)
1860                     cm_ClientStrCpy(temp, lengthof(temp), uidp->unp->name);
1861                 else 
1862                     cm_ClientStrCpy(temp, lengthof(temp), _C(" "));
1863                 cm_ClientStrLwr(temp);
1864                 smb_subst(p, cchlen, var, lengthof(VNLCUserName), temp);
1865             }
1866             else if (var = smb_stristr(p, VNComputerName)) 
1867             {
1868                 sizeTemp = lengthof(temp);
1869                 GetComputerNameW(temp, &sizeTemp);
1870                 smb_subst(p, cchlen, var, lengthof(VNComputerName), temp);
1871             }
1872             else if (var = smb_stristr(p, VNLCComputerName)) 
1873             {
1874                 sizeTemp = lengthof(temp);
1875                 GetComputerName((LPTSTR)temp, &sizeTemp);
1876                 cm_ClientStrLwr(temp);
1877                 smb_subst(p, cchlen, var, lengthof(VNLCComputerName), temp);
1878             }
1879             else     
1880                 break;
1881         }
1882         *pathNamep = cm_ClientStrDup(p);
1883         return 1;
1884     } 
1885     else
1886     {
1887         /* First lookup shareName in root.afs */
1888         cm_req_t req;
1889         smb_findShare_rock_t vrock;
1890         osi_hyper_t thyper;
1891         fschar_t ftemp[1024];
1892         clientchar_t * p = shareName; 
1893         int rw = 0;
1894
1895         /*  attempt to locate a partial match in root.afs.  This is because
1896             when using the ANSI RAP calls, the share name is limited to 13 chars
1897             and hence is truncated. Of course we prefer exact matches. */
1898         smb_InitReq(&req);
1899         thyper.HighPart = 0;
1900         thyper.LowPart = 0;
1901
1902         vrock.shareName = cm_ClientStringToNormStringAlloc(shareName, -1, NULL);
1903         if (vrock.shareName == NULL) 
1904             return 0;
1905         vrock.match = NULL;
1906         vrock.matchType = 0;
1907
1908         cm_HoldSCache(cm_data.rootSCachep);
1909         code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1910                            (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1911         cm_ReleaseSCache(cm_data.rootSCachep);
1912
1913         free(vrock.shareName);
1914         vrock.shareName = NULL;
1915
1916         if (vrock.matchType) {
1917             cm_ClientStrPrintfN(pathName, lengthof(pathName), _C("/%s/"), vrock.match);
1918             *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
1919             free(vrock.match);
1920             return 1;
1921         }
1922
1923         /* if we get here, there was no match for the share in root.afs */
1924         /* so try to create  \\<netbiosName>\<cellname>  */
1925         if ( *p == '.' ) {
1926             p++;
1927             rw = 1;
1928         }
1929         /* Get the full name for this cell */
1930         cellname = cm_ClientStringToFsStringAlloc(p, -1, NULL);
1931         code = cm_SearchCellRegistry(1, cellname, ftemp, 0, 0, 0);
1932         if (code && code != CM_ERROR_FORCE_DNS_LOOKUP)
1933             code = cm_SearchCellFile(cellname, ftemp, 0, 0);
1934 #ifdef AFS_AFSDB_ENV
1935         if (code && cm_dnsEnabled) {
1936             int ttl;
1937             code = cm_SearchCellByDNS(cellname, ftemp, &ttl, 0, 0);
1938         }
1939 #endif
1940         if (cellname)
1941             free(cellname);
1942
1943         /* construct the path */
1944         if (code == 0) {
1945             clientchar_t temp[1024];
1946
1947             if (cm_FsStringToClientString(ftemp, -1, temp, 1024) != 0) {
1948             cm_ClientStrPrintfN(pathName, (int)lengthof(pathName),
1949                                 rw ? _C("/.%S/") : _C("/%S/"), temp);
1950             *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
1951             return 1;
1952         }
1953     }
1954     }
1955     /* failure */
1956     *pathNamep = NULL;
1957     return 0;
1958 }
1959
1960 /* Client-side offline caching policy types */
1961 #define CSC_POLICY_MANUAL 0
1962 #define CSC_POLICY_DOCUMENTS 1
1963 #define CSC_POLICY_PROGRAMS 2
1964 #define CSC_POLICY_DISABLE 3
1965
1966 int smb_FindShareCSCPolicy(clientchar_t *shareName)
1967 {
1968     DWORD len;
1969     clientchar_t policy[1024];
1970     DWORD dwType;
1971     HKEY hkCSCPolicy;
1972     int  retval = CSC_POLICY_MANUAL;
1973
1974     RegCreateKeyEx( HKEY_LOCAL_MACHINE, 
1975                     AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1976                     0, 
1977                     "AFS", 
1978                     REG_OPTION_NON_VOLATILE,
1979                     KEY_READ,
1980                     NULL, 
1981                     &hkCSCPolicy,
1982                     NULL );
1983
1984     len = sizeof(policy);
1985     if ( RegQueryValueExW( hkCSCPolicy, shareName, 0, &dwType, (LPBYTE) policy, &len ) ||
1986          len == 0) {
1987         retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1988     }
1989     else if (cm_ClientStrCmpIA(policy, _C("documents")) == 0)
1990     {
1991         retval = CSC_POLICY_DOCUMENTS;
1992     }
1993     else if (cm_ClientStrCmpIA(policy, _C("programs")) == 0)
1994     {
1995         retval = CSC_POLICY_PROGRAMS;
1996     }
1997     else if (cm_ClientStrCmpIA(policy, _C("disable")) == 0)
1998     {
1999         retval = CSC_POLICY_DISABLE;
2000     }
2001         
2002     RegCloseKey(hkCSCPolicy);
2003     return retval;
2004 }
2005
2006 /* find a dir search structure by cookie value, and return it held.
2007  * Must be called with smb_globalLock held.
2008  */
2009 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
2010 {
2011     smb_dirSearch_t *dsp;
2012         
2013     for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2014         if (dsp->cookie == cookie) {
2015             if (dsp != smb_firstDirSearchp) {
2016                 /* move to head of LRU queue, too, if we're not already there */
2017                 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
2018                     smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2019                 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2020                 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2021                 if (!smb_lastDirSearchp)
2022                     smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2023             }
2024             dsp->refCount++;
2025             break;
2026         }
2027     }
2028
2029     if (dsp == NULL) {
2030         osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
2031         for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2032             osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
2033         }
2034     }
2035     return dsp;
2036 }       
2037
2038 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
2039 {
2040     lock_ObtainMutex(&dsp->mx);
2041     osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p", 
2042               dsp->cookie, dsp, dsp->scp);
2043     dsp->flags |= SMB_DIRSEARCH_DELETE;
2044     if (dsp->scp != NULL) {
2045         lock_ObtainWrite(&dsp->scp->rw);
2046         if (dsp->flags & SMB_DIRSEARCH_BULKST) {
2047             dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2048             dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2049             dsp->scp->bulkStatProgress = hzero;
2050         }       
2051         lock_ReleaseWrite(&dsp->scp->rw);
2052     }   
2053     lock_ReleaseMutex(&dsp->mx);
2054 }               
2055
2056 /* Must be called with the smb_globalLock held */
2057 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
2058 {
2059     cm_scache_t *scp = NULL;
2060
2061     osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
2062     if (dsp->refCount == 0) {
2063         lock_ObtainMutex(&dsp->mx);
2064         if (dsp->flags & SMB_DIRSEARCH_DELETE) {
2065             if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
2066                 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
2067             osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2068             lock_ReleaseMutex(&dsp->mx);
2069             lock_FinalizeMutex(&dsp->mx);
2070             scp = dsp->scp;
2071             osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p", 
2072                      dsp->cookie, dsp, scp);
2073             free(dsp);
2074         } else {
2075             lock_ReleaseMutex(&dsp->mx);
2076         }
2077     }
2078     /* do this now to avoid spurious locking hierarchy creation */
2079     if (scp) 
2080         cm_ReleaseSCache(scp);
2081 }       
2082
2083 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
2084 {
2085     lock_ObtainWrite(&smb_globalLock);
2086     smb_ReleaseDirSearchNoLock(dsp);
2087     lock_ReleaseWrite(&smb_globalLock);
2088 }       
2089
2090 /* find a dir search structure by cookie value, and return it held */
2091 smb_dirSearch_t *smb_FindDirSearch(long cookie)
2092 {
2093     smb_dirSearch_t *dsp;
2094
2095     lock_ObtainWrite(&smb_globalLock);
2096     dsp = smb_FindDirSearchNoLock(cookie);
2097     lock_ReleaseWrite(&smb_globalLock);
2098     return dsp;
2099 }
2100
2101 /* GC some dir search entries, in the address space expected by the specific protocol.
2102  * Must be called with smb_globalLock held; release the lock temporarily.
2103  */
2104 #define SMB_DIRSEARCH_GCMAX     10      /* how many at once */
2105 void smb_GCDirSearches(int isV3)
2106 {
2107     smb_dirSearch_t *prevp;
2108     smb_dirSearch_t *dsp;
2109     smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
2110     int victimCount;
2111     int i;
2112         
2113     victimCount = 0;    /* how many have we got so far */
2114     for (dsp = smb_lastDirSearchp; dsp; dsp=prevp) {
2115         /* we'll move tp from queue, so
2116          * do this early.
2117          */
2118         prevp = (smb_dirSearch_t *) osi_QPrev(&dsp->q); 
2119         /* if no one is using this guy, and we're either in the new protocol,
2120          * or we're in the old one and this is a small enough ID to be useful
2121          * to the old protocol, GC this guy.
2122          */
2123         if (dsp->refCount == 0 && (isV3 || dsp->cookie <= 255)) {
2124             /* hold and delete */
2125             lock_ObtainMutex(&dsp->mx);
2126             dsp->flags |= SMB_DIRSEARCH_DELETE;
2127             lock_ReleaseMutex(&dsp->mx);
2128             victimsp[victimCount++] = dsp;
2129             dsp->refCount++;
2130         }
2131
2132         /* don't do more than this */
2133         if (victimCount >= SMB_DIRSEARCH_GCMAX) 
2134             break;
2135     }
2136         
2137     /* now release them */
2138     for (i = 0; i < victimCount; i++) {
2139         smb_ReleaseDirSearchNoLock(victimsp[i]);
2140     }
2141 }
2142
2143 /* function for allocating a dir search entry.  We need these to remember enough context
2144  * since we don't get passed the path from call to call during a directory search.
2145  *
2146  * Returns a held dir search structure, and bumps the reference count on the vnode,
2147  * since it saves a pointer to the vnode.
2148  */
2149 smb_dirSearch_t *smb_NewDirSearch(int isV3)
2150 {
2151     smb_dirSearch_t *dsp;
2152     int counter;
2153     int maxAllowed;
2154     int start;
2155     int wrapped = 0;
2156
2157     lock_ObtainWrite(&smb_globalLock);
2158     counter = 0;
2159
2160     /* what's the biggest ID allowed in this version of the protocol */
2161     /* TODO: do we really want a non v3 dir search request to wrap
2162        smb_dirSearchCounter? */
2163     maxAllowed = isV3 ? 65535 : 255;
2164     if (smb_dirSearchCounter > maxAllowed)
2165         smb_dirSearchCounter = 1;
2166
2167     start = smb_dirSearchCounter;
2168
2169     while (1) {
2170         /* twice so we have enough tries to find guys we GC after one pass;
2171          * 10 extra is just in case I mis-counted.
2172          */
2173         if (++counter > 2*maxAllowed+10) 
2174             osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2175
2176         if (smb_dirSearchCounter > maxAllowed) {        
2177             smb_dirSearchCounter = 1;
2178         }
2179         if (smb_dirSearchCounter == start) {
2180             if (wrapped)
2181                 smb_GCDirSearches(isV3);
2182             wrapped++;
2183         }
2184         dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2185         if (dsp) {
2186             /* don't need to watch for refcount zero and deleted, since
2187             * we haven't dropped the global lock.
2188             */
2189             dsp->refCount--;
2190             ++smb_dirSearchCounter;
2191             continue;
2192         }       
2193
2194         dsp = malloc(sizeof(*dsp));
2195         memset(dsp, 0, sizeof(*dsp));
2196         dsp->cookie = smb_dirSearchCounter;
2197         ++smb_dirSearchCounter;
2198         dsp->refCount = 1;
2199         lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t", LOCK_HIERARCHY_SMB_DIRSEARCH);
2200         dsp->lastTime = osi_Time();
2201         osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2202         if (!smb_lastDirSearchp) 
2203             smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2204     
2205         osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p", 
2206                  dsp->cookie, dsp);
2207         break;
2208     }   
2209     lock_ReleaseWrite(&smb_globalLock);
2210     return dsp;
2211 }
2212
2213 static smb_packet_t *smb_GetPacket(void)
2214 {
2215     smb_packet_t *tbp;
2216
2217     lock_ObtainWrite(&smb_globalLock);
2218     tbp = smb_packetFreeListp;
2219     if (tbp) 
2220         smb_packetFreeListp = tbp->nextp;
2221     lock_ReleaseWrite(&smb_globalLock);
2222     if (!tbp) {
2223         tbp = calloc(sizeof(*tbp),1);
2224         tbp->magic = SMB_PACKETMAGIC;
2225         tbp->ncbp = NULL;
2226         tbp->vcp = NULL;
2227         tbp->resumeCode = 0;
2228         tbp->inCount = 0;
2229         tbp->fid = 0;
2230         tbp->wctp = NULL;
2231         tbp->inCom = 0;
2232         tbp->oddByte = 0;
2233         tbp->ncb_length = 0;
2234         tbp->flags = 0;
2235         tbp->spacep = NULL;
2236         tbp->stringsp = NULL;
2237     }
2238     osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2239
2240     return tbp;
2241 }
2242
2243 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2244 {
2245     smb_packet_t *tbp;
2246     tbp = smb_GetPacket();
2247     memcpy(tbp, pkt, sizeof(smb_packet_t));
2248     tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2249     tbp->stringsp = NULL;
2250     if (tbp->vcp)
2251         smb_HoldVC(tbp->vcp);
2252     return tbp;
2253 }
2254
2255 static NCB *smb_GetNCB(void)
2256 {
2257     smb_ncb_t *tbp;
2258     NCB *ncbp;
2259
2260     lock_ObtainWrite(&smb_globalLock);
2261     tbp = smb_ncbFreeListp;
2262     if (tbp) 
2263         smb_ncbFreeListp = tbp->nextp;
2264     lock_ReleaseWrite(&smb_globalLock);
2265     if (!tbp) {
2266         tbp = calloc(sizeof(*tbp),1);
2267         tbp->magic = SMB_NCBMAGIC;
2268     }
2269         
2270     osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2271
2272     memset(&tbp->ncb, 0, sizeof(NCB));
2273     ncbp = &tbp->ncb;
2274     return ncbp;
2275 }
2276
2277 static void FreeSMBStrings(smb_packet_t * pkt)
2278 {
2279     cm_space_t * s;
2280     cm_space_t * ns;
2281
2282     for (s = pkt->stringsp; s; s = ns) {
2283         ns = s->nextp;
2284         cm_FreeSpace(s);
2285     }
2286     pkt->stringsp = NULL;
2287 }
2288
2289 void smb_FreePacket(smb_packet_t *tbp)
2290 {
2291     smb_vc_t * vcp = NULL;
2292     osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2293         
2294     lock_ObtainWrite(&smb_globalLock);
2295     tbp->nextp = smb_packetFreeListp;
2296     smb_packetFreeListp = tbp;
2297     tbp->magic = SMB_PACKETMAGIC;
2298     tbp->ncbp = NULL;
2299     vcp = tbp->vcp;
2300     tbp->vcp = NULL;
2301     tbp->resumeCode = 0;
2302     tbp->inCount = 0;
2303     tbp->fid = 0;
2304     tbp->wctp = NULL;
2305     tbp->inCom = 0;
2306     tbp->oddByte = 0;
2307     tbp->ncb_length = 0;
2308     tbp->flags = 0;
2309     FreeSMBStrings(tbp);
2310     lock_ReleaseWrite(&smb_globalLock);
2311
2312     if (vcp)
2313         smb_ReleaseVC(vcp);
2314 }
2315
2316 static void smb_FreeNCB(NCB *bufferp)
2317 {
2318     smb_ncb_t *tbp;
2319         
2320     tbp = (smb_ncb_t *) bufferp;
2321     osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2322         
2323     lock_ObtainWrite(&smb_globalLock);
2324     tbp->nextp = smb_ncbFreeListp;
2325     smb_ncbFreeListp = tbp;
2326     lock_ReleaseWrite(&smb_globalLock);
2327 }
2328
2329 /* get a ptr to the data part of a packet, and its count */
2330 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2331 {
2332     int parmBytes;
2333     int dataBytes;
2334     unsigned char *afterParmsp;
2335
2336     parmBytes = *smbp->wctp << 1;
2337     afterParmsp = smbp->wctp + parmBytes + 1;
2338         
2339     dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2340     if (nbytesp) *nbytesp = dataBytes;
2341         
2342     /* don't forget to skip the data byte count, since it follows
2343      * the parameters; that's where the "2" comes from below.
2344      */
2345     return (unsigned char *) (afterParmsp + 2);
2346 }
2347
2348 /* must set all the returned parameters before playing around with the
2349  * data region, since the data region is located past the end of the
2350  * variable number of parameters.
2351  */
2352 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2353 {
2354     unsigned char *afterParmsp;
2355
2356     afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2357         
2358     *afterParmsp++ = dsize & 0xff;
2359     *afterParmsp = (dsize>>8) & 0xff;
2360 }       
2361
2362 /* return the parm'th parameter in the smbp packet */
2363 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2364 {
2365     int parmCount;
2366     unsigned char *parmDatap;
2367
2368     parmCount = *smbp->wctp;
2369
2370     if (parm >= parmCount) {
2371         char s[100];
2372
2373         sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2374                 parm, parmCount, smbp->ncb_length);
2375         osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2376                  parm, parmCount, smbp->ncb_length);
2377         LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM, 
2378                  __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2379         osi_panic(s, __FILE__, __LINE__);
2380     }
2381     parmDatap = smbp->wctp + (2*parm) + 1;
2382         
2383     return parmDatap[0] + (parmDatap[1] << 8);
2384 }
2385
2386 /* return the parm'th parameter in the smbp packet */
2387 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2388 {
2389     int parmCount;
2390     unsigned char *parmDatap;
2391
2392     parmCount = *smbp->wctp;
2393
2394     if (parm >= parmCount) {
2395         char s[100];
2396
2397         sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2398                 parm, parmCount, smbp->ncb_length);
2399         osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2400                  parm, parmCount, smbp->ncb_length);
2401         LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM, 
2402                  __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2403         osi_panic(s, __FILE__, __LINE__);
2404     }
2405     parmDatap = smbp->wctp + (2*parm) + 1;
2406         
2407     return parmDatap[0];
2408 }
2409
2410 /* return the parm'th parameter in the smbp packet */
2411 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2412 {
2413     int parmCount;
2414     unsigned char *parmDatap;
2415
2416     parmCount = *smbp->wctp;
2417
2418     if (parm + 1 >= parmCount) {
2419         char s[100];
2420
2421         sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2422                 parm, parmCount, smbp->ncb_length);
2423         osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2424                  parm, parmCount, smbp->ncb_length);
2425         LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM, 
2426                  __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2427         osi_panic(s, __FILE__, __LINE__);
2428     }
2429     parmDatap = smbp->wctp + (2*parm) + 1;
2430         
2431     return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2432 }
2433
2434 /* return the parm'th parameter in the smbp packet */
2435 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2436 {
2437     int parmCount;
2438     unsigned char *parmDatap;
2439
2440     parmCount = *smbp->wctp;
2441
2442     if (parm * 2 + offset >= parmCount * 2) {
2443         char s[100];
2444
2445         sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2446                 parm, offset, parmCount, smbp->ncb_length);
2447         LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET, 
2448                  __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2449         osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2450                 parm, offset, parmCount, smbp->ncb_length);
2451         osi_panic(s, __FILE__, __LINE__);
2452     }
2453     parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2454         
2455     return parmDatap[0] + (parmDatap[1] << 8);
2456 }
2457
2458 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2459 {
2460     unsigned char *parmDatap;
2461
2462     /* make sure we have enough slots */
2463     if (*smbp->wctp <= slot) 
2464         *smbp->wctp = slot+1;
2465         
2466     parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2467     *parmDatap++ = parmValue & 0xff;
2468     *parmDatap = (parmValue>>8) & 0xff;
2469 }       
2470
2471 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2472 {
2473     unsigned char *parmDatap;
2474
2475     /* make sure we have enough slots */
2476     if (*smbp->wctp <= slot) 
2477         *smbp->wctp = slot+2;
2478
2479     parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2480     *parmDatap++ = parmValue & 0xff;
2481     *parmDatap++ = (parmValue>>8) & 0xff;
2482     *parmDatap++ = (parmValue>>16) & 0xff;
2483     *parmDatap   = (parmValue>>24) & 0xff;
2484 }
2485
2486 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2487 {
2488     unsigned char *parmDatap;
2489     int i;
2490
2491     /* make sure we have enough slots */
2492     if (*smbp->wctp <= slot) 
2493         *smbp->wctp = slot+4;
2494
2495     parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2496     for (i=0; i<8; i++)
2497         *parmDatap++ = *parmValuep++;
2498 }       
2499
2500 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2501 {
2502     unsigned char *parmDatap;
2503
2504     /* make sure we have enough slots */
2505     if (*smbp->wctp <= slot) {
2506         if (smbp->oddByte) {
2507             smbp->oddByte = 0;
2508             *smbp->wctp = slot+1;
2509         } else
2510             smbp->oddByte = 1;
2511     }
2512
2513     parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2514     *parmDatap++ = parmValue & 0xff;
2515 }
2516
2517
2518
2519 void smb_StripLastComponent(clientchar_t *outPathp, clientchar_t **lastComponentp,
2520                             clientchar_t *inPathp)
2521 {
2522     clientchar_t *lastSlashp;
2523         
2524     lastSlashp = cm_ClientStrRChr(inPathp, '\\');
2525     if (lastComponentp)
2526         *lastComponentp = lastSlashp;
2527     if (lastSlashp) {
2528         while (1) {
2529             if (inPathp == lastSlashp) 
2530                 break;
2531             *outPathp++ = *inPathp++;
2532         }
2533         *outPathp++ = 0;
2534     }
2535     else {
2536         *outPathp++ = 0;
2537     }
2538 }
2539
2540 clientchar_t *smb_ParseASCIIBlock(smb_packet_t * pktp, unsigned char *inp,
2541                                   char **chainpp, int flags)
2542 {
2543     size_t cb;
2544     afs_uint32 type = *inp++;
2545
2546     /* 
2547      * The first byte specifies the type of the input string.
2548      * CIFS TR 1.0 3.2.10.  This function only parses null terminated
2549      * strings.
2550      */
2551     switch (type) {
2552     /* Length Counted */
2553     case 0x1: /* Data Block */
2554     case 0x5: /* Variable Block */
2555         cb = *inp++ << 16 | *inp++;
2556         break;
2557
2558     /* Null-terminated string */
2559     case 0x4: /* ASCII */
2560     case 0x3: /* Pathname */
2561     case 0x2: /* Dialect */
2562         cb = sizeof(pktp->data) - (inp - pktp->data);
2563         if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2564 #ifdef DEBUG_UNICODE
2565             DebugBreak();
2566 #endif
2567             cb = sizeof(pktp->data);
2568         }
2569         break;
2570
2571     default:
2572         return NULL;            /* invalid input */
2573     }
2574
2575 #ifdef SMB_UNICODE
2576     if (type == 0x2 /* Dialect */ || !WANTS_UNICODE(pktp))
2577         flags |= SMB_STRF_FORCEASCII;
2578 #endif
2579
2580     return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2581 }
2582
2583 clientchar_t *smb_ParseString(smb_packet_t * pktp, unsigned char * inp,
2584                               char ** chainpp, int flags)
2585 {
2586     size_t cb;
2587
2588 #ifdef SMB_UNICODE
2589     if (!WANTS_UNICODE(pktp))
2590         flags |= SMB_STRF_FORCEASCII;
2591 #endif
2592
2593     cb = sizeof(pktp->data) - (inp - pktp->data);
2594     if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2595 #ifdef DEBUG_UNICODE
2596         DebugBreak();
2597 #endif
2598         cb = sizeof(pktp->data);
2599     }
2600     return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp,
2601                               flags | SMB_STRF_SRCNULTERM);
2602 }
2603
2604 clientchar_t *smb_ParseStringCb(smb_packet_t * pktp, unsigned char * inp,
2605                                 size_t cb, char ** chainpp, int flags)
2606 {
2607 #ifdef SMB_UNICODE
2608     if (!WANTS_UNICODE(pktp))
2609         flags |= SMB_STRF_FORCEASCII;
2610 #endif
2611
2612     return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2613 }
2614
2615 clientchar_t *smb_ParseStringCch(smb_packet_t * pktp, unsigned char * inp,
2616                                  size_t cch, char ** chainpp, int flags)
2617 {
2618     size_t cb = cch;
2619
2620 #ifdef SMB_UNICODE
2621     if (!WANTS_UNICODE(pktp))
2622         flags |= SMB_STRF_FORCEASCII;
2623     else
2624         cb = cch * sizeof(wchar_t);
2625 #endif
2626
2627     return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2628 }
2629
2630 clientchar_t *
2631 smb_ParseStringBuf(const unsigned char * bufbase,
2632                    cm_space_t ** stringspp,
2633                    unsigned char *inp, size_t *pcb_max,
2634                    char **chainpp, int flags)
2635 {
2636 #ifdef SMB_UNICODE
2637     if (!(flags & SMB_STRF_FORCEASCII)) {
2638         size_t cch_src;
2639         cm_space_t * spacep;
2640         int    null_terms = 0;
2641
2642         if (bufbase && ((inp - bufbase) % 2) != 0) {
2643             inp++;              /* unicode strings are always word aligned */
2644         }
2645
2646         if (*pcb_max > 0) {
2647             if (FAILED(StringCchLengthW((const wchar_t *) inp, *pcb_max / sizeof(wchar_t),
2648                                         &cch_src))) {
2649                 cch_src = *pcb_max / sizeof(wchar_t);
2650                 *pcb_max = 0;
2651                 null_terms = 0;
2652             } else {
2653                 *pcb_max -= (cch_src + 1) * sizeof(wchar_t);
2654                 null_terms = 1;
2655             }
2656         } else {
2657             cch_src = 0;
2658         }
2659
2660         spacep = cm_GetSpace();
2661         spacep->nextp = *stringspp;
2662         *stringspp = spacep;
2663
2664         if (cch_src == 0) {
2665             if (chainpp) {
2666                 *chainpp = inp + sizeof(wchar_t);
2667             }
2668
2669             *(spacep->wdata) = 0;
2670             return spacep->wdata;
2671         }
2672
2673         StringCchCopyNW(spacep->wdata,
2674                         lengthof(spacep->wdata),
2675                         (const clientchar_t *) inp, cch_src);
2676
2677         if (chainpp)
2678             *chainpp = inp + (cch_src + null_terms)*sizeof(wchar_t);
2679
2680         return spacep->wdata;
2681
2682     } else {
2683 #endif
2684         cm_space_t * spacep;
2685         int cchdest;
2686
2687         /* Not using Unicode */
2688         if (chainpp) {
2689             *chainpp = inp + strlen(inp) + 1;
2690         }
2691
2692         spacep = cm_GetSpace();
2693         spacep->nextp = *stringspp;
2694         *stringspp = spacep;
2695
2696         cchdest = lengthof(spacep->wdata);
2697         cm_Utf8ToUtf16(inp, (int)((flags & SMB_STRF_SRCNULTERM)? -1 : *pcb_max),
2698                        spacep->wdata, cchdest);
2699
2700         return spacep->wdata;
2701 #ifdef SMB_UNICODE
2702     }
2703 #endif
2704 }
2705
2706 unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
2707                             clientchar_t * str,
2708                             size_t * plen, int flags)
2709 {
2710     size_t buffersize;
2711     int align = 0;
2712
2713     if (outp == NULL) {
2714         /* we are only calculating the required size */
2715
2716         if (plen == NULL)
2717             return NULL;
2718
2719 #ifdef SMB_UNICODE
2720
2721         if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2722
2723             StringCbLengthW(str, SMB_STRINGBUFSIZE * sizeof(wchar_t), plen);
2724             if (!(flags & SMB_STRF_IGNORENUL))
2725                 *plen += sizeof(wchar_t);
2726
2727             return (unsigned char *) 1; /* return TRUE if we are using unicode */
2728         }
2729         else
2730 #endif
2731         {
2732             /* Storing ANSI */
2733
2734             size_t cch_str;
2735             size_t cch_dest;
2736
2737             cch_str = cm_ClientStrLen(str);
2738             cch_dest = cm_ClientStringToUtf8(str, (int)cch_str, NULL, 0);
2739
2740             if (plen)
2741                 *plen = ((flags & SMB_STRF_IGNORENUL)? cch_dest: cch_dest+1);
2742
2743             return NULL;
2744         }
2745
2746         /* Not reached. */
2747     }
2748
2749     /* if outp != NULL ... */
2750
2751     /* Number of bytes left in the buffer.
2752
2753        If outp lies inside the packet data buffer, we assume that the
2754        buffer is the packet data buffer.  Otherwise we assume that the
2755        buffer is sizeof(packet->data).
2756
2757     */
2758     if (outp >= pktp->data && outp < pktp->data + sizeof(pktp->data)) {
2759         align = (int)((outp - pktp->data) % 2);
2760         buffersize = (pktp->data + sizeof(pktp->data)) - ((char *) outp);
2761     } else {
2762         align = (int)(((size_t) outp) % 2);
2763         buffersize = (int)sizeof(pktp->data);
2764     }
2765
2766 #ifdef SMB_UNICODE
2767
2768     if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2769         int nchars;
2770
2771         if (align)
2772             *outp++ = '\0';
2773
2774         if (*str == _C('\0')) {
2775
2776             if (buffersize < sizeof(wchar_t))
2777                 return NULL;
2778
2779             *((wchar_t *) outp) = L'\0';
2780             if (plen && !(flags & SMB_STRF_IGNORENUL))
2781                 *plen += sizeof(wchar_t);
2782             return outp + sizeof(wchar_t);
2783         }
2784
2785         nchars = cm_ClientStringToUtf16(str, -1, (wchar_t *) outp, (int)(buffersize / sizeof(wchar_t)));
2786         if (nchars == 0) {
2787             osi_Log2(smb_logp, "UnparseString: Can't convert string to Unicode [%S], GLE=%d",
2788                      osi_LogSaveClientString(smb_logp, str),
2789                      GetLastError());
2790             return NULL;
2791         }
2792
2793         if (plen)
2794             *plen += sizeof(wchar_t) * ((flags & SMB_STRF_IGNORENUL)? nchars - 1: nchars);
2795
2796         return outp + sizeof(wchar_t) * nchars;
2797     }
2798     else
2799 #endif
2800     {
2801         /* Storing ANSI */
2802         size_t cch_dest;
2803
2804         cch_dest = cm_ClientStringToUtf8(str, -1, outp, (int)buffersize);
2805
2806         if (plen)
2807             *plen += ((flags & SMB_STRF_IGNORENUL)? cch_dest - 1: cch_dest);
2808
2809         return outp + cch_dest;
2810     }
2811 }
2812
2813 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2814 {
2815     int tlen;
2816
2817     if (*inp++ != 0x5) 
2818         return NULL;
2819     tlen = inp[0] + (inp[1]<<8);
2820     inp += 2;           /* skip length field */
2821
2822     if (chainpp) {
2823         *chainpp = inp + tlen;
2824     }
2825         
2826     if (lengthp) 
2827         *lengthp = tlen;
2828         
2829     return inp;
2830 }       
2831
2832 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2833 {
2834     int tlen;
2835
2836     if (*inp++ != 0x1) return NULL;
2837     tlen = inp[0] + (inp[1]<<8);
2838     inp += 2;           /* skip length field */
2839         
2840     if (chainpp) {
2841         *chainpp = inp + tlen;
2842     }   
2843
2844     if (lengthp) *lengthp = tlen;
2845         
2846     return inp;
2847 }
2848
2849 /* format a packet as a response */
2850 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2851 {
2852     smb_t *outp;
2853     smb_t *inSmbp;
2854
2855     outp = (smb_t *) op;
2856         
2857     /* zero the basic structure through the smb_wct field, and zero the data
2858      * size field, assuming that wct stays zero; otherwise, you have to 
2859      * explicitly set the data size field, too.
2860      */
2861     inSmbp = (smb_t *) inp;
2862     memset(outp, 0, sizeof(smb_t)+2);
2863     outp->id[0] = 0xff;
2864     outp->id[1] = 'S';
2865     outp->id[2] = 'M';
2866     outp->id[3] = 'B';
2867     if (inp) {
2868         outp->com = inSmbp->com;
2869         outp->tid = inSmbp->tid;
2870         outp->pid = inSmbp->pid;
2871         outp->uid = inSmbp->uid;
2872         outp->mid = inSmbp->mid;
2873         outp->res[0] = inSmbp->res[0];
2874         outp->res[1] = inSmbp->res[1];
2875         op->inCom = inSmbp->com;
2876     }
2877     outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
2878 #ifdef SEND_CANONICAL_PATHNAMES
2879     outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
2880 #endif
2881     outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2882 #ifdef SMB_UNICODE
2883     if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
2884         outp->flg2 |= SMB_FLAGS2_UNICODE;
2885 #endif
2886
2887     /* copy fields in generic packet area */
2888     op->wctp = &outp->wct;
2889 }       
2890
2891 /* send a (probably response) packet; vcp tells us to whom to send it.
2892  * we compute the length by looking at wct and bcc fields.
2893  */
2894 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2895 {
2896     NCB *ncbp;
2897     int extra;
2898     long code = 0;
2899     unsigned char *tp;
2900     int localNCB = 0;
2901         
2902     ncbp = inp->ncbp;
2903     if (ncbp == NULL) {
2904         ncbp = smb_GetNCB();
2905         localNCB = 1;
2906     }
2907  
2908     memset((char *)ncbp, 0, sizeof(NCB));
2909
2910     extra = 2 * (*inp->wctp);   /* space used by parms, in bytes */
2911     tp = inp->wctp + 1+ extra;  /* points to count of data bytes */
2912     extra += tp[0] + (tp[1]<<8);
2913     extra += (unsigned int)(inp->wctp - inp->data);     /* distance to last wct field */
2914     extra += 3;                 /* wct and length fields */
2915         
2916     ncbp->ncb_length = extra;   /* bytes to send */
2917     ncbp->ncb_lsn = (unsigned char) vcp->lsn;   /* vc to use */
2918     ncbp->ncb_lana_num = vcp->lana;
2919     ncbp->ncb_command = NCBSEND;        /* op means send data */
2920     ncbp->ncb_buffer = (char *) inp;/* packet */
2921     code = Netbios(ncbp);
2922         
2923     if (code != 0) {
2924         const char * s = ncb_error_string(code);
2925         osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2926         LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
2927
2928         lock_ObtainMutex(&vcp->mx);
2929         if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
2930             osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
2931                       vcp, vcp->usersp);
2932             vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2933             lock_ReleaseMutex(&vcp->mx);
2934             lock_ObtainWrite(&smb_globalLock);
2935             dead_sessions[vcp->session] = TRUE;
2936             lock_ReleaseWrite(&smb_globalLock);
2937             smb_CleanupDeadVC(vcp);
2938         } else {
2939             lock_ReleaseMutex(&vcp->mx);
2940         }
2941     }
2942
2943     if (localNCB)
2944         smb_FreeNCB(ncbp);
2945 }
2946
2947 void smb_MapNTError(long code, unsigned long *NTStatusp)
2948 {
2949     unsigned long NTStatus;
2950
2951     /* map CM_ERROR_* errors to NT 32-bit status codes */
2952     /* NT Status codes are listed in ntstatus.h not winerror.h */
2953     if (code == 0) {
2954         NTStatus = 0;
2955     } 
2956     else if (code == CM_ERROR_NOSUCHCELL) {
2957         NTStatus = 0xC000000FL; /* No such file */
2958     }
2959     else if (code == CM_ERROR_NOSUCHVOLUME) {
2960         NTStatus = 0xC000000FL; /* No such file */
2961     }
2962     else if (code == CM_ERROR_TIMEDOUT) {
2963 #ifdef COMMENT
2964         NTStatus = 0xC00000CFL; /* Sharing Paused */
2965 #else
2966         NTStatus = 0x00000102L; /* Timeout */
2967 #endif
2968     }
2969     else if (code == CM_ERROR_RETRY) {
2970         NTStatus = 0xC000022DL; /* Retry */
2971     }
2972     else if (code == CM_ERROR_NOACCESS) {
2973         NTStatus = 0xC0000022L; /* Access denied */
2974     }
2975     else if (code == CM_ERROR_READONLY) {
2976         NTStatus = 0xC00000A2L; /* Write protected */
2977     }
2978     else if (code == CM_ERROR_NOSUCHFILE ||
2979              code == CM_ERROR_BPLUS_NOMATCH) {
2980         NTStatus = 0xC000000FL; /* No such file */
2981     }
2982     else if (code == CM_ERROR_NOSUCHPATH) {
2983         NTStatus = 0xC000003AL; /* Object path not found */
2984     }           
2985     else if (code == CM_ERROR_TOOBIG) {
2986         NTStatus = 0xC000007BL; /* Invalid image format */
2987     }
2988     else if (code == CM_ERROR_INVAL) {
2989         NTStatus = 0xC000000DL; /* Invalid parameter */
2990     }
2991     else if (code == CM_ERROR_BADFD) {
2992         NTStatus = 0xC0000008L; /* Invalid handle */
2993     }
2994     else if (code == CM_ERROR_BADFDOP) {
2995         NTStatus = 0xC0000022L; /* Access denied */
2996     }
2997     else if (code == CM_ERROR_EXISTS) {
2998         NTStatus = 0xC0000035L; /* Object name collision */
2999     }
3000     else if (code == CM_ERROR_NOTEMPTY) {
3001         NTStatus = 0xC0000101L; /* Directory not empty */
3002     }   
3003     else if (code == CM_ERROR_CROSSDEVLINK) {
3004         NTStatus = 0xC00000D4L; /* Not same device */
3005     }
3006     else if (code == CM_ERROR_NOTDIR) {
3007         NTStatus = 0xC0000103L; /* Not a directory */
3008     }
3009     else if (code == CM_ERROR_ISDIR) {
3010         NTStatus = 0xC00000BAL; /* File is a directory */
3011     }
3012     else if (code == CM_ERROR_BADOP) {
3013 #ifdef COMMENT
3014         /* I have no idea where this comes from */
3015         NTStatus = 0xC09820FFL; /* SMB no support */
3016 #else
3017         NTStatus = 0xC00000BBL;     /* Not supported */
3018 #endif /* COMMENT */
3019     }
3020     else if (code == CM_ERROR_BADSHARENAME) {
3021         NTStatus = 0xC00000BEL; /* Bad network path (server valid, share bad) */
3022     }
3023     else if (code == CM_ERROR_NOIPC) {
3024 #ifdef COMMENT
3025         NTStatus = 0xC0000022L; /* Access Denied */
3026 #else   
3027         NTStatus = 0xC000013DL; /* Remote Resources */
3028 #endif
3029     }
3030     else if (code == CM_ERROR_CLOCKSKEW) {
3031         NTStatus = 0xC0000133L; /* Time difference at DC */
3032     }
3033     else if (code == CM_ERROR_BADTID) {
3034         NTStatus = 0xC0982005L; /* SMB bad TID */
3035     }
3036     else if (code == CM_ERROR_USESTD) {
3037         NTStatus = 0xC09820FBL; /* SMB use standard */
3038     }
3039     else if (code == CM_ERROR_QUOTA) {
3040         NTStatus = 0xC0000044L; /* Quota exceeded */
3041     }
3042     else if (code == CM_ERROR_SPACE) {
3043         NTStatus = 0xC000007FL; /* Disk full */
3044     }
3045     else if (code == CM_ERROR_ATSYS) {
3046         NTStatus = 0xC0000033L; /* Object name invalid */
3047     }
3048     else if (code == CM_ERROR_BADNTFILENAME) {
3049         NTStatus = 0xC0000033L; /* Object name invalid */
3050     }
3051     else if (code == CM_ERROR_WOULDBLOCK) {
3052         NTStatus = 0xC00000D8L; /* Can't wait */
3053     }
3054     else if (code == CM_ERROR_SHARING_VIOLATION) {
3055         NTStatus = 0xC0000043L; /* Sharing violation */
3056     }
3057     else if (code == CM_ERROR_LOCK_CONFLICT) {
3058         NTStatus = 0xC0000054L; /* Lock conflict */
3059     }
3060     else if (code == CM_ERROR_PARTIALWRITE) {
3061         NTStatus = 0xC000007FL; /* Disk full */
3062     }
3063     else if (code == CM_ERROR_BUFFERTOOSMALL) {
3064         NTStatus = 0xC0000023L; /* Buffer too small */
3065     }
3066     else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3067         NTStatus = 0xC0000035L; /* Object name collision */
3068     }   
3069     else if (code == CM_ERROR_BADPASSWORD) {
3070         NTStatus = 0xC000006DL; /* unknown username or bad password */
3071     }
3072     else if (code == CM_ERROR_BADLOGONTYPE) {
3073         NTStatus = 0xC000015BL; /* logon type not granted */
3074     }
3075     else if (code == CM_ERROR_GSSCONTINUE) {
3076         NTStatus = 0xC0000016L; /* more processing required */
3077     }
3078     else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3079 #ifdef COMMENT
3080         NTStatus = 0xC0000280L; /* reparse point not resolved */
3081 #else
3082         NTStatus = 0xC0000022L; /* Access Denied */
3083 #endif
3084     }
3085     else if (code == CM_ERROR_PATH_NOT_COVERED) {
3086         NTStatus = 0xC0000257L; /* Path Not Covered */
3087     } 
3088     else if (code == CM_ERROR_ALLBUSY) {
3089         NTStatus = 0xC000022DL; /* Retry */
3090     } 
3091     else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3092         NTStatus = 0xC000003AL; /* Path not found */
3093     } 
3094     else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3095         NTStatus = 0xC0000322L; /* No Kerberos key */
3096     } 
3097     else if (code == CM_ERROR_BAD_LEVEL) {
3098         NTStatus = 0xC0000148L; /* Invalid Level */
3099     } 
3100     else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3101         NTStatus = 0xC000007EL; /* Range Not Locked */
3102     } 
3103     else if (code == CM_ERROR_NOSUCHDEVICE) {
3104         NTStatus = 0xC000000EL; /* No Such Device */
3105     }
3106     else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3107         NTStatus = 0xC0000055L; /* Lock Not Granted */
3108     }
3109     else if (code == ENOMEM) {
3110         NTStatus = 0xC0000017L; /* Out of Memory */
3111     }
3112     else if (code == CM_ERROR_RPC_MOREDATA) {
3113         NTStatus = 0x80000005L; /* Buffer overflow */
3114     }
3115     else  {
3116         NTStatus = 0xC0982001L; /* SMB non-specific error */
3117     }
3118
3119     *NTStatusp = NTStatus;
3120     osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
3121 }       
3122
3123 /* 
3124  * NTSTATUS <-> Win32 Error Translation 
3125  * http://support.microsoft.com/kb/113996 
3126  */
3127 void smb_MapWin32Error(long code, unsigned long *Win32Ep)
3128 {
3129     unsigned long Win32E;
3130
3131     /* map CM_ERROR_* errors to Win32 32-bit error codes */
3132     if (code == 0) {
3133         Win32E = 0;
3134     } 
3135     else if (code == CM_ERROR_NOSUCHCELL) {
3136         Win32E = ERROR_FILE_NOT_FOUND;  /* No such file */
3137     }
3138     else if (code == CM_ERROR_NOSUCHVOLUME) {
3139         Win32E = ERROR_FILE_NOT_FOUND;  /* No such file */
3140     }
3141     else if (code == CM_ERROR_TIMEDOUT) {
3142 #ifdef COMMENT
3143         Win32E = ERROR_SHARING_PAUSED;  /* Sharing Paused */
3144 #else
3145         Win32E = ERROR_UNEXP_NET_ERR;   /* Timeout */
3146 #endif
3147     }
3148     else if (code == CM_ERROR_RETRY) {
3149         Win32E = ERROR_RETRY;           /* Retry */
3150     }
3151     else if (code == CM_ERROR_NOACCESS) {
3152         Win32E = ERROR_ACCESS_DENIED;   /* Access denied */
3153     }
3154     else if (code == CM_ERROR_READONLY) {
3155         Win32E = ERROR_WRITE_PROTECT;   /* Write protected */
3156     }
3157     else if (code == CM_ERROR_NOSUCHFILE ||
3158              code == CM_ERROR_BPLUS_NOMATCH) {
3159         Win32E = ERROR_FILE_NOT_FOUND;  /* No such file */
3160     }
3161     else if (code == CM_ERROR_NOSUCHPATH) {
3162         Win32E = ERROR_PATH_NOT_FOUND;  /* Object path not found */
3163     }           
3164     else if (code == CM_ERROR_TOOBIG) {
3165         Win32E = ERROR_BAD_EXE_FORMAT;  /* Invalid image format */
3166     }
3167     else if (code == CM_ERROR_INVAL) {
3168         Win32E = ERROR_INVALID_PARAMETER;/* Invalid parameter */
3169     }
3170     else if (code == CM_ERROR_BADFD) {
3171         Win32E = ERROR_INVALID_HANDLE;  /* Invalid handle */
3172     }
3173     else if (code == CM_ERROR_BADFDOP) {
3174         Win32E = ERROR_ACCESS_DENIED;   /* Access denied */
3175     }
3176     else if (code == CM_ERROR_EXISTS) {
3177         Win32E = ERROR_ALREADY_EXISTS;  /* Object name collision */
3178     }
3179     else if (code == CM_ERROR_NOTEMPTY) {
3180         Win32E = ERROR_DIR_NOT_EMPTY;   /* Directory not empty */
3181     }   
3182     else if (code == CM_ERROR_CROSSDEVLINK) {
3183         Win32E = ERROR_NOT_SAME_DEVICE; /* Not same device */
3184     }
3185     else if (code == CM_ERROR_NOTDIR) {
3186         Win32E = ERROR_DIRECTORY;       /* Not a directory */
3187     }
3188     else if (code == CM_ERROR_ISDIR) {
3189         Win32E = ERROR_ACCESS_DENIED;   /* File is a directory */
3190     }
3191     else if (code == CM_ERROR_BADOP) {
3192         Win32E = ERROR_NOT_SUPPORTED;   /* Not supported */
3193     }
3194     else if (code == CM_ERROR_BADSHARENAME) {
3195         Win32E = ERROR_BAD_NETPATH;     /* Bad network path (server valid, share bad) */
3196     }
3197     else if (code == CM_ERROR_NOIPC) {
3198 #ifdef COMMENT
3199         Win32E = ERROR_ACCESS_DENIED;   /* Access Denied */
3200 #else   
3201         Win32E = ERROR_REM_NOT_LIST;    /* Remote Resources */
3202 #endif
3203     }
3204     else if (code == CM_ERROR_CLOCKSKEW) {
3205         Win32E = ERROR_TIME_SKEW;       /* Time difference at DC */
3206     }
3207     else if (code == CM_ERROR_BADTID) {
3208         Win32E = ERROR_FILE_NOT_FOUND;  /* SMB bad TID */
3209     }
3210     else if (code == CM_ERROR_USESTD) {
3211         Win32E = ERROR_ACCESS_DENIED;   /* SMB use standard */
3212     }
3213     else if (code == CM_ERROR_QUOTA) {
3214         Win32E = ERROR_NOT_ENOUGH_QUOTA;/* Quota exceeded */
3215     }
3216     else if (code == CM_ERROR_SPACE) {
3217         Win32E = ERROR_DISK_FULL;       /* Disk full */
3218     }
3219     else if (code == CM_ERROR_ATSYS) {
3220         Win32E = ERROR_INVALID_NAME;    /* Object name invalid */
3221     }
3222     else if (code == CM_ERROR_BADNTFILENAME) {
3223         Win32E = ERROR_INVALID_NAME;    /* Object name invalid */
3224     }
3225     else if (code == CM_ERROR_WOULDBLOCK) {
3226         Win32E = WAIT_TIMEOUT;          /* Can't wait */
3227     }
3228     else if (code == CM_ERROR_SHARING_VIOLATION) {
3229         Win32E = ERROR_SHARING_VIOLATION; /* Sharing violation */
3230     }
3231     else if (code == CM_ERROR_LOCK_CONFLICT) {
3232         Win32E = ERROR_LOCK_VIOLATION;   /* Lock conflict */
3233     }
3234     else if (code == CM_ERROR_PARTIALWRITE) {
3235         Win32E = ERROR_DISK_FULL;       /* Disk full */
3236     }
3237     else if (code == CM_ERROR_BUFFERTOOSMALL) {
3238         Win32E = ERROR_INSUFFICIENT_BUFFER;     /* Buffer too small */
3239     }
3240     else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3241         Win32E = ERROR_ALREADY_EXISTS;  /* Object name collision */
3242     }   
3243     else if (code == CM_ERROR_BADPASSWORD) {
3244         Win32E = ERROR_LOGON_FAILURE;   /* unknown username or bad password */
3245     }
3246     else if (code == CM_ERROR_BADLOGONTYPE) {
3247         Win32E = ERROR_INVALID_LOGON_TYPE; /* logon type not granted */
3248     }
3249     else if (code == CM_ERROR_GSSCONTINUE) {
3250         Win32E = ERROR_MORE_DATA;       /* more processing required */
3251     }
3252     else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3253 #ifdef COMMENT
3254         Win32E = ERROR_CANT_RESOLVE_FILENAME; /* reparse point not resolved */
3255 #else
3256         Win32E = ERROR_ACCESS_DENIED;   /* Access Denied */
3257 #endif
3258     }
3259     else if (code == CM_ERROR_PATH_NOT_COVERED) {
3260         Win32E = ERROR_HOST_UNREACHABLE; /* Path Not Covered */
3261     } 
3262     else if (code == CM_ERROR_ALLBUSY) {
3263         Win32E = ERROR_RETRY;           /* Retry */
3264     } 
3265     else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3266         Win32E = ERROR_HOST_UNREACHABLE; /* Path not found */
3267     } 
3268     else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3269         Win32E = SEC_E_NO_KERB_KEY;     /* No Kerberos key */
3270     } 
3271     else if (code == CM_ERROR_BAD_LEVEL) {
3272         Win32E = ERROR_INVALID_LEVEL;   /* Invalid Level */
3273     } 
3274     else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3275         Win32E = ERROR_NOT_LOCKED;      /* Range Not Locked */
3276     } 
3277     else if (code == CM_ERROR_NOSUCHDEVICE) {
3278         Win32E = ERROR_FILE_NOT_FOUND;  /* No Such Device */
3279     }
3280     else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3281         Win32E = ERROR_LOCK_VIOLATION;  /* Lock Not Granted */
3282     }
3283     else if (code == ENOMEM) {
3284         Win32E = ERROR_NOT_ENOUGH_MEMORY; /* Out of Memory */
3285     }
3286     else if (code == CM_ERROR_RPC_MOREDATA) {
3287         Win32E = ERROR_MORE_DATA;       /* Buffer overflow */
3288     }
3289     else  {
3290         Win32E = ERROR_GEN_FAILURE;     /* SMB non-specific error */
3291     }
3292
3293     *Win32Ep = Win32E;
3294     osi_Log2(smb_logp, "SMB SEND code %lX as Win32 %lX", code, Win32E);
3295 }       
3296
3297 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
3298                       unsigned char *classp)
3299 {
3300     unsigned char class;
3301     unsigned short error;
3302
3303     /* map CM_ERROR_* errors to SMB errors */
3304     if (code == CM_ERROR_NOSUCHCELL) {
3305         class = 1;
3306         error = 3;      /* bad path */
3307     }
3308     else if (code == CM_ERROR_NOSUCHVOLUME) {
3309         class = 1;
3310         error = 3;      /* bad path */
3311     }
3312     else if (code == CM_ERROR_TIMEDOUT) {
3313         class = 2;
3314         error = 81;     /* server is paused */
3315     }
3316     else if (code == CM_ERROR_RETRY) {
3317         class = 2;      /* shouldn't happen */
3318         error = 1;
3319     }
3320     else if (code == CM_ERROR_NOACCESS) {
3321         class = 2;
3322         error = 4;      /* bad access */
3323     }
3324     else if (code == CM_ERROR_READONLY) {
3325         class = 3;
3326         error = 19;     /* read only */
3327     }
3328     else if (code == CM_ERROR_NOSUCHFILE ||
3329              code == CM_ERROR_BPLUS_NOMATCH) {
3330         class = 1;
3331         error = 2;      /* ENOENT! */
3332     }
3333     else if (code == CM_ERROR_NOSUCHPATH) {
3334         class = 1;
3335         error = 3;      /* Bad path */
3336     }
3337     else if (code == CM_ERROR_TOOBIG) {
3338         class = 1;
3339         error = 11;     /* bad format */
3340     }
3341     else if (code == CM_ERROR_INVAL) {
3342         class = 2;      /* server non-specific error code */
3343         error = 1;
3344     }
3345     else if (code == CM_ERROR_BADFD) {
3346         class = 1;
3347         error = 6;      /* invalid file handle */
3348     }
3349     else if (code == CM_ERROR_BADFDOP) {
3350         class = 1;      /* invalid op on FD */
3351         error = 5;
3352     }
3353     else if (code == CM_ERROR_EXISTS) {
3354         class = 1;
3355         error = 80;     /* file already exists */
3356     }
3357     else if (code == CM_ERROR_NOTEMPTY) {
3358         class = 1;
3359         error = 5;      /* delete directory not empty */
3360     }
3361     else if (code == CM_ERROR_CROSSDEVLINK) {
3362         class = 1;
3363         error = 17;     /* EXDEV */
3364     }
3365     else if (code == CM_ERROR_NOTDIR) {
3366         class = 1;      /* bad path */
3367         error = 3;
3368     }
3369     else if (code == CM_ERROR_ISDIR) {
3370         class = 1;      /* access denied; DOS doesn't have a good match */
3371         error = 5;
3372     }       
3373     else if (code == CM_ERROR_BADOP) {
3374         class = 2;
3375         error = 65535;
3376     }
3377     else if (code == CM_ERROR_BADSHARENAME) {
3378         class = 2;
3379         error = 6;
3380     }
3381     else if (code == CM_ERROR_NOIPC) {
3382         class = 2;
3383         error = 4; /* bad access */
3384     }
3385     else if (code == CM_ERROR_CLOCKSKEW) {
3386         class = 1;      /* invalid function */
3387         error = 1;
3388     }
3389     else if (code == CM_ERROR_BADTID) {
3390         class = 2;
3391         error = 5;
3392     }
3393     else if (code == CM_ERROR_USESTD) {
3394         class = 2;
3395         error = 251;
3396     }
3397     else if (code == CM_ERROR_REMOTECONN) {
3398         class = 2;
3399         error = 82;
3400     }
3401     else if (code == CM_ERROR_QUOTA) {
3402         if (vcp->flags & SMB_VCFLAG_USEV3) {
3403             class = 3;
3404             error = 39; /* disk full */
3405         }
3406         else {
3407             class = 1;
3408             error = 5;  /* access denied */
3409         }
3410     }
3411     else if (code == CM_ERROR_SPACE) {
3412         if (vcp->flags & SMB_VCFLAG_USEV3) {
3413             class = 3;
3414             error = 39; /* disk full */
3415         }
3416         else {
3417             class = 1;
3418             error = 5;  /* access denied */
3419         }
3420     }
3421     else if (code == CM_ERROR_PARTIALWRITE) {
3422         class = 3;
3423         error = 39;     /* disk full */
3424     }
3425     else if (code == CM_ERROR_ATSYS) {
3426         class = 1;
3427         error = 2;      /* ENOENT */
3428     }
3429     else if (code == CM_ERROR_WOULDBLOCK) {
3430         class = 1;
3431         error = 33;     /* lock conflict */
3432     }
3433     else if (code == CM_ERROR_LOCK_CONFLICT) {
3434         class = 1;
3435         error = 33;     /* lock conflict */
3436     }
3437     else if (code == CM_ERROR_SHARING_VIOLATION) {
3438         class = 1;
3439         error = 33;     /* lock conflict */
3440     }
3441     else if (code == CM_ERROR_NOFILES) {
3442         class = 1;
3443         error = 18;     /* no files in search */
3444     }
3445     else if (code == CM_ERROR_RENAME_IDENTICAL) {
3446         class = 1;
3447         error = 183;     /* Samba uses this */
3448     }
3449     else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
3450         /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
3451         class = 2;
3452         error = 2; /* bad password */
3453     }
3454     else if (code == CM_ERROR_PATH_NOT_COVERED) {
3455         class = 2;
3456         error = 3;     /* bad path */
3457     }
3458     else {
3459         class = 2;
3460         error = 1;
3461     }
3462
3463     *scodep = error;
3464     *classp = class;
3465     osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
3466 }       
3467
3468 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3469 {
3470     osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
3471     return CM_ERROR_BADOP;
3472 }
3473
3474 /* SMB_COM_ECHO */
3475 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3476 {
3477     unsigned short EchoCount, i;
3478     char *data, *outdata;
3479     int dataSize;
3480
3481     EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
3482
3483     for (i=1; i<=EchoCount; i++) {
3484         data = smb_GetSMBData(inp, &dataSize);
3485         smb_SetSMBParm(outp, 0, i);
3486         smb_SetSMBDataLength(outp, dataSize);
3487         outdata = smb_GetSMBData(outp, NULL);
3488         memcpy(outdata, data, dataSize);
3489         smb_SendPacket(vcp, outp);
3490     }
3491
3492     return 0;
3493 }
3494
3495 /* SMB_COM_READ_RAW */
3496 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3497 {
3498     osi_hyper_t offset;
3499     long count, minCount, finalCount;
3500     unsigned short fd;
3501     unsigned pid;
3502     smb_fid_t *fidp;
3503     smb_t *smbp = (smb_t*) inp;
3504     long code = 0;
3505     cm_user_t *userp = NULL;
3506     NCB *ncbp;
3507     int rc;
3508     char *rawBuf = NULL;
3509
3510     rawBuf = NULL;
3511     finalCount = 0;
3512
3513     fd = smb_GetSMBParm(inp, 0);
3514     count = smb_GetSMBParm(inp, 3);
3515     minCount = smb_GetSMBParm(inp, 4);
3516     offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3517
3518     if (*inp->wctp == 10) {
3519         /* we were sent a request with 64-bit file offsets */
3520 #ifdef AFS_LARGEFILES
3521         offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
3522
3523         if (LargeIntegerLessThanZero(offset)) {
3524             osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
3525             goto send1;
3526         }
3527 #else
3528         if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
3529             osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset.  Dropping request.");
3530             goto send1;
3531         } else {
3532             offset.HighPart = 0;
3533         }
3534 #endif
3535     } else {
3536         /* we were sent a request with 32-bit file offsets */
3537         offset.HighPart = 0;
3538     }
3539
3540     osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
3541              fd, offset.HighPart, offset.LowPart, count);
3542
3543     fidp = smb_FindFID(vcp, fd, 0);
3544     if (!fidp)
3545         goto send1;
3546
3547     lock_ObtainMutex(&fidp->mx);
3548     if (!fidp->scp) {
3549         lock_ReleaseMutex(&fidp->mx);
3550         smb_ReleaseFID(fidp);
3551         return CM_ERROR_BADFD;
3552     }
3553
3554     if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
3555         lock_ReleaseMutex(&fidp->mx);
3556         smb_CloseFID(vcp, fidp, NULL, 0);
3557         code = CM_ERROR_NOSUCHFILE;
3558         goto send1a;
3559     }
3560
3561     pid = smbp->pid;
3562     {
3563         LARGE_INTEGER LOffset, LLength;
3564         cm_key_t key;
3565
3566         key = cm_GenerateKey(vcp->vcID, pid, fd);
3567
3568         LOffset.HighPart = offset.HighPart;
3569         LOffset.LowPart = offset.LowPart;
3570         LLength.HighPart = 0;
3571         LLength.LowPart = count;
3572
3573         lock_ObtainWrite(&fidp->scp->rw);
3574         code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
3575         lock_ReleaseWrite(&fidp->scp->rw);
3576     }    
3577     if (code) {
3578         lock_ReleaseMutex(&fidp->mx);
3579         goto send1a;
3580     }
3581
3582     lock_ObtainMutex(&smb_RawBufLock);
3583     if (smb_RawBufs) {
3584         /* Get a raw buf, from head of list */
3585         rawBuf = smb_RawBufs;
3586         smb_RawBufs = *(char **)smb_RawBufs;
3587     }
3588     lock_ReleaseMutex(&smb_RawBufLock);
3589     if (!rawBuf) {
3590         lock_ReleaseMutex(&fidp->mx);
3591         goto send1a;
3592     }
3593
3594     if (fidp->flags & SMB_FID_IOCTL)
3595     {
3596         rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
3597         if (rawBuf) {
3598             /* Give back raw buffer */
3599             lock_ObtainMutex(&smb_RawBufLock);
3600             *((char **) rawBuf) = smb_RawBufs;
3601             
3602             smb_RawBufs = rawBuf;
3603             lock_ReleaseMutex(&smb_RawBufLock);
3604         }
3605
3606         lock_ReleaseMutex(&fidp->mx);
3607         smb_ReleaseFID(fidp);
3608         return rc;
3609     }
3610     lock_ReleaseMutex(&fidp->mx);
3611
3612     userp = smb_GetUserFromVCP(vcp, inp);
3613
3614     code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
3615
3616     if (code != 0)
3617         goto send;
3618
3619   send:
3620     cm_ReleaseUser(userp);
3621
3622   send1a:
3623     smb_ReleaseFID(fidp);
3624
3625   send1:
3626     ncbp = outp->ncbp;
3627     memset((char *)ncbp, 0, sizeof(NCB));
3628
3629     ncbp->ncb_length = (unsigned short) finalCount;
3630     ncbp->ncb_lsn = (unsigned char) vcp->lsn;
3631     ncbp->ncb_lana_num = vcp->lana;
3632     ncbp->ncb_command = NCBSEND;
3633     ncbp->ncb_buffer = rawBuf;
3634
3635     code = Netbios(ncbp);
3636     if (code != 0)
3637         osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
3638
3639     if (rawBuf) {
3640         /* Give back raw buffer */
3641         lock_ObtainMutex(&smb_RawBufLock);
3642         *((char **) rawBuf) = smb_RawBufs;
3643
3644         smb_RawBufs = rawBuf;
3645         lock_ReleaseMutex(&smb_RawBufLock);
3646     }
3647
3648     return 0;
3649 }
3650
3651 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3652 {
3653     osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3654                          ongoingOps - 1);
3655     return 0;
3656 }
3657
3658 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3659 {
3660     osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3661                          ongoingOps - 1);
3662     return 0;
3663 }
3664
3665 /* SMB_COM_NEGOTIATE */
3666 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3667 {
3668     char *namep;
3669     char *datap;
3670     int coreProtoIndex;
3671     int v3ProtoIndex;
3672     int NTProtoIndex;
3673     int VistaProtoIndex;
3674     int protoIndex;                             /* index we're using */
3675     int namex;
3676     int dbytes;
3677     int entryLength;
3678     int tcounter;
3679     char protocol_array[10][1024];  /* protocol signature of the client */
3680     int caps;                       /* capabilities */
3681     time_t unixTime;
3682     afs_uint32 dosTime;
3683     TIME_ZONE_INFORMATION tzi;
3684
3685     osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3686                          ongoingOps - 1);
3687
3688     namep = smb_GetSMBData(inp, &dbytes);
3689     namex = 0;
3690     tcounter = 0;
3691     coreProtoIndex = -1;                /* not found */
3692     v3ProtoIndex = -1;
3693     NTProtoIndex = -1;
3694     VistaProtoIndex = -1;
3695     while(namex < dbytes) {
3696         osi_Log1(smb_logp, "Protocol %s",
3697                   osi_LogSaveString(smb_logp, namep+1));
3698         strcpy(protocol_array[tcounter], namep+1);
3699
3700         /* namep points at the first protocol, or really, a 0x02
3701          * byte preceding the null-terminated ASCII name.
3702          */
3703         if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3704             coreProtoIndex = tcounter;
3705         }       
3706         else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3707             v3ProtoIndex = tcounter;
3708         }
3709         else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3710             NTProtoIndex = tcounter;
3711         }
3712         else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3713             VistaProtoIndex = tcounter;
3714         }
3715
3716         /* compute size of protocol entry */
3717         entryLength = (int)strlen(namep+1);
3718         entryLength += 2;       /* 0x02 bytes and null termination */
3719
3720         /* advance over this protocol entry */
3721         namex += entryLength;
3722         namep += entryLength;
3723         tcounter++;             /* which proto entry we're looking at */
3724     }
3725
3726     lock_ObtainMutex(&vcp->mx);
3727 #if 0
3728     if (VistaProtoIndex != -1) {
3729         protoIndex = VistaProtoIndex;
3730         vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3731     } else 
3732 #endif  
3733         if (NTProtoIndex != -1) {
3734         protoIndex = NTProtoIndex;
3735         vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3736     }
3737     else if (v3ProtoIndex != -1) {
3738         protoIndex = v3ProtoIndex;
3739         vcp->flags |= SMB_VCFLAG_USEV3;
3740     }   
3741     else if (coreProtoIndex != -1) {
3742         protoIndex = coreProtoIndex;
3743         vcp->flags |= SMB_VCFLAG_USECORE;
3744     }   
3745     else protoIndex = -1;
3746     lock_ReleaseMutex(&vcp->mx);
3747
3748     if (protoIndex == -1)
3749         return CM_ERROR_INVAL;
3750     else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3751         smb_SetSMBParm(outp, 0, protoIndex);
3752         if (smb_authType != SMB_AUTH_NONE) {
3753             smb_SetSMBParmByte(outp, 1,
3754                                NEGOTIATE_SECURITY_USER_LEVEL |
3755                                NEGOTIATE_SECURITY_CHALLENGE_RESPONSE);  /* user level security, challenge response */
3756         } else {
3757             smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3758         }
3759         smb_SetSMBParm(outp, 1, smb_maxMpxRequests);    /* max multiplexed requests */
3760         smb_SetSMBParm(outp, 2, smb_maxVCPerServer);    /* max VCs per consumer/server connection */
3761         smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE);    /* xmit buffer size */
3762         smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE);    /* raw buffer size */
3763         /* The session key is not a well documented field however most clients
3764          * will echo back the session key to the server.  Currently we are using
3765          * the same value for all sessions.  We should generate a random value
3766          * and store it into the vcp 
3767          */
3768         smb_SetSMBParm(outp, 7, 1);     /* next 2: session key */
3769         smb_SetSMBParm(outp, 8, 1);
3770         /* 
3771          * Tried changing the capabilities to support for W2K - defect 117695
3772          * Maybe something else needs to be changed here?
3773          */
3774         /*
3775         if (isWindows2000) 
3776         smb_SetSMBParmLong(outp, 9, 0x43fd);
3777         else 
3778         smb_SetSMBParmLong(outp, 9, 0x251);
3779         */
3780         /* Capabilities: *
3781          * 32-bit error codes *
3782          * and NT Find *
3783          * and NT SMB's *
3784          * and raw mode 
3785          * and DFS
3786          * and Unicode */
3787         caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3788 #ifdef DFS_SUPPORT
3789                NTNEGOTIATE_CAPABILITY_DFS |
3790 #endif
3791 #ifdef AFS_LARGEFILES
3792                NTNEGOTIATE_CAPABILITY_LARGEFILES |
3793 #endif
3794                NTNEGOTIATE_CAPABILITY_NTFIND |
3795                NTNEGOTIATE_CAPABILITY_RAWMODE |
3796                NTNEGOTIATE_CAPABILITY_NTSMB;
3797
3798         if ( smb_authType == SMB_AUTH_EXTENDED )
3799             caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3800
3801 #ifdef SMB_UNICODE
3802         if ( smb_UseUnicode ) {
3803             caps |= NTNEGOTIATE_CAPABILITY_UNICODE;
3804         }
3805 #endif
3806
3807         smb_SetSMBParmLong(outp, 9, caps);
3808         time(&unixTime);
3809         cm_SearchTimeFromUnixTime(&dosTime, unixTime);
3810         smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3811         smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3812
3813         GetTimeZoneInformation(&tzi);
3814         smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias);    /* server tzone */
3815
3816         if (smb_authType == SMB_AUTH_NTLM) {
3817             smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3818             smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3819             /* paste in encryption key */
3820             datap = smb_GetSMBData(outp, NULL);
3821             memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3822             /* and the faux domain name */
3823             cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3824                                   datap + MSV1_0_CHALLENGE_LENGTH,
3825                                   (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3826         } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3827             void * secBlob;
3828             int secBlobLength;
3829
3830             smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3831
3832             smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3833
3834             smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3835                         
3836             datap = smb_GetSMBData(outp, NULL);
3837             memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3838
3839             if (secBlob) {
3840                 datap += sizeof(smb_ServerGUID);
3841                 memcpy(datap, secBlob, secBlobLength);
3842                 free(secBlob);
3843             }
3844         } else {
3845             smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3846             smb_SetSMBDataLength(outp, 0);   /* Perhaps we should specify 8 bytes anyway */
3847         }
3848     }
3849     else if (v3ProtoIndex != -1) {
3850         smb_SetSMBParm(outp, 0, protoIndex);
3851
3852         /* NOTE: Extended authentication cannot be negotiated with v3
3853          * therefore we fail over to NTLM 
3854          */
3855         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3856             smb_SetSMBParm(outp, 1,
3857                            NEGOTIATE_SECURITY_USER_LEVEL |
3858                            NEGOTIATE_SECURITY_CHALLENGE_RESPONSE);      /* user level security, challenge response */
3859         } else {
3860             smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3861         }
3862         smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3863         smb_SetSMBParm(outp, 3, smb_maxMpxRequests);    /* max multiplexed requests */
3864         smb_SetSMBParm(outp, 4, smb_maxVCPerServer);    /* max VCs per consumer/server connection */
3865         smb_SetSMBParm(outp, 5, 0);     /* no support of block mode for read or write */
3866         smb_SetSMBParm(outp, 6, 1);     /* next 2: session key */
3867         smb_SetSMBParm(outp, 7, 1);
3868         time(&unixTime);
3869         cm_SearchTimeFromUnixTime(&dosTime, unixTime);
3870         smb_SetSMBParm(outp, 8, LOWORD(dosTime));       /* server time */
3871         smb_SetSMBParm(outp, 9, HIWORD(dosTime));       /* server date */
3872
3873         GetTimeZoneInformation(&tzi);
3874         smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias);    /* server tzone */
3875
3876         /* NOTE: Extended authentication cannot be negotiated with v3
3877          * therefore we fail over to NTLM 
3878          */
3879         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3880             smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH);  /* encryption key length */
3881             smb_SetSMBParm(outp, 12, 0);        /* resvd */
3882             smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);   /* perhaps should specify 8 bytes anyway */
3883             datap = smb_GetSMBData(outp, NULL);
3884             /* paste in a new encryption key */
3885             memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3886             /* and the faux domain name */
3887             cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3888                                   datap + MSV1_0_CHALLENGE_LENGTH,
3889                                   (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3890         } else {
3891             smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3892             smb_SetSMBParm(outp, 12, 0); /* resvd */
3893             smb_SetSMBDataLength(outp, 0);
3894         }
3895     }
3896     else if (coreProtoIndex != -1) {     /* not really supported anymore */
3897         smb_SetSMBParm(outp, 0, protoIndex);
3898         smb_SetSMBDataLength(outp, 0);
3899     }
3900     return 0;
3901 }
3902
3903 void smb_CheckVCs(void)
3904 {
3905     smb_vc_t * vcp, *nextp;
3906     smb_packet_t * outp = smb_GetPacket();
3907     smb_t *smbp;
3908             
3909     lock_ObtainWrite(&smb_rctLock);
3910     for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp ) 
3911     {
3912         if (vcp->magic != SMB_VC_MAGIC)
3913             osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp", 
3914                        __FILE__, __LINE__);
3915
3916         /* on the first pass hold 'vcp' which was not held as 'nextp' */
3917         if (vcp != nextp)
3918             smb_HoldVCNoLock(vcp);
3919
3920         /* 
3921          * obtain a reference to 'nextp' now because we drop the
3922          * smb_rctLock later and the list contents could change 
3923          * or 'vcp' could be destroyed when released.
3924          */
3925         nextp = vcp->nextp;
3926         if (nextp)
3927             smb_HoldVCNoLock(nextp);
3928
3929         if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
3930             smb_ReleaseVCNoLock(vcp);
3931             continue;
3932         }
3933
3934         smb_FormatResponsePacket(vcp, NULL, outp);
3935         smbp = (smb_t *)outp;
3936         outp->inCom = smbp->com = 0x2b /* Echo */;
3937         smbp->tid = 0xFFFF;
3938         smbp->pid = 0;
3939         smbp->uid = 0;
3940         smbp->mid = 0;
3941         smbp->res[0] = 0;
3942         smbp->res[1] = 0;
3943
3944         smb_SetSMBParm(outp, 0, 0);
3945         smb_SetSMBDataLength(outp, 0);
3946         lock_ReleaseWrite(&smb_rctLock);
3947
3948         smb_SendPacket(vcp, outp);
3949
3950         lock_ObtainWrite(&smb_rctLock);
3951         smb_ReleaseVCNoLock(vcp);
3952     }
3953     lock_ReleaseWrite(&smb_rctLock);
3954     smb_FreePacket(outp);
3955 }
3956
3957 void smb_Daemon(void *parmp)
3958 {
3959     afs_uint32 count = 0;
3960     smb_username_t    **unpp;
3961     time_t              now;
3962
3963     while(smbShutdownFlag == 0) {
3964         count++;
3965         thrd_Sleep(10000);
3966
3967         if (smbShutdownFlag == 1)
3968             break;
3969         
3970         if ((count % 72) == 0)  {       /* every five minutes */
3971             struct tm myTime;
3972             time_t old_localZero = smb_localZero;
3973                  
3974             /* Initialize smb_localZero */
3975             myTime.tm_isdst = -1;               /* compute whether on DST or not */
3976             myTime.tm_year = 70;
3977             myTime.tm_mon = 0;
3978             myTime.tm_mday = 1;
3979             myTime.tm_hour = 0;
3980             myTime.tm_min = 0;
3981             myTime.tm_sec = 0;
3982             smb_localZero = mktime(&myTime);
3983
3984 #ifdef AFS_FREELANCE
3985             if ( smb_localZero != old_localZero )
3986                 cm_noteLocalMountPointChange();
3987 #endif
3988
3989             smb_CheckVCs();
3990         }
3991
3992         /* GC smb_username_t objects that will no longer be used */
3993         now = osi_Time();
3994         lock_ObtainWrite(&smb_rctLock);
3995         for ( unpp=&usernamesp; *unpp; ) {
3996             int deleteOk = 0;
3997             smb_username_t *unp;
3998
3999             lock_ObtainMutex(&(*unpp)->mx);
4000             if ( (*unpp)->refCount > 0 || 
4001                  ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) || 
4002                  !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
4003                 ;
4004             else if (!smb_LogoffTokenTransfer ||
4005                      ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
4006                 deleteOk = 1;
4007             lock_ReleaseMutex(&(*unpp)->mx);
4008
4009             if (deleteOk) {
4010                 cm_user_t * userp;
4011
4012                 unp = *unpp;    
4013                 *unpp = unp->nextp;
4014                 unp->nextp = NULL;
4015                 lock_FinalizeMutex(&unp->mx);
4016                 userp = unp->userp;
4017                 free(unp->name);
4018                 free(unp->machine);
4019                 free(unp);
4020                 if (userp)
4021                     cm_ReleaseUser(userp);
4022             } else {
4023                 unpp = &(*unpp)->nextp;
4024             }
4025         }
4026         lock_ReleaseWrite(&smb_rctLock);
4027
4028         /* XXX GC dir search entries */
4029     }
4030 }
4031
4032 void smb_WaitingLocksDaemon()
4033 {
4034     smb_waitingLockRequest_t *wlRequest, *nwlRequest;
4035     smb_waitingLock_t *wl, *wlNext;
4036     int first;
4037     smb_vc_t *vcp;
4038     smb_packet_t *inp, *outp;
4039     NCB *ncbp;
4040     long code = 0;
4041
4042     while (smbShutdownFlag == 0) {
4043         lock_ObtainWrite(&smb_globalLock);
4044         nwlRequest = smb_allWaitingLocks;
4045         if (nwlRequest == NULL) {
4046             osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
4047             thrd_Sleep(1000);
4048             continue;
4049         } else {
4050             first = 1;
4051             osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
4052         }
4053
4054         do {
4055             if (first)
4056                 first = 0;
4057             else
4058                 lock_ObtainWrite(&smb_globalLock);
4059
4060             osi_Log1(smb_logp, "    Checking waiting lock request %p", nwlRequest);
4061
4062             wlRequest = nwlRequest;
4063             nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
4064             lock_ReleaseWrite(&smb_globalLock);
4065
4066             code = 0;
4067
4068             for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
4069                 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4070                     continue;
4071
4072                 if (wl->state == SMB_WAITINGLOCKSTATE_CANCELLED) {
4073                     code = CM_ERROR_LOCK_NOT_GRANTED;
4074                     break;
4075                 }
4076
4077                 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
4078                 
4079                 /* wl->state is either _DONE or _WAITING.  _ERROR
4080                    would no longer be on the queue. */
4081                 code = cm_RetryLock( wl->lockp,
4082                                      !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
4083
4084                 if (code == 0) {
4085                     wl->state = SMB_WAITINGLOCKSTATE_DONE;
4086                 } else if (code != CM_ERROR_WOULDBLOCK) {
4087                     wl->state = SMB_WAITINGLOCKSTATE_ERROR;
4088                     break;
4089                 }
4090             }
4091
4092             if (code == CM_ERROR_WOULDBLOCK) {
4093
4094                 /* no progress */
4095                 if (wlRequest->msTimeout != 0xffffffff
4096                      && ((osi_Time() - wlRequest->start_t) * 1000 > wlRequest->msTimeout))
4097                     goto endWait;
4098
4099                 continue;
4100             }
4101
4102           endWait:
4103
4104             if (code != 0) {
4105                 cm_scache_t * scp;
4106                 cm_req_t req;
4107
4108                 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
4109                          wlRequest);
4110
4111                 scp = wlRequest->scp;
4112                 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
4113
4114                 smb_InitReq(&req);
4115
4116                 lock_ObtainWrite(&scp->rw);
4117
4118                 for (wl = wlRequest->locks; wl; wl = wlNext) {
4119                     wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4120                 
4121                     if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4122                         cm_Unlock(scp, wlRequest->lockType, wl->LOffset, 
4123                                   wl->LLength, wl->key, 0, NULL, &req);
4124
4125                     osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4126
4127                     free(wl);
4128                 }
4129                 
4130                 lock_ReleaseWrite(&scp->rw);
4131
4132             } else {
4133
4134                 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
4135                          wlRequest);
4136
4137                 for (wl = wlRequest->locks; wl; wl = wlNext) {
4138                     wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4139                     osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4140                     free(wl);
4141                 }
4142             }
4143
4144             vcp = wlRequest->vcp;
4145             inp = wlRequest->inp;
4146             outp = wlRequest->outp;
4147             ncbp = smb_GetNCB();
4148             ncbp->ncb_length = inp->ncb_length;
4149             inp->spacep = cm_GetSpace();
4150
4151             /* Remove waitingLock from list */
4152             lock_ObtainWrite(&smb_globalLock);
4153             osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
4154                          &wlRequest->q);
4155             lock_ReleaseWrite(&smb_globalLock);
4156
4157             /* Resume packet processing */
4158             if (code == 0)
4159                 smb_SetSMBDataLength(outp, 0);
4160             outp->flags |= SMB_PACKETFLAG_SUSPENDED;
4161             outp->resumeCode = code;
4162             outp->ncbp = ncbp;
4163             smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
4164
4165             /* Clean up */
4166             cm_FreeSpace(inp->spacep);
4167             smb_FreePacket(inp);
4168             smb_FreePacket(outp);
4169             smb_ReleaseVC(vcp);
4170             cm_ReleaseSCache(wlRequest->scp);
4171             smb_FreeNCB(ncbp);
4172             free(wlRequest);
4173         } while (nwlRequest && smbShutdownFlag == 0);
4174         thrd_Sleep(1000);
4175     }
4176 }
4177
4178 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4179 {
4180     osi_Log0(smb_logp, "SMB receive get disk attributes");
4181
4182     smb_SetSMBParm(outp, 0, 32000);
4183     smb_SetSMBParm(outp, 1, 64);
4184     smb_SetSMBParm(outp, 2, 1024);
4185     smb_SetSMBParm(outp, 3, 30000);
4186     smb_SetSMBParm(outp, 4, 0);
4187     smb_SetSMBDataLength(outp, 0);
4188     return 0;
4189 }
4190
4191 /* SMB_COM_TREE_CONNECT */
4192 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
4193 {
4194     smb_tid_t *tidp;
4195     smb_user_t *uidp;
4196     unsigned short newTid;
4197     clientchar_t shareName[AFSPATHMAX];
4198     clientchar_t *sharePath;
4199     int shareFound;
4200     clientchar_t *tp;
4201     clientchar_t *pathp;
4202     cm_user_t *userp;
4203
4204     osi_Log0(smb_logp, "SMB receive tree connect");
4205
4206     /* parse input parameters */
4207     {
4208         char *tbp;
4209         tbp = smb_GetSMBData(inp, NULL);
4210         pathp = smb_ParseASCIIBlock(inp, tbp, &tbp, SMB_STRF_ANSIPATH);
4211         if (!pathp)
4212             return CM_ERROR_BADSMB;
4213     }
4214     tp = cm_ClientStrRChr(pathp, '\\');
4215     if (!tp)
4216         return CM_ERROR_BADSMB;
4217     cm_ClientStrCpy(shareName, lengthof(shareName), tp+1);
4218
4219     lock_ObtainMutex(&vcp->mx);
4220     newTid = vcp->tidCounter++;
4221     lock_ReleaseMutex(&vcp->mx);
4222
4223     tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
4224     uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
4225     if (!uidp)
4226         return CM_ERROR_BADSMB;
4227     userp = smb_GetUserFromUID(uidp);
4228     shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
4229     smb_ReleaseUID(uidp);
4230     if (!shareFound) {
4231         smb_ReleaseTID(tidp, FALSE);
4232         return CM_ERROR_BADSHARENAME;
4233     }
4234     lock_ObtainMutex(&tidp->mx);
4235     tidp->userp = userp;
4236     tidp->pathname = sharePath;
4237     lock_ReleaseMutex(&tidp->mx);
4238     smb_ReleaseTID(tidp, FALSE);
4239
4240     smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
4241     smb_SetSMBParm(rsp, 1, newTid);
4242     smb_SetSMBDataLength(rsp, 0);
4243
4244     osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
4245     return 0;
4246 }
4247
4248 /* set maskp to the mask part of the incoming path.
4249  * Mask is 11 bytes long (8.3 with the dot elided).
4250  * Returns true if succeeds with a valid name, otherwise it does
4251  * its best, but returns false.
4252  */
4253 int smb_Get8Dot3MaskFromPath(clientchar_t *maskp, clientchar_t *pathp)
4254 {
4255     clientchar_t *tp;
4256     clientchar_t *up;
4257     int i;
4258     int tc;
4259     int valid8Dot3;
4260
4261     /* starts off valid */
4262     valid8Dot3 = 1;
4263
4264     /* mask starts out all blanks */
4265     memset(maskp, ' ', 11);
4266     maskp[11] = '\0';
4267
4268     /* find last backslash, or use whole thing if there is none */
4269     tp = cm_ClientStrRChr(pathp, '\\');
4270     if (!tp) 
4271         tp = pathp;
4272     else 
4273         tp++;   /* skip slash */
4274         
4275     up = maskp;
4276
4277     /* names starting with a dot are illegal */
4278     if (*tp == '.') 
4279         valid8Dot3 = 0;
4280
4281     for(i=0;; i++) {
4282         tc = *tp++;
4283         if (tc == 0) 
4284             return valid8Dot3;
4285         if (tc == '.' || tc == '"') 
4286             break;
4287         if (i < 8) 
4288             *up++ = tc;
4289         else
4290             valid8Dot3 = 0;
4291     }
4292         
4293     /* if we get here, tp point after the dot */
4294     up = maskp+8;       /* ext goes here */
4295     for(i=0;;i++) {
4296         tc = *tp++;
4297         if (tc == 0) 
4298             return valid8Dot3;
4299
4300         /* too many dots */
4301         if (tc == '.' || tc == '"') 
4302             valid8Dot3 = 0;
4303
4304         /* copy extension if not too long */
4305         if (i < 3) 
4306             *up++ = tc;
4307         else 
4308             valid8Dot3 = 0;
4309     }   
4310
4311     /* unreachable */
4312 }
4313
4314 int smb_Match8Dot3Mask(clientchar_t *unixNamep, clientchar_t *maskp)
4315 {
4316     clientchar_t umask[11];
4317     int valid;
4318     int i;
4319     clientchar_t tc1;
4320     clientchar_t tc2;
4321     clientchar_t *tp1;
4322     clientchar_t *tp2;
4323
4324     /* XXX redo this, calling cm_MatchMask with a converted mask */
4325
4326     valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
4327     if (!valid) 
4328         return 0;
4329  
4330     /* otherwise, we have a valid 8.3 name; see if we have a match,
4331      * treating '?' as a wildcard in maskp (but not in the file name).
4332      */
4333     tp1 = umask;        /* real name, in mask format */
4334     tp2 = maskp;        /* mask, in mask format */
4335     for(i=0; i<11; i++) {
4336         tc1 = *tp1++;   /* clientchar_t from real name */
4337         tc2 = *tp2++;   /* clientchar_t from mask */
4338         tc1 = (clientchar_t) cm_foldUpper[(clientchar_t)tc1];
4339         tc2 = (clientchar_t) cm_foldUpper[(clientchar_t)tc2];
4340         if (tc1 == tc2) 
4341             continue;
4342         if (tc2 == '?' && tc1 != ' ') 
4343             continue;
4344         if (tc2 == '>') 
4345             continue;
4346         return 0;
4347     }
4348
4349     /* we got a match */
4350     return 1;
4351 }
4352
4353 clientchar_t *smb_FindMask(clientchar_t *pathp)
4354 {
4355     clientchar_t *tp;
4356         
4357     tp = cm_ClientStrRChr(pathp, '\\'); /* find last slash */
4358
4359     if (tp) 
4360         return tp+1;    /* skip the slash */
4361     else 
4362         return pathp;   /* no slash, return the entire path */
4363 }       
4364
4365 /* SMB_COM_SEARCH for a volume label
4366
4367    (This is called from smb_ReceiveCoreSearchDir() and not an actual
4368    dispatch function.) */
4369 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4370 {
4371     clientchar_t *pathp;
4372     unsigned char *tp;
4373     clientchar_t mask[12];
4374     unsigned char *statBlockp;
4375     unsigned char initStatBlock[21];
4376     int statLen;
4377         
4378     osi_Log0(smb_logp, "SMB receive search volume");
4379
4380     /* pull pathname and stat block out of request */
4381     tp = smb_GetSMBData(inp, NULL);
4382     pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4383                                 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4384     if (!pathp)
4385         return CM_ERROR_BADSMB;
4386     statBlockp = smb_ParseVblBlock(tp, &tp, &statLen);
4387     osi_assertx(statBlockp != NULL, "null statBlock");
4388     if (statLen == 0) {
4389         statBlockp = initStatBlock;
4390         statBlockp[0] = 8;
4391     }
4392   &nb