Don't cast the pointer past to memset
[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) {
1422         if (!(flags & SMB_FLAG_CREATE))
1423             return NULL;
1424         newFid = 1;
1425     }
1426
1427     lock_ObtainWrite(&smb_rctLock);
1428     if (newFid)
1429         fid = vcp->fidCounter;
1430   retry:
1431
1432     for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1433         if (fidp->refCount == 0 && fidp->deleteOk) {
1434             fidp->refCount++;
1435             lock_ReleaseWrite(&smb_rctLock);
1436             smb_ReleaseFID(fidp);
1437             lock_ObtainWrite(&smb_rctLock);
1438             /*
1439              * We dropped the smb_rctLock so the fid value we are using
1440              * may now be used by another thread.  Start over with the
1441              * current vcp->fidCounter.
1442              */
1443             if (newFid)
1444                 fid = vcp->fidCounter;
1445             goto retry;
1446         }
1447         if (fid == fidp->fid) {
1448             if (newFid) {
1449                 osi_Log1(smb_logp, "smb_FindFID New Fid Requested.  fid %d found -- retrying ...", fid);
1450                 fid++;
1451                 if (fid == 0xFFFF) {
1452                     osi_Log1(smb_logp,
1453                              "New FID number wraps on vcp 0x%x", vcp);
1454                     fid = 1;
1455                 }
1456                 goto retry;
1457             }
1458             fidp->refCount++;
1459             break;
1460         }
1461     }
1462
1463     if (!fidp && (flags & SMB_FLAG_CREATE)) {
1464         char eventName[MAX_PATH];
1465         EVENT_HANDLE event;
1466
1467         if (!newFid)
1468             osi_Log1(smb_logp, "smb_FindFID New Fid Not Requested, Fid %d Not Found and CREATE flag set.", fid);
1469         else
1470             osi_Log1(smb_logp, "smb_FindFID New Fid Requested.  Creating fid %d", fid);
1471
1472         sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1473         event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1474         if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1475             osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1476             thrd_CloseHandle(event);
1477             fid++;
1478             if (fid == 0xFFFF) {
1479                 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1480                 fid = 1;
1481             }
1482             goto retry;
1483         }
1484
1485         fidp = malloc(sizeof(*fidp));
1486         memset(fidp, 0, sizeof(*fidp));
1487         osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1488         fidp->refCount = 1;
1489         fidp->vcp = vcp;
1490         smb_HoldVCNoLock(vcp);
1491         lock_InitializeMutex(&fidp->mx, "fid_t mutex", LOCK_HIERARCHY_SMB_FID);
1492         fidp->fid = fid;
1493         fidp->curr_chunk = fidp->prev_chunk = -2;
1494         fidp->raw_write_event = event;
1495         if (newFid) {
1496             vcp->fidCounter = fid+1;
1497             if (vcp->fidCounter == 0xFFFF) {
1498                 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1499                          vcp);
1500                 vcp->fidCounter = 1;
1501             }
1502         }
1503     }
1504
1505 #ifdef DEBUG_SMB_REFCOUNT
1506     if (fidp) {
1507         afsi_log("%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1508         osi_Log4(smb_logp,"%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1509     }
1510 #endif
1511     lock_ReleaseWrite(&smb_rctLock);
1512     return fidp;
1513 }
1514
1515
1516 /* Must not be called with scp->rw held because smb_ReleaseFID might be called */
1517 #ifdef DEBUG_SMB_REFCOUNT
1518 smb_fid_t *smb_FindFIDByScacheDbg(smb_vc_t *vcp, cm_scache_t * scp, char *file, long line)
1519 #else
1520 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1521 #endif
1522 {
1523     smb_fid_t *fidp = NULL, *nextp = NULL;
1524         
1525     if (!scp)
1526         return NULL;
1527
1528     /* 
1529      * If the fidp->scp changes out from under us then
1530      * we must not grab a refCount.  It means the *fidp
1531      * was processed by smb_CloseFID() and the *fidp is 
1532      * no longer valid for use.
1533      */
1534     lock_ObtainWrite(&smb_rctLock);
1535         for(fidp = vcp->fidsp, (fidp ? fidp->refCount++ : 0); fidp; fidp = nextp, nextp = NULL) {
1536         nextp = (smb_fid_t *) osi_QNext(&fidp->q);
1537         if (nextp)
1538             nextp->refCount++;
1539
1540         if (scp == fidp->scp) {
1541             lock_ReleaseWrite(&smb_rctLock);
1542             lock_ObtainMutex(&fidp->mx);
1543             lock_ObtainWrite(&smb_rctLock);
1544             if (scp == fidp->scp) {
1545                 lock_ReleaseMutex(&fidp->mx);
1546                 break;
1547             }
1548             lock_ReleaseMutex(&fidp->mx);
1549         }
1550
1551         if (fidp->refCount > 1) {
1552             fidp->refCount--;
1553         } else {
1554             lock_ReleaseWrite(&smb_rctLock);
1555             smb_ReleaseFID(fidp);
1556             lock_ObtainWrite(&smb_rctLock);
1557         }
1558     }
1559
1560     if (nextp) {
1561         if (nextp->refCount > 1) {
1562             nextp->refCount--;
1563         } else {
1564             lock_ReleaseWrite(&smb_rctLock);
1565             smb_ReleaseFID(nextp);
1566             lock_ObtainWrite(&smb_rctLock);
1567         }
1568     }
1569
1570 #ifdef DEBUG_SMB_REFCOUNT
1571     if (fidp) {
1572         afsi_log("%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1573         osi_Log4(smb_logp,"%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1574       }
1575 #endif
1576     lock_ReleaseWrite(&smb_rctLock);
1577     return (fidp);
1578 }
1579
1580 #ifdef DEBUG_SMB_REFCOUNT
1581 void smb_HoldFIDNoLockDbg(smb_fid_t *fidp, char *file, long line)
1582 #else
1583 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1584 #endif
1585 {
1586     lock_AssertWrite(&smb_rctLock);
1587     fidp->refCount++;
1588 #ifdef DEBUG_SMB_REFCOUNT
1589     afsi_log("%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1590     osi_Log4(smb_logp,"%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1591 #endif
1592 }
1593
1594
1595 /* smb_ReleaseFID cannot be called while a cm_scache_t rwlock is held */
1596 /* the smb_fid_t->mx and smb_rctLock must not be held */
1597 #ifdef DEBUG_SMB_REFCOUNT
1598 void smb_ReleaseFIDDbg(smb_fid_t *fidp, char *file, long line)
1599 #else
1600 void smb_ReleaseFID(smb_fid_t *fidp)
1601 #endif
1602 {
1603     cm_scache_t *scp = NULL;
1604     cm_user_t *userp = NULL;
1605     smb_vc_t *vcp = NULL;
1606     smb_ioctl_t *ioctlp;
1607
1608     lock_ObtainMutex(&fidp->mx);
1609     lock_ObtainWrite(&smb_rctLock);
1610     osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
1611 #ifdef DEBUG_SMB_REFCOUNT
1612     afsi_log("%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1613     osi_Log5(smb_logp,"%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1614 #endif
1615     if (fidp->refCount == 0) {
1616         if (fidp->deleteOk) {
1617             vcp = fidp->vcp;
1618             fidp->vcp = NULL;
1619             scp = fidp->scp;    /* release after lock is released */
1620             if (scp) {
1621                 lock_ObtainWrite(&scp->rw);
1622                 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1623                 lock_ReleaseWrite(&scp->rw);
1624                 osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1625                 fidp->scp = NULL;
1626             }
1627             userp = fidp->userp;
1628             fidp->userp = NULL;
1629
1630             if (vcp->fidsp) 
1631                 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1632             thrd_CloseHandle(fidp->raw_write_event);
1633
1634             /* and see if there is ioctl stuff to free */
1635             ioctlp = fidp->ioctlp;
1636             if (ioctlp) {
1637                 if (ioctlp->prefix)
1638                 cm_FreeSpace(ioctlp->prefix);
1639                 if (ioctlp->ioctl.inAllocp)
1640                     free(ioctlp->ioctl.inAllocp);
1641                 if (ioctlp->ioctl.outAllocp)
1642                     free(ioctlp->ioctl.outAllocp);
1643                 free(ioctlp);
1644             }
1645
1646             smb_CleanupRPCFid(fidp);
1647
1648             lock_ReleaseMutex(&fidp->mx);
1649             lock_FinalizeMutex(&fidp->mx);
1650             free(fidp);
1651             fidp = NULL;
1652
1653             if (vcp)
1654                 smb_ReleaseVCNoLock(vcp);
1655         }
1656     }
1657     if (fidp)
1658         lock_ReleaseMutex(&fidp->mx);
1659
1660     lock_ReleaseWrite(&smb_rctLock);
1661
1662     /* now release the scache structure */
1663     if (scp) 
1664         cm_ReleaseSCache(scp);
1665
1666     if (userp)
1667         cm_ReleaseUser(userp);
1668 }       
1669
1670 /*
1671  * Case-insensitive search for one string in another;
1672  * used to find variable names in submount pathnames.
1673  */
1674 static clientchar_t *smb_stristr(clientchar_t *str1, clientchar_t *str2)
1675 {
1676     clientchar_t *cursor;
1677
1678     for (cursor = str1; *cursor; cursor++)
1679         if (cm_ClientStrCmpI(cursor, str2) == 0)
1680             return cursor;
1681
1682     return NULL;
1683 }
1684
1685 /*
1686  * Substitute a variable value for its name in a submount pathname.  Variable
1687  * name has been identified by smb_stristr() and is in substr.  Variable name
1688  * length (plus one) is in substr_size.  Variable value is in newstr.
1689  */
1690 static void smb_subst(clientchar_t *str1, int cchstr1, clientchar_t *substr,
1691                       unsigned int substr_size, clientchar_t *newstr)
1692 {
1693     clientchar_t temp[1024];
1694
1695     cm_ClientStrCpy(temp, lengthof(temp), substr + substr_size - 1);
1696     cm_ClientStrCpy(substr, cchstr1 - (substr - str1), newstr);
1697     cm_ClientStrCat(str1, cchstr1, temp);
1698 }
1699
1700 clientchar_t VNUserName[] = _C("%USERNAME%");
1701 clientchar_t VNLCUserName[] = _C("%LCUSERNAME%");
1702 clientchar_t VNComputerName[] = _C("%COMPUTERNAME%");
1703 clientchar_t VNLCComputerName[] = _C("%LCCOMPUTERNAME%");
1704
1705 typedef struct smb_findShare_rock {
1706     clientchar_t * shareName;
1707     clientchar_t * match;
1708     int matchType;
1709 } smb_findShare_rock_t;
1710
1711 #define SMB_FINDSHARE_EXACT_MATCH 1
1712 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1713
1714 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1715                        osi_hyper_t *offp)
1716 {
1717     int matchType = 0;
1718     smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1719     normchar_t normName[MAX_PATH];
1720
1721     if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(normName[0])) == 0) {
1722         osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
1723                  osi_LogSaveString(smb_logp, dep->name));
1724         return 0;
1725     }
1726
1727     if (!cm_ClientStrCmpNI(normName, vrock->shareName, 12)) {
1728         if(!cm_ClientStrCmpI(normName, vrock->shareName))
1729             matchType = SMB_FINDSHARE_EXACT_MATCH;
1730         else
1731             matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1732         if(vrock->match) 
1733             free(vrock->match);
1734         vrock->match = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
1735         vrock->matchType = matchType;
1736
1737         if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1738             return CM_ERROR_STOPNOW;
1739     }
1740     return 0;
1741 }
1742
1743
1744 /* find a shareName in the table of submounts */
1745 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp,
1746                   clientchar_t *shareName,
1747                   clientchar_t **pathNamep)
1748 {
1749     DWORD cblen;
1750     DWORD cchlen;
1751     clientchar_t pathName[1024];
1752     clientchar_t *var;
1753     DWORD sizeTemp;
1754     clientchar_t *p, *q;
1755     fschar_t *cellname = NULL;
1756     HKEY parmKey;
1757     DWORD code;
1758     DWORD allSubmount = 1;
1759
1760     /* if allSubmounts == 0, only return the //mountRoot/all share 
1761      * if in fact it has been been created in the subMounts table.  
1762      * This is to allow sites that want to restrict access to the 
1763      * world to do so.
1764      */
1765     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1766                         0, KEY_QUERY_VALUE, &parmKey);
1767     if (code == ERROR_SUCCESS) {
1768         cblen = sizeof(allSubmount);
1769         code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1770                                (BYTE *) &allSubmount, &cblen);
1771         if (code != ERROR_SUCCESS) {
1772             allSubmount = 1;
1773         }
1774         RegCloseKey (parmKey);
1775     }
1776
1777     if (allSubmount && cm_ClientStrCmpI(shareName, _C("all")) == 0) {
1778         *pathNamep = NULL;
1779         return 1;
1780     }
1781
1782     /* In case, the all share is disabled we need to still be able
1783      * to handle ioctl requests 
1784      */
1785     if (cm_ClientStrCmpI(shareName, _C("ioctl$")) == 0) {
1786         *pathNamep = cm_ClientStrDup(_C("/.__ioctl__"));
1787         return 1;
1788     }
1789
1790     if (MSRPC_IsWellKnownService(shareName) ||
1791         cm_ClientStrCmpIA(shareName, _C(SMB_IOCTL_FILENAME_NOSLASH)) == 0 ||
1792         cm_ClientStrCmpIA(shareName, _C("DESKTOP.INI")) == 0
1793         ) {
1794         *pathNamep = NULL;
1795         return 0;
1796     }
1797
1798     /* Check for volume references
1799      * 
1800      * They look like <cell>{%,#}<volume>
1801      */
1802     if (cm_ClientStrChr(shareName, '%') != NULL ||
1803         cm_ClientStrChr(shareName, '#') != NULL) {
1804         clientchar_t pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
1805         /* make room for '/@vol:' + mountchar + NULL terminator*/
1806
1807         osi_Log1(smb_logp, "smb_FindShare found volume reference [%S]",
1808                  osi_LogSaveClientString(smb_logp, shareName));
1809
1810         cm_ClientStrPrintfN(pathstr, lengthof(pathstr),
1811                             _C("/") _C(CM_PREFIX_VOL) _C("%s"), shareName);
1812         cchlen = (DWORD)(cm_ClientStrLen(pathstr) + 1);
1813
1814         *pathNamep = malloc(cchlen * sizeof(clientchar_t));
1815         if (*pathNamep) {
1816             cm_ClientStrCpy(*pathNamep, cchlen, pathstr);
1817             cm_ClientStrLwr(*pathNamep);
1818             osi_Log1(smb_logp, "   returning pathname [%S]",
1819                      osi_LogSaveClientString(smb_logp, *pathNamep));
1820
1821             return 1;
1822         } else {
1823             return 0;
1824         }
1825     }
1826
1827     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1828                         0, KEY_QUERY_VALUE, &parmKey);
1829     if (code == ERROR_SUCCESS) {
1830         cblen = sizeof(pathName);
1831         code = RegQueryValueExW(parmKey, shareName, NULL, NULL,
1832                                 (BYTE *) pathName, &cblen);
1833         if (code != ERROR_SUCCESS)
1834             cblen = 0;
1835         RegCloseKey (parmKey);
1836     } else {
1837         cblen = 0;
1838     }
1839     cchlen = cblen / sizeof(clientchar_t);
1840     if (cchlen != 0 && cchlen != lengthof(pathName) - 1) {
1841         /* We can accept either unix or PC style AFS pathnames.  Convert
1842          * Unix-style to PC style here for internal use. 
1843          */
1844         p = pathName;
1845         cchlen = lengthof(pathName);
1846
1847         /* within this code block, we maintain, cchlen = writeable
1848            buffer length of p */
1849
1850         if (cm_ClientStrCmpN(p, cm_mountRootC, cm_mountRootCLen) == 0) {
1851             p += cm_mountRootCLen;  /* skip mount path */
1852             cchlen -= (DWORD)(p - pathName);
1853         }
1854
1855         q = p;
1856         while (*q) {
1857             if (*q == _C('/')) *q = _C('\\');    /* change to \ */
1858             q++;
1859         }
1860
1861         while (1)
1862         {
1863             clientchar_t temp[1024];
1864
1865             if (var = smb_stristr(p, VNUserName)) {
1866                 if (uidp && uidp->unp)
1867                     smb_subst(p, cchlen, var, lengthof(VNUserName),uidp->unp->name);
1868                 else
1869                     smb_subst(p, cchlen, var, lengthof(VNUserName), _C(" "));
1870             }
1871             else if (var = smb_stristr(p, VNLCUserName)) 
1872             {
1873                 if (uidp && uidp->unp)
1874                     cm_ClientStrCpy(temp, lengthof(temp), uidp->unp->name);
1875                 else 
1876                     cm_ClientStrCpy(temp, lengthof(temp), _C(" "));
1877                 cm_ClientStrLwr(temp);
1878                 smb_subst(p, cchlen, var, lengthof(VNLCUserName), temp);
1879             }
1880             else if (var = smb_stristr(p, VNComputerName)) 
1881             {
1882                 sizeTemp = lengthof(temp);
1883                 GetComputerNameW(temp, &sizeTemp);
1884                 smb_subst(p, cchlen, var, lengthof(VNComputerName), temp);
1885             }
1886             else if (var = smb_stristr(p, VNLCComputerName)) 
1887             {
1888                 sizeTemp = lengthof(temp);
1889                 GetComputerName((LPTSTR)temp, &sizeTemp);
1890                 cm_ClientStrLwr(temp);
1891                 smb_subst(p, cchlen, var, lengthof(VNLCComputerName), temp);
1892             }
1893             else     
1894                 break;
1895         }
1896         *pathNamep = cm_ClientStrDup(p);
1897         return 1;
1898     } 
1899     else
1900     {
1901         /* First lookup shareName in root.afs */
1902         cm_req_t req;
1903         smb_findShare_rock_t vrock;
1904         osi_hyper_t thyper;
1905         fschar_t ftemp[1024];
1906         clientchar_t * p = shareName; 
1907         int rw = 0;
1908
1909         /*  attempt to locate a partial match in root.afs.  This is because
1910             when using the ANSI RAP calls, the share name is limited to 13 chars
1911             and hence is truncated. Of course we prefer exact matches. */
1912         smb_InitReq(&req);
1913         thyper.HighPart = 0;
1914         thyper.LowPart = 0;
1915
1916         vrock.shareName = cm_ClientStringToNormStringAlloc(shareName, -1, NULL);
1917         if (vrock.shareName == NULL) 
1918             return 0;
1919         vrock.match = NULL;
1920         vrock.matchType = 0;
1921
1922         cm_HoldSCache(cm_data.rootSCachep);
1923         code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1924                            (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1925         cm_ReleaseSCache(cm_data.rootSCachep);
1926
1927         free(vrock.shareName);
1928         vrock.shareName = NULL;
1929
1930         if (vrock.matchType) {
1931             cm_ClientStrPrintfN(pathName, lengthof(pathName), _C("/%s/"), vrock.match);
1932             *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
1933             free(vrock.match);
1934             return 1;
1935         }
1936
1937         /* if we get here, there was no match for the share in root.afs */
1938         /* so try to create  \\<netbiosName>\<cellname>  */
1939         if ( *p == '.' ) {
1940             p++;
1941             rw = 1;
1942         }
1943         /* Get the full name for this cell */
1944         cellname = cm_ClientStringToFsStringAlloc(p, -1, NULL);
1945         code = cm_SearchCellRegistry(1, cellname, ftemp, 0, 0, 0);
1946         if (code && code != CM_ERROR_FORCE_DNS_LOOKUP)
1947             code = cm_SearchCellFile(cellname, ftemp, 0, 0);
1948 #ifdef AFS_AFSDB_ENV
1949         if (code && cm_dnsEnabled) {
1950             int ttl;
1951             code = cm_SearchCellByDNS(cellname, ftemp, &ttl, 0, 0);
1952         }
1953 #endif
1954         if (cellname)
1955             free(cellname);
1956
1957         /* construct the path */
1958         if (code == 0) {
1959             clientchar_t temp[1024];
1960
1961             if (cm_FsStringToClientString(ftemp, -1, temp, 1024) != 0) {
1962             cm_ClientStrPrintfN(pathName, (int)lengthof(pathName),
1963                                 rw ? _C("/.%S/") : _C("/%S/"), temp);
1964             *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
1965             return 1;
1966         }
1967     }
1968     }
1969     /* failure */
1970     *pathNamep = NULL;
1971     return 0;
1972 }
1973
1974 /* Client-side offline caching policy types */
1975 #define CSC_POLICY_MANUAL 0
1976 #define CSC_POLICY_DOCUMENTS 1
1977 #define CSC_POLICY_PROGRAMS 2
1978 #define CSC_POLICY_DISABLE 3
1979
1980 int smb_FindShareCSCPolicy(clientchar_t *shareName)
1981 {
1982     DWORD len;
1983     clientchar_t policy[1024];
1984     DWORD dwType;
1985     HKEY hkCSCPolicy;
1986     int  retval = CSC_POLICY_MANUAL;
1987
1988     if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1989                         AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1990                         0,
1991                         "AFS",
1992                         REG_OPTION_NON_VOLATILE,
1993                         KEY_READ,
1994                         NULL,
1995                         &hkCSCPolicy,
1996                         NULL ) != ERROR_SUCCESS)
1997         retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1998
1999     len = sizeof(policy);
2000     if ( RegQueryValueExW( hkCSCPolicy, shareName, 0, &dwType, (LPBYTE) policy, &len ) ||
2001          len == 0) {
2002         retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
2003     }
2004     else if (cm_ClientStrCmpIA(policy, _C("manual")) == 0)
2005     {
2006         retval = CSC_POLICY_MANUAL;
2007     }
2008     else if (cm_ClientStrCmpIA(policy, _C("documents")) == 0)
2009     {
2010         retval = CSC_POLICY_DOCUMENTS;
2011     }
2012     else if (cm_ClientStrCmpIA(policy, _C("programs")) == 0)
2013     {
2014         retval = CSC_POLICY_PROGRAMS;
2015     }
2016     else if (cm_ClientStrCmpIA(policy, _C("disable")) == 0)
2017     {
2018         retval = CSC_POLICY_DISABLE;
2019     }
2020         
2021     RegCloseKey(hkCSCPolicy);
2022     return retval;
2023 }
2024
2025 /* find a dir search structure by cookie value, and return it held.
2026  * Must be called with smb_globalLock held.
2027  */
2028 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
2029 {
2030     smb_dirSearch_t *dsp;
2031         
2032     for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2033         if (dsp->cookie == cookie) {
2034             if (dsp != smb_firstDirSearchp) {
2035                 /* move to head of LRU queue, too, if we're not already there */
2036                 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
2037                     smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2038                 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2039                 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2040                 if (!smb_lastDirSearchp)
2041                     smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2042             }
2043             dsp->refCount++;
2044             break;
2045         }
2046     }
2047
2048     if (dsp == NULL) {
2049         osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
2050         for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2051             osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
2052         }
2053     }
2054     return dsp;
2055 }       
2056
2057 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
2058 {
2059     lock_ObtainMutex(&dsp->mx);
2060     osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p", 
2061               dsp->cookie, dsp, dsp->scp);
2062     dsp->flags |= SMB_DIRSEARCH_DELETE;
2063     if (dsp->scp != NULL) {
2064         lock_ObtainWrite(&dsp->scp->rw);
2065         if (dsp->flags & SMB_DIRSEARCH_BULKST) {
2066             dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2067             dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2068             dsp->scp->bulkStatProgress = hzero;
2069         }       
2070         lock_ReleaseWrite(&dsp->scp->rw);
2071     }   
2072     lock_ReleaseMutex(&dsp->mx);
2073 }               
2074
2075 /* Must be called with the smb_globalLock held */
2076 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
2077 {
2078     cm_scache_t *scp = NULL;
2079
2080     osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
2081     if (dsp->refCount == 0) {
2082         lock_ObtainMutex(&dsp->mx);
2083         if (dsp->flags & SMB_DIRSEARCH_DELETE) {
2084             if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
2085                 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
2086             osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2087             lock_ReleaseMutex(&dsp->mx);
2088             lock_FinalizeMutex(&dsp->mx);
2089             scp = dsp->scp;
2090             osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p", 
2091                      dsp->cookie, dsp, scp);
2092             free(dsp);
2093         } else {
2094             lock_ReleaseMutex(&dsp->mx);
2095         }
2096     }
2097     /* do this now to avoid spurious locking hierarchy creation */
2098     if (scp) 
2099         cm_ReleaseSCache(scp);
2100 }       
2101
2102 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
2103 {
2104     lock_ObtainWrite(&smb_globalLock);
2105     smb_ReleaseDirSearchNoLock(dsp);
2106     lock_ReleaseWrite(&smb_globalLock);
2107 }       
2108
2109 /* find a dir search structure by cookie value, and return it held */
2110 smb_dirSearch_t *smb_FindDirSearch(long cookie)
2111 {
2112     smb_dirSearch_t *dsp;
2113
2114     lock_ObtainWrite(&smb_globalLock);
2115     dsp = smb_FindDirSearchNoLock(cookie);
2116     lock_ReleaseWrite(&smb_globalLock);
2117     return dsp;
2118 }
2119
2120 /* GC some dir search entries, in the address space expected by the specific protocol.
2121  * Must be called with smb_globalLock held; release the lock temporarily.
2122  */
2123 #define SMB_DIRSEARCH_GCMAX     10      /* how many at once */
2124 void smb_GCDirSearches(int isV3)
2125 {
2126     smb_dirSearch_t *prevp;
2127     smb_dirSearch_t *dsp;
2128     smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
2129     int victimCount;
2130     int i;
2131         
2132     victimCount = 0;    /* how many have we got so far */
2133     for (dsp = smb_lastDirSearchp; dsp; dsp=prevp) {
2134         /* we'll move tp from queue, so
2135          * do this early.
2136          */
2137         prevp = (smb_dirSearch_t *) osi_QPrev(&dsp->q); 
2138         /* if no one is using this guy, and we're either in the new protocol,
2139          * or we're in the old one and this is a small enough ID to be useful
2140          * to the old protocol, GC this guy.
2141          */
2142         if (dsp->refCount == 0 && (isV3 || dsp->cookie <= 255)) {
2143             /* hold and delete */
2144             lock_ObtainMutex(&dsp->mx);
2145             dsp->flags |= SMB_DIRSEARCH_DELETE;
2146             lock_ReleaseMutex(&dsp->mx);
2147             victimsp[victimCount++] = dsp;
2148             dsp->refCount++;
2149         }
2150
2151         /* don't do more than this */
2152         if (victimCount >= SMB_DIRSEARCH_GCMAX) 
2153             break;
2154     }
2155         
2156     /* now release them */
2157     for (i = 0; i < victimCount; i++) {
2158         smb_ReleaseDirSearchNoLock(victimsp[i]);
2159     }
2160 }
2161
2162 /* function for allocating a dir search entry.  We need these to remember enough context
2163  * since we don't get passed the path from call to call during a directory search.
2164  *
2165  * Returns a held dir search structure, and bumps the reference count on the vnode,
2166  * since it saves a pointer to the vnode.
2167  */
2168 smb_dirSearch_t *smb_NewDirSearch(int isV3)
2169 {
2170     smb_dirSearch_t *dsp;
2171     int counter;
2172     int maxAllowed;
2173     int start;
2174     int wrapped = 0;
2175
2176     lock_ObtainWrite(&smb_globalLock);
2177     counter = 0;
2178
2179     /* what's the biggest ID allowed in this version of the protocol */
2180     /* TODO: do we really want a non v3 dir search request to wrap
2181        smb_dirSearchCounter? */
2182     maxAllowed = isV3 ? 65535 : 255;
2183     if (smb_dirSearchCounter > maxAllowed)
2184         smb_dirSearchCounter = 1;
2185
2186     start = smb_dirSearchCounter;
2187
2188     while (1) {
2189         /* twice so we have enough tries to find guys we GC after one pass;
2190          * 10 extra is just in case I mis-counted.
2191          */
2192         if (++counter > 2*maxAllowed+10) 
2193             osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2194
2195         if (smb_dirSearchCounter > maxAllowed) {        
2196             smb_dirSearchCounter = 1;
2197         }
2198         if (smb_dirSearchCounter == start) {
2199             if (wrapped)
2200                 smb_GCDirSearches(isV3);
2201             wrapped++;
2202         }
2203         dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2204         if (dsp) {
2205             /* don't need to watch for refcount zero and deleted, since
2206             * we haven't dropped the global lock.
2207             */
2208             dsp->refCount--;
2209             ++smb_dirSearchCounter;
2210             continue;
2211         }       
2212
2213         dsp = malloc(sizeof(*dsp));
2214         memset(dsp, 0, sizeof(*dsp));
2215         dsp->cookie = smb_dirSearchCounter;
2216         ++smb_dirSearchCounter;
2217         dsp->refCount = 1;
2218         lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t", LOCK_HIERARCHY_SMB_DIRSEARCH);
2219         dsp->lastTime = osi_Time();
2220         osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2221         if (!smb_lastDirSearchp) 
2222             smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2223     
2224         osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p", 
2225                  dsp->cookie, dsp);
2226         break;
2227     }   
2228     lock_ReleaseWrite(&smb_globalLock);
2229     return dsp;
2230 }
2231
2232 static smb_packet_t *smb_GetPacket(void)
2233 {
2234     smb_packet_t *tbp;
2235
2236     lock_ObtainWrite(&smb_globalLock);
2237     tbp = smb_packetFreeListp;
2238     if (tbp) 
2239         smb_packetFreeListp = tbp->nextp;
2240     lock_ReleaseWrite(&smb_globalLock);
2241     if (!tbp) {
2242         tbp = calloc(sizeof(*tbp),1);
2243         tbp->magic = SMB_PACKETMAGIC;
2244         tbp->ncbp = NULL;
2245         tbp->vcp = NULL;
2246         tbp->resumeCode = 0;
2247         tbp->inCount = 0;
2248         tbp->fid = 0;
2249         tbp->wctp = NULL;
2250         tbp->inCom = 0;
2251         tbp->oddByte = 0;
2252         tbp->ncb_length = 0;
2253         tbp->flags = 0;
2254         tbp->spacep = NULL;
2255         tbp->stringsp = NULL;
2256     }
2257     osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2258
2259     return tbp;
2260 }
2261
2262 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2263 {
2264     smb_packet_t *tbp;
2265     tbp = smb_GetPacket();
2266     memcpy(tbp, pkt, sizeof(smb_packet_t));
2267     tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2268     tbp->stringsp = NULL;
2269     if (tbp->vcp)
2270         smb_HoldVC(tbp->vcp);
2271     return tbp;
2272 }
2273
2274 static NCB *smb_GetNCB(void)
2275 {
2276     smb_ncb_t *tbp;
2277     NCB *ncbp;
2278
2279     lock_ObtainWrite(&smb_globalLock);
2280     tbp = smb_ncbFreeListp;
2281     if (tbp) 
2282         smb_ncbFreeListp = tbp->nextp;
2283     lock_ReleaseWrite(&smb_globalLock);
2284     if (!tbp) {
2285         tbp = calloc(sizeof(*tbp),1);
2286         tbp->magic = SMB_NCBMAGIC;
2287     }
2288         
2289     osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2290
2291     memset(&tbp->ncb, 0, sizeof(NCB));
2292     ncbp = &tbp->ncb;
2293     return ncbp;
2294 }
2295
2296 static void FreeSMBStrings(smb_packet_t * pkt)
2297 {
2298     cm_space_t * s;
2299     cm_space_t * ns;
2300
2301     for (s = pkt->stringsp; s; s = ns) {
2302         ns = s->nextp;
2303         cm_FreeSpace(s);
2304     }
2305     pkt->stringsp = NULL;
2306 }
2307
2308 void smb_FreePacket(smb_packet_t *tbp)
2309 {
2310     smb_vc_t * vcp = NULL;
2311     osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2312         
2313     lock_ObtainWrite(&smb_globalLock);
2314     tbp->nextp = smb_packetFreeListp;
2315     smb_packetFreeListp = tbp;
2316     tbp->magic = SMB_PACKETMAGIC;
2317     tbp->ncbp = NULL;
2318     vcp = tbp->vcp;
2319     tbp->vcp = NULL;
2320     tbp->resumeCode = 0;
2321     tbp->inCount = 0;
2322     tbp->fid = 0;
2323     tbp->wctp = NULL;
2324     tbp->inCom = 0;
2325     tbp->oddByte = 0;
2326     tbp->ncb_length = 0;
2327     tbp->flags = 0;
2328     FreeSMBStrings(tbp);
2329     lock_ReleaseWrite(&smb_globalLock);
2330
2331     if (vcp)
2332         smb_ReleaseVC(vcp);
2333 }
2334
2335 static void smb_FreeNCB(NCB *bufferp)
2336 {
2337     smb_ncb_t *tbp;
2338         
2339     tbp = (smb_ncb_t *) bufferp;
2340     osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2341         
2342     lock_ObtainWrite(&smb_globalLock);
2343     tbp->nextp = smb_ncbFreeListp;
2344     smb_ncbFreeListp = tbp;
2345     lock_ReleaseWrite(&smb_globalLock);
2346 }
2347
2348 /* get a ptr to the data part of a packet, and its count */
2349 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2350 {
2351     int parmBytes;
2352     int dataBytes;
2353     unsigned char *afterParmsp;
2354
2355     parmBytes = *smbp->wctp << 1;
2356     afterParmsp = smbp->wctp + parmBytes + 1;
2357         
2358     dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2359     if (nbytesp) *nbytesp = dataBytes;
2360         
2361     /* don't forget to skip the data byte count, since it follows
2362      * the parameters; that's where the "2" comes from below.
2363      */
2364     return (unsigned char *) (afterParmsp + 2);
2365 }
2366
2367 /* must set all the returned parameters before playing around with the
2368  * data region, since the data region is located past the end of the
2369  * variable number of parameters.
2370  */
2371 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2372 {
2373     unsigned char *afterParmsp;
2374
2375     afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2376         
2377     *afterParmsp++ = dsize & 0xff;
2378     *afterParmsp = (dsize>>8) & 0xff;
2379 }       
2380
2381 /* return the parm'th parameter in the smbp packet */
2382 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2383 {
2384     int parmCount;
2385     unsigned char *parmDatap;
2386
2387     parmCount = *smbp->wctp;
2388
2389     if (parm >= parmCount) {
2390         char s[100];
2391
2392         sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2393                 parm, parmCount, smbp->ncb_length);
2394         osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2395                  parm, parmCount, smbp->ncb_length);
2396         LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM, 
2397                  __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2398         osi_panic(s, __FILE__, __LINE__);
2399     }
2400     parmDatap = smbp->wctp + (2*parm) + 1;
2401         
2402     return parmDatap[0] + (parmDatap[1] << 8);
2403 }
2404
2405 /* return the parm'th parameter in the smbp packet */
2406 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2407 {
2408     int parmCount;
2409     unsigned char *parmDatap;
2410
2411     parmCount = *smbp->wctp;
2412
2413     if (parm >= parmCount) {
2414         char s[100];
2415
2416         sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2417                 parm, parmCount, smbp->ncb_length);
2418         osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2419                  parm, parmCount, smbp->ncb_length);
2420         LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM, 
2421                  __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2422         osi_panic(s, __FILE__, __LINE__);
2423     }
2424     parmDatap = smbp->wctp + (2*parm) + 1;
2425         
2426     return parmDatap[0];
2427 }
2428
2429 /* return the parm'th parameter in the smbp packet */
2430 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2431 {
2432     int parmCount;
2433     unsigned char *parmDatap;
2434
2435     parmCount = *smbp->wctp;
2436
2437     if (parm + 1 >= parmCount) {
2438         char s[100];
2439
2440         sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2441                 parm, parmCount, smbp->ncb_length);
2442         osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2443                  parm, parmCount, smbp->ncb_length);
2444         LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM, 
2445                  __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2446         osi_panic(s, __FILE__, __LINE__);
2447     }
2448     parmDatap = smbp->wctp + (2*parm) + 1;
2449         
2450     return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2451 }
2452
2453 /* return the parm'th parameter in the smbp packet */
2454 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2455 {
2456     int parmCount;
2457     unsigned char *parmDatap;
2458
2459     parmCount = *smbp->wctp;
2460
2461     if (parm * 2 + offset >= parmCount * 2) {
2462         char s[100];
2463
2464         sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2465                 parm, offset, parmCount, smbp->ncb_length);
2466         LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET, 
2467                  __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2468         osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2469                 parm, offset, parmCount, smbp->ncb_length);
2470         osi_panic(s, __FILE__, __LINE__);
2471     }
2472     parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2473         
2474     return parmDatap[0] + (parmDatap[1] << 8);
2475 }
2476
2477 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2478 {
2479     unsigned char *parmDatap;
2480
2481     /* make sure we have enough slots */
2482     if (*smbp->wctp <= slot) 
2483         *smbp->wctp = slot+1;
2484         
2485     parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2486     *parmDatap++ = parmValue & 0xff;
2487     *parmDatap = (parmValue>>8) & 0xff;
2488 }       
2489
2490 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2491 {
2492     unsigned char *parmDatap;
2493
2494     /* make sure we have enough slots */
2495     if (*smbp->wctp <= slot) 
2496         *smbp->wctp = slot+2;
2497
2498     parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2499     *parmDatap++ = parmValue & 0xff;
2500     *parmDatap++ = (parmValue>>8) & 0xff;
2501     *parmDatap++ = (parmValue>>16) & 0xff;
2502     *parmDatap   = (parmValue>>24) & 0xff;
2503 }
2504
2505 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2506 {
2507     unsigned char *parmDatap;
2508     int i;
2509
2510     /* make sure we have enough slots */
2511     if (*smbp->wctp <= slot) 
2512         *smbp->wctp = slot+4;
2513
2514     parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2515     for (i=0; i<8; i++)
2516         *parmDatap++ = *parmValuep++;
2517 }       
2518
2519 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2520 {
2521     unsigned char *parmDatap;
2522
2523     /* make sure we have enough slots */
2524     if (*smbp->wctp <= slot) {
2525         if (smbp->oddByte) {
2526             smbp->oddByte = 0;
2527             *smbp->wctp = slot+1;
2528         } else
2529             smbp->oddByte = 1;
2530     }
2531
2532     parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2533     *parmDatap++ = parmValue & 0xff;
2534 }
2535
2536
2537
2538 void smb_StripLastComponent(clientchar_t *outPathp, clientchar_t **lastComponentp,
2539                             clientchar_t *inPathp)
2540 {
2541     clientchar_t *lastSlashp;
2542     clientchar_t *streamp = NULL;
2543     clientchar_t *typep = NULL;
2544
2545     lastSlashp = cm_ClientStrRChr(inPathp, '\\');
2546     if (lastComponentp) {
2547         *lastComponentp = lastSlashp;
2548     }
2549     if (lastSlashp) {
2550         /*
2551          * If the name contains a stream name and a type
2552          * and the stream name is the nul-string and the
2553          * type is $DATA, then strip "::$DATA" from the
2554          * last component string that is returned.
2555          *
2556          * Otherwise, return the full path name and allow
2557          * the file name to be rejected because it contains
2558          * a colon.
2559          */
2560         typep = cm_ClientStrRChr(lastSlashp, L':');
2561         if (typep && cm_ClientStrCmpI(typep, L":$DATA") == 0) {
2562             *typep = '\0';
2563             streamp = cm_ClientStrRChr(lastSlashp, L':');
2564             if (streamp && cm_ClientStrCmpI(streamp, L":") == 0) {
2565                 *streamp = '\0';
2566             } else
2567                 *typep = ':';
2568             osi_Log2(smb_logp, "smb_StripLastComponent found stream [%S] type [%S]",
2569                      osi_LogSaveClientString(smb_logp,streamp),
2570                      osi_LogSaveClientString(smb_logp,typep));
2571         }
2572
2573         while (1) {
2574             if (inPathp == lastSlashp) 
2575                 break;
2576             *outPathp++ = *inPathp++;
2577         }
2578         *outPathp++ = 0;
2579     }
2580     else {
2581         *outPathp++ = 0;
2582     }
2583 }
2584
2585 clientchar_t *smb_ParseASCIIBlock(smb_packet_t * pktp, unsigned char *inp,
2586                                   char **chainpp, int flags)
2587 {
2588     size_t cb;
2589     afs_uint32 type = *inp++;
2590
2591     /* 
2592      * The first byte specifies the type of the input string.
2593      * CIFS TR 1.0 3.2.10.  This function only parses null terminated
2594      * strings.
2595      */
2596     switch (type) {
2597     /* Length Counted */
2598     case 0x1: /* Data Block */
2599     case 0x5: /* Variable Block */
2600         cb = *inp++ << 16 | *inp++;
2601         break;
2602
2603     /* Null-terminated string */
2604     case 0x4: /* ASCII */
2605     case 0x3: /* Pathname */
2606     case 0x2: /* Dialect */
2607         cb = sizeof(pktp->data) - (inp - pktp->data);
2608         if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2609 #ifdef DEBUG_UNICODE
2610             DebugBreak();
2611 #endif
2612             cb = sizeof(pktp->data);
2613         }
2614         break;
2615
2616     default:
2617         return NULL;            /* invalid input */
2618     }
2619
2620 #ifdef SMB_UNICODE
2621     if (type == 0x2 /* Dialect */ || !WANTS_UNICODE(pktp))
2622         flags |= SMB_STRF_FORCEASCII;
2623 #endif
2624
2625     return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2626 }
2627
2628 clientchar_t *smb_ParseString(smb_packet_t * pktp, unsigned char * inp,
2629                               char ** chainpp, int flags)
2630 {
2631     size_t cb;
2632
2633 #ifdef SMB_UNICODE
2634     if (!WANTS_UNICODE(pktp))
2635         flags |= SMB_STRF_FORCEASCII;
2636 #endif
2637
2638     cb = sizeof(pktp->data) - (inp - pktp->data);
2639     if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2640 #ifdef DEBUG_UNICODE
2641         DebugBreak();
2642 #endif
2643         cb = sizeof(pktp->data);
2644     }
2645     return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp,
2646                               flags | SMB_STRF_SRCNULTERM);
2647 }
2648
2649 clientchar_t *smb_ParseStringCb(smb_packet_t * pktp, unsigned char * inp,
2650                                 size_t cb, char ** chainpp, int flags)
2651 {
2652 #ifdef SMB_UNICODE
2653     if (!WANTS_UNICODE(pktp))
2654         flags |= SMB_STRF_FORCEASCII;
2655 #endif
2656
2657     return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2658 }
2659
2660 clientchar_t *smb_ParseStringCch(smb_packet_t * pktp, unsigned char * inp,
2661                                  size_t cch, char ** chainpp, int flags)
2662 {
2663     size_t cb = cch;
2664
2665 #ifdef SMB_UNICODE
2666     if (!WANTS_UNICODE(pktp))
2667         flags |= SMB_STRF_FORCEASCII;
2668     else
2669         cb = cch * sizeof(wchar_t);
2670 #endif
2671
2672     return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2673 }
2674
2675 clientchar_t *
2676 smb_ParseStringBuf(const unsigned char * bufbase,
2677                    cm_space_t ** stringspp,
2678                    unsigned char *inp, size_t *pcb_max,
2679                    char **chainpp, int flags)
2680 {
2681 #ifdef SMB_UNICODE
2682     if (!(flags & SMB_STRF_FORCEASCII)) {
2683         size_t cch_src;
2684         cm_space_t * spacep;
2685         int    null_terms = 0;
2686
2687         if (bufbase && ((inp - bufbase) % 2) != 0) {
2688             inp++;              /* unicode strings are always word aligned */
2689         }
2690
2691         if (*pcb_max > 0) {
2692             if (FAILED(StringCchLengthW((const wchar_t *) inp, *pcb_max / sizeof(wchar_t),
2693                                         &cch_src))) {
2694                 cch_src = *pcb_max / sizeof(wchar_t);
2695                 *pcb_max = 0;
2696                 null_terms = 0;
2697             } else {
2698                 *pcb_max -= (cch_src + 1) * sizeof(wchar_t);
2699                 null_terms = 1;
2700             }
2701         } else {
2702             cch_src = 0;
2703         }
2704
2705         spacep = cm_GetSpace();
2706         spacep->nextp = *stringspp;
2707         *stringspp = spacep;
2708
2709         if (cch_src == 0) {
2710             if (chainpp) {
2711                 *chainpp = inp + sizeof(wchar_t);
2712             }
2713
2714             *(spacep->wdata) = 0;
2715             return spacep->wdata;
2716         }
2717
2718         StringCchCopyNW(spacep->wdata,
2719                         lengthof(spacep->wdata),
2720                         (const clientchar_t *) inp, cch_src);
2721
2722         if (chainpp)
2723             *chainpp = inp + (cch_src + null_terms)*sizeof(wchar_t);
2724
2725         return spacep->wdata;
2726
2727     } else {
2728 #endif
2729         cm_space_t * spacep;
2730         int cchdest;
2731
2732         /* Not using Unicode */
2733         if (chainpp) {
2734             *chainpp = inp + strlen(inp) + 1;
2735         }
2736
2737         spacep = cm_GetSpace();
2738         spacep->nextp = *stringspp;
2739         *stringspp = spacep;
2740
2741         cchdest = lengthof(spacep->wdata);
2742         cm_Utf8ToUtf16(inp, (int)((flags & SMB_STRF_SRCNULTERM)? -1 : *pcb_max),
2743                        spacep->wdata, cchdest);
2744
2745         return spacep->wdata;
2746 #ifdef SMB_UNICODE
2747     }
2748 #endif
2749 }
2750
2751 unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
2752                             clientchar_t * str,
2753                             size_t * plen, int flags)
2754 {
2755     size_t buffersize;
2756     int align = 0;
2757
2758     if (outp == NULL) {
2759         /* we are only calculating the required size */
2760
2761         if (plen == NULL)
2762             return NULL;
2763
2764 #ifdef SMB_UNICODE
2765
2766         if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2767
2768             StringCbLengthW(str, SMB_STRINGBUFSIZE * sizeof(wchar_t), plen);
2769             if (!(flags & SMB_STRF_IGNORENUL))
2770                 *plen += sizeof(wchar_t);
2771
2772             return (unsigned char *) 1; /* return TRUE if we are using unicode */
2773         }
2774         else
2775 #endif
2776         {
2777             /* Storing ANSI */
2778
2779             size_t cch_str;
2780             size_t cch_dest;
2781
2782             cch_str = cm_ClientStrLen(str);
2783             cch_dest = cm_ClientStringToUtf8(str, (int)cch_str, NULL, 0);
2784
2785             if (plen)
2786                 *plen = ((flags & SMB_STRF_IGNORENUL)? cch_dest: cch_dest+1);
2787
2788             return NULL;
2789         }
2790
2791         /* Not reached. */
2792     }
2793
2794     /* if outp != NULL ... */
2795
2796     /* Number of bytes left in the buffer.
2797
2798        If outp lies inside the packet data buffer, we assume that the
2799        buffer is the packet data buffer.  Otherwise we assume that the
2800        buffer is sizeof(packet->data).
2801
2802     */
2803     if (outp >= pktp->data && outp < pktp->data + sizeof(pktp->data)) {
2804         align = (int)((outp - pktp->data) % 2);
2805         buffersize = (pktp->data + sizeof(pktp->data)) - ((char *) outp);
2806     } else {
2807         align = (int)(((size_t) outp) % 2);
2808         buffersize = (int)sizeof(pktp->data);
2809     }
2810
2811 #ifdef SMB_UNICODE
2812
2813     if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2814         int nchars;
2815
2816         if (align)
2817             *outp++ = '\0';
2818
2819         if (*str == _C('\0')) {
2820
2821             if (buffersize < sizeof(wchar_t))
2822                 return NULL;
2823
2824             *((wchar_t *) outp) = L'\0';
2825             if (plen && !(flags & SMB_STRF_IGNORENUL))
2826                 *plen += sizeof(wchar_t);
2827             return outp + sizeof(wchar_t);
2828         }
2829
2830         nchars = cm_ClientStringToUtf16(str, -1, (wchar_t *) outp, (int)(buffersize / sizeof(wchar_t)));
2831         if (nchars == 0) {
2832             osi_Log2(smb_logp, "UnparseString: Can't convert string to Unicode [%S], GLE=%d",
2833                      osi_LogSaveClientString(smb_logp, str),
2834                      GetLastError());
2835             return NULL;
2836         }
2837
2838         if (plen)
2839             *plen += sizeof(wchar_t) * ((flags & SMB_STRF_IGNORENUL)? nchars - 1: nchars);
2840
2841         return outp + sizeof(wchar_t) * nchars;
2842     }
2843     else
2844 #endif
2845     {
2846         /* Storing ANSI */
2847         size_t cch_dest;
2848
2849         cch_dest = cm_ClientStringToUtf8(str, -1, outp, (int)buffersize);
2850
2851         if (plen)
2852             *plen += ((flags & SMB_STRF_IGNORENUL)? cch_dest - 1: cch_dest);
2853
2854         return outp + cch_dest;
2855     }
2856 }
2857
2858 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2859 {
2860     int tlen;
2861
2862     if (*inp++ != 0x5) 
2863         return NULL;
2864     tlen = inp[0] + (inp[1]<<8);
2865     inp += 2;           /* skip length field */
2866
2867     if (chainpp) {
2868         *chainpp = inp + tlen;
2869     }
2870         
2871     if (lengthp) 
2872         *lengthp = tlen;
2873         
2874     return inp;
2875 }       
2876
2877 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2878 {
2879     int tlen;
2880
2881     if (*inp++ != 0x1) return NULL;
2882     tlen = inp[0] + (inp[1]<<8);
2883     inp += 2;           /* skip length field */
2884         
2885     if (chainpp) {
2886         *chainpp = inp + tlen;
2887     }   
2888
2889     if (lengthp) *lengthp = tlen;
2890         
2891     return inp;
2892 }
2893
2894 /* format a packet as a response */
2895 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2896 {
2897     smb_t *outp;
2898     smb_t *inSmbp;
2899
2900     outp = (smb_t *) op;
2901         
2902     /* zero the basic structure through the smb_wct field, and zero the data
2903      * size field, assuming that wct stays zero; otherwise, you have to 
2904      * explicitly set the data size field, too.
2905      */
2906     inSmbp = (smb_t *) inp;
2907     memset(outp, 0, sizeof(smb_t)+2);
2908     outp->id[0] = 0xff;
2909     outp->id[1] = 'S';
2910     outp->id[2] = 'M';
2911     outp->id[3] = 'B';
2912     if (inp) {
2913         outp->com = inSmbp->com;
2914         outp->tid = inSmbp->tid;
2915         outp->pid = inSmbp->pid;
2916         outp->uid = inSmbp->uid;
2917         outp->mid = inSmbp->mid;
2918         outp->res[0] = inSmbp->res[0];
2919         outp->res[1] = inSmbp->res[1];
2920         op->inCom = inSmbp->com;
2921     }
2922     outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
2923 #ifdef SEND_CANONICAL_PATHNAMES
2924     outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
2925 #endif
2926     outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2927 #ifdef SMB_UNICODE
2928     if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
2929         outp->flg2 |= SMB_FLAGS2_UNICODE;
2930 #endif
2931
2932     /* copy fields in generic packet area */
2933     op->wctp = &outp->wct;
2934 }       
2935
2936 /* send a (probably response) packet; vcp tells us to whom to send it.
2937  * we compute the length by looking at wct and bcc fields.
2938  */
2939 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2940 {
2941     NCB *ncbp;
2942     int extra;
2943     long code = 0;
2944     unsigned char *tp;
2945     int localNCB = 0;
2946         
2947     ncbp = inp->ncbp;
2948     if (ncbp == NULL) {
2949         ncbp = smb_GetNCB();
2950         localNCB = 1;
2951     }
2952  
2953     memset(ncbp, 0, sizeof(NCB));
2954
2955     extra = 2 * (*inp->wctp);   /* space used by parms, in bytes */
2956     tp = inp->wctp + 1+ extra;  /* points to count of data bytes */
2957     extra += tp[0] + (tp[1]<<8);
2958     extra += (unsigned int)(inp->wctp - inp->data);     /* distance to last wct field */
2959     extra += 3;                 /* wct and length fields */
2960         
2961     ncbp->ncb_length = extra;   /* bytes to send */
2962     ncbp->ncb_lsn = (unsigned char) vcp->lsn;   /* vc to use */
2963     ncbp->ncb_lana_num = vcp->lana;
2964     ncbp->ncb_command = NCBSEND;        /* op means send data */
2965     ncbp->ncb_buffer = (char *) inp;/* packet */
2966     code = Netbios(ncbp);
2967         
2968     if (code != 0) {
2969         const char * s = ncb_error_string(code);
2970         osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2971         LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
2972
2973         lock_ObtainMutex(&vcp->mx);
2974         if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
2975             osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
2976                       vcp, vcp->usersp);
2977             vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2978             lock_ReleaseMutex(&vcp->mx);
2979             lock_ObtainWrite(&smb_globalLock);
2980             dead_sessions[vcp->session] = TRUE;
2981             lock_ReleaseWrite(&smb_globalLock);
2982             smb_CleanupDeadVC(vcp);
2983         } else {
2984             lock_ReleaseMutex(&vcp->mx);
2985         }
2986     }
2987
2988     if (localNCB)
2989         smb_FreeNCB(ncbp);
2990 }
2991
2992 void smb_MapNTError(long code, unsigned long *NTStatusp)
2993 {
2994     unsigned long NTStatus;
2995
2996     /* map CM_ERROR_* errors to NT 32-bit status codes */
2997     /* NT Status codes are listed in ntstatus.h not winerror.h */
2998     if (code == 0) {
2999         NTStatus = 0;
3000     } 
3001     else if (code == CM_ERROR_NOSUCHCELL) {
3002         NTStatus = 0xC0000034L; /* Name not found */
3003     }
3004     else if (code == CM_ERROR_NOSUCHVOLUME) {
3005         NTStatus = 0xC0000034L; /* Name not found */
3006     }
3007     else if (code == CM_ERROR_TIMEDOUT) {
3008 #ifdef COMMENT
3009         NTStatus = 0xC00000CFL; /* Sharing Paused */
3010
3011         /* Do not send Timeout to the SMB redirector.
3012          * It causes the redirector to drop the connection */
3013         NTStatus = 0x00000102L; /* Timeout */
3014 #else
3015         NTStatus = 0xC000022DL; /* Retry */
3016 #endif
3017     }
3018     else if (code == CM_ERROR_RETRY) {
3019         NTStatus = 0xC000022DL; /* Retry */
3020     }
3021     else if (code == CM_ERROR_NOACCESS) {
3022         NTStatus = 0xC0000022L; /* Access denied */
3023     }
3024     else if (code == CM_ERROR_READONLY) {
3025         NTStatus = 0xC00000A2L; /* Write protected */
3026     }
3027     else if (code == CM_ERROR_NOSUCHFILE ||
3028              code == CM_ERROR_BPLUS_NOMATCH) {
3029         NTStatus = 0xC0000034L; /* Name not found */
3030     }
3031     else if (code == CM_ERROR_NOSUCHPATH) {
3032         NTStatus = 0xC000003AL; /* Object path not found */
3033     }           
3034     else if (code == CM_ERROR_TOOBIG) {
3035         NTStatus = 0xC000007BL; /* Invalid image format */
3036     }
3037     else if (code == CM_ERROR_INVAL) {
3038         NTStatus = 0xC000000DL; /* Invalid parameter */
3039     }
3040     else if (code == CM_ERROR_BADFD) {
3041         NTStatus = 0xC0000008L; /* Invalid handle */
3042     }
3043     else if (code == CM_ERROR_BADFDOP) {
3044         NTStatus = 0xC0000022L; /* Access denied */
3045     }
3046     else if (code == CM_ERROR_UNKNOWN) {
3047         NTStatus = 0xC0000022L; /* Access denied */
3048     }
3049     else if (code == CM_ERROR_EXISTS) {
3050         NTStatus = 0xC0000035L; /* Object name collision */
3051     }
3052     else if (code == CM_ERROR_NOTEMPTY) {
3053         NTStatus = 0xC0000101L; /* Directory not empty */
3054     }   
3055     else if (code == CM_ERROR_CROSSDEVLINK) {
3056         NTStatus = 0xC00000D4L; /* Not same device */
3057     }
3058     else if (code == CM_ERROR_NOTDIR) {
3059         NTStatus = 0xC0000103L; /* Not a directory */
3060     }
3061     else if (code == CM_ERROR_ISDIR) {
3062         NTStatus = 0xC00000BAL; /* File is a directory */
3063     }
3064     else if (code == CM_ERROR_BADOP) {
3065 #ifdef COMMENT
3066         /* I have no idea where this comes from */
3067         NTStatus = 0xC09820FFL; /* SMB no support */
3068 #else
3069         NTStatus = 0xC00000BBL;     /* Not supported */
3070 #endif /* COMMENT */
3071     }
3072     else if (code == CM_ERROR_BADSHARENAME) {
3073         NTStatus = 0xC00000BEL; /* Bad network path (server valid, share bad) */
3074     }
3075     else if (code == CM_ERROR_NOIPC) {
3076 #ifdef COMMENT
3077         NTStatus = 0xC0000022L; /* Access Denied */
3078 #else   
3079         NTStatus = 0xC000013DL; /* Remote Resources */
3080 #endif
3081     }
3082     else if (code == CM_ERROR_CLOCKSKEW ||
3083              code == RXKADNOAUTH) {
3084         NTStatus = 0xC0000133L; /* Time difference at DC */
3085     }
3086     else if (code == CM_ERROR_BADTID) {
3087         NTStatus = 0xC0982005L; /* SMB bad TID */
3088     }
3089     else if (code == CM_ERROR_USESTD) {
3090         NTStatus = 0xC09820FBL; /* SMB use standard */
3091     }
3092     else if (code == CM_ERROR_QUOTA) {
3093         NTStatus = 0xC0000044L; /* Quota exceeded */
3094     }
3095     else if (code == CM_ERROR_SPACE) {
3096         NTStatus = 0xC000007FL; /* Disk full */
3097     }
3098     else if (code == CM_ERROR_ATSYS) {
3099         NTStatus = 0xC0000033L; /* Object name invalid */
3100     }
3101     else if (code == CM_ERROR_BADNTFILENAME) {
3102         NTStatus = 0xC0000033L; /* Object name invalid */
3103     }
3104     else if (code == CM_ERROR_WOULDBLOCK) {
3105         NTStatus = 0xC00000D8L; /* Can't wait */
3106     }
3107     else if (code == CM_ERROR_SHARING_VIOLATION) {
3108         NTStatus = 0xC0000043L; /* Sharing violation */
3109     }
3110     else if (code == CM_ERROR_LOCK_CONFLICT) {
3111         NTStatus = 0xC0000054L; /* Lock conflict */
3112     }
3113     else if (code == CM_ERROR_PARTIALWRITE) {
3114         NTStatus = 0xC000007FL; /* Disk full */
3115     }
3116     else if (code == CM_ERROR_BUFFERTOOSMALL) {
3117         NTStatus = 0xC0000023L; /* Buffer too small */
3118     }
3119     else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3120         NTStatus = 0xC0000035L; /* Object name collision */
3121     }   
3122     else if (code == CM_ERROR_BADPASSWORD) {
3123         NTStatus = 0xC000006DL; /* unknown username or bad password */
3124     }
3125     else if (code == CM_ERROR_BADLOGONTYPE) {
3126         NTStatus = 0xC000015BL; /* logon type not granted */
3127     }
3128     else if (code == CM_ERROR_GSSCONTINUE) {
3129         NTStatus = 0xC0000016L; /* more processing required */
3130     }
3131     else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3132 #ifdef COMMENT
3133         NTStatus = 0xC0000280L; /* reparse point not resolved */
3134 #else
3135         NTStatus = 0xC0000022L; /* Access Denied */
3136 #endif
3137     }
3138     else if (code == CM_ERROR_PATH_NOT_COVERED) {
3139         NTStatus = 0xC0000257L; /* Path Not Covered */
3140     } 
3141     else if (code == CM_ERROR_ALLBUSY) {
3142         NTStatus = 0xC000022DL; /* Retry */
3143     } 
3144     else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3145         NTStatus = 0xC000003AL; /* Path not found */
3146     } 
3147     else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3148         NTStatus = 0xC0000322L; /* No Kerberos key */
3149     } 
3150     else if (code == CM_ERROR_BAD_LEVEL) {
3151         NTStatus = 0xC0000148L; /* Invalid Level */
3152     } 
3153     else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3154         NTStatus = 0xC000007EL; /* Range Not Locked */
3155     } 
3156     else if (code == CM_ERROR_NOSUCHDEVICE) {
3157         NTStatus = 0xC000000EL; /* No Such Device */
3158     }
3159     else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3160         NTStatus = 0xC0000055L; /* Lock Not Granted */
3161     }
3162     else if (code == ENOMEM) {
3163         NTStatus = 0xC0000017L; /* Out of Memory */
3164     }
3165     else if (code == CM_ERROR_RPC_MOREDATA) {
3166         NTStatus = 0x80000005L; /* Buffer overflow */
3167     }
3168     else  {
3169         NTStatus = 0xC0982001L; /* SMB non-specific error */
3170     }
3171
3172     *NTStatusp = NTStatus;
3173     osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
3174 }       
3175
3176 /* 
3177  * NTSTATUS <-> Win32 Error Translation 
3178  * http://support.microsoft.com/kb/113996 
3179  */
3180 void smb_MapWin32Error(long code, unsigned long *Win32Ep)
3181 {
3182     unsigned long Win32E;
3183
3184     /* map CM_ERROR_* errors to Win32 32-bit error codes */
3185     if (code == 0) {
3186         Win32E = 0;
3187     } 
3188     else if (code == CM_ERROR_NOSUCHCELL) {
3189         Win32E = ERROR_FILE_NOT_FOUND;  /* No such file */
3190     }
3191     else if (code == CM_ERROR_NOSUCHVOLUME) {
3192         Win32E = ERROR_FILE_NOT_FOUND;  /* No such file */
3193     }
3194     else if (code == CM_ERROR_TIMEDOUT) {
3195 #ifdef COMMENT
3196         Win32E = ERROR_SHARING_PAUSED;  /* Sharing Paused */
3197 #else
3198         Win32E = ERROR_UNEXP_NET_ERR;   /* Timeout */
3199 #endif
3200     }
3201     else if (code == CM_ERROR_RETRY) {
3202         Win32E = ERROR_RETRY;           /* Retry */
3203     }
3204     else if (code == CM_ERROR_NOACCESS) {
3205         Win32E = ERROR_ACCESS_DENIED;   /* Access denied */
3206     }
3207     else if (code == CM_ERROR_READONLY) {
3208         Win32E = ERROR_WRITE_PROTECT;   /* Write protected */
3209     }
3210     else if (code == CM_ERROR_NOSUCHFILE ||
3211              code == CM_ERROR_BPLUS_NOMATCH) {
3212         Win32E = ERROR_FILE_NOT_FOUND;  /* No such file */
3213     }
3214     else if (code == CM_ERROR_NOSUCHPATH) {
3215         Win32E = ERROR_PATH_NOT_FOUND;  /* Object path not found */
3216     }           
3217     else if (code == CM_ERROR_TOOBIG) {
3218         Win32E = ERROR_BAD_EXE_FORMAT;  /* Invalid image format */
3219     }
3220     else if (code == CM_ERROR_INVAL) {
3221         Win32E = ERROR_INVALID_PARAMETER;/* Invalid parameter */
3222     }
3223     else if (code == CM_ERROR_BADFD) {
3224         Win32E = ERROR_INVALID_HANDLE;  /* Invalid handle */
3225     }
3226     else if (code == CM_ERROR_BADFDOP) {
3227         Win32E = ERROR_ACCESS_DENIED;   /* Access denied */
3228     }
3229     else if (code == CM_ERROR_UNKNOWN) {
3230         Win32E = ERROR_ACCESS_DENIED;   /* Access denied */
3231     }
3232     else if (code == CM_ERROR_EXISTS) {
3233         Win32E = ERROR_ALREADY_EXISTS;  /* Object name collision */
3234     }
3235     else if (code == CM_ERROR_NOTEMPTY) {
3236         Win32E = ERROR_DIR_NOT_EMPTY;   /* Directory not empty */
3237     }   
3238     else if (code == CM_ERROR_CROSSDEVLINK) {
3239         Win32E = ERROR_NOT_SAME_DEVICE; /* Not same device */
3240     }
3241     else if (code == CM_ERROR_NOTDIR) {
3242         Win32E = ERROR_DIRECTORY;       /* Not a directory */
3243     }
3244     else if (code == CM_ERROR_ISDIR) {
3245         Win32E = ERROR_ACCESS_DENIED;   /* File is a directory */
3246     }
3247     else if (code == CM_ERROR_BADOP) {
3248         Win32E = ERROR_NOT_SUPPORTED;   /* Not supported */
3249     }
3250     else if (code == CM_ERROR_BADSHARENAME) {
3251         Win32E = ERROR_BAD_NETPATH;     /* Bad network path (server valid, share bad) */
3252     }
3253     else if (code == CM_ERROR_NOIPC) {
3254 #ifdef COMMENT
3255         Win32E = ERROR_ACCESS_DENIED;   /* Access Denied */
3256 #else   
3257         Win32E = ERROR_REM_NOT_LIST;    /* Remote Resources */
3258 #endif
3259     }
3260     else if (code == CM_ERROR_CLOCKSKEW ||
3261              code == RXKADNOAUTH) {
3262         Win32E = ERROR_TIME_SKEW;       /* Time difference at DC */
3263     }
3264     else if (code == CM_ERROR_BADTID) {
3265         Win32E = ERROR_FILE_NOT_FOUND;  /* SMB bad TID */
3266     }
3267     else if (code == CM_ERROR_USESTD) {
3268         Win32E = ERROR_ACCESS_DENIED;   /* SMB use standard */
3269     }
3270     else if (code == CM_ERROR_QUOTA) {
3271         Win32E = ERROR_NOT_ENOUGH_QUOTA;/* Quota exceeded */
3272     }
3273     else if (code == CM_ERROR_SPACE) {
3274         Win32E = ERROR_DISK_FULL;       /* Disk full */
3275     }
3276     else if (code == CM_ERROR_ATSYS) {
3277         Win32E = ERROR_INVALID_NAME;    /* Object name invalid */
3278     }
3279     else if (code == CM_ERROR_BADNTFILENAME) {
3280         Win32E = ERROR_INVALID_NAME;    /* Object name invalid */
3281     }
3282     else if (code == CM_ERROR_WOULDBLOCK) {
3283         Win32E = WAIT_TIMEOUT;          /* Can't wait */
3284     }
3285     else if (code == CM_ERROR_SHARING_VIOLATION) {
3286         Win32E = ERROR_SHARING_VIOLATION; /* Sharing violation */
3287     }
3288     else if (code == CM_ERROR_LOCK_CONFLICT) {
3289         Win32E = ERROR_LOCK_VIOLATION;   /* Lock conflict */
3290     }
3291     else if (code == CM_ERROR_PARTIALWRITE) {
3292         Win32E = ERROR_DISK_FULL;       /* Disk full */
3293     }
3294     else if (code == CM_ERROR_BUFFERTOOSMALL) {
3295         Win32E = ERROR_INSUFFICIENT_BUFFER;     /* Buffer too small */
3296     }
3297     else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3298         Win32E = ERROR_ALREADY_EXISTS;  /* Object name collision */
3299     }   
3300     else if (code == CM_ERROR_BADPASSWORD) {
3301         Win32E = ERROR_LOGON_FAILURE;   /* unknown username or bad password */
3302     }
3303     else if (code == CM_ERROR_BADLOGONTYPE) {
3304         Win32E = ERROR_INVALID_LOGON_TYPE; /* logon type not granted */
3305     }
3306     else if (code == CM_ERROR_GSSCONTINUE) {
3307         Win32E = ERROR_MORE_DATA;       /* more processing required */
3308     }
3309     else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3310 #ifdef COMMENT
3311         Win32E = ERROR_CANT_RESOLVE_FILENAME; /* reparse point not resolved */
3312 #else
3313         Win32E = ERROR_ACCESS_DENIED;   /* Access Denied */
3314 #endif
3315     }
3316     else if (code == CM_ERROR_PATH_NOT_COVERED) {
3317         Win32E = ERROR_HOST_UNREACHABLE; /* Path Not Covered */
3318     } 
3319     else if (code == CM_ERROR_ALLBUSY) {
3320         Win32E = ERROR_RETRY;           /* Retry */
3321     } 
3322     else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3323         Win32E = ERROR_HOST_UNREACHABLE; /* Path not found */
3324     } 
3325     else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3326         Win32E = SEC_E_NO_KERB_KEY;     /* No Kerberos key */
3327     } 
3328     else if (code == CM_ERROR_BAD_LEVEL) {
3329         Win32E = ERROR_INVALID_LEVEL;   /* Invalid Level */
3330     } 
3331     else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3332         Win32E = ERROR_NOT_LOCKED;      /* Range Not Locked */
3333     } 
3334     else if (code == CM_ERROR_NOSUCHDEVICE) {
3335         Win32E = ERROR_FILE_NOT_FOUND;  /* No Such Device */
3336     }
3337     else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3338         Win32E = ERROR_LOCK_VIOLATION;  /* Lock Not Granted */
3339     }
3340     else if (code == ENOMEM) {
3341         Win32E = ERROR_NOT_ENOUGH_MEMORY; /* Out of Memory */
3342     }
3343     else if (code == CM_ERROR_RPC_MOREDATA) {
3344         Win32E = ERROR_MORE_DATA;       /* Buffer overflow */
3345     }
3346     else  {
3347         Win32E = ERROR_GEN_FAILURE;     /* SMB non-specific error */
3348     }
3349
3350     *Win32Ep = Win32E;
3351     osi_Log2(smb_logp, "SMB SEND code %lX as Win32 %lX", code, Win32E);
3352 }       
3353
3354 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
3355                       unsigned char *classp)
3356 {
3357     unsigned char class;
3358     unsigned short error;
3359
3360     /* map CM_ERROR_* errors to SMB errors */
3361     if (code == CM_ERROR_NOSUCHCELL) {
3362         class = 1;
3363         error = 3;      /* bad path */
3364     }
3365     else if (code == CM_ERROR_NOSUCHVOLUME) {
3366         class = 1;
3367         error = 3;      /* bad path */
3368     }
3369     else if (code == CM_ERROR_TIMEDOUT) {
3370         class = 2;
3371         error = 81;     /* server is paused */
3372     }
3373     else if (code == CM_ERROR_RETRY) {
3374         class = 2;      /* shouldn't happen */
3375         error = 1;
3376     }
3377     else if (code == CM_ERROR_NOACCESS) {
3378         class = 2;
3379         error = 4;      /* bad access */
3380     }
3381     else if (code == CM_ERROR_READONLY) {
3382         class = 3;
3383         error = 19;     /* read only */
3384     }
3385     else if (code == CM_ERROR_NOSUCHFILE ||
3386              code == CM_ERROR_BPLUS_NOMATCH) {
3387         class = 1;
3388         error = 2;      /* ENOENT! */
3389     }
3390     else if (code == CM_ERROR_NOSUCHPATH) {
3391         class = 1;
3392         error = 3;      /* Bad path */
3393     }
3394     else if (code == CM_ERROR_TOOBIG) {
3395         class = 1;
3396         error = 11;     /* bad format */
3397     }
3398     else if (code == CM_ERROR_INVAL) {
3399         class = 2;      /* server non-specific error code */
3400         error = 1;
3401     }
3402     else if (code == CM_ERROR_BADFD) {
3403         class = 1;
3404         error = 6;      /* invalid file handle */
3405     }
3406     else if (code == CM_ERROR_BADFDOP) {
3407         class = 1;      /* invalid op on FD */
3408         error = 5;
3409     }
3410     else if (code == CM_ERROR_EXISTS) {
3411         class = 1;
3412         error = 80;     /* file already exists */
3413     }
3414     else if (code == CM_ERROR_NOTEMPTY) {
3415         class = 1;
3416         error = 5;      /* delete directory not empty */
3417     }
3418     else if (code == CM_ERROR_CROSSDEVLINK) {
3419         class = 1;
3420         error = 17;     /* EXDEV */
3421     }
3422     else if (code == CM_ERROR_NOTDIR) {
3423         class = 1;      /* bad path */
3424         error = 3;
3425     }
3426     else if (code == CM_ERROR_ISDIR) {
3427         class = 1;      /* access denied; DOS doesn't have a good match */
3428         error = 5;
3429     }       
3430     else if (code == CM_ERROR_BADOP) {
3431         class = 2;
3432         error = 65535;
3433     }
3434     else if (code == CM_ERROR_BADSHARENAME) {
3435         class = 2;
3436         error = 6;
3437     }
3438     else if (code == CM_ERROR_NOIPC) {
3439         class = 2;
3440         error = 4; /* bad access */
3441     }
3442     else if (code == CM_ERROR_CLOCKSKEW) {
3443         class = 1;      /* invalid function */
3444         error = 1;
3445     }
3446     else if (code == CM_ERROR_BADTID) {
3447         class = 2;
3448         error = 5;
3449     }
3450     else if (code == CM_ERROR_USESTD) {
3451         class = 2;
3452         error = 251;
3453     }
3454     else if (code == CM_ERROR_REMOTECONN) {
3455         class = 2;
3456         error = 82;
3457     }
3458     else if (code == CM_ERROR_QUOTA) {
3459         if (vcp->flags & SMB_VCFLAG_USEV3) {
3460             class = 3;
3461             error = 39; /* disk full */
3462         }
3463         else {
3464             class = 1;
3465             error = 5;  /* access denied */
3466         }
3467     }
3468     else if (code == CM_ERROR_SPACE) {
3469         if (vcp->flags & SMB_VCFLAG_USEV3) {
3470             class = 3;
3471             error = 39; /* disk full */
3472         }
3473         else {
3474             class = 1;
3475             error = 5;  /* access denied */
3476         }
3477     }
3478     else if (code == CM_ERROR_PARTIALWRITE) {
3479         class = 3;
3480         error = 39;     /* disk full */
3481     }
3482     else if (code == CM_ERROR_ATSYS) {
3483         class = 1;
3484         error = 2;      /* ENOENT */
3485     }
3486     else if (code == CM_ERROR_WOULDBLOCK) {
3487         class = 1;
3488         error = 33;     /* lock conflict */
3489     }
3490     else if (code == CM_ERROR_LOCK_CONFLICT) {
3491         class = 1;
3492         error = 33;     /* lock conflict */
3493     }
3494     else if (code == CM_ERROR_SHARING_VIOLATION) {
3495         class = 1;
3496         error = 33;     /* lock conflict */
3497     }
3498     else if (code == CM_ERROR_NOFILES) {
3499         class = 1;
3500         error = 18;     /* no files in search */
3501     }
3502     else if (code == CM_ERROR_RENAME_IDENTICAL) {
3503         class = 1;
3504         error = 183;     /* Samba uses this */
3505     }
3506     else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
3507         /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
3508         class = 2;
3509         error = 2; /* bad password */
3510     }
3511     else if (code == CM_ERROR_PATH_NOT_COVERED) {
3512         class = 2;
3513         error = 3;     /* bad path */
3514     }
3515     else {
3516         class = 2;
3517         error = 1;
3518     }
3519
3520     *scodep = error;
3521     *classp = class;
3522     osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
3523 }       
3524
3525 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3526 {
3527     osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
3528     return CM_ERROR_BADOP;
3529 }
3530
3531 /* SMB_COM_ECHO */
3532 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3533 {
3534     unsigned short EchoCount, i;
3535     char *data, *outdata;
3536     int dataSize;
3537
3538     EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
3539
3540     for (i=1; i<=EchoCount; i++) {
3541         data = smb_GetSMBData(inp, &dataSize);
3542         smb_SetSMBParm(outp, 0, i);
3543         smb_SetSMBDataLength(outp, dataSize);
3544         outdata = smb_GetSMBData(outp, NULL);
3545         memcpy(outdata, data, dataSize);
3546         smb_SendPacket(vcp, outp);
3547     }
3548
3549     return 0;
3550 }
3551
3552 /* SMB_COM_READ_RAW */
3553 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3554 {
3555     osi_hyper_t offset;
3556     long count, minCount, finalCount;
3557     unsigned short fd;
3558     unsigned pid;
3559     smb_fid_t *fidp;
3560     smb_t *smbp = (smb_t*) inp;
3561     long code = 0;
3562     cm_user_t *userp = NULL;
3563     NCB *ncbp;
3564     int rc;
3565     char *rawBuf = NULL;
3566
3567     rawBuf = NULL;
3568     finalCount = 0;
3569
3570     fd = smb_GetSMBParm(inp, 0);
3571     count = smb_GetSMBParm(inp, 3);
3572     minCount = smb_GetSMBParm(inp, 4);
3573     offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3574
3575     if (*inp->wctp == 10) {
3576         /* we were sent a request with 64-bit file offsets */
3577 #ifdef AFS_LARGEFILES
3578         offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
3579
3580         if (LargeIntegerLessThanZero(offset)) {
3581             osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
3582             goto send1;
3583         }
3584 #else
3585         if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
3586             osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset.  Dropping request.");
3587             goto send1;
3588         } else {
3589             offset.HighPart = 0;
3590         }
3591 #endif
3592     } else {
3593         /* we were sent a request with 32-bit file offsets */
3594         offset.HighPart = 0;
3595     }
3596
3597     osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
3598              fd, offset.HighPart, offset.LowPart, count);
3599
3600     fidp = smb_FindFID(vcp, fd, 0);
3601     if (!fidp) {
3602         osi_Log2(smb_logp, "smb_ReceiveCoreReadRaw Unknown SMB Fid vcp 0x%p fid %d",
3603                  vcp, fd);
3604         goto send1;
3605     }
3606     lock_ObtainMutex(&fidp->mx);
3607     if (!fidp->scp) {
3608         lock_ReleaseMutex(&fidp->mx);
3609         smb_ReleaseFID(fidp);
3610         return CM_ERROR_BADFD;
3611     }
3612
3613     if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
3614         lock_ReleaseMutex(&fidp->mx);
3615         smb_CloseFID(vcp, fidp, NULL, 0);
3616         code = CM_ERROR_NOSUCHFILE;
3617         goto send1a;
3618     }
3619
3620     pid = smbp->pid;
3621     {
3622         LARGE_INTEGER LOffset, LLength;
3623         cm_key_t key;
3624
3625         key = cm_GenerateKey(vcp->vcID, pid, fd);
3626
3627         LOffset.HighPart = offset.HighPart;
3628         LOffset.LowPart = offset.LowPart;
3629         LLength.HighPart = 0;
3630         LLength.LowPart = count;
3631
3632         lock_ObtainWrite(&fidp->scp->rw);
3633         code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
3634         lock_ReleaseWrite(&fidp->scp->rw);
3635     }    
3636     if (code) {
3637         lock_ReleaseMutex(&fidp->mx);
3638         goto send1a;
3639     }
3640
3641     lock_ObtainMutex(&smb_RawBufLock);
3642     if (smb_RawBufs) {
3643         /* Get a raw buf, from head of list */
3644         rawBuf = smb_RawBufs;
3645         smb_RawBufs = *(char **)smb_RawBufs;
3646     }
3647     lock_ReleaseMutex(&smb_RawBufLock);
3648     if (!rawBuf) {
3649         lock_ReleaseMutex(&fidp->mx);
3650         goto send1a;
3651     }
3652
3653     if (fidp->flags & SMB_FID_IOCTL)
3654     {
3655         rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
3656         if (rawBuf) {
3657             /* Give back raw buffer */
3658             lock_ObtainMutex(&smb_RawBufLock);
3659             *((char **) rawBuf) = smb_RawBufs;
3660             
3661             smb_RawBufs = rawBuf;
3662             lock_ReleaseMutex(&smb_RawBufLock);
3663         }
3664
3665         lock_ReleaseMutex(&fidp->mx);
3666         smb_ReleaseFID(fidp);
3667         return rc;
3668     }
3669     lock_ReleaseMutex(&fidp->mx);
3670
3671     userp = smb_GetUserFromVCP(vcp, inp);
3672
3673     code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
3674
3675     if (code != 0)
3676         goto send;
3677
3678   send:
3679     cm_ReleaseUser(userp);
3680
3681   send1a:
3682     smb_ReleaseFID(fidp);
3683
3684   send1:
3685     ncbp = outp->ncbp;
3686     memset(ncbp, 0, sizeof(NCB));
3687
3688     ncbp->ncb_length = (unsigned short) finalCount;
3689     ncbp->ncb_lsn = (unsigned char) vcp->lsn;
3690     ncbp->ncb_lana_num = vcp->lana;
3691     ncbp->ncb_command = NCBSEND;
3692     ncbp->ncb_buffer = rawBuf;
3693
3694     code = Netbios(ncbp);
3695     if (code != 0)
3696         osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
3697
3698     if (rawBuf) {
3699         /* Give back raw buffer */
3700         lock_ObtainMutex(&smb_RawBufLock);
3701         *((char **) rawBuf) = smb_RawBufs;
3702
3703         smb_RawBufs = rawBuf;
3704         lock_ReleaseMutex(&smb_RawBufLock);
3705     }
3706
3707     return 0;
3708 }
3709
3710 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3711 {
3712     osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3713                          ongoingOps - 1);
3714     return 0;
3715 }
3716
3717 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3718 {
3719     osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3720                          ongoingOps - 1);
3721     return 0;
3722 }
3723
3724 /* SMB_COM_NEGOTIATE */
3725 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3726 {
3727     char *namep;
3728     char *datap;
3729     int coreProtoIndex;
3730     int v3ProtoIndex;
3731     int NTProtoIndex;
3732     int VistaProtoIndex;
3733     int protoIndex;                             /* index we're using */
3734     int namex;
3735     int dbytes;
3736     int entryLength;
3737     int tcounter;
3738     char protocol_array[10][1024];  /* protocol signature of the client */
3739     int caps;                       /* capabilities */
3740     time_t unixTime;
3741     afs_uint32 dosTime;
3742     TIME_ZONE_INFORMATION tzi;
3743
3744     osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3745                          ongoingOps - 1);
3746
3747     namep = smb_GetSMBData(inp, &dbytes);
3748     namex = 0;
3749     tcounter = 0;
3750     coreProtoIndex = -1;                /* not found */
3751     v3ProtoIndex = -1;
3752     NTProtoIndex = -1;
3753     VistaProtoIndex = -1;
3754     while(namex < dbytes) {
3755         osi_Log1(smb_logp, "Protocol %s",
3756                   osi_LogSaveString(smb_logp, namep+1));
3757         strcpy(protocol_array[tcounter], namep+1);
3758
3759         /* namep points at the first protocol, or really, a 0x02
3760          * byte preceding the null-terminated ASCII name.
3761          */
3762         if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3763             coreProtoIndex = tcounter;
3764         }       
3765         else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3766             v3ProtoIndex = tcounter;
3767         }
3768         else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3769             NTProtoIndex = tcounter;
3770         }
3771         else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3772             VistaProtoIndex = tcounter;
3773         }
3774
3775         /* compute size of protocol entry */
3776         entryLength = (int)strlen(namep+1);
3777         entryLength += 2;       /* 0x02 bytes and null termination */
3778
3779         /* advance over this protocol entry */
3780         namex += entryLength;
3781         namep += entryLength;
3782         tcounter++;             /* which proto entry we're looking at */
3783     }
3784
3785     lock_ObtainMutex(&vcp->mx);
3786 #if 0
3787     if (VistaProtoIndex != -1) {
3788         protoIndex = VistaProtoIndex;
3789         vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3790     } else 
3791 #endif  
3792         if (NTProtoIndex != -1) {
3793         protoIndex = NTProtoIndex;
3794         vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3795     }
3796     else if (v3ProtoIndex != -1) {
3797         protoIndex = v3ProtoIndex;
3798         vcp->flags |= SMB_VCFLAG_USEV3;
3799     }   
3800     else if (coreProtoIndex != -1) {
3801         protoIndex = coreProtoIndex;
3802         vcp->flags |= SMB_VCFLAG_USECORE;
3803     }   
3804     else protoIndex = -1;
3805     lock_ReleaseMutex(&vcp->mx);
3806
3807     if (protoIndex == -1)
3808         return CM_ERROR_INVAL;
3809     else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3810         smb_SetSMBParm(outp, 0, protoIndex);
3811         if (smb_authType != SMB_AUTH_NONE) {
3812             smb_SetSMBParmByte(outp, 1,
3813                                NEGOTIATE_SECURITY_USER_LEVEL |
3814                                NEGOTIATE_SECURITY_CHALLENGE_RESPONSE);  /* user level security, challenge response */
3815         } else {
3816             smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3817         }
3818         smb_SetSMBParm(outp, 1, smb_maxMpxRequests);    /* max multiplexed requests */
3819         smb_SetSMBParm(outp, 2, smb_maxVCPerServer);    /* max VCs per consumer/server connection */
3820         smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE);    /* xmit buffer size */
3821         smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE);    /* raw buffer size */
3822         /* The session key is not a well documented field however most clients
3823          * will echo back the session key to the server.  Currently we are using
3824          * the same value for all sessions.  We should generate a random value
3825          * and store it into the vcp 
3826          */
3827         smb_SetSMBParm(outp, 7, 1);     /* next 2: session key */
3828         smb_SetSMBParm(outp, 8, 1);
3829         /* 
3830          * Tried changing the capabilities to support for W2K - defect 117695
3831          * Maybe something else needs to be changed here?
3832          */
3833         /*
3834         if (isWindows2000) 
3835         smb_SetSMBParmLong(outp, 9, 0x43fd);
3836         else 
3837         smb_SetSMBParmLong(outp, 9, 0x251);
3838         */
3839         /* Capabilities: *
3840          * 32-bit error codes *
3841          * and NT Find *
3842          * and NT SMB's *
3843          * and raw mode 
3844          * and DFS
3845          * and Unicode */
3846         caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3847 #ifdef DFS_SUPPORT
3848                NTNEGOTIATE_CAPABILITY_DFS |
3849 #endif
3850 #ifdef AFS_LARGEFILES
3851                NTNEGOTIATE_CAPABILITY_LARGEFILES |
3852 #endif
3853                NTNEGOTIATE_CAPABILITY_NTFIND |
3854                NTNEGOTIATE_CAPABILITY_RAWMODE |
3855                NTNEGOTIATE_CAPABILITY_NTSMB;
3856
3857         if ( smb_authType == SMB_AUTH_EXTENDED )
3858             caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3859
3860 #ifdef SMB_UNICODE
3861         if ( smb_UseUnicode ) {
3862             caps |= NTNEGOTIATE_CAPABILITY_UNICODE;
3863         }
3864 #endif
3865
3866         smb_SetSMBParmLong(outp, 9, caps);
3867         time(&unixTime);
3868         cm_SearchTimeFromUnixTime(&dosTime, unixTime);
3869         smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3870         smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3871
3872         GetTimeZoneInformation(&tzi);
3873         smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias);    /* server tzone */
3874
3875         if (smb_authType == SMB_AUTH_NTLM) {
3876             smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3877             smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3878             /* paste in encryption key */
3879             datap = smb_GetSMBData(outp, NULL);
3880             memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3881             /* and the faux domain name */
3882             cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3883                                   datap + MSV1_0_CHALLENGE_LENGTH,
3884                                   (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3885         } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3886             void * secBlob;
3887             int secBlobLength;
3888
3889             smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3890
3891             smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3892
3893             smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3894                         
3895             datap = smb_GetSMBData(outp, NULL);
3896             memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3897
3898             if (secBlob) {
3899                 datap += sizeof(smb_ServerGUID);
3900                 memcpy(datap, secBlob, secBlobLength);
3901                 free(secBlob);
3902             }
3903         } else {
3904             smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3905             smb_SetSMBDataLength(outp, 0);   /* Perhaps we should specify 8 bytes anyway */
3906         }
3907     }
3908     else if (v3ProtoIndex != -1) {
3909         smb_SetSMBParm(outp, 0, protoIndex);
3910
3911         /* NOTE: Extended authentication cannot be negotiated with v3
3912          * therefore we fail over to NTLM 
3913          */
3914         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3915             smb_SetSMBParm(outp, 1,
3916                            NEGOTIATE_SECURITY_USER_LEVEL |
3917                            NEGOTIATE_SECURITY_CHALLENGE_RESPONSE);      /* user level security, challenge response */
3918         } else {
3919             smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3920         }
3921         smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3922         smb_SetSMBParm(outp, 3, smb_maxMpxRequests);    /* max multiplexed requests */
3923         smb_SetSMBParm(outp, 4, smb_maxVCPerServer);    /* max VCs per consumer/server connection */
3924         smb_SetSMBParm(outp, 5, 0);     /* no support of block mode for read or write */
3925         smb_SetSMBParm(outp, 6, 1);     /* next 2: session key */
3926         smb_SetSMBParm(outp, 7, 1);
3927         time(&unixTime);
3928         cm_SearchTimeFromUnixTime(&dosTime, unixTime);
3929         smb_SetSMBParm(outp, 8, LOWORD(dosTime));       /* server time */
3930         smb_SetSMBParm(outp, 9, HIWORD(dosTime));       /* server date */
3931
3932         GetTimeZoneInformation(&tzi);
3933         smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias);    /* server tzone */
3934
3935         /* NOTE: Extended authentication cannot be negotiated with v3
3936          * therefore we fail over to NTLM 
3937          */
3938         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3939             smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH);  /* encryption key length */
3940             smb_SetSMBParm(outp, 12, 0);        /* resvd */
3941             smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);   /* perhaps should specify 8 bytes anyway */
3942             datap = smb_GetSMBData(outp, NULL);
3943             /* paste in a new encryption key */
3944             memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3945             /* and the faux domain name */
3946             cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3947                                   datap + MSV1_0_CHALLENGE_LENGTH,
3948                                   (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3949         } else {
3950             smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3951             smb_SetSMBParm(outp, 12, 0); /* resvd */
3952             smb_SetSMBDataLength(outp, 0);
3953         }
3954     }
3955     else if (coreProtoIndex != -1) {     /* not really supported anymore */
3956         smb_SetSMBParm(outp, 0, protoIndex);
3957         smb_SetSMBDataLength(outp, 0);
3958     }
3959     return 0;
3960 }
3961
3962 void smb_CheckVCs(void)
3963 {
3964     smb_vc_t * vcp, *nextp;
3965     smb_packet_t * outp = smb_GetPacket();
3966     smb_t *smbp;
3967             
3968     lock_ObtainWrite(&smb_rctLock);
3969     for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp ) 
3970     {
3971         if (vcp->magic != SMB_VC_MAGIC)
3972             osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp", 
3973                        __FILE__, __LINE__);
3974
3975         /* on the first pass hold 'vcp' which was not held as 'nextp' */
3976         if (vcp != nextp)
3977             smb_HoldVCNoLock(vcp);
3978
3979         /* 
3980          * obtain a reference to 'nextp' now because we drop the
3981          * smb_rctLock later and the list contents could change 
3982          * or 'vcp' could be destroyed when released.
3983          */
3984         nextp = vcp->nextp;
3985         if (nextp)
3986             smb_HoldVCNoLock(nextp);
3987
3988         if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
3989             smb_ReleaseVCNoLock(vcp);
3990             continue;
3991         }
3992
3993         smb_FormatResponsePacket(vcp, NULL, outp);
3994         smbp = (smb_t *)outp;
3995         outp->inCom = smbp->com = 0x2b /* Echo */;
3996         smbp->tid = 0xFFFF;
3997         smbp->pid = 0;
3998         smbp->uid = 0;
3999         smbp->mid = 0;
4000         smbp->res[0] = 0;
4001         smbp->res[1] = 0;
4002
4003         smb_SetSMBParm(outp, 0, 0);
4004         smb_SetSMBDataLength(outp, 0);
4005         lock_ReleaseWrite(&smb_rctLock);
4006
4007         smb_SendPacket(vcp, outp);
4008
4009         lock_ObtainWrite(&smb_rctLock);
4010         smb_ReleaseVCNoLock(vcp);
4011     }
4012     lock_ReleaseWrite(&smb_rctLock);
4013     smb_FreePacket(outp);
4014 }
4015
4016 void smb_Daemon(void *parmp)
4017 {
4018     afs_uint32 count = 0;
4019     smb_username_t    **unpp;
4020     time_t              now;
4021
4022     while(smbShutdownFlag == 0) {
4023         count++;
4024         thrd_Sleep(10000);
4025
4026         if (smbShutdownFlag == 1)
4027             break;
4028         
4029         if ((count % 72) == 0)  {       /* every five minutes */
4030             struct tm myTime;
4031             time_t old_localZero = smb_localZero;
4032                  
4033             /* Initialize smb_localZero */
4034             myTime.tm_isdst = -1;               /* compute whether on DST or not */
4035             myTime.tm_year = 70;
4036             myTime.tm_mon = 0;
4037             myTime.tm_mday = 1;
4038             myTime.tm_hour = 0;
4039             myTime.tm_min = 0;
4040             myTime.tm_sec = 0;
4041             smb_localZero = mktime(&myTime);
4042
4043 #ifdef AFS_FREELANCE
4044             if ( smb_localZero != old_localZero )
4045                 cm_noteLocalMountPointChange();
4046 #endif
4047
4048             smb_CheckVCs();
4049         }
4050
4051         /* GC smb_username_t objects that will no longer be used */
4052         now = osi_Time();
4053         lock_ObtainWrite(&smb_rctLock);
4054         for ( unpp=&usernamesp; *unpp; ) {
4055             int deleteOk = 0;
4056             smb_username_t *unp;
4057
4058             lock_ObtainMutex(&(*unpp)->mx);
4059             if ( (*unpp)->refCount > 0 || 
4060                  ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) || 
4061                  !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
4062                 ;
4063             else if (!smb_LogoffTokenTransfer ||
4064                      ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
4065                 deleteOk = 1;
4066             lock_ReleaseMutex(&(*unpp)->mx);
4067
4068             if (deleteOk) {
4069                 cm_user_t * userp;
4070
4071                 unp = *unpp;    
4072                 *unpp = unp->nextp;
4073                 unp->nextp = NULL;
4074                 lock_FinalizeMutex(&unp->mx);
4075                 userp = unp->userp;
4076                 free(unp->name);
4077                 free(unp->machine);
4078                 free(unp);
4079                 if (userp)
4080                     cm_ReleaseUser(userp);
4081             } else {
4082                 unpp = &(*unpp)->nextp;
4083             }
4084         }
4085         lock_ReleaseWrite(&smb_rctLock);
4086
4087         /* XXX GC dir search entries */
4088     }
4089 }
4090
4091 void smb_WaitingLocksDaemon()
4092 {
4093     smb_waitingLockRequest_t *wlRequest, *nwlRequest;
4094     smb_waitingLock_t *wl, *wlNext;
4095     int first;
4096     smb_vc_t *vcp;
4097     smb_packet_t *inp, *outp;
4098     NCB *ncbp;
4099     long code = 0;
4100
4101     while (smbShutdownFlag == 0) {
4102         lock_ObtainWrite(&smb_globalLock);
4103         nwlRequest = smb_allWaitingLocks;
4104         if (nwlRequest == NULL) {
4105             osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
4106             thrd_Sleep(1000);
4107             continue;
4108         } else {
4109             first = 1;
4110             osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
4111         }
4112
4113         do {
4114             if (first)
4115                 first = 0;
4116             else
4117                 lock_ObtainWrite(&smb_globalLock);
4118
4119             osi_Log1(smb_logp, "    Checking waiting lock request %p", nwlRequest);
4120
4121             wlRequest = nwlRequest;
4122             nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
4123             lock_ReleaseWrite(&smb_globalLock);
4124
4125             code = 0;
4126
4127             for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
4128                 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4129                     continue;
4130
4131                 if (wl->state == SMB_WAITINGLOCKSTATE_CANCELLED) {
4132                     code = CM_ERROR_LOCK_NOT_GRANTED;
4133                     break;
4134                 }
4135
4136                 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
4137                 
4138                 /* wl->state is either _DONE or _WAITING.  _ERROR
4139                    would no longer be on the queue. */
4140                 code = cm_RetryLock( wl->lockp,
4141                                      !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
4142
4143                 if (code == 0) {
4144                     wl->state = SMB_WAITINGLOCKSTATE_DONE;
4145                 } else if (code != CM_ERROR_WOULDBLOCK) {
4146                     wl->state = SMB_WAITINGLOCKSTATE_ERROR;
4147                     break;
4148                 }
4149             }
4150
4151             if (code == CM_ERROR_WOULDBLOCK) {
4152
4153                 /* no progress */
4154                 if (wlRequest->msTimeout != 0xffffffff
4155                      && ((osi_Time() - wlRequest->start_t) * 1000 > wlRequest->msTimeout))
4156                     goto endWait;
4157
4158                 continue;
4159             }
4160
4161           endWait:
4162
4163             if (code != 0) {
4164                 cm_scache_t * scp;
4165                 cm_req_t req;
4166
4167                 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
4168                          wlRequest);
4169
4170                 scp = wlRequest->scp;
4171                 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
4172
4173                 smb_InitReq(&req);
4174
4175                 lock_ObtainWrite(&scp->rw);
4176
4177                 for (wl = wlRequest->locks; wl; wl = wlNext) {
4178                     wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4179                 
4180                     if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4181                         cm_Unlock(scp, wlRequest->lockType, wl->LOffset, 
4182                                   wl->LLength, wl->key, 0, NULL, &req);
4183
4184                     osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4185
4186                     free(wl);
4187                 }
4188                 
4189                 lock_ReleaseWrite(&scp->rw);
4190
4191             } else {
4192
4193                 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
4194                          wlRequest);
4195
4196                 for (wl = wlRequest->locks; wl; wl = wlNext) {
4197                     wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4198                     osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4199                     free(wl);
4200                 }
4201             }
4202
4203             vcp = wlRequest->vcp;
4204             inp = wlRequest->inp;
4205             outp = wlRequest->outp;
4206             ncbp = smb_GetNCB();
4207             ncbp->ncb_length = inp->ncb_length;
4208             inp->spacep = cm_GetSpace();
4209
4210             /* Remove waitingLock from list */
4211             lock_ObtainWrite(&smb_globalLock);
4212             osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
4213                          &wlRequest->q);
4214             lock_ReleaseWrite(&smb_globalLock);
4215
4216             /* Resume packet processing */
4217             if (code == 0)
4218                 smb_SetSMBDataLength(outp, 0);
4219             outp->flags |= SMB_PACKETFLAG_SUSPENDED;
4220             outp->resumeCode = code;
4221             outp->ncbp = ncbp;
4222             smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
4223
4224             /* Clean up */
4225             cm_FreeSpace(inp->spacep);
4226             smb_FreePacket(inp);
4227             smb_FreePacket(outp);
4228             smb_ReleaseVC(vcp);
4229             cm_ReleaseSCache(wlRequest->scp);
4230             smb_FreeNCB(ncbp);
4231             free(wlRequest);
4232         } while (nwlRequest && smbShutdownFlag == 0);
4233         thrd_Sleep(1000);
4234     }
4235 }
4236
4237 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4238 {
4239     osi_Log0(smb_logp, "SMB receive get disk attributes");
4240
4241     smb_SetSMBParm(outp, 0, 32000);
4242     smb_SetSMBParm(outp, 1, 64);
4243     smb_SetSMBParm(outp, 2, 1024);
4244     smb_SetSMBParm(outp, 3, 30000);
4245     smb_SetSMBParm(outp, 4, 0);
4246     smb_SetSMBDataLength(outp, 0);
4247     return 0;
4248 }
4249
4250 /* SMB_COM_TREE_CONNECT */
4251 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
4252 {
4253     smb_tid_t *tidp;
4254     smb_user_t *uidp;
4255     unsigned short newTid;
4256     clientchar_t shareName[AFSPATHMAX];
4257     clientchar_t *sharePath;
4258     int shareFound;
4259     clientchar_t *tp;
4260     clientchar_t *pathp;
4261     cm_user_t *userp;
4262
4263     osi_Log0(smb_logp, "SMB receive tree connect");
4264
4265     /* parse input parameters */
4266     {
4267         char *tbp;
4268         tbp = smb_GetSMBData(inp, NULL);
4269         pathp = smb_ParseASCIIBlock(inp, tbp, &tbp, SMB_STRF_ANSIPATH);
4270         if (!pathp)
4271             return CM_ERROR_BADSMB;
4272     }
4273     tp = cm_ClientStrRChr(pathp, '\\');
4274     if (!tp)
4275         return CM_ERROR_BADSMB;
4276     cm_ClientStrCpy(shareName, lengthof(shareName), tp+1);
4277
4278     lock_ObtainMutex(&vcp->mx);
4279     newTid = vcp->tidCounter++;
4280     lock_ReleaseMutex(&vcp->mx);
4281
4282     tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
4283     uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
4284     if (!uidp)
4285         return CM_ERROR_BADSMB;
4286     userp = smb_GetUserFromUID(uidp);
4287     shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
4288     smb_ReleaseUID(uidp);
4289     if (!shareFound) {
4290         smb_ReleaseTID(tidp, FALSE);
4291         return CM_ERROR_BADSHARENAME;
4292     }
4293     lock_ObtainMutex(&tidp->mx);
4294     tidp->userp = userp;
4295     tidp->pathname = sharePath;
4296     lock_ReleaseMutex(&tidp->mx);
4297     smb_ReleaseTID(tidp, FALSE);
4298
4299     smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
4300     smb_SetSMBParm(rsp, 1, newTid);
4301     smb_SetSMBDataLength(rsp, 0);
4302
4303     osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
4304     return 0;
4305 }
4306
4307 /* set maskp to the mask part of the incoming path.
4308  * Mask is 11 bytes long (8.3 with the dot elided).
4309  * Returns true if succeeds with a valid name, otherwise it does
4310  * its best, but returns false.
4311  */
4312 int smb_Get8Dot3MaskFromPath(clientchar_t *maskp, clientchar_t *pathp)
4313 {
4314     clientchar_t *tp;
4315     clientchar_t *up;
4316     int i;
4317     int tc;
4318     int valid8Dot3;
4319
4320     /* starts off valid */
4321     valid8Dot3 = 1;
4322
4323     /* mask starts out all blanks */
4324     memset(maskp, ' ', 11);
4325     maskp[11] = '\0';
4326
4327     /* find last backslash, or use whole thing if there is none */
4328     tp = cm_ClientStrRChr(pathp, '\\');
4329     if (!tp) 
4330         tp = pathp;
4331     else 
4332         tp++;   /* skip slash */
4333         
4334     up = maskp;
4335
4336     /* names starting with a dot are illegal */
4337     if (*tp == '.') 
4338         valid8Dot3 = 0;
4339
4340     for(i=0;; i++) {
4341         tc = *tp++;
4342         if (tc == 0) 
4343             return valid8Dot3;
4344         if (tc == '.' || tc == '"') 
4345             break;
4346         if (i < 8) 
4347             *up++ = tc;
4348         else
4349             valid8Dot3 = 0;
4350     }
4351         
4352     /* if we get here, tp point after the dot */
4353     up = maskp+8;       /* ext goes here */
4354     for(i=0;;i++) {
4355         tc = *tp++;
4356         if (tc == 0) 
4357             return valid8Dot3;
4358
4359         /* too many dots */
4360         if (tc == '.' || tc == '"') 
4361             valid8Dot3 = 0;
4362
4363         /* copy extension if not too long */
4364         if (i < 3) 
4365             *up++ = tc;
4366         else 
4367             valid8Dot3 = 0;
4368     }   
4369
4370     /* unreachable */
4371 }
4372
4373 int smb_Match8Dot3Mask(clientchar_t *unixNamep, clientchar_t *maskp)
4374 {
4375     clientchar_t umask[11];
4376     int valid;
4377     int i;
4378     clientchar_t tc1;
4379     clientchar_t tc2;
4380     clientchar_t *tp1;
4381     clientchar_t *tp2;
4382
4383     /* XXX redo this, calling cm_MatchMask with a converted mask */
4384
4385     valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
4386     if (!valid) 
4387         return 0;
4388  
4389     /* otherwise, we have a valid 8.3 name; see if we have a match,
4390      * treating '?' as a wildcard in maskp (but not in the file name).
4391      */
4392     tp1 = umask;        /* real name, in mask format */
4393     tp2 = maskp;        /* mask, in mask format */
4394     for(i=0; i<11; i++) {
4395         tc1 = *tp1++;   /* clientchar_t from real name */
4396         tc2 = *tp2++;   /* clientchar_t from mask */
4397         tc1 = (clientchar_t) cm_foldUpper[(clientchar_t)tc1];
4398         tc2 = (clientchar_t) cm_foldUpper[(clientchar_t)tc2];
4399         if (tc1 == tc2) 
4400             continue;
4401         if (tc2 == '?' && tc1 != ' ') 
4402             continue;
4403         if (tc2 == '>') 
4404             continue;
4405         return 0;
4406     }
4407
4408     /* we got a match */
4409     return 1;
4410 }
4411
4412 clientchar_t *smb_FindMask(clientchar_t *pathp)
4413 {
4414     clientchar_t *tp;
4415         
4416     tp = cm_ClientStrRChr(pathp, '\\'); /* find last slash */
4417
4418     if (tp) 
4419         return tp+1;    /* skip the slash */
4420     else 
4421         return pathp;   /* no slash, return the entire path */
4422 }       
4423
4424 /* SMB_COM_SEARCH for a volume label
4425
4426    (This is called from smb_ReceiveCoreSearchDir() and not an actual
4427    dispatch function.) */
4428 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4429 {
4430     clientchar_t *pathp;
4431     unsigned char *tp;
4432     clientchar_t mask[12];
4433     unsigned char *statBlockp;
4434     unsigned char initStatBlock[21];
4435     int statLen;
4436         
4437     osi_Log0(smb_logp, "SMB receive search volume");
4438
4439     /* pull pathname and stat block out of request */
4440     tp = smb_GetSMBData(inp, NULL);
4441     pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4442                                 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4443     if (!pathp)
4444         return CM_ERROR_BADSMB;
4445     statBlockp = smb_ParseVblBlock(tp, &tp, &statLen);
4446     osi_assertx(statBlockp != NULL, "null statBlock");
4447     if (statLen == 0) {
4448         statBlockp = initStatBlock;
4449         statBlockp[0] = 8;
4450     }
4451         
4452     /* for returning to caller */
4453     smb_Get8Dot3MaskFromPath(mask, pathp);
4454
4455     smb_SetSMBParm(outp, 0, 1);         /* we're returning one entry */
4456     tp = smb_GetSMBData(outp, NULL);
4457     *tp++ = 5;
4458     *tp++ = 43; /* bytes in a dir entry */
4459     *tp++ = 0;  /* high byte in counter */
4460
4461     /* now marshall the dir entry, starting with the search status */
4462     *tp++ = statBlockp[0];              /* Reserved */
4463     memcpy(tp, mask, 11); tp += 11;     /* FileName */
4464
4465     /* now pass back server use info, with 1st byte non-zero */
4466     *tp++ = 1;
4467     memset(tp, 0, 4); tp += 4;  /* reserved for server use */
4468
4469     memcpy(tp, statBlockp+17, 4); tp += 4;      /* reserved for consumer */
4470
4471     *tp++ = 0x8;                /* attribute: volume */
4472
4473     /* copy out time */
4474     *tp++ = 0;
4475     *tp++ = 0;
4476
4477     /* copy out date */
4478     *tp++ = 18;
4479     *tp++ = 178;
4480
4481     /* 4 byte file size */
4482     *tp++ = 0;
4483     *tp++ = 0;
4484     *tp++ = 0;
4485     *tp++ = 0;
4486
4487     /* The filename is a UCHAR buffer that is ASCII even if Unicode
4488        was negotiated. */
4489
4490     /* finally, null-terminated 8.3 pathname, which we set to AFS */
4491     memset(tp, ' ', 13);
4492     strcpy(tp, "AFS");
4493
4494     /* set the length of the data part of the packet to 43 + 3, for the dir
4495      * entry plus the 5 and the length fields.
4496      */
4497     smb_SetSMBDataLength(outp, 46);
4498     return 0;
4499 }       
4500
4501 static long 
4502 smb_ApplyDirListPatches(cm_scache_t * dscp, smb_dirListPatch_t **dirPatchespp,
4503                         clientchar_t * tidPathp, clientchar_t * relPathp,
4504                         cm_user_t *userp, cm_req_t *reqp)
4505 {
4506     long code = 0;
4507     cm_scache_t *scp;
4508     char *dptr;
4509     afs_uint32 dosTime;
4510     u_short shortTemp;
4511     char attr;
4512     smb_dirListPatch_t *patchp;
4513     smb_dirListPatch_t *npatchp;
4514     clientchar_t path[AFSPATHMAX];
4515     afs_uint32 rights;
4516     afs_int32 mustFake = 0;
4517
4518     code = cm_FindACLCache(dscp, userp, &rights);
4519     if (code == -1) {
4520         lock_ObtainWrite(&dscp->rw);
4521         code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4522                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4523         lock_ReleaseWrite(&dscp->rw);
4524         if (code == CM_ERROR_NOACCESS) {
4525             mustFake = 1;
4526             code = 0;
4527         }
4528     }
4529     if (code)
4530         goto cleanup;
4531
4532     if (!mustFake) {    /* Bulk Stat */
4533         afs_uint32 count;
4534         cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4535
4536         memset(bsp, 0, sizeof(cm_bulkStat_t));
4537
4538         for (patchp = *dirPatchespp, count=0; 
4539              patchp; 
4540              patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4541             cm_scache_t *tscp = cm_FindSCache(&patchp->fid);
4542             int i;
4543
4544             if (tscp) {
4545                 if (lock_TryWrite(&tscp->rw)) {
4546                     /* we have an entry that we can look at */
4547                     if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
4548                         /* we have a callback on it.  Don't bother
4549                         * fetching this stat entry, since we're happy
4550                         * with the info we have.
4551                         */
4552                         lock_ReleaseWrite(&tscp->rw);
4553                         cm_ReleaseSCache(tscp);
4554                         continue;
4555                     }
4556                     lock_ReleaseWrite(&tscp->rw);
4557                 } /* got lock */
4558                 cm_ReleaseSCache(tscp);
4559             }   /* found entry */
4560
4561             i = bsp->counter++;
4562             bsp->fids[i].Volume = patchp->fid.volume;
4563             bsp->fids[i].Vnode = patchp->fid.vnode;
4564             bsp->fids[i].Unique = patchp->fid.unique;
4565
4566             if (bsp->counter == AFSCBMAX) {
4567                 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4568                 memset(bsp, 0, sizeof(cm_bulkStat_t));
4569             }
4570         }
4571
4572         if (bsp->counter > 0)
4573             code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4574
4575         free(bsp);
4576     }
4577
4578     for (patchp = *dirPatchespp; patchp; patchp =
4579          (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4580
4581         dptr = patchp->dptr;
4582
4583         cm_ClientStrPrintfN(path, AFSPATHMAX, _C("%s\\%s"),
4584                             relPathp ? relPathp : _C(""), patchp->dep->name);
4585         reqp->relPathp = path;
4586         reqp->tidPathp = tidPathp;
4587
4588         code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4589         reqp->relPathp = reqp->tidPathp = NULL;
4590
4591         if (code) {
4592             if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
4593                 *dptr++ = SMB_ATTR_HIDDEN;
4594             continue;
4595         }
4596         lock_ObtainWrite(&scp->rw);
4597         if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
4598             lock_ReleaseWrite(&scp->rw);
4599
4600             /* set the attribute */
4601             switch (scp->fileType) {
4602             case CM_SCACHETYPE_DIRECTORY:
4603             case CM_SCACHETYPE_MOUNTPOINT:
4604             case CM_SCACHETYPE_INVALID:
4605                 attr = SMB_ATTR_DIRECTORY;
4606                 break;
4607             case CM_SCACHETYPE_SYMLINK:
4608                 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4609                     attr = SMB_ATTR_DIRECTORY;
4610                 else
4611                     attr = SMB_ATTR_NORMAL;
4612                 break;
4613             default:
4614                 /* if we get here we either have a normal file
4615                 * or we have a file for which we have never 
4616                 * received status info.  In this case, we can
4617                 * check the even/odd value of the entry's vnode.
4618                 * odd means it is to be treated as a directory
4619                 * and even means it is to be treated as a file.
4620                 */
4621                 if (mustFake && (scp->fid.vnode & 0x1))
4622                     attr = SMB_ATTR_DIRECTORY;
4623                 else
4624                     attr = SMB_ATTR_NORMAL;
4625             }
4626             *dptr++ = attr;
4627
4628             /* 1969-12-31 23:59:58 +00*/
4629             dosTime = 0xEBBFBF7D;
4630
4631             /* copy out time */
4632             shortTemp = (unsigned short) (dosTime & 0xffff);
4633             *((u_short *)dptr) = shortTemp;
4634             dptr += 2;
4635
4636             /* and copy out date */
4637             shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4638             *((u_short *)dptr) = shortTemp;
4639             dptr += 2;
4640                 
4641             /* copy out file length */
4642             *((u_long *)dptr) = 0;
4643             dptr += 4;
4644         } else {
4645             lock_ConvertWToR(&scp->rw);
4646             attr = smb_Attributes(scp);
4647             /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
4648             if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
4649                 attr |= SMB_ATTR_HIDDEN;
4650             *dptr++ = attr;
4651
4652             /* get dos time */
4653             cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4654                 
4655             /* copy out time */
4656             shortTemp = (unsigned short) (dosTime & 0xffff);
4657             *((u_short *)dptr) = shortTemp;
4658             dptr += 2;
4659
4660             /* and copy out date */
4661             shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4662             *((u_short *)dptr) = shortTemp;
4663             dptr += 2;
4664                 
4665             /* copy out file length */
4666             *((u_long *)dptr) = scp->length.LowPart;
4667             dptr += 4;
4668             lock_ReleaseRead(&scp->rw);
4669         }
4670         cm_ReleaseSCache(scp);
4671     }
4672         
4673     /* now free the patches */
4674     for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4675         npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4676         free(patchp);
4677     }   
4678         
4679     /* and mark the list as empty */
4680     *dirPatchespp = NULL;
4681
4682   cleanup:
4683     return code;
4684 }
4685
4686 /* SMB_COM_SEARCH */
4687 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4688 {
4689     int attribute;
4690     long nextCookie;
4691     unsigned char *tp;
4692     long code = 0;
4693     clientchar_t *pathp;
4694     cm_dirEntry_t *dep = 0;
4695     int maxCount;
4696     smb_dirListPatch_t *dirListPatchesp;
4697     smb_dirListPatch_t *curPatchp;
4698     int dataLength;
4699     cm_buf_t *bufferp;
4700     long temp;
4701     osi_hyper_t dirLength;
4702     osi_hyper_t bufferOffset;
4703     osi_hyper_t curOffset;
4704     osi_hyper_t thyper;
4705     unsigned char *inCookiep;
4706     smb_dirSearch_t *dsp;
4707     cm_scache_t *scp;
4708     long entryInDir;
4709     long entryInBuffer;
4710     unsigned long clientCookie;
4711     cm_pageHeader_t *pageHeaderp;
4712     cm_user_t *userp = NULL;
4713     int slotInPage;
4714     clientchar_t mask[12];
4715     int returnedNames;
4716     long nextEntryCookie;
4717     int numDirChunks;           /* # of 32 byte dir chunks in this entry */
4718     char resByte;               /* reserved byte from the cookie */
4719     char *op;                   /* output data ptr */
4720     char *origOp;               /* original value of op */
4721     cm_space_t *spacep;         /* for pathname buffer */
4722     int starPattern;
4723     int rootPath = 0;
4724     int caseFold;
4725     clientchar_t *tidPathp = 0;
4726     cm_req_t req;
4727     cm_fid_t fid;
4728     int fileType;
4729
4730     smb_InitReq(&req);
4731
4732     maxCount = smb_GetSMBParm(inp, 0);
4733
4734     dirListPatchesp = NULL;
4735         
4736     caseFold = CM_FLAG_CASEFOLD;
4737
4738     tp = smb_GetSMBData(inp, NULL);
4739     pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4740                                 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4741     if (!pathp)
4742         return CM_ERROR_BADSMB;
4743
4744     inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
4745     if (!tp)
4746         return CM_ERROR_BADSMB;
4747
4748     /* We can handle long names */
4749     if (vcp->flags & SMB_VCFLAG_USENT)
4750         ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
4751
4752     /* make sure we got a whole search status */
4753     if (dataLength < 21) {
4754         nextCookie = 0;         /* start at the beginning of the dir */
4755         resByte = 0;
4756         clientCookie = 0;
4757         attribute = smb_GetSMBParm(inp, 1);
4758
4759         /* handle volume info in another function */
4760         if (attribute & 0x8)
4761             return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
4762
4763         osi_Log2(smb_logp, "SMB receive search dir count %d [%S]",
4764                  maxCount, osi_LogSaveClientString(smb_logp, pathp));
4765
4766         if (*pathp == 0) {      /* null pathp, treat as root dir */
4767             if (!(attribute & SMB_ATTR_DIRECTORY))      /* exclude dirs */
4768                 return CM_ERROR_NOFILES;
4769             rootPath = 1;
4770         }
4771
4772         dsp = smb_NewDirSearch(0);
4773         dsp->attribute = attribute;
4774         smb_Get8Dot3MaskFromPath(mask, pathp);
4775         memcpy(dsp->mask, mask, 12);
4776
4777         /* track if this is likely to match a lot of entries */
4778         if (smb_Is8Dot3StarMask(mask)) 
4779             starPattern = 1;
4780         else 
4781             starPattern = 0;
4782     } else {
4783         /* pull the next cookie value out of the search status block */
4784         nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
4785             + (inCookiep[16]<<24);
4786         dsp = smb_FindDirSearch(inCookiep[12]);
4787         if (!dsp) {
4788             /* can't find dir search status; fatal error */
4789             osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%S]",
4790                      inCookiep[12], nextCookie, osi_LogSaveClientString(smb_logp, pathp));
4791             return CM_ERROR_BADFD;
4792         }
4793         attribute = dsp->attribute;
4794         resByte = inCookiep[0];
4795
4796         /* copy out client cookie, in host byte order.  Don't bother
4797          * interpreting it, since we're just passing it through, anyway.
4798          */
4799         memcpy(&clientCookie, &inCookiep[17], 4);
4800
4801         memcpy(mask, dsp->mask, 12);
4802
4803         /* assume we're doing a star match if it has continued for more
4804          * than one call.
4805          */
4806         starPattern = 1;
4807     }
4808
4809     osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
4810              nextCookie, dsp->cookie, attribute);
4811
4812     userp = smb_GetUserFromVCP(vcp, inp);
4813
4814     /* try to get the vnode for the path name next */
4815     lock_ObtainMutex(&dsp->mx);
4816     if (dsp->scp) {
4817         scp = dsp->scp;
4818         osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
4819         cm_HoldSCache(scp);
4820         code = 0;
4821     } else {
4822         spacep = inp->spacep;
4823         smb_StripLastComponent(spacep->wdata, NULL, pathp);
4824         code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4825         if (code) {
4826             lock_ReleaseMutex(&dsp->mx);
4827             cm_ReleaseUser(userp);
4828             smb_DeleteDirSearch(dsp);
4829             smb_ReleaseDirSearch(dsp);
4830             return CM_ERROR_NOFILES;
4831         }
4832         cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
4833         cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
4834
4835         code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
4836                         caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
4837         if (code == 0) {
4838 #ifdef DFS_SUPPORT
4839             if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4840                 int pnc;
4841
4842                 pnc  = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->wdata);
4843                 cm_ReleaseSCache(scp);
4844                 lock_ReleaseMutex(&dsp->mx);
4845                 cm_ReleaseUser(userp);
4846                 smb_DeleteDirSearch(dsp);
4847                 smb_ReleaseDirSearch(dsp);
4848                 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4849                     return CM_ERROR_PATH_NOT_COVERED;
4850                 else
4851                     return CM_ERROR_NOSUCHPATH;
4852             }
4853 #endif /* DFS_SUPPORT */
4854
4855             dsp->scp = scp;
4856             osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
4857             /* we need one hold for the entry we just stored into,
4858              * and one for our own processing.  When we're done with this
4859              * function, we'll drop the one for our own processing.
4860              * We held it once from the namei call, and so we do another hold
4861              * now.
4862              */
4863             cm_HoldSCache(scp);
4864             lock_ObtainWrite(&scp->rw);
4865             dsp->flags |= SMB_DIRSEARCH_BULKST;
4866             lock_ReleaseWrite(&scp->rw);
4867         }
4868     }
4869     lock_ReleaseMutex(&dsp->mx);
4870     if (code) {
4871         cm_ReleaseUser(userp);
4872         smb_DeleteDirSearch(dsp);
4873         smb_ReleaseDirSearch(dsp);
4874         return code;
4875     }
4876
4877     /* reserves space for parameter; we'll adjust it again later to the
4878      * real count of the # of entries we returned once we've actually
4879      * assembled the directory listing.
4880      */
4881     smb_SetSMBParm(outp, 0, 0);
4882
4883     /* get the directory size */
4884     lock_ObtainWrite(&scp->rw);
4885     code = cm_SyncOp(scp, NULL, userp, &req, 0,
4886                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4887     if (code) {
4888         lock_ReleaseWrite(&scp->rw);
4889         cm_ReleaseSCache(scp);
4890         cm_ReleaseUser(userp);
4891         smb_DeleteDirSearch(dsp);
4892         smb_ReleaseDirSearch(dsp);
4893         return code;
4894     }
4895         
4896     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4897
4898     dirLength = scp->length;
4899     bufferp = NULL;
4900     bufferOffset.LowPart = bufferOffset.HighPart = 0;
4901     curOffset.HighPart = 0;
4902     curOffset.LowPart = nextCookie;
4903     origOp = op = smb_GetSMBData(outp, NULL);
4904     /* and write out the basic header */
4905     *op++ = 5;          /* variable block */
4906     op += 2;            /* skip vbl block length; we'll fill it in later */
4907     code = 0;
4908     returnedNames = 0;
4909     while (1) {
4910         clientchar_t *actualName = NULL;
4911         int           free_actualName = 0;
4912         clientchar_t shortName[13];
4913         clientchar_t *shortNameEnd;
4914
4915         /* make sure that curOffset.LowPart doesn't point to the first
4916          * 32 bytes in the 2nd through last dir page, and that it doesn't
4917          * point at the first 13 32-byte chunks in the first dir page,
4918          * since those are dir and page headers, and don't contain useful
4919          * information.
4920          */
4921         temp = curOffset.LowPart & (2048-1);
4922         if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4923             /* we're in the first page */
4924             if (temp < 13*32) temp = 13*32;
4925         }
4926         else {
4927             /* we're in a later dir page */
4928             if (temp < 32) temp = 32;
4929         }
4930
4931         /* make sure the low order 5 bits are zero */
4932         temp &= ~(32-1);
4933
4934         /* now put temp bits back ito curOffset.LowPart */
4935         curOffset.LowPart &= ~(2048-1);
4936         curOffset.LowPart |= temp;
4937
4938         /* check if we've returned all the names that will fit in the
4939          * response packet.
4940          */
4941         if (returnedNames >= maxCount) {
4942             osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
4943                       returnedNames, maxCount);
4944             break;
4945         }
4946                 
4947         /* check if we've passed the dir's EOF */
4948         if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
4949
4950         /* see if we can use the bufferp we have now; compute in which page
4951          * the current offset would be, and check whether that's the offset
4952          * of the buffer we have.  If not, get the buffer.
4953          */
4954         thyper.HighPart = curOffset.HighPart;
4955         thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4956         if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4957             /* wrong buffer */
4958             if (bufferp) {
4959                 buf_Release(bufferp);
4960                 bufferp = NULL;
4961             }   
4962             lock_ReleaseWrite(&scp->rw);
4963             code = buf_Get(scp, &thyper, &req, &bufferp);
4964             lock_ObtainMutex(&dsp->mx);
4965
4966             /* now, if we're doing a star match, do bulk fetching of all of 
4967              * the status info for files in the dir.
4968              */
4969             if (starPattern)
4970                 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
4971
4972             lock_ObtainWrite(&scp->rw);
4973             lock_ReleaseMutex(&dsp->mx);
4974             if (code) {
4975                 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
4976                 break;
4977             }
4978
4979             bufferOffset = thyper;
4980
4981             /* now get the data in the cache */
4982             while (1) {
4983                 code = cm_SyncOp(scp, bufferp, userp, &req,
4984                                  PRSFS_LOOKUP,
4985                                  CM_SCACHESYNC_NEEDCALLBACK |
4986                                  CM_SCACHESYNC_READ);
4987                 if (code) {
4988                     osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
4989                     break;
4990                 }
4991                                 
4992                 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
4993
4994                 if (cm_HaveBuffer(scp, bufferp, 0)) {
4995                     osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4996                     break;
4997                 }
4998
4999                 /* otherwise, load the buffer and try again */
5000                 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
5001                 if (code) {
5002                     osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d", 
5003                               scp, bufferp, code);
5004                     break;
5005                 }
5006             }
5007             if (code) {
5008                 buf_Release(bufferp);
5009                 bufferp = NULL;
5010                 break;
5011             }
5012         }       /* if (wrong buffer) ... */
5013
5014         /* now we have the buffer containing the entry we're interested in; copy
5015          * it out if it represents a non-deleted entry.
5016          */
5017         entryInDir = curOffset.LowPart & (2048-1);
5018         entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5019
5020         /* page header will help tell us which entries are free.  Page header
5021          * can change more often than once per buffer, since AFS 3 dir page size
5022          * may be less than (but not more than a buffer package buffer.
5023          */
5024         temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);  /* only look intra-buffer */
5025         temp &= ~(2048 - 1);    /* turn off intra-page bits */
5026         pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5027
5028         /* now determine which entry we're looking at in the page.  If it is
5029          * free (there's a free bitmap at the start of the dir), we should
5030          * skip these 32 bytes.
5031          */
5032         slotInPage = (entryInDir & 0x7e0) >> 5;
5033         if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
5034             /* this entry is free */
5035             numDirChunks = 1;           /* only skip this guy */
5036             goto nextEntry;
5037         }
5038
5039         tp = bufferp->datap + entryInBuffer;
5040         dep = (cm_dirEntry_t *) tp;             /* now points to AFS3 dir entry */
5041
5042         /* while we're here, compute the next entry's location, too,
5043          * since we'll need it when writing out the cookie into the dir
5044          * listing stream.
5045          *
5046          * XXXX Probably should do more sanity checking.
5047          */
5048         numDirChunks = cm_NameEntries(dep->name, NULL);
5049
5050         /* compute the offset of the cookie representing the next entry */
5051         nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5052
5053         /* Compute 8.3 name if necessary */
5054         actualName = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
5055         if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
5056             if (actualName)
5057                 free(actualName);
5058             cm_Gen8Dot3NameInt(dep->name, &dep->fid, shortName, &shortNameEnd);
5059             actualName = shortName;
5060             free_actualName = 0;
5061         } else {
5062             free_actualName = 1;
5063         }
5064
5065         if (actualName == NULL) {
5066             /* Couldn't convert the name for some reason */
5067             osi_Log1(smb_logp, "SMB search dir skipping entry :[%s]",
5068                      osi_LogSaveString(smb_logp, dep->name));
5069             goto nextEntry;
5070         }
5071
5072         osi_Log3(smb_logp, "SMB search dir vn %d name %s (%S)",
5073                  dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
5074                  osi_LogSaveClientString(smb_logp, actualName));
5075
5076         if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
5077             /* this is one of the entries to use: it is not deleted
5078              * and it matches the star pattern we're looking for.
5079              */
5080
5081             /* Eliminate entries that don't match requested
5082              * attributes */
5083
5084             /* no hidden files */
5085             if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
5086                 osi_Log0(smb_logp, "SMB search dir skipping hidden");
5087                 goto nextEntry;
5088             }
5089
5090             if (!(dsp->attribute & SMB_ATTR_DIRECTORY))  /* no directories */
5091             {
5092                 /* We have already done the cm_TryBulkStat above */
5093                 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5094                 fileType = cm_FindFileType(&fid);
5095                 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
5096                          "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
5097                           fileType);
5098                 if (fileType == CM_SCACHETYPE_DIRECTORY ||
5099                     fileType == CM_SCACHETYPE_MOUNTPOINT ||
5100                     fileType == CM_SCACHETYPE_DFSLINK ||
5101                     fileType == CM_SCACHETYPE_INVALID)
5102                     osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
5103                 goto nextEntry;
5104             }
5105
5106             *op++ = resByte;
5107             memcpy(op, mask, 11); op += 11;
5108             *op++ = (unsigned char) dsp->cookie;        /* they say it must be non-zero */
5109             *op++ = (unsigned char)(nextEntryCookie & 0xff);
5110             *op++ = (unsigned char)((nextEntryCookie>>8) & 0xff);
5111             *op++ = (unsigned char)((nextEntryCookie>>16) & 0xff);
5112             *op++ = (unsigned char)((nextEntryCookie>>24) & 0xff);
5113             memcpy(op, &clientCookie, 4); op += 4;
5114
5115             /* now we emit the attribute.  This is sort of tricky,
5116              * since we need to really stat the file to find out
5117              * what type of entry we've got.  Right now, we're
5118              * copying out data from a buffer, while holding the
5119              * scp locked, so it isn't really convenient to stat
5120              * something now.  We'll put in a place holder now,
5121              * and make a second pass before returning this to get
5122              * the real attributes.  So, we just skip the data for
5123              * now, and adjust it later.  We allocate a patch
5124              * record to make it easy to find this point later.
5125              * The replay will happen at a time when it is safe to
5126              * unlock the directory.
5127              */
5128             curPatchp = malloc(sizeof(*curPatchp));
5129             osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
5130             curPatchp->dptr = op;
5131             cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5132
5133             /* do hidden attribute here since name won't be around when applying
5134              * dir list patches
5135              */
5136
5137             if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
5138                 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5139             else
5140                 curPatchp->flags = 0;
5141
5142             op += 9;    /* skip attr, time, date and size */
5143
5144             /* zero out name area.  The spec says to pad with
5145              * spaces, but Samba doesn't, and neither do we.
5146              */
5147             memset(op, 0, 13);
5148
5149             /* finally, we get to copy out the name; we know that
5150              * it fits in 8.3 or the pattern wouldn't match, but it
5151              * never hurts to be sure.
5152              */
5153             cm_ClientStringToUtf8(actualName, -1, op, 13);
5154             if (smb_StoreAnsiFilenames)
5155                 CharToOem(op, op);
5156             /* This is a UCHAR field, which is ASCII even if Unicode
5157                is negotiated. */
5158
5159             /* Uppercase if requested by client */
5160             if (!KNOWS_LONG_NAMES(inp))
5161                 _strupr(op);
5162
5163             op += 13;
5164
5165             /* now, adjust the # of entries copied */
5166             returnedNames++;
5167         }       /* if we're including this name */
5168
5169       nextEntry:
5170         if (free_actualName && actualName) {
5171             free(actualName);
5172             actualName = NULL;
5173         }
5174
5175         /* and adjust curOffset to be where the new cookie is */
5176         thyper.HighPart = 0;
5177         thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5178         curOffset = LargeIntegerAdd(thyper, curOffset);
5179     }           /* while copying data for dir listing */
5180
5181     /* release the mutex */
5182     lock_ReleaseWrite(&scp->rw);
5183     if (bufferp) {
5184         buf_Release(bufferp);
5185         bufferp = NULL;
5186     }
5187
5188     /* apply and free last set of patches; if not doing a star match, this
5189      * will be empty, but better safe (and freeing everything) than sorry.
5190      */
5191     smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
5192
5193     /* special return code for unsuccessful search */
5194     if (code == 0 && dataLength < 21 && returnedNames == 0)
5195         code = CM_ERROR_NOFILES;
5196
5197     osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
5198              returnedNames, code);
5199
5200     if (code != 0) {
5201         smb_DeleteDirSearch(dsp);
5202         smb_ReleaseDirSearch(dsp);
5203         cm_ReleaseSCache(scp);
5204         cm_ReleaseUser(userp);
5205         return code;
5206     }
5207
5208     /* finalize the output buffer */
5209     smb_SetSMBParm(outp, 0, returnedNames);
5210     temp = (long) (op - origOp);
5211     smb_SetSMBDataLength(outp, temp);
5212
5213     /* the data area is a variable block, which has a 5 (already there)
5214      * followed by the length of the # of data bytes.  We now know this to
5215      * be "temp," although that includes the 3 bytes of vbl block header.
5216      * Deduct for them and fill in the length field.
5217      */
5218     temp -= 3;          /* deduct vbl block info */
5219     osi_assertx(temp == (43 * returnedNames), "unexpected data length");
5220     origOp[1] = (unsigned char)(temp & 0xff);
5221     origOp[2] = (unsigned char)((temp>>8) & 0xff);
5222     if (returnedNames == 0) 
5223         smb_DeleteDirSearch(dsp);
5224     smb_ReleaseDirSearch(dsp);
5225     cm_ReleaseSCache(scp);
5226     cm_ReleaseUser(userp);
5227     return code;
5228 }       
5229
5230
5231 /* verify that this is a valid path to a directory.  I don't know why they
5232  * don't use the get file attributes call.
5233  *
5234  * SMB_COM_CHECK_DIRECTORY
5235  */
5236 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5237 {
5238     clientchar_t *pathp;
5239     long code = 0;
5240     cm_scache_t *rootScp;
5241     cm_scache_t *newScp;
5242     cm_user_t *userp;
5243     unsigned int attrs;
5244     int caseFold;
5245     clientchar_t *tidPathp;
5246     cm_req_t req;
5247     char * pdata;
5248
5249     smb_InitReq(&req);
5250
5251     pdata = smb_GetSMBData(inp, NULL);
5252     pathp = smb_ParseASCIIBlock(inp, pdata, NULL, SMB_STRF_ANSIPATH);
5253     if (!pathp)
5254         return CM_ERROR_BADSMB;
5255     osi_Log1(smb_logp, "SMB receive check path %S",
5256              osi_LogSaveClientString(smb_logp, pathp));
5257         
5258     rootScp = cm_data.rootSCachep;
5259         
5260     userp = smb_GetUserFromVCP(vcp, inp);
5261
5262     caseFold = CM_FLAG_CASEFOLD;
5263
5264     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5265     if (code) {
5266         cm_ReleaseUser(userp);
5267         return CM_ERROR_NOSUCHPATH;
5268     }
5269     code = cm_NameI(rootScp, pathp,
5270                     caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
5271                     userp, tidPathp, &req, &newScp);
5272
5273     if (code) {
5274         cm_ReleaseUser(userp);
5275         return code;
5276     }
5277         
5278 #ifdef DFS_SUPPORT
5279     if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5280         int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5281         cm_ReleaseSCache(newScp);
5282         cm_ReleaseUser(userp);
5283         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5284             return CM_ERROR_PATH_NOT_COVERED;
5285         else
5286             return CM_ERROR_NOSUCHPATH;
5287     }
5288 #endif /* DFS_SUPPORT */
5289
5290     /* now lock the vnode with a callback; returns with newScp locked */
5291     lock_ObtainWrite(&newScp->rw);
5292     code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
5293                      CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5294     if (code) {
5295         if (code != CM_ERROR_NOACCESS) {
5296             lock_ReleaseWrite(&newScp->rw);
5297             cm_ReleaseSCache(newScp);
5298             cm_ReleaseUser(userp);
5299             return code;
5300         }
5301     } else {
5302         cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5303     }
5304
5305     attrs = smb_Attributes(newScp);
5306
5307     if (!(attrs & SMB_ATTR_DIRECTORY))
5308         code = CM_ERROR_NOTDIR;
5309
5310     lock_ReleaseWrite(&newScp->rw);
5311
5312     cm_ReleaseSCache(newScp);
5313     cm_ReleaseUser(userp);
5314     return code;
5315 }       
5316
5317 /* SMB_COM_SET_INFORMATION */
5318 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5319 {
5320     clientchar_t *pathp;
5321     long code = 0;
5322     cm_scache_t *rootScp;
5323     unsigned short attribute;
5324     cm_attr_t attr;
5325     cm_scache_t *newScp;
5326     afs_uint32 dosTime;
5327     cm_user_t *userp;
5328     int caseFold;
5329     clientchar_t *tidPathp;
5330     char * datap;
5331     cm_req_t req;
5332
5333     smb_InitReq(&req);
5334
5335     /* decode basic attributes we're passed */
5336     attribute = smb_GetSMBParm(inp, 0);
5337     dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5338
5339     datap = smb_GetSMBData(inp, NULL);
5340     pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5341     if (!pathp)
5342         return CM_ERROR_BADSMB;
5343                
5344     osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
5345              dosTime, attribute);
5346
5347     rootScp = cm_data.rootSCachep;
5348         
5349     userp = smb_GetUserFromVCP(vcp, inp);
5350
5351     caseFold = CM_FLAG_CASEFOLD;
5352
5353     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5354     if (code) {
5355         cm_ReleaseUser(userp);
5356         return CM_ERROR_NOSUCHFILE;
5357     }
5358     code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5359                     tidPathp, &req, &newScp);
5360
5361     if (code) {
5362         cm_ReleaseUser(userp);
5363         return code;
5364     }
5365
5366 #ifdef DFS_SUPPORT
5367     if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5368         int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5369         cm_ReleaseSCache(newScp);
5370         cm_ReleaseUser(userp);
5371         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5372             return CM_ERROR_PATH_NOT_COVERED;
5373         else
5374             return CM_ERROR_NOSUCHPATH;
5375     }
5376 #endif /* DFS_SUPPORT */
5377
5378     /* now lock the vnode with a callback; returns with newScp locked; we
5379      * need the current status to determine what the new status is, in some
5380      * cases.
5381      */
5382     lock_ObtainWrite(&newScp->rw);
5383     code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5384                      CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5385     if (code) {
5386         lock_ReleaseWrite(&newScp->rw);
5387         cm_ReleaseSCache(newScp);
5388         cm_ReleaseUser(userp);
5389         return code;
5390     }
5391
5392     cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5393
5394     /* Check for RO volume */
5395     if (newScp->flags & CM_SCACHEFLAG_RO) {
5396         lock_ReleaseWrite(&newScp->rw);
5397         cm_ReleaseSCache(newScp);
5398         cm_ReleaseUser(userp);
5399         return CM_ERROR_READONLY;
5400     }
5401
5402     /* prepare for setattr call */
5403     attr.mask = 0;
5404     if (dosTime != 0) {
5405         attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
5406         smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
5407     }
5408     if ((newScp->unixModeBits & 0222) && (attribute & SMB_ATTR_READONLY) != 0) {
5409         /* we're told to make a writable file read-only */
5410         attr.unixModeBits = newScp->unixModeBits & ~0222;
5411         attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5412     }
5413     else if ((newScp->unixModeBits & 0222) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
5414         /* we're told to make a read-only file writable */
5415         attr.unixModeBits = newScp->unixModeBits | 0222;
5416         attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5417     }
5418     lock_ReleaseWrite(&newScp->rw);
5419
5420     /* now call setattr */
5421     if (attr.mask)
5422         code = cm_SetAttr(newScp, &attr, userp, &req);
5423     else
5424         code = 0;
5425         
5426     cm_ReleaseSCache(newScp);
5427     cm_ReleaseUser(userp);
5428
5429     return code;
5430 }
5431
5432
5433 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5434 {
5435     clientchar_t *pathp;
5436     long code = 0;
5437     cm_scache_t *rootScp;
5438     cm_scache_t *newScp, *dscp;
5439     afs_uint32 dosTime;
5440     int attrs;
5441     cm_user_t *userp;
5442     int caseFold;
5443     clientchar_t *tidPathp;
5444     cm_space_t *spacep;
5445     clientchar_t *lastComp;
5446     char * datap;
5447     cm_req_t req;
5448
5449     smb_InitReq(&req);
5450
5451     datap = smb_GetSMBData(inp, NULL);
5452     pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5453     if (!pathp)
5454         return CM_ERROR_BADSMB;
5455         
5456     if (*pathp == 0)            /* null path */
5457         pathp = _C("\\");
5458
5459     osi_Log1(smb_logp, "SMB receive getfile attributes path %S",
5460              osi_LogSaveClientString(smb_logp, pathp));
5461
5462     rootScp = cm_data.rootSCachep;
5463         
5464     userp = smb_GetUserFromVCP(vcp, inp);
5465
5466     /* we shouldn't need this for V3 requests, but we seem to */
5467     caseFold = CM_FLAG_CASEFOLD;
5468
5469     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5470     if (code) {
5471         cm_ReleaseUser(userp);
5472         return CM_ERROR_NOSUCHFILE;
5473     }
5474
5475     /*
5476      * XXX Strange hack XXX
5477      *
5478      * As of Patch 5 (16 July 97), we are having the following problem:
5479      * In NT Explorer 4.0, whenever we click on a directory, AFS gets
5480      * requests to look up "desktop.ini" in all the subdirectories.
5481      * This can cause zillions of timeouts looking up non-existent cells
5482      * and volumes, especially in the top-level directory.
5483      *
5484      * We have not found any way to avoid this or work around it except
5485      * to explicitly ignore the requests for mount points that haven't
5486      * yet been evaluated and for directories that haven't yet been
5487      * fetched.
5488      *
5489      * We should modify this hack to provide a fake desktop.ini file
5490      * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
5491      */
5492     spacep = inp->spacep;
5493     smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
5494 #ifndef SPECIAL_FOLDERS
5495     if (lastComp && cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
5496         code = cm_NameI(rootScp, spacep->wdata,
5497                         caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
5498                         userp, tidPathp, &req, &dscp);
5499         if (code == 0) {
5500 #ifdef DFS_SUPPORT
5501             if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5502                 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
5503                                                           spacep->wdata);
5504                 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5505                     return CM_ERROR_PATH_NOT_COVERED;
5506                 else
5507                     return CM_ERROR_NOSUCHPATH;
5508             } else
5509 #endif /* DFS_SUPPORT */
5510             if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
5511                 code = CM_ERROR_NOSUCHFILE;
5512             else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
5513                 cm_buf_t *bp = buf_Find(dscp, &hzero);
5514                 if (bp) {
5515                     buf_Release(bp);
5516                     bp = NULL;
5517                 } else
5518                     code = CM_ERROR_NOSUCHFILE;
5519             }
5520             cm_ReleaseSCache(dscp);
5521             if (code) {
5522                 cm_ReleaseUser(userp);
5523                 return code;
5524             }
5525         }
5526     }
5527 #endif /* SPECIAL_FOLDERS */
5528
5529     code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5530                     tidPathp, &req, &newScp);
5531     if (code) {
5532         cm_ReleaseUser(userp);
5533         return code;
5534     }
5535         
5536 #ifdef DFS_SUPPORT
5537     if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5538         int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5539         cm_ReleaseSCache(newScp);
5540         cm_ReleaseUser(userp);
5541         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5542             return CM_ERROR_PATH_NOT_COVERED;
5543         else
5544             return CM_ERROR_NOSUCHPATH;
5545     }
5546 #endif /* DFS_SUPPORT */
5547
5548     /* now lock the vnode with a callback; returns with newScp locked */
5549     lock_ObtainWrite(&newScp->rw);
5550     code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5551                      CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5552     if (code) {
5553         lock_ReleaseWrite(&newScp->rw);
5554         cm_ReleaseSCache(newScp);
5555         cm_ReleaseUser(userp);
5556         return code;
5557     }
5558
5559     cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5560
5561     attrs = smb_Attributes(newScp);
5562
5563     smb_SetSMBParm(outp, 0, attrs);
5564         
5565     smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
5566     smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
5567     smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
5568     smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
5569     smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
5570     smb_SetSMBParm(outp, 5, 0);
5571     smb_SetSMBParm(outp, 6, 0);
5572     smb_SetSMBParm(outp, 7, 0);
5573     smb_SetSMBParm(outp, 8, 0);
5574     smb_SetSMBParm(outp, 9, 0);
5575     smb_SetSMBDataLength(outp, 0);
5576     lock_ReleaseWrite(&newScp->rw);
5577
5578     cm_ReleaseSCache(newScp);
5579     cm_ReleaseUser(userp);
5580
5581     return 0;
5582 }       
5583
5584 /* SMB_COM_TREE_DISCONNECT */
5585 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5586 {
5587     smb_tid_t *tidp;
5588         
5589     osi_Log0(smb_logp, "SMB receive tree disconnect");
5590
5591     /* find the tree and free it */
5592     tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
5593     if (tidp) {
5594         lock_ObtainWrite(&smb_rctLock);
5595         tidp->deleteOk = 1;
5596         smb_ReleaseTID(tidp, TRUE);
5597         lock_ReleaseWrite(&smb_rctLock);
5598     }
5599
5600     return 0;
5601 }
5602
5603 /* SMB_COM_0PEN */
5604 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5605 {
5606     smb_fid_t *fidp;
5607     clientchar_t *pathp;
5608     clientchar_t *lastNamep;
5609     int share;
5610     int attribute;
5611     long code = 0;
5612     cm_user_t *userp;
5613     cm_scache_t *scp;
5614     afs_uint32 dosTime;
5615     int caseFold;
5616     cm_space_t *spacep;
5617     clientchar_t *tidPathp;
5618     char * datap;
5619     cm_req_t req;
5620
5621     smb_InitReq(&req);
5622
5623     datap = smb_GetSMBData(inp, NULL);
5624     pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5625     if (!pathp)
5626         return CM_ERROR_BADSMB;
5627
5628     osi_Log1(smb_logp, "SMB receive open file [%S]", osi_LogSaveClientString(smb_logp, pathp));
5629
5630 #ifdef DEBUG_VERBOSE
5631     {
5632         char *hexpath;
5633
5634         hexpath = osi_HexifyString( pathp );
5635         DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
5636         free(hexpath);
5637     }
5638 #endif
5639
5640     share = smb_GetSMBParm(inp, 0);
5641     attribute = smb_GetSMBParm(inp, 1);
5642
5643     spacep = inp->spacep;
5644     /* smb_StripLastComponent will strip "::$DATA" if present */
5645     smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5646
5647     if (!cm_IsValidClientString(pathp)) {
5648 #ifdef DEBUG
5649         clientchar_t * hexp;
5650
5651         hexp = cm_GetRawCharsAlloc(pathp, -1);
5652         osi_Log1(smb_logp, "CoreOpen rejecting invalid name. [%S]",
5653                  osi_LogSaveClientString(smb_logp, hexp));
5654         if (hexp)
5655             free(hexp);
5656 #else
5657         osi_Log0(smb_logp, "CoreOpen rejecting invalid name");
5658 #endif
5659         return CM_ERROR_BADNTFILENAME;
5660     }
5661
5662     if (lastNamep && cm_ClientStrCmp(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0) {
5663         /* special case magic file name for receiving IOCTL requests
5664          * (since IOCTL calls themselves aren't getting through).
5665          */
5666         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5667         smb_SetupIoctlFid(fidp, spacep);
5668         smb_SetSMBParm(outp, 0, fidp->fid);
5669         smb_SetSMBParm(outp, 1, 0);     /* attrs */
5670         smb_SetSMBParm(outp, 2, 0);     /* next 2 are DOS time */
5671         smb_SetSMBParm(outp, 3, 0);
5672         smb_SetSMBParm(outp, 4, 0);     /* next 2 are length */
5673         smb_SetSMBParm(outp, 5, 0x7fff);
5674         /* pass the open mode back */
5675         smb_SetSMBParm(outp, 6, (share & 0xf));
5676         smb_SetSMBDataLength(outp, 0);
5677         smb_ReleaseFID(fidp);
5678         return 0;
5679     }
5680
5681     userp = smb_GetUserFromVCP(vcp, inp);
5682
5683     caseFold = CM_FLAG_CASEFOLD;
5684
5685     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5686     if (code) {
5687         cm_ReleaseUser(userp);
5688         return CM_ERROR_NOSUCHPATH;
5689     }
5690     code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5691                     tidPathp, &req, &scp);
5692         
5693     if (code) {
5694         cm_ReleaseUser(userp);
5695         return code;
5696     }
5697
5698 #ifdef DFS_SUPPORT
5699     if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5700         int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
5701         cm_ReleaseSCache(scp);
5702         cm_ReleaseUser(userp);
5703         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5704             return CM_ERROR_PATH_NOT_COVERED;
5705         else
5706             return CM_ERROR_NOSUCHPATH;
5707     }
5708 #endif /* DFS_SUPPORT */
5709
5710     code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
5711     if (code) {
5712         cm_ReleaseSCache(scp);
5713         cm_ReleaseUser(userp);
5714         return code;
5715     }
5716
5717     /* don't need callback to check file type, since file types never
5718      * change, and namei and cm_Lookup all stat the object at least once on
5719      * a successful return.
5720      */
5721     if (scp->fileType != CM_SCACHETYPE_FILE) {
5722         cm_ReleaseSCache(scp);
5723         cm_ReleaseUser(userp);
5724         return CM_ERROR_ISDIR;
5725     }
5726
5727     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5728     osi_assertx(fidp, "null smb_fid_t");
5729
5730     lock_ObtainMutex(&fidp->mx);
5731     if ((share & 0xf) == 0)
5732         fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5733     else if ((share & 0xf) == 1)
5734         fidp->flags |= SMB_FID_OPENWRITE;
5735     else 
5736         fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
5737
5738     /* save the  user */
5739     cm_HoldUser(userp);
5740     fidp->userp = userp;
5741
5742     /* and a pointer to the vnode */
5743     fidp->scp = scp;
5744     osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
5745     lock_ObtainWrite(&scp->rw);
5746     scp->flags |= CM_SCACHEFLAG_SMB_FID;
5747  
5748     smb_SetSMBParm(outp, 0, fidp->fid);
5749     smb_SetSMBParm(outp, 1, smb_Attributes(scp));
5750     smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5751     smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
5752     smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
5753     smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
5754     smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
5755     /* pass the open mode back; XXXX add access checks */
5756     smb_SetSMBParm(outp, 6, (share & 0xf));
5757     smb_SetSMBDataLength(outp, 0);
5758         lock_ReleaseMutex(&fidp->mx);
5759     lock_ReleaseRead(&scp->rw);
5760         
5761     /* notify open */
5762     cm_Open(scp, 0, userp);
5763
5764     /* send and free packet */
5765     smb_ReleaseFID(fidp);
5766     cm_ReleaseUser(userp);
5767     /* don't release scp, since we've squirreled away the pointer in the fid struct */
5768     return 0;
5769 }
5770
5771 typedef struct smb_unlinkRock {
5772     cm_scache_t *dscp;
5773     cm_user_t *userp;
5774     cm_req_t *reqp;
5775     smb_vc_t *vcp;
5776     clientchar_t *maskp;                /* pointer to the star pattern */
5777     int flags;
5778     int any;
5779     cm_dirEntryList_t * matches;
5780 } smb_unlinkRock_t;
5781
5782 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5783 {
5784     long code = 0;
5785     smb_unlinkRock_t *rockp;
5786     int caseFold;
5787     int match;
5788     normchar_t matchName[MAX_PATH];
5789         
5790     rockp = vrockp;
5791
5792     caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5793     if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5794         caseFold |= CM_FLAG_8DOT3;
5795
5796     if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
5797         /* Can't convert name */
5798         osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string.",
5799                  osi_LogSaveString(smb_logp, dep->name));
5800         return 0;
5801     }
5802
5803     match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5804     if (!match &&
5805         (rockp->flags & SMB_MASKFLAG_TILDE) &&
5806         !cm_Is8Dot3(matchName)) {
5807         cm_Gen8Dot3Name(dep, matchName, NULL);
5808         /* 8.3 matches are always case insensitive */
5809         match = cm_MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
5810     }
5811     if (match) {
5812         osi_Log1(smb_logp, "Found match %S",
5813                  osi_LogSaveClientString(smb_logp, matchName));
5814
5815         cm_DirEntryListAdd(dep->name, &rockp->matches);
5816
5817         rockp->any = 1;
5818
5819         /* If we made a case sensitive exact match, we might as well quit now. */
5820         if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !cm_ClientStrCmp(matchName, rockp->maskp))
5821             code = CM_ERROR_STOPNOW;
5822         else
5823             code = 0;
5824     }
5825     else code = 0;
5826
5827     return code;
5828 }
5829
5830 /* SMB_COM_DELETE */
5831 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5832 {
5833     int attribute;
5834     long code = 0;
5835     clientchar_t *pathp;
5836     unsigned char *tp;
5837     cm_space_t *spacep;
5838     cm_scache_t *dscp;
5839     clientchar_t *lastNamep;
5840     smb_unlinkRock_t rock;
5841     cm_user_t *userp;
5842     osi_hyper_t thyper;
5843     int caseFold;
5844     clientchar_t *tidPathp;
5845     cm_req_t req;
5846
5847     smb_InitReq(&req);
5848     memset(&rock, 0, sizeof(rock));
5849
5850     attribute = smb_GetSMBParm(inp, 0);
5851         
5852     tp = smb_GetSMBData(inp, NULL);
5853     pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
5854     if (!pathp)
5855         return CM_ERROR_BADSMB;
5856
5857     osi_Log1(smb_logp, "SMB receive unlink %S",
5858              osi_LogSaveClientString(smb_logp, pathp));
5859
5860     spacep = inp->spacep;
5861     smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5862
5863     userp = smb_GetUserFromVCP(vcp, inp);
5864
5865     caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5866
5867     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5868     if (code) {
5869         cm_ReleaseUser(userp);
5870         return CM_ERROR_NOSUCHPATH;
5871     }
5872     code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold, userp, tidPathp,
5873                     &req, &dscp);
5874     if (code) {
5875         cm_ReleaseUser(userp);
5876         return code;
5877     }
5878         
5879 #ifdef DFS_SUPPORT
5880     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5881         int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
5882         cm_ReleaseSCache(dscp);
5883         cm_ReleaseUser(userp);
5884         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5885             return CM_ERROR_PATH_NOT_COVERED;
5886         else
5887             return CM_ERROR_NOSUCHPATH;
5888     }
5889 #endif /* DFS_SUPPORT */
5890
5891     /* otherwise, scp points to the parent directory. */
5892     if (!lastNamep) 
5893         lastNamep = pathp;
5894     else 
5895         lastNamep++;
5896
5897     rock.any = 0;
5898     rock.maskp = cm_ClientStringToNormStringAlloc(smb_FindMask(pathp), -1, NULL);
5899     if (!rock.maskp) {
5900         code = CM_ERROR_NOSUCHFILE;
5901         goto done;
5902     }
5903     rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5904
5905     thyper.LowPart = 0;
5906     thyper.HighPart = 0;
5907     rock.userp = userp;
5908     rock.reqp = &req;
5909     rock.dscp = dscp;
5910     rock.vcp = vcp;
5911     rock.matches = NULL;
5912
5913     /* Now, if we aren't dealing with a wildcard match, we first try an exact 
5914      * match.  If that fails, we do a case insensitve match. 
5915      */
5916     if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
5917         !smb_IsStarMask(rock.maskp)) {
5918         code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5919         if (!rock.any) {
5920             thyper.LowPart = 0;
5921             thyper.HighPart = 0;
5922             rock.flags |= SMB_MASKFLAG_CASEFOLD;
5923         }
5924     }
5925  
5926     if (!rock.any)
5927         code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5928     
5929     if (code == CM_ERROR_STOPNOW) 
5930         code = 0;
5931
5932     if (code == 0 && rock.matches) {
5933         cm_dirEntryList_t * entry;
5934
5935         for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
5936             normchar_t normalizedName[MAX_PATH];
5937
5938             /* Note: entry->name is a non-normalized name */
5939
5940             osi_Log1(smb_logp, "Unlinking %s",
5941                      osi_LogSaveString(smb_logp, entry->name));
5942
5943             /* We assume this works because entry->name was
5944                successfully converted in smb_UnlinkProc() once. */
5945             cm_FsStringToNormString(entry->name, -1,
5946                                     normalizedName, lengthof(normalizedName));
5947
5948             code = cm_Unlink(dscp, entry->name, normalizedName, userp, &req);
5949
5950             if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5951                 smb_NotifyChange(FILE_ACTION_REMOVED,
5952                                  FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5953                                  dscp, normalizedName, NULL, TRUE);
5954         }
5955     }
5956
5957     cm_DirEntryListFree(&rock.matches);
5958
5959   done:
5960     if (userp)
5961     cm_ReleaseUser(userp);
5962         
5963     if (dscp)
5964     cm_ReleaseSCache(dscp);
5965
5966     if (rock.maskp)
5967     free(rock.maskp);
5968
5969     if (code == 0 && !rock.any)
5970         code = CM_ERROR_NOSUCHFILE;
5971     return code;
5972 }       
5973
5974 typedef struct smb_renameRock {
5975     cm_scache_t *odscp;  /* old dir */
5976     cm_scache_t *ndscp;  /* new dir */
5977     cm_user_t *userp;    /* user */
5978     cm_req_t *reqp;      /* request struct */
5979     smb_vc_t *vcp;       /* virtual circuit */
5980     normchar_t *maskp;   /* pointer to star pattern of old file name */
5981     int flags;           /* tilde, casefold, etc */
5982     clientchar_t *newNamep;     /* ptr to the new file's name */
5983     fschar_t fsOldName[MAX_PATH]; /* raw FS name */
5984     clientchar_t clOldName[MAX_PATH]; /* client name */
5985     int any;
5986 } smb_renameRock_t;
5987
5988 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5989 {
5990     long code = 0;
5991     smb_renameRock_t *rockp;
5992     int caseFold;
5993     int match;
5994     normchar_t matchName[MAX_PATH];
5995
5996     rockp = (smb_renameRock_t *) vrockp;
5997
5998     if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
5999         /* Can't convert string */
6000         osi_Log1(smb_logp, "Skpping entry [%s]. Can't normalize FS string",
6001                  osi_LogSaveString(smb_logp, dep->name));
6002         return 0;
6003     }
6004
6005     caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
6006     if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
6007         caseFold |= CM_FLAG_8DOT3;
6008
6009     match = cm_MatchMask(matchName, rockp->maskp, caseFold);
6010     if (!match &&
6011         (rockp->flags & SMB_MASKFLAG_TILDE) &&
6012         !cm_Is8Dot3(matchName)) {
6013         cm_Gen8Dot3Name(dep, matchName, NULL);
6014         match = cm_MatchMask(matchName, rockp->maskp, caseFold);
6015     }
6016
6017     if (match) {
6018         rockp->any = 1;
6019         StringCbCopyA(rockp->fsOldName, sizeof(rockp->fsOldName), dep->name);
6020         cm_ClientStrCpy(rockp->clOldName, lengthof(rockp->clOldName),
6021                         matchName);
6022         code = CM_ERROR_STOPNOW;
6023     } else {
6024         code = 0;
6025     }
6026
6027     return code;
6028 }
6029
6030
6031 long 
6032 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp, int attrs)
6033 {
6034     long code = 0;
6035     cm_space_t *spacep = NULL;
6036     smb_renameRock_t rock;
6037     cm_scache_t *oldDscp = NULL;
6038     cm_scache_t *newDscp = NULL;
6039     cm_scache_t *tmpscp= NULL;
6040     cm_scache_t *tmpscp2 = NULL;
6041     clientchar_t *oldLastNamep;
6042     clientchar_t *newLastNamep;
6043     osi_hyper_t thyper;
6044     cm_user_t *userp;
6045     int caseFold;
6046     clientchar_t *tidPathp;
6047     DWORD filter;
6048     cm_req_t req;
6049
6050     userp = smb_GetUserFromVCP(vcp, inp);
6051     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6052     if (code) {
6053         cm_ReleaseUser(userp);
6054         return CM_ERROR_NOSUCHPATH;
6055     }
6056
6057     smb_InitReq(&req);
6058     memset(&rock, 0, sizeof(rock));
6059
6060     spacep = inp->spacep;
6061     smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6062
6063     caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6064     code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6065                     userp, tidPathp, &req, &oldDscp);
6066     if (code) {
6067         cm_ReleaseUser(userp);
6068         return code;
6069     }
6070         
6071 #ifdef DFS_SUPPORT
6072     if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6073         int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6074         cm_ReleaseSCache(oldDscp);
6075         cm_ReleaseUser(userp);
6076         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6077             return CM_ERROR_PATH_NOT_COVERED;
6078         else
6079             return CM_ERROR_NOSUCHPATH;
6080     }
6081 #endif /* DFS_SUPPORT */
6082
6083     smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6084     code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6085                     userp, tidPathp, &req, &newDscp);
6086
6087     if (code) {
6088         cm_ReleaseSCache(oldDscp);
6089         cm_ReleaseUser(userp);
6090         return code;
6091     }
6092
6093 #ifdef DFS_SUPPORT
6094     if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6095         int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6096         cm_ReleaseSCache(oldDscp);
6097         cm_ReleaseSCache(newDscp);
6098         cm_ReleaseUser(userp);
6099         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6100             return CM_ERROR_PATH_NOT_COVERED;
6101         else
6102             return CM_ERROR_NOSUCHPATH;
6103     }
6104 #endif /* DFS_SUPPORT */
6105
6106
6107     /* otherwise, oldDscp and newDscp point to the corresponding directories.
6108      * next, get the component names, and lower case them.
6109      */
6110
6111     /* handle the old name first */
6112     if (!oldLastNamep) 
6113         oldLastNamep = oldPathp;
6114     else 
6115         oldLastNamep++;
6116
6117     /* and handle the new name, too */
6118     if (!newLastNamep) 
6119         newLastNamep = newPathp;
6120     else 
6121         newLastNamep++;
6122
6123     /* TODO: The old name could be a wildcard.  The new name must not be */
6124
6125     /* Check if the file already exists; if so return error */
6126     code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6127     if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6128         (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) 
6129     {
6130         osi_Log2(smb_logp, "  lookup returns %ld for [%S]", code,
6131                  osi_LogSaveClientString(smb_logp, newLastNamep));
6132
6133         /* Check if the old and the new names differ only in case. If so return
6134          * success, else return CM_ERROR_EXISTS 
6135          */
6136         if (!code && oldDscp == newDscp && !cm_ClientStrCmpI(oldLastNamep, newLastNamep)) {
6137
6138             /* This would be a success only if the old file is *as same as* the new file */
6139             code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
6140             if (!code) {
6141                 if (tmpscp == tmpscp2) 
6142                     code = 0;
6143                 else 
6144                     code = CM_ERROR_EXISTS;
6145                 cm_ReleaseSCache(tmpscp2);
6146                 tmpscp2 = NULL;
6147             } else {
6148                 code = CM_ERROR_NOSUCHFILE;
6149             }
6150         } else {
6151             /* file exist, do not rename, also fixes move */
6152             osi_Log0(smb_logp, "Can't rename.  Target already exists");
6153             code = CM_ERROR_EXISTS;
6154         }
6155         goto done;
6156     }
6157
6158     /* do the vnode call */
6159     rock.odscp = oldDscp;
6160     rock.ndscp = newDscp;
6161     rock.userp = userp;
6162     rock.reqp = &req;
6163     rock.vcp = vcp;
6164     rock.maskp = cm_ClientStringToNormStringAlloc(oldLastNamep, -1, NULL);
6165     if (!rock.maskp) {
6166         code = CM_ERROR_NOSUCHFILE;
6167         goto done;
6168     }
6169     rock.flags = ((cm_ClientStrChr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6170     rock.newNamep = newLastNamep;
6171     rock.fsOldName[0] = '\0';
6172     rock.clOldName[0] = '\0';
6173     rock.any = 0;
6174
6175     /* Now search the directory for the pattern, and do the appropriate rename when found */
6176     thyper.LowPart = 0;         /* search dir from here */
6177     thyper.HighPart = 0;
6178
6179     code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6180     if (code == 0 && !rock.any) {
6181         thyper.LowPart = 0;
6182         thyper.HighPart = 0;
6183         rock.flags |= SMB_MASKFLAG_CASEFOLD;
6184         code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6185     }
6186     osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
6187
6188     if (code == CM_ERROR_STOPNOW && rock.fsOldName[0] != '\0') {
6189         code = cm_Rename(rock.odscp, rock.fsOldName, rock.clOldName,
6190                          rock.ndscp, rock.newNamep, rock.userp,
6191                          rock.reqp);
6192         /* if the call worked, stop doing the search now, since we
6193          * really only want to rename one file.
6194          */
6195     if (code)
6196         osi_Log0(smb_logp, "cm_Rename failure");
6197         osi_Log1(smb_logp, "cm_Rename returns %ld", code);
6198     } else if (code == 0) {
6199         code = CM_ERROR_NOSUCHFILE;
6200     }
6201
6202     /* Handle Change Notification */
6203     /*
6204     * Being lazy, not distinguishing between files and dirs in this
6205     * filter, since we'd have to do a lookup.
6206     */
6207     if (code == 0) {
6208         filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
6209         if (oldDscp == newDscp) {
6210             if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6211                 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6212                                  filter, oldDscp, rock.clOldName,
6213                                  newLastNamep, TRUE);
6214         } else {
6215             if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6216                 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6217                                   filter, oldDscp, rock.clOldName,
6218                                   NULL, TRUE);
6219             if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6220                 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
6221                                  filter, newDscp, newLastNamep,
6222                                  NULL, TRUE);
6223         }
6224     }
6225
6226   done:
6227     if (tmpscp != NULL) 
6228         cm_ReleaseSCache(tmpscp);
6229     if (userp)
6230         cm_ReleaseUser(userp);
6231     if (oldDscp)
6232         cm_ReleaseSCache(oldDscp);
6233     if (newDscp)
6234         cm_ReleaseSCache(newDscp);
6235     if (rock.maskp)
6236         free(rock.maskp);
6237
6238     return code;
6239 }       
6240
6241 long 
6242 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp) 
6243 {
6244     long code = 0;
6245     cm_space_t *spacep = NULL;
6246     cm_scache_t *oldDscp = NULL;
6247     cm_scache_t *newDscp = NULL;
6248     cm_scache_t *tmpscp= NULL;
6249     cm_scache_t *tmpscp2 = NULL;
6250     cm_scache_t *sscp = NULL;
6251     clientchar_t *oldLastNamep;
6252     clientchar_t *newLastNamep;
6253     cm_user_t *userp;
6254     int caseFold;
6255     clientchar_t *tidPathp;
6256     DWORD filter;
6257     cm_req_t req;
6258
6259     userp = smb_GetUserFromVCP(vcp, inp);
6260
6261     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6262     if (code) {
6263         cm_ReleaseUser(userp);
6264         return CM_ERROR_NOSUCHPATH;
6265     }
6266
6267     smb_InitReq(&req);
6268
6269     caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6270
6271     spacep = inp->spacep;
6272     smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6273     
6274     code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6275                     userp, tidPathp, &req, &oldDscp);
6276     if (code) {
6277         cm_ReleaseUser(userp);
6278         return code;
6279     }
6280         
6281 #ifdef DFS_SUPPORT
6282     if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6283         int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6284         cm_ReleaseSCache(oldDscp);
6285         cm_ReleaseUser(userp);
6286         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6287             return CM_ERROR_PATH_NOT_COVERED;
6288         else
6289             return CM_ERROR_NOSUCHPATH;
6290     }
6291 #endif /* DFS_SUPPORT */
6292
6293     smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6294     code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6295                     userp, tidPathp, &req, &newDscp);
6296     if (code) {
6297         cm_ReleaseSCache(oldDscp);
6298         cm_ReleaseUser(userp);
6299         return code;
6300     }
6301
6302 #ifdef DFS_SUPPORT
6303     if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6304         int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6305         cm_ReleaseSCache(newDscp);
6306         cm_ReleaseSCache(oldDscp);
6307         cm_ReleaseUser(userp);
6308         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6309             return CM_ERROR_PATH_NOT_COVERED;
6310         else
6311             return CM_ERROR_NOSUCHPATH;
6312     }
6313 #endif /* DFS_SUPPORT */
6314
6315     /* Now, although we did two lookups for the two directories (because the same
6316      * directory can be referenced through different paths), we only allow hard links
6317      * within the same directory. */
6318     if (oldDscp != newDscp) {
6319         cm_ReleaseSCache(oldDscp);
6320         cm_ReleaseSCache(newDscp);
6321         cm_ReleaseUser(userp);
6322         return CM_ERROR_CROSSDEVLINK;
6323     }
6324
6325     /* handle the old name first */
6326     if (!oldLastNamep) 
6327         oldLastNamep = oldPathp;
6328     else 
6329         oldLastNamep++;
6330
6331     /* and handle the new name, too */
6332     if (!newLastNamep) 
6333         newLastNamep = newPathp;
6334     else 
6335         newLastNamep++;
6336
6337     /* now lookup the old name */
6338     osi_Log1(smb_logp,"  looking up [%S]", osi_LogSaveClientString(smb_logp,oldLastNamep));
6339     code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
6340     if (code) {
6341         cm_ReleaseSCache(oldDscp);
6342         cm_ReleaseSCache(newDscp);
6343         cm_ReleaseUser(userp);
6344         return code;
6345     }
6346
6347     /* Check if the file already exists; if so return error */
6348     code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6349     if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) && 
6350         (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) 
6351     {
6352         osi_Log2(smb_logp, "  lookup returns %ld for [%S]", code,
6353                  osi_LogSaveClientString(smb_logp, newLastNamep));
6354
6355         /* if the existing link is to the same file, then we return success */
6356         if (!code) {
6357             if(sscp == tmpscp) {
6358                 code = 0;
6359             } else {
6360                 osi_Log0(smb_logp, "Can't create hardlink.  Target already exists");
6361                 code = CM_ERROR_EXISTS;
6362             }
6363         }
6364
6365         if (tmpscp != NULL)
6366             cm_ReleaseSCache(tmpscp);
6367         cm_ReleaseSCache(sscp);
6368         cm_ReleaseSCache(newDscp);
6369         cm_ReleaseSCache(oldDscp);
6370         cm_ReleaseUser(userp);
6371         return code; 
6372     }
6373
6374     /* now create the hardlink */
6375     osi_Log1(smb_logp,"  Attempting to create new link [%S]", osi_LogSaveClientString(smb_logp, newLastNamep));
6376     code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
6377     osi_Log1(smb_logp,"  Link returns 0x%x", code);
6378
6379     /* Handle Change Notification */
6380     if (code == 0) {
6381         filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
6382         if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6383             smb_NotifyChange(FILE_ACTION_ADDED,
6384                              filter, newDscp, newLastNamep,
6385                              NULL, TRUE);
6386     }
6387
6388     if (tmpscp != NULL) 
6389         cm_ReleaseSCache(tmpscp);
6390     cm_ReleaseUser(userp);
6391     cm_ReleaseSCache(sscp);
6392     cm_ReleaseSCache(oldDscp);
6393     cm_ReleaseSCache(newDscp);
6394     return code;
6395 }
6396
6397 /* SMB_COM_RENAME */
6398 long 
6399 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6400 {
6401     clientchar_t *oldPathp;
6402     clientchar_t *newPathp;
6403     unsigned char *tp;
6404     long code;
6405
6406     tp = smb_GetSMBData(inp, NULL);
6407     oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6408     if (!oldPathp)
6409         return CM_ERROR_BADSMB;
6410     newPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6411     if (!newPathp)
6412         return CM_ERROR_BADSMB;
6413
6414     osi_Log2(smb_logp, "smb rename [%S] to [%S]",
6415              osi_LogSaveClientString(smb_logp, oldPathp),
6416              osi_LogSaveClientString(smb_logp, newPathp));
6417
6418     if (!cm_IsValidClientString(newPathp)) {
6419 #ifdef DEBUG
6420         clientchar_t * hexp;
6421
6422         hexp = cm_GetRawCharsAlloc(newPathp, -1);
6423         osi_Log1(smb_logp, "CoreRename rejecting invalid name. [%S]",
6424                  osi_LogSaveClientString(smb_logp, hexp));
6425         if (hexp)
6426             free(hexp);
6427 #else
6428         osi_Log0(smb_logp, "CoreRename rejecting invalid name");
6429 #endif
6430         return CM_ERROR_BADNTFILENAME;
6431     }
6432
6433     code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
6434
6435     osi_Log1(smb_logp, "smb rename returns 0x%x", code);
6436     return code;
6437 }
6438
6439
6440
6441 typedef struct smb_rmdirRock {
6442     cm_scache_t *dscp;
6443     cm_user_t *userp;
6444     cm_req_t *reqp;
6445     normchar_t *maskp;          /* pointer to the star pattern */
6446     int flags;
6447     int any;
6448     cm_dirEntryList_t * matches;
6449 } smb_rmdirRock_t;
6450
6451 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6452 {       
6453     long code = 0;
6454     smb_rmdirRock_t *rockp;
6455     int match;
6456     normchar_t matchName[MAX_PATH];
6457         
6458     rockp = (smb_rmdirRock_t *) vrockp;
6459
6460     if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6461         osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6462                  osi_LogSaveString(smb_logp, dep->name));
6463         return 0;
6464     }
6465
6466     if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
6467         match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6468     else
6469         match = (cm_ClientStrCmp(matchName, rockp->maskp) == 0);
6470     if (!match &&
6471          (rockp->flags & SMB_MASKFLAG_TILDE) &&
6472          !cm_Is8Dot3(matchName)) {
6473         cm_Gen8Dot3Name(dep, matchName, NULL);
6474         match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6475     }       
6476
6477     if (match) {
6478         rockp->any = 1;
6479         cm_DirEntryListAdd(dep->name, &rockp->matches);
6480     }
6481
6482     return 0;
6483 }
6484
6485
6486 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6487 {
6488     long code = 0;
6489     clientchar_t *pathp;
6490     unsigned char *tp;
6491     cm_space_t *spacep;
6492     cm_scache_t *dscp;
6493     clientchar_t *lastNamep;
6494     smb_rmdirRock_t rock;
6495     cm_user_t *userp;
6496     osi_hyper_t thyper;
6497     int caseFold;
6498     clientchar_t *tidPathp;
6499     cm_req_t req;
6500
6501     smb_InitReq(&req);
6502     memset(&rock, 0, sizeof(rock));
6503
6504     tp = smb_GetSMBData(inp, NULL);
6505     pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6506     if (!pathp)
6507         return CM_ERROR_BADSMB;
6508
6509     spacep = inp->spacep;
6510     smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
6511
6512     userp = smb_GetUserFromVCP(vcp, inp);
6513
6514     caseFold = CM_FLAG_CASEFOLD;
6515
6516     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6517     if (code) {
6518         cm_ReleaseUser(userp);
6519         return CM_ERROR_NOSUCHPATH;
6520     }
6521     code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
6522                     userp, tidPathp, &req, &dscp);
6523
6524     if (code) {
6525         cm_ReleaseUser(userp);
6526         return code;
6527     }
6528         
6529 #ifdef DFS_SUPPORT
6530     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6531         int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
6532         cm_ReleaseSCache(dscp);
6533         cm_ReleaseUser(userp);
6534         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6535             return CM_ERROR_PATH_NOT_COVERED;
6536         else
6537             return CM_ERROR_NOSUCHPATH;
6538     }
6539 #endif /* DFS_SUPPORT */
6540
6541     /* otherwise, scp points to the parent directory. */
6542     if (!lastNamep) 
6543         lastNamep = pathp;
6544     else 
6545         lastNamep++;
6546         
6547     rock.any = 0;
6548     rock.maskp = cm_ClientStringToNormStringAlloc(lastNamep, -1, NULL);
6549     if (!rock.maskp) {
6550         code = CM_ERROR_NOSUCHFILE;
6551         goto done;
6552     }
6553     rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6554
6555     thyper.LowPart = 0;
6556     thyper.HighPart = 0;
6557     rock.userp = userp;
6558     rock.reqp = &req;
6559     rock.dscp = dscp;
6560     rock.matches = NULL;
6561
6562     /* First do a case sensitive match, and if that fails, do a case insensitive match */
6563     code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6564     if (code == 0 && !rock.any) {
6565         thyper.LowPart = 0;
6566         thyper.HighPart = 0;
6567         rock.flags |= SMB_MASKFLAG_CASEFOLD;
6568         code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6569     }
6570
6571     if (code == 0 && rock.matches) {
6572         cm_dirEntryList_t * entry;
6573
6574         for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
6575             clientchar_t clientName[MAX_PATH];
6576
6577             /* We assume this will succeed because smb_RmdirProc()
6578                successfully converted entry->name once above. */
6579             cm_FsStringToClientString(entry->name, -1, clientName, lengthof(clientName));
6580
6581             osi_Log1(smb_logp, "Removing directory %s",
6582                      osi_LogSaveString(smb_logp, entry->name));
6583
6584             code = cm_RemoveDir(dscp, entry->name, clientName, userp, &req);
6585
6586             if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6587                 smb_NotifyChange(FILE_ACTION_REMOVED,
6588                                  FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6589                                  dscp, clientName, NULL, TRUE);
6590         }
6591     }
6592
6593   done:
6594     if (rock.matches)
6595     cm_DirEntryListFree(&rock.matches);
6596
6597     if (userp)
6598     cm_ReleaseUser(userp);
6599         
6600     if (dscp)
6601     cm_ReleaseSCache(dscp);
6602
6603     if (code == 0 && !rock.any)
6604         code = CM_ERROR_NOSUCHFILE;        
6605
6606     if (rock.maskp)
6607     free(rock.maskp);
6608
6609     return code;
6610 }
6611
6612 /* SMB_COM_FLUSH */
6613 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6614 {
6615     unsigned short fid;
6616     smb_fid_t *fidp;
6617     cm_user_t *userp;
6618     long code = 0;
6619     cm_req_t req;
6620
6621     smb_InitReq(&req);
6622
6623     fid = smb_GetSMBParm(inp, 0);
6624
6625     osi_Log1(smb_logp, "SMB flush fid %d", fid);
6626
6627     fid = smb_ChainFID(fid, inp);
6628     fidp = smb_FindFID(vcp, fid, 0);
6629     if (!fidp) {
6630         osi_Log2(smb_logp, "smb_ReceiveCoreFlush Unknown SMB Fid vcp 0x%p fid %d",
6631                  vcp, fid);
6632         return CM_ERROR_BADFD;
6633     }
6634     userp = smb_GetUserFromVCP(vcp, inp);
6635
6636     lock_ObtainMutex(&fidp->mx);
6637     if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
6638         cm_ReleaseUser(userp);
6639         lock_ReleaseMutex(&fidp->mx);
6640         smb_ReleaseFID(fidp);
6641         return CM_ERROR_BADFD;
6642     }
6643
6644     if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
6645         lock_ReleaseMutex(&fidp->mx);
6646         cm_ReleaseUser(userp);
6647         smb_CloseFID(vcp, fidp, NULL, 0);
6648         smb_ReleaseFID(fidp);
6649         return CM_ERROR_NOSUCHFILE;
6650     }
6651
6652     if ((fidp->flags & SMB_FID_OPENWRITE) && smb_AsyncStore != 2) {
6653         cm_scache_t * scp = fidp->scp;
6654         cm_HoldSCache(scp);
6655         lock_ReleaseMutex(&fidp->mx);
6656         code = cm_FSync(scp, userp, &req);
6657         cm_ReleaseSCache(scp);
6658     } else {
6659         lock_ReleaseMutex(&fidp->mx);
6660         code = 0;
6661     }
6662         
6663     cm_ReleaseUser(userp);
6664     smb_ReleaseFID(fidp);                
6665     return code;
6666 }
6667
6668 struct smb_FullNameRock {
6669     clientchar_t *name;
6670     cm_scache_t  *vnode;
6671     clientchar_t *fullName;
6672     fschar_t     *originalName;
6673 };
6674
6675 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
6676                      osi_hyper_t *offp)
6677 {
6678     normchar_t matchName[MAX_PATH];
6679     struct smb_FullNameRock *vrockp;
6680
6681     vrockp = (struct smb_FullNameRock *)rockp;
6682
6683     if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6684         osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6685                  osi_LogSaveString(smb_logp, dep->name));
6686         return 0;
6687     }
6688
6689     if (!cm_Is8Dot3(matchName)) {
6690         clientchar_t shortName[13];
6691
6692         cm_Gen8Dot3Name(dep, shortName, NULL);
6693
6694         if (cm_ClientStrCmpIA(shortName, vrockp->name) == 0) {
6695             vrockp->fullName = cm_ClientStrDup(matchName);
6696             vrockp->originalName = cm_FsStrDup(dep->name);
6697             return CM_ERROR_STOPNOW;
6698         }
6699     }
6700     if (cm_ClientStrCmpI(matchName, vrockp->name) == 0 &&
6701         ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
6702         ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
6703         vrockp->fullName = cm_ClientStrDup(matchName);
6704         vrockp->originalName = cm_FsStrDup(dep->name);
6705         return CM_ERROR_STOPNOW;
6706     }
6707     return 0;
6708 }
6709
6710 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, clientchar_t *pathp,
6711                   clientchar_t **newPathp, fschar_t ** originalPathp,
6712                   cm_user_t *userp, cm_req_t *reqp)
6713 {
6714     struct smb_FullNameRock rock;
6715     long code = 0;
6716
6717     memset(&rock, 0, sizeof(rock));
6718     rock.name = pathp;
6719     rock.vnode = scp;
6720
6721     code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL); 
6722     if (code == CM_ERROR_STOPNOW) {
6723         *newPathp = rock.fullName;
6724         *originalPathp = rock.originalName;
6725     } else {
6726         *newPathp = cm_ClientStrDup(pathp);
6727         *originalPathp = cm_ClientStringToFsStringAlloc(pathp, -1, NULL);
6728     }
6729 }
6730
6731 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
6732                   afs_uint32 dosTime) {
6733     long code = 0;
6734     cm_req_t req;
6735     cm_scache_t *dscp = NULL;
6736     clientchar_t *pathp = NULL;
6737     cm_scache_t * scp = NULL;
6738     cm_scache_t *delscp = NULL;
6739     int nullcreator = 0;
6740
6741     osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
6742              fidp, fidp->fid, scp, vcp);
6743
6744     if (!userp) {
6745         lock_ObtainMutex(&fidp->mx);
6746         if (!fidp->userp && !(fidp->flags & (SMB_FID_IOCTL|
6747                                              SMB_FID_RPC))) {
6748             lock_ReleaseMutex(&fidp->mx);
6749             osi_Log0(smb_logp, "  No user specified.  Not closing fid");
6750             return CM_ERROR_BADFD;
6751         }
6752         
6753         userp = fidp->userp;    /* no hold required since fidp is held
6754                                    throughout the function */
6755         lock_ReleaseMutex(&fidp->mx);
6756     }
6757
6758     smb_InitReq(&req);
6759
6760     lock_ObtainWrite(&smb_rctLock);
6761     if (fidp->deleteOk) {
6762         osi_Log0(smb_logp, "  Fid already closed.");
6763         lock_ReleaseWrite(&smb_rctLock);    
6764         return CM_ERROR_BADFD;
6765     }
6766     fidp->deleteOk = 1;
6767     lock_ReleaseWrite(&smb_rctLock);
6768
6769     lock_ObtainMutex(&fidp->mx);
6770     if (fidp->NTopen_dscp) {
6771         dscp = fidp->NTopen_dscp;   
6772         cm_HoldSCache(dscp);
6773     }
6774
6775     if (fidp->NTopen_pathp)
6776         pathp = cm_ClientStrDup(fidp->NTopen_pathp);
6777
6778     if (fidp->scp) {
6779         scp = fidp->scp;
6780         cm_HoldSCache(scp);
6781     }
6782
6783     /* Don't jump the gun on an async raw write */
6784     while (fidp->raw_writers) {
6785         lock_ReleaseMutex(&fidp->mx);
6786         thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
6787         lock_ObtainMutex(&fidp->mx);
6788     }
6789
6790     /* watch for ioctl closes, and read-only opens */
6791     if (scp != NULL &&
6792         (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
6793          == SMB_FID_OPENWRITE) {
6794         if (dosTime != 0 && dosTime != -1) {
6795             scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6796             /* This fixes defect 10958 */
6797             CompensateForSmbClientLastWriteTimeBugs(&dosTime);
6798             smb_UnixTimeFromDosUTime(&scp->clientModTime, dosTime);
6799         }
6800         if (smb_AsyncStore != 2) {
6801             lock_ReleaseMutex(&fidp->mx);
6802             code = cm_FSync(scp, userp, &req);
6803             lock_ObtainMutex(&fidp->mx);
6804         }
6805     }
6806     else 
6807         code = 0;
6808
6809     /* unlock any pending locks */
6810     if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
6811         scp->fileType == CM_SCACHETYPE_FILE) {
6812         cm_key_t key;
6813         long tcode;
6814
6815         lock_ReleaseMutex(&fidp->mx);
6816
6817         /* CM_UNLOCK_BY_FID doesn't look at the process ID.  We pass
6818               * in zero. */
6819         key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
6820         lock_ObtainWrite(&scp->rw);
6821
6822         tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
6823                           CM_SCACHESYNC_NEEDCALLBACK
6824                           | CM_SCACHESYNC_GETSTATUS
6825                           | CM_SCACHESYNC_LOCK);
6826
6827         if (tcode) {
6828             osi_Log1(smb_logp,
6829                      "smb CoreClose SyncOp failure code 0x%x", tcode);
6830             goto post_syncopdone;
6831         }
6832
6833         cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
6834
6835         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
6836
6837     post_syncopdone:
6838
6839         lock_ReleaseWrite(&scp->rw);
6840         lock_ObtainMutex(&fidp->mx);
6841     }
6842
6843     if (fidp->flags & SMB_FID_DELONCLOSE) {
6844         clientchar_t *fullPathp = NULL;
6845         fschar_t *originalNamep = NULL;
6846
6847         lock_ReleaseMutex(&fidp->mx);
6848
6849         code = cm_Lookup(dscp, pathp, CM_FLAG_NOMOUNTCHASE, userp, &req, &delscp);
6850         if (code) {
6851             cm_HoldSCache(scp);
6852             delscp = scp;
6853         }
6854         smb_FullName(dscp, delscp, pathp, &fullPathp, &originalNamep, userp, &req);
6855         if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
6856             code = cm_RemoveDir(dscp, originalNamep, fullPathp, userp, &req);
6857             if (code == 0) {
6858                 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6859                     smb_NotifyChange(FILE_ACTION_REMOVED,
6860                                       FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6861                                       dscp, fullPathp, NULL, TRUE);
6862             }
6863         } else {
6864             code = cm_Unlink(dscp, originalNamep, fullPathp, userp, &req);
6865             if (code == 0) {                            
6866                 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6867                     smb_NotifyChange(FILE_ACTION_REMOVED,
6868                                       FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6869                                       dscp, fullPathp, NULL, TRUE);
6870             }
6871         }
6872
6873         if (fullPathp)
6874             free(fullPathp);
6875         if (originalNamep)
6876             free(originalNamep);
6877
6878         lock_ObtainMutex(&fidp->mx);
6879         fidp->flags &= ~SMB_FID_DELONCLOSE;
6880     }
6881
6882     /* if this was a newly created file, then clear the creator
6883      * in the stat cache entry. */
6884     if (fidp->flags & SMB_FID_CREATED) {
6885         nullcreator = 1;
6886         fidp->flags &= ~SMB_FID_CREATED;
6887     }
6888
6889     if (fidp->flags & SMB_FID_NTOPEN) {
6890         cm_ReleaseSCache(fidp->NTopen_dscp);
6891         fidp->NTopen_dscp = NULL;
6892         free(fidp->NTopen_pathp);
6893         fidp->NTopen_pathp = NULL;
6894         fidp->flags &= ~SMB_FID_NTOPEN;
6895     } else {
6896         osi_assertx(fidp->NTopen_dscp == NULL, "null NTopen_dsc");
6897         osi_assertx(fidp->NTopen_pathp == NULL, "null NTopen_path");
6898     }
6899
6900     if (fidp->NTopen_wholepathp) {
6901         free(fidp->NTopen_wholepathp);
6902         fidp->NTopen_wholepathp = NULL;
6903     }
6904
6905     if (fidp->scp) {
6906         cm_ReleaseSCache(fidp->scp);
6907         fidp->scp = NULL;
6908     }
6909     lock_ReleaseMutex(&fidp->mx);
6910
6911     if (dscp)
6912         cm_ReleaseSCache(dscp);
6913
6914     if (delscp) {
6915         cm_ReleaseSCache(delscp);
6916     }
6917
6918     if (scp) {
6919         lock_ObtainWrite(&scp->rw);
6920         if (nullcreator && scp->creator == userp)
6921             scp->creator = NULL;
6922         scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
6923         lock_ReleaseWrite(&scp->rw);
6924         cm_ReleaseSCache(scp);
6925     }
6926
6927     if (pathp)
6928         free(pathp);
6929
6930     return code;
6931 }
6932
6933 /* SMB_COM_CLOSE */
6934 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6935 {
6936     unsigned short fid;
6937     smb_fid_t *fidp;
6938     cm_user_t *userp;
6939     long code = 0;
6940     afs_uint32 dosTime;
6941
6942     fid = smb_GetSMBParm(inp, 0);
6943     dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6944
6945     osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
6946
6947     fid = smb_ChainFID(fid, inp);
6948     fidp = smb_FindFID(vcp, fid, 0);
6949     if (!fidp) {
6950         osi_Log2(smb_logp, "smb_ReceiveCoreClose Unknown SMB Fid vcp 0x%p fid %d",
6951                  vcp, fid);
6952         return CM_ERROR_BADFD;
6953     }
6954         
6955     userp = smb_GetUserFromVCP(vcp, inp);
6956
6957     code = smb_CloseFID(vcp, fidp, userp, dosTime);
6958     
6959     smb_ReleaseFID(fidp);
6960     cm_ReleaseUser(userp);
6961     return code;
6962 }
6963
6964 /*
6965  * smb_ReadData -- common code for Read, Read And X, and Raw Read
6966  */
6967 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
6968         cm_user_t *userp, long *readp)
6969 {
6970     osi_hyper_t offset;
6971     long code = 0;
6972     cm_scache_t *scp;
6973     cm_buf_t *bufferp;
6974     osi_hyper_t fileLength;
6975     osi_hyper_t thyper;
6976     osi_hyper_t lastByte;
6977     osi_hyper_t bufferOffset;
6978     long bufIndex;
6979     afs_uint32 nbytes;
6980     int chunk;
6981     int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
6982     cm_req_t req;
6983
6984     osi_Log3(smb_logp, "smb_ReadData fid %d, off 0x%x, size 0x%x",
6985               fidp->fid, offsetp->LowPart, count);
6986
6987     *readp = 0;
6988
6989     lock_ObtainMutex(&fidp->mx);
6990     /* make sure we have a readable FD */
6991     if (!(fidp->flags & SMB_FID_OPENREAD_LISTDIR)) {
6992         osi_Log2(smb_logp, "smb_ReadData fid %d not OPENREAD_LISTDIR flags 0x%x",
6993                   fidp->fid, fidp->flags);
6994         lock_ReleaseMutex(&fidp->mx);
6995         code = CM_ERROR_BADFDOP;
6996         goto done2;
6997     }
6998
6999     if (!fidp->scp) {
7000         lock_ReleaseMutex(&fidp->mx);
7001         code = CM_ERROR_BADFD;
7002         goto done2;
7003     }
7004         
7005     smb_InitReq(&req);
7006
7007     bufferp = NULL;
7008     offset = *offsetp;
7009
7010     scp = fidp->scp;
7011     cm_HoldSCache(scp);
7012     lock_ObtainWrite(&scp->rw);
7013
7014     if (offset.HighPart == 0) {
7015         chunk = offset.LowPart >> cm_logChunkSize;
7016         if (chunk != fidp->curr_chunk) {
7017             fidp->prev_chunk = fidp->curr_chunk;
7018             fidp->curr_chunk = chunk;
7019         }
7020         if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
7021             sequential = 1;
7022     }
7023     lock_ReleaseMutex(&fidp->mx);
7024
7025     /* start by looking up the file's end */
7026     code = cm_SyncOp(scp, NULL, userp, &req, 0,
7027                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7028     if (code) 
7029         goto done;
7030
7031     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7032
7033     /* now we have the entry locked, look up the length */
7034     fileLength = scp->length;
7035
7036     /* adjust count down so that it won't go past EOF */
7037     thyper.LowPart = count;
7038     thyper.HighPart = 0;
7039     thyper = LargeIntegerAdd(offset, thyper);   /* where read should end */
7040     lastByte = thyper;
7041     if (LargeIntegerGreaterThan(thyper, fileLength)) {
7042         /* we'd read past EOF, so just stop at fileLength bytes.
7043          * Start by computing how many bytes remain in the file.
7044          */
7045         thyper = LargeIntegerSubtract(fileLength, offset);
7046
7047         /* if we are past EOF, read 0 bytes */
7048         if (LargeIntegerLessThanZero(thyper))
7049             count = 0;
7050         else
7051             count = thyper.LowPart;
7052     }       
7053
7054     *readp = count;
7055
7056     /* now, copy the data one buffer at a time,
7057      * until we've filled the request packet
7058      */
7059     while (1) {
7060         /* if we've copied all the data requested, we're done */
7061         if (count <= 0) break;
7062
7063         /* otherwise, load up a buffer of data */
7064         thyper.HighPart = offset.HighPart;
7065         thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7066         if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7067             /* wrong buffer */
7068             if (bufferp) {
7069                 buf_Release(bufferp);
7070                 bufferp = NULL;
7071             }
7072             lock_ReleaseWrite(&scp->rw);
7073
7074             code = buf_Get(scp, &thyper, &req, &bufferp);
7075
7076             lock_ObtainWrite(&scp->rw);
7077             if (code) goto done;
7078             bufferOffset = thyper;
7079
7080             /* now get the data in the cache */
7081             while (1) {
7082                 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7083                                  CM_SCACHESYNC_NEEDCALLBACK |
7084                                  CM_SCACHESYNC_READ);
7085                 if (code) 
7086                     goto done;
7087                     
7088                 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
7089
7090                 if (cm_HaveBuffer(scp, bufferp, 0)) break;
7091
7092                 /* otherwise, load the buffer and try again */
7093                 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
7094                 if (code) break;
7095             }
7096             if (code) {
7097                 buf_Release(bufferp);
7098                 bufferp = NULL;
7099                 goto done;
7100             }
7101         }       /* if (wrong buffer) ... */
7102
7103         /* now we have the right buffer loaded.  Copy out the
7104          * data from here to the user's buffer.
7105          */
7106         bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7107
7108         /* and figure out how many bytes we want from this buffer */
7109         nbytes = cm_data.buf_blockSize - bufIndex;      /* what remains in buffer */
7110         if (nbytes > count) nbytes = count;     /* don't go past EOF */
7111
7112         /* now copy the data */
7113         memcpy(op, bufferp->datap + bufIndex, nbytes);
7114                 
7115         /* adjust counters, pointers, etc. */
7116         op += nbytes;
7117         count -= nbytes;
7118         thyper.LowPart = nbytes;
7119         thyper.HighPart = 0;
7120         offset = LargeIntegerAdd(thyper, offset);
7121     } /* while 1 */
7122
7123   done:
7124     lock_ReleaseWrite(&scp->rw);
7125     if (bufferp)
7126         buf_Release(bufferp);
7127
7128     if (code == 0 && sequential)
7129         cm_ConsiderPrefetch(scp, &lastByte, *readp, userp, &req);
7130
7131     cm_ReleaseSCache(scp);
7132
7133   done2:
7134     osi_Log3(smb_logp, "smb_ReadData fid %d returns 0x%x read %d bytes",
7135               fidp->fid, code, *readp);
7136     return code;
7137 }
7138
7139 /*
7140  * smb_WriteData -- common code for Write and Raw Write
7141  */
7142 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
7143         cm_user_t *userp, long *writtenp)
7144 {
7145     osi_hyper_t offset = *offsetp;
7146     long code = 0;
7147     long written = 0;
7148     cm_scache_t *scp = NULL;
7149     osi_hyper_t fileLength;     /* file's length at start of write */
7150     osi_hyper_t minLength;      /* don't read past this */
7151     afs_uint32 nbytes;          /* # of bytes to transfer this iteration */
7152     cm_buf_t *bufferp = NULL;
7153     osi_hyper_t thyper;         /* hyper tmp variable */
7154     osi_hyper_t bufferOffset;
7155     afs_uint32 bufIndex;                /* index in buffer where our data is */
7156     int doWriteBack = 0;
7157     osi_hyper_t writeBackOffset;/* offset of region to write back when I/O is done */
7158     DWORD filter = 0;
7159     cm_req_t req;
7160
7161     osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
7162               fidp->fid, offsetp->LowPart, count);
7163
7164     *writtenp = 0;
7165
7166     lock_ObtainMutex(&fidp->mx);
7167     /* make sure we have a writable FD */
7168     if (!(fidp->flags & SMB_FID_OPENWRITE)) {
7169         osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
7170                   fidp->fid, fidp->flags);
7171         lock_ReleaseMutex(&fidp->mx);
7172         code = CM_ERROR_BADFDOP;
7173         goto done2;
7174     }
7175     
7176     smb_InitReq(&req);
7177
7178     scp = fidp->scp;
7179     cm_HoldSCache(scp);
7180     lock_ReleaseMutex(&fidp->mx);
7181
7182     lock_ObtainWrite(&scp->rw);
7183     /* start by looking up the file's end */
7184     code = cm_SyncOp(scp, NULL, userp, &req, 0,
7185                       CM_SCACHESYNC_NEEDCALLBACK
7186                       | CM_SCACHESYNC_SETSTATUS
7187                       | CM_SCACHESYNC_GETSTATUS);
7188     if (code) 
7189         goto done;
7190         
7191     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
7192
7193     /* now we have the entry locked, look up the length */
7194     fileLength = scp->length;
7195     minLength = fileLength;
7196     if (LargeIntegerGreaterThan(minLength, scp->serverLength))
7197         minLength = scp->serverLength;
7198
7199     /* adjust file length if we extend past EOF */
7200     thyper.LowPart = count;
7201     thyper.HighPart = 0;
7202     thyper = LargeIntegerAdd(offset, thyper);   /* where write should end */
7203     if (LargeIntegerGreaterThan(thyper, fileLength)) {
7204         /* we'd write past EOF, so extend the file */
7205         scp->mask |= CM_SCACHEMASK_LENGTH;
7206         scp->length = thyper;
7207         filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
7208     } else
7209         filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
7210
7211     /* now, if the new position (thyper) and the old (offset) are in
7212      * different storeback windows, remember to store back the previous
7213      * storeback window when we're done with the write.
7214      *
7215      * the purpose of this logic is to slow down the CIFS client 
7216      * in order to avoid the client disconnecting during the CLOSE
7217      * operation if there are too many dirty buffers left to write
7218      * than can be accomplished during 45 seconds.  This used to be
7219      * based upon cm_chunkSize but we desire cm_chunkSize to be large
7220      * so that we can read larger amounts of data at a time.
7221      */
7222     if (smb_AsyncStore == 1 && 
7223          (thyper.LowPart & ~(smb_AsyncStoreSize-1)) !=
7224          (offset.LowPart & ~(smb_AsyncStoreSize-1))) {
7225         /* they're different */
7226         doWriteBack = 1;
7227         writeBackOffset.HighPart = offset.HighPart;
7228         writeBackOffset.LowPart = offset.LowPart & ~(smb_AsyncStoreSize-1);
7229     }
7230
7231     *writtenp = count;
7232
7233     /* now, copy the data one buffer at a time, until we've filled the
7234      * request packet */
7235     while (1) {
7236         /* if we've copied all the data requested, we're done */
7237         if (count <= 0) 
7238             break;
7239
7240         /* handle over quota or out of space */
7241         if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
7242             *writtenp = written;
7243             code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
7244             break;
7245         }
7246
7247         /* otherwise, load up a buffer of data */
7248         thyper.HighPart = offset.HighPart;
7249         thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7250         if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7251             /* wrong buffer */
7252             if (bufferp) {
7253                 lock_ReleaseMutex(&bufferp->mx);
7254                 buf_Release(bufferp);
7255                 bufferp = NULL;
7256             }   
7257             lock_ReleaseWrite(&scp->rw);
7258
7259             code = buf_Get(scp, &thyper, &req, &bufferp);
7260
7261             lock_ObtainMutex(&bufferp->mx);
7262             lock_ObtainWrite(&scp->rw);
7263             if (code) goto done;
7264
7265             bufferOffset = thyper;
7266
7267             /* now get the data in the cache */
7268             while (1) {
7269                 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7270                                   CM_SCACHESYNC_NEEDCALLBACK
7271                                   | CM_SCACHESYNC_WRITE
7272                                   | CM_SCACHESYNC_BUFLOCKED);
7273                 if (code) 
7274                     goto done;
7275
7276                 cm_SyncOpDone(scp, bufferp, 
7277                                CM_SCACHESYNC_NEEDCALLBACK 
7278                                | CM_SCACHESYNC_WRITE 
7279                                | CM_SCACHESYNC_BUFLOCKED);
7280
7281                 /* If we're overwriting the entire buffer, or
7282                  * if we're writing at or past EOF, mark the
7283                  * buffer as current so we don't call
7284                  * cm_GetBuffer.  This skips the fetch from the
7285                  * server in those cases where we're going to 
7286                  * obliterate all the data in the buffer anyway,
7287                  * or in those cases where there is no useful
7288                  * data at the server to start with.
7289                  *
7290                  * Use minLength instead of scp->length, since
7291                  * the latter has already been updated by this
7292                  * call.
7293                  */
7294                 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
7295                      || LargeIntegerEqualTo(offset, bufferp->offset)
7296                      && (count >= cm_data.buf_blockSize
7297                           || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
7298                                                                                ConvertLongToLargeInteger(count)),
7299                                                                minLength))) {
7300                     if (count < cm_data.buf_blockSize
7301                          && bufferp->dataVersion == CM_BUF_VERSION_BAD)
7302                         memset(bufferp->datap, 0,
7303                                 cm_data.buf_blockSize);
7304                     bufferp->dataVersion = scp->dataVersion;
7305                 }
7306
7307                 if (cm_HaveBuffer(scp, bufferp, 1)) break;
7308
7309                 /* otherwise, load the buffer and try again */
7310                 lock_ReleaseMutex(&bufferp->mx);
7311                 code = cm_GetBuffer(scp, bufferp, NULL, userp,
7312                                      &req);
7313                 lock_ReleaseWrite(&scp->rw);
7314                 lock_ObtainMutex(&bufferp->mx);
7315                 lock_ObtainWrite(&scp->rw);
7316                 if (code) break;
7317             }
7318             if (code) {
7319                 lock_ReleaseMutex(&bufferp->mx);
7320                 buf_Release(bufferp);
7321                 bufferp = NULL;
7322                 goto done;
7323             }
7324         }       /* if (wrong buffer) ... */
7325
7326         /* now we have the right buffer loaded.  Copy out the
7327          * data from here to the user's buffer.
7328          */
7329         bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7330
7331         /* and figure out how many bytes we want from this buffer */
7332         nbytes = cm_data.buf_blockSize - bufIndex;      /* what remains in buffer */
7333         if (nbytes > count) 
7334             nbytes = count;     /* don't go past end of request */
7335
7336         /* now copy the data */
7337         memcpy(bufferp->datap + bufIndex, op, nbytes);
7338         buf_SetDirty(bufferp, bufIndex, nbytes, userp);
7339
7340         /* adjust counters, pointers, etc. */
7341         op += nbytes;
7342         count -= nbytes;
7343         written += nbytes;
7344         thyper.LowPart = nbytes;
7345         thyper.HighPart = 0;
7346         offset = LargeIntegerAdd(thyper, offset);
7347     } /* while 1 */
7348
7349   done:
7350     lock_ReleaseWrite(&scp->rw);
7351
7352     if (bufferp) {
7353         lock_ReleaseMutex(&bufferp->mx);
7354         buf_Release(bufferp);
7355     }
7356
7357     lock_ObtainMutex(&fidp->mx);
7358     if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
7359          && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) 
7360     {
7361         lock_ReleaseMutex(&fidp->mx);
7362         smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
7363                           fidp->NTopen_dscp, fidp->NTopen_pathp,
7364                           NULL, TRUE);
7365     } else {
7366         lock_ReleaseMutex(&fidp->mx);
7367     }
7368
7369     if (code == 0) {
7370         if (smb_AsyncStore > 0) {
7371             if (doWriteBack) {
7372                 long code2;
7373
7374                 lock_ObtainWrite(&scp->rw);
7375                 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
7376                           fidp->fid);
7377                 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
7378                 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
7379                           fidp->fid, code2);
7380                 lock_ReleaseWrite(&scp->rw);
7381                 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
7382                                     writeBackOffset.HighPart, 
7383                                     smb_AsyncStoreSize, 0, userp);
7384                 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
7385             }
7386         } else {
7387             cm_BufWrite(scp, offsetp, *writtenp, 0, userp, &req);
7388         }
7389     }
7390
7391     cm_ReleaseSCache(scp);
7392
7393   done2:
7394     osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
7395               fidp->fid, code, *writtenp);
7396     return code;
7397 }
7398
7399 /* SMB_COM_WRITE */
7400 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7401 {
7402     unsigned short fd;
7403     unsigned short count;
7404     osi_hyper_t offset;
7405     unsigned short hint;
7406     long written = 0, total_written = 0;
7407     unsigned pid;
7408     smb_fid_t *fidp;
7409     smb_t* smbp = (smb_t*) inp;
7410     long code = 0;
7411     cm_user_t *userp;
7412         cm_scache_t *scp;
7413     cm_attr_t truncAttr;        /* attribute struct used for truncating file */
7414     char *op;
7415     int inDataBlockCount;
7416
7417     fd = smb_GetSMBParm(inp, 0);
7418     count = smb_GetSMBParm(inp, 1);
7419     offset.HighPart = 0;        /* too bad */
7420     offset.LowPart = smb_GetSMBParmLong(inp, 2);
7421     hint = smb_GetSMBParm(inp, 4);
7422
7423     op = smb_GetSMBData(inp, NULL);
7424     op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
7425
7426     osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
7427              fd, offset.LowPart, count);
7428         
7429     fd = smb_ChainFID(fd, inp);
7430     fidp = smb_FindFID(vcp, fd, 0);
7431     if (!fidp) {
7432         osi_Log2(smb_logp, "smb_ReceiveCoreWrite Unknown SMB Fid vcp 0x%p fid %d",
7433                  vcp, fd);
7434         return CM_ERROR_BADFD;
7435     }
7436         
7437     lock_ObtainMutex(&fidp->mx);
7438     if (fidp->flags & SMB_FID_IOCTL) {
7439         lock_ReleaseMutex(&fidp->mx);
7440         code = smb_IoctlWrite(fidp, vcp, inp, outp);
7441         smb_ReleaseFID(fidp);
7442         osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
7443         return code;
7444     }
7445
7446     if (fidp->flags & SMB_FID_RPC) {
7447         lock_ReleaseMutex(&fidp->mx);
7448         code = smb_RPCWrite(fidp, vcp, inp, outp);
7449         smb_ReleaseFID(fidp);
7450         osi_Log1(smb_logp, "smb_ReceiveCoreWrite RPC code 0x%x", code);
7451         return code;
7452     }
7453
7454     if (!fidp->scp) {
7455         lock_ReleaseMutex(&fidp->mx);
7456         smb_ReleaseFID(fidp);
7457         return CM_ERROR_BADFD;
7458     }
7459
7460     if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7461         lock_ReleaseMutex(&fidp->mx);
7462         smb_CloseFID(vcp, fidp, NULL, 0);
7463         smb_ReleaseFID(fidp);
7464         return CM_ERROR_NOSUCHFILE;
7465     }
7466
7467     scp = fidp->scp;
7468     cm_HoldSCache(scp);
7469     lock_ReleaseMutex(&fidp->mx);
7470     userp = smb_GetUserFromVCP(vcp, inp);
7471
7472     {
7473         cm_key_t key;
7474         LARGE_INTEGER LOffset;
7475         LARGE_INTEGER LLength;
7476
7477         pid = smbp->pid;
7478         key = cm_GenerateKey(vcp->vcID, pid, fd);
7479
7480         LOffset.HighPart = offset.HighPart;
7481         LOffset.LowPart = offset.LowPart;
7482         LLength.HighPart = 0;
7483         LLength.LowPart = count;
7484
7485         lock_ObtainWrite(&scp->rw);
7486         code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7487         lock_ReleaseWrite(&scp->rw);
7488
7489         if (code) {
7490             osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
7491             goto done;
7492         }
7493     }
7494
7495     /* special case: 0 bytes transferred means truncate to this position */
7496     if (count == 0) {
7497         cm_req_t req;
7498
7499         osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
7500         
7501         smb_InitReq(&req);
7502
7503         truncAttr.mask = CM_ATTRMASK_LENGTH;
7504         truncAttr.length.LowPart = offset.LowPart;
7505         truncAttr.length.HighPart = 0;
7506         lock_ObtainMutex(&fidp->mx);
7507         code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
7508         fidp->flags |= SMB_FID_LENGTHSETDONE;
7509         lock_ReleaseMutex(&fidp->mx);
7510         smb_SetSMBParm(outp, 0, 0 /* count */);
7511         smb_SetSMBDataLength(outp, 0);
7512         goto done;
7513     }
7514
7515     /*
7516      * Work around bug in NT client
7517      *
7518      * When copying a file, the NT client should first copy the data,
7519      * then copy the last write time.  But sometimes the NT client does
7520      * these in the wrong order, so the data copies would inadvertently
7521      * cause the last write time to be overwritten.  We try to detect this,
7522      * and don't set client mod time if we think that would go against the
7523      * intention.
7524      */
7525     lock_ObtainMutex(&fidp->mx);
7526     if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
7527         fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7528         fidp->scp->clientModTime = time(NULL);
7529     }
7530     lock_ReleaseMutex(&fidp->mx);
7531
7532     code = 0;
7533     while ( code == 0 && count > 0 ) {
7534         code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7535         if (code == 0 && written == 0)
7536             code = CM_ERROR_PARTIALWRITE;
7537
7538         offset = LargeIntegerAdd(offset,
7539                                  ConvertLongToLargeInteger(written));
7540         count -= (unsigned short)written;
7541         total_written += written;
7542         written = 0;
7543     }
7544     
7545     osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
7546              total_written, code);
7547         
7548     /* set the packet data length to 3 bytes for the data block header,
7549      * plus the size of the data.
7550      */
7551     smb_SetSMBParm(outp, 0, total_written);
7552     smb_SetSMBParmLong(outp, 1, offset.LowPart);
7553     smb_SetSMBParm(outp, 3, hint);
7554     smb_SetSMBDataLength(outp, 0);
7555
7556   done:
7557     smb_ReleaseFID(fidp);
7558     cm_ReleaseUser(userp);
7559         cm_ReleaseSCache(scp);
7560
7561     return code;
7562 }
7563
7564 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7565                           NCB *ncbp, raw_write_cont_t *rwcp)
7566 {
7567     unsigned short fd;
7568     smb_fid_t *fidp;
7569     cm_user_t *userp;
7570     char *rawBuf;
7571     long written = 0;
7572     long code = 0;
7573
7574     fd = smb_GetSMBParm(inp, 0);
7575     fidp = smb_FindFID(vcp, fd, 0);
7576
7577     lock_ObtainMutex(&fidp->mx);
7578     if (!fidp->scp) {
7579         lock_ReleaseMutex(&fidp->mx);
7580         smb_ReleaseFID(fidp);
7581         return;
7582     }
7583
7584     if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7585         lock_ReleaseMutex(&fidp->mx);
7586         smb_CloseFID(vcp, fidp, NULL, 0);
7587         smb_ReleaseFID(fidp);
7588         return;
7589     }
7590     lock_ReleaseMutex(&fidp->mx);
7591         
7592     osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
7593              rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
7594
7595     userp = smb_GetUserFromVCP(vcp, inp);
7596
7597     rawBuf = rwcp->buf;
7598     code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
7599                                                  &written);
7600     if (rwcp->writeMode & 0x1) {        /* synchronous */
7601         smb_t *op;
7602
7603         smb_FormatResponsePacket(vcp, inp, outp);
7604         op = (smb_t *) outp;
7605         op->com = 0x20;         /* SMB_COM_WRITE_COMPLETE */
7606         smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
7607         smb_SetSMBDataLength(outp,  0);
7608         smb_SendPacket(vcp, outp);
7609         smb_FreePacket(outp);
7610     }
7611     else {                              /* asynchronous */
7612         lock_ObtainMutex(&fidp->mx);
7613         fidp->raw_writers--;
7614         if (fidp->raw_writers == 0)
7615             thrd_SetEvent(fidp->raw_write_event);
7616         lock_ReleaseMutex(&fidp->mx);
7617     }
7618
7619     /* Give back raw buffer */
7620     lock_ObtainMutex(&smb_RawBufLock);
7621     *((char **)rawBuf) = smb_RawBufs;
7622     smb_RawBufs = rawBuf;
7623     lock_ReleaseMutex(&smb_RawBufLock);
7624
7625     smb_ReleaseFID(fidp);
7626     cm_ReleaseUser(userp);
7627 }
7628
7629 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7630 {
7631     return 0;
7632 }
7633
7634 /* SMB_COM_WRITE_RAW */
7635 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
7636 {
7637     osi_hyper_t offset;
7638     long count, written = 0, total_written = 0;
7639     long totalCount;
7640     unsigned short fd;
7641     smb_fid_t *fidp;
7642     smb_t *smbp = (smb_t*) inp;
7643     long code = 0;
7644     cm_user_t *userp;
7645         cm_scache_t *scp;
7646     char *op;
7647     unsigned short writeMode;
7648     char *rawBuf;
7649     fd = smb_GetSMBParm(inp, 0);
7650     totalCount = smb_GetSMBParm(inp, 1);
7651     count = smb_GetSMBParm(inp, 10);
7652     writeMode = smb_GetSMBParm(inp, 7);
7653
7654     op = (char *) inp->data;
7655     op += smb_GetSMBParm(inp, 11);
7656
7657     offset.HighPart = 0;
7658     offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
7659
7660     if (*inp->wctp == 14) {
7661         /* we received a 64-bit file offset */
7662 #ifdef AFS_LARGEFILES
7663         offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
7664
7665         if (LargeIntegerLessThanZero(offset)) {
7666             osi_Log2(smb_logp,
7667                      "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
7668                      offset.HighPart, offset.LowPart);
7669             return CM_ERROR_BADSMB;
7670         }
7671 #else
7672         if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
7673             osi_Log0(smb_logp,
7674                      "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files");
7675             return CM_ERROR_BADSMB;
7676         }
7677
7678         offset.HighPart = 0;
7679 #endif
7680     } else {
7681         offset.HighPart = 0;    /* 32-bit file offset */
7682     }
7683     
7684     osi_Log4(smb_logp,
7685              "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
7686              fd, offset.HighPart, offset.LowPart, count);
7687     osi_Log1(smb_logp,
7688              "               WriteRaw WriteMode 0x%x",
7689              writeMode);
7690         
7691     fd = smb_ChainFID(fd, inp);
7692     fidp = smb_FindFID(vcp, fd, 0);
7693     if (!fidp) {
7694         osi_Log2(smb_logp, "smb_ReceiveCoreWriteRaw Unknown SMB Fid vcp 0x%p fid %d",
7695                  vcp, fd);
7696         return CM_ERROR_BADFD;
7697     }
7698     lock_ObtainMutex(&fidp->mx);
7699     if (!fidp->scp) {
7700         lock_ReleaseMutex(&fidp->mx);
7701         smb_ReleaseFID(fidp);
7702         return CM_ERROR_BADFD;
7703     }
7704
7705     if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7706         lock_ReleaseMutex(&fidp->mx);
7707         smb_CloseFID(vcp, fidp, NULL, 0);
7708         smb_ReleaseFID(fidp);
7709         return CM_ERROR_NOSUCHFILE;
7710     }
7711
7712     scp = fidp->scp;
7713     cm_HoldSCache(scp);
7714     lock_ReleaseMutex(&fidp->mx);
7715
7716     {
7717         unsigned pid;
7718         cm_key_t key;
7719         LARGE_INTEGER LOffset;
7720         LARGE_INTEGER LLength;
7721
7722         pid = smbp->pid;
7723         key = cm_GenerateKey(vcp->vcID, pid, fd);
7724
7725         LOffset.HighPart = offset.HighPart;
7726         LOffset.LowPart = offset.LowPart;
7727         LLength.HighPart = 0;
7728         LLength.LowPart = count;
7729
7730         lock_ObtainWrite(&scp->rw);
7731         code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7732         lock_ReleaseWrite(&scp->rw);
7733
7734         if (code) {
7735             cm_ReleaseSCache(scp);
7736             smb_ReleaseFID(fidp);
7737             return code;
7738         }
7739     }
7740         
7741     userp = smb_GetUserFromVCP(vcp, inp);
7742
7743     /*
7744      * Work around bug in NT client
7745      *
7746      * When copying a file, the NT client should first copy the data,
7747      * then copy the last write time.  But sometimes the NT client does
7748      * these in the wrong order, so the data copies would inadvertently
7749      * cause the last write time to be overwritten.  We try to detect this,
7750      * and don't set client mod time if we think that would go against the
7751      * intention.
7752      */
7753     lock_ObtainMutex(&fidp->mx);
7754     if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
7755         fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7756         fidp->scp->clientModTime = time(NULL);
7757     }
7758     lock_ReleaseMutex(&fidp->mx);
7759
7760     code = 0;
7761     while ( code == 0 && count > 0 ) {
7762         code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7763         if (code == 0 && written == 0)
7764             code = CM_ERROR_PARTIALWRITE;
7765
7766         offset = LargeIntegerAdd(offset,
7767                                  ConvertLongToLargeInteger(written));
7768
7769         count -= written;
7770         total_written += written;
7771         written = 0;
7772     }
7773
7774     /* Get a raw buffer */
7775     if (code == 0) {
7776         rawBuf = NULL;
7777         lock_ObtainMutex(&smb_RawBufLock);
7778         if (smb_RawBufs) {
7779             /* Get a raw buf, from head of list */
7780             rawBuf = smb_RawBufs;
7781             smb_RawBufs = *(char **)smb_RawBufs;
7782         }
7783         else
7784             code = CM_ERROR_USESTD;
7785                 
7786         lock_ReleaseMutex(&smb_RawBufLock);
7787     }
7788
7789     /* Don't allow a premature Close */
7790     if (code == 0 && (writeMode & 1) == 0) {
7791         lock_ObtainMutex(&fidp->mx);
7792         fidp->raw_writers++;
7793         thrd_ResetEvent(fidp->raw_write_event);
7794         lock_ReleaseMutex(&fidp->mx);
7795     }
7796
7797     smb_ReleaseFID(fidp);
7798     cm_ReleaseUser(userp);
7799     cm_ReleaseSCache(scp);
7800
7801     if (code) {
7802         smb_SetSMBParm(outp, 0, total_written);
7803         smb_SetSMBDataLength(outp, 0);
7804         ((smb_t *)outp)->com = 0x20;    /* SMB_COM_WRITE_COMPLETE */
7805         rwcp->code = code;
7806         return code;
7807     }
7808
7809     offset = LargeIntegerAdd(offset,
7810                              ConvertLongToLargeInteger(count));
7811
7812     rwcp->code = 0;
7813     rwcp->buf = rawBuf;
7814     rwcp->offset.HighPart = offset.HighPart;
7815     rwcp->offset.LowPart = offset.LowPart;
7816     rwcp->count = totalCount - count;
7817     rwcp->writeMode = writeMode;
7818     rwcp->alreadyWritten = total_written;
7819
7820     /* set the packet data length to 3 bytes for the data block header,
7821      * plus the size of the data.
7822      */
7823     smb_SetSMBParm(outp, 0, 0xffff);
7824     smb_SetSMBDataLength(outp, 0);
7825
7826     return 0;
7827 }
7828
7829 /* SMB_COM_READ */
7830 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7831 {
7832     osi_hyper_t offset;
7833     long count, finalCount;
7834     unsigned short fd;
7835     unsigned pid;
7836     smb_fid_t *fidp;
7837     smb_t *smbp = (smb_t*) inp;
7838     long code = 0;
7839     cm_user_t *userp;
7840     cm_scache_t *scp;
7841     char *op;
7842         
7843     fd = smb_GetSMBParm(inp, 0);
7844     count = smb_GetSMBParm(inp, 1);
7845     offset.HighPart = 0;        /* too bad */
7846     offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7847         
7848     osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
7849              fd, offset.LowPart, count);
7850         
7851     fd = smb_ChainFID(fd, inp);
7852     fidp = smb_FindFID(vcp, fd, 0);
7853     if (!fidp) {
7854         osi_Log2(smb_logp, "smb_ReceiveCoreRead Unknown SMB Fid vcp 0x%p fid %d",
7855                  vcp, fd);
7856         return CM_ERROR_BADFD;
7857     }
7858     lock_ObtainMutex(&fidp->mx);
7859     if (fidp->flags & SMB_FID_IOCTL) {
7860         lock_ReleaseMutex(&fidp->mx);
7861         code = smb_IoctlRead(fidp, vcp, inp, outp);
7862         smb_ReleaseFID(fidp);
7863         return code;
7864     }
7865
7866     if (fidp->flags & SMB_FID_RPC) {
7867         lock_ReleaseMutex(&fidp->mx);
7868         code = smb_RPCRead(fidp, vcp, inp, outp);
7869         smb_ReleaseFID(fidp);
7870         return code;
7871     }
7872
7873     if (!fidp->scp) {
7874         lock_ReleaseMutex(&fidp->mx);
7875         smb_ReleaseFID(fidp);
7876         return CM_ERROR_BADFD;
7877     }
7878
7879     if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7880         lock_ReleaseMutex(&fidp->mx);
7881         smb_CloseFID(vcp, fidp, NULL, 0);
7882         smb_ReleaseFID(fidp);
7883         return CM_ERROR_NOSUCHFILE;
7884     }
7885
7886     scp = fidp->scp;
7887     cm_HoldSCache(scp);
7888     lock_ReleaseMutex(&fidp->mx);
7889
7890     {
7891         LARGE_INTEGER LOffset, LLength;
7892         cm_key_t key;
7893
7894         pid = smbp->pid;
7895         key = cm_GenerateKey(vcp->vcID, pid, fd);
7896
7897         LOffset.HighPart = 0;
7898         LOffset.LowPart = offset.LowPart;
7899         LLength.HighPart = 0;
7900         LLength.LowPart = count;
7901         
7902         lock_ObtainWrite(&scp->rw);
7903         code = cm_LockCheckRead(scp, LOffset, LLength, key);
7904         lock_ReleaseWrite(&scp->rw);
7905     }
7906     if (code) {
7907         cm_ReleaseSCache(scp);
7908         smb_ReleaseFID(fidp);
7909         return code;
7910     }
7911         
7912     userp = smb_GetUserFromVCP(vcp, inp);
7913
7914     /* remember this for final results */
7915     smb_SetSMBParm(outp, 0, count);
7916     smb_SetSMBParm(outp, 1, 0);
7917     smb_SetSMBParm(outp, 2, 0);
7918     smb_SetSMBParm(outp, 3, 0);
7919     smb_SetSMBParm(outp, 4, 0);
7920
7921     /* set the packet data length to 3 bytes for the data block header,
7922      * plus the size of the data.
7923      */
7924     smb_SetSMBDataLength(outp, count+3);
7925         
7926     /* get op ptr after putting in the parms, since otherwise we don't
7927      * know where the data really is.
7928      */
7929     op = smb_GetSMBData(outp, NULL);
7930
7931     /* now emit the data block header: 1 byte of type and 2 bytes of length */
7932     *op++ = 1;  /* data block marker */
7933     *op++ = (unsigned char) (count & 0xff);
7934     *op++ = (unsigned char) ((count >> 8) & 0xff);
7935                 
7936     code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
7937
7938     /* fix some things up */
7939     smb_SetSMBParm(outp, 0, finalCount);
7940     smb_SetSMBDataLength(outp, finalCount+3);
7941
7942     smb_ReleaseFID(fidp);
7943         
7944     cm_ReleaseUser(userp);
7945     cm_ReleaseSCache(scp);
7946     return code;
7947 }
7948
7949 /* SMB_COM_CREATE_DIRECTORY */
7950 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7951 {
7952     clientchar_t *pathp;
7953     long code = 0;
7954     cm_space_t *spacep;
7955     unsigned char *tp;
7956     cm_user_t *userp;
7957     cm_scache_t *dscp;                  /* dir we're dealing with */
7958     cm_scache_t *scp;                   /* file we're creating */
7959     cm_attr_t setAttr;
7960     int initialModeBits;
7961     clientchar_t *lastNamep;
7962     int caseFold;
7963     clientchar_t *tidPathp;
7964     cm_req_t req;
7965
7966     smb_InitReq(&req);
7967
7968     scp = NULL;
7969         
7970     /* compute initial mode bits based on read-only flag in attributes */
7971     initialModeBits = 0777;
7972         
7973     tp = smb_GetSMBData(inp, NULL);
7974     pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
7975     if (!pathp)
7976         return CM_ERROR_BADSMB;
7977
7978     spacep = inp->spacep;
7979     smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
7980
7981     if (cm_ClientStrCmp(pathp, _C("\\")) == 0)
7982         return CM_ERROR_EXISTS;
7983
7984     userp = smb_GetUserFromVCP(vcp, inp);
7985
7986     caseFold = CM_FLAG_CASEFOLD;
7987
7988     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7989     if (code) {
7990         cm_ReleaseUser(userp);
7991         return CM_ERROR_NOSUCHPATH;
7992     }
7993
7994     code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
7995                     caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
7996                     userp, tidPathp, &req, &dscp);
7997
7998     if (code) {
7999         cm_ReleaseUser(userp);
8000         return code;
8001     }
8002         
8003 #ifdef DFS_SUPPORT
8004     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8005         int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8006         cm_ReleaseSCache(dscp);
8007         cm_ReleaseUser(userp);
8008         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8009             return CM_ERROR_PATH_NOT_COVERED;
8010         else
8011             return CM_ERROR_NOSUCHPATH;
8012     }
8013 #endif /* DFS_SUPPORT */
8014
8015     /* otherwise, scp points to the parent directory.  Do a lookup, and
8016      * fail if we find it.  Otherwise, we do the create.
8017      */
8018     if (!lastNamep) 
8019         lastNamep = pathp;
8020     else 
8021         lastNamep++;
8022     code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
8023     if (scp) cm_ReleaseSCache(scp);
8024     if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8025         if (code == 0) code = CM_ERROR_EXISTS;
8026         cm_ReleaseSCache(dscp);
8027         cm_ReleaseUser(userp);
8028         return code;
8029     }
8030         
8031     setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8032     setAttr.clientModTime = time(NULL);
8033     code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
8034     if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
8035         smb_NotifyChange(FILE_ACTION_ADDED,
8036                          FILE_NOTIFY_CHANGE_DIR_NAME,
8037                          dscp, lastNamep, NULL, TRUE);
8038         
8039     /* we don't need this any longer */
8040     cm_ReleaseSCache(dscp);
8041
8042     if (code) {
8043         /* something went wrong creating or truncating the file */
8044         cm_ReleaseUser(userp);
8045         return code;
8046     }
8047         
8048     /* otherwise we succeeded */
8049     smb_SetSMBDataLength(outp, 0);
8050     cm_ReleaseUser(userp);
8051
8052     return 0;
8053 }
8054
8055 BOOL smb_IsLegalFilename(clientchar_t *filename)
8056 {
8057     /* 
8058      *  Find the longest substring of filename that does not contain
8059      *  any of the chars in illegalChars.  If that substring is less
8060      *  than the length of the whole string, then one or more of the
8061      *  illegal chars is in filename. 
8062      */
8063     if (cm_ClientStrCSpn(filename, illegalChars) < cm_ClientStrLen(filename))
8064         return FALSE;
8065
8066     return TRUE;
8067 }
8068
8069 /* SMB_COM_CREATE and SMB_COM_CREATE_NEW */
8070 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8071 {
8072     clientchar_t *pathp;
8073     long code = 0;
8074     cm_space_t *spacep;
8075     unsigned char *tp;
8076     int excl;
8077     cm_user_t *userp;
8078     cm_scache_t *dscp;                  /* dir we're dealing with */
8079     cm_scache_t *scp;                   /* file we're creating */
8080     cm_attr_t setAttr;
8081     int initialModeBits;
8082     smb_fid_t *fidp;
8083     int attributes;
8084     clientchar_t *lastNamep;
8085     int caseFold;
8086     afs_uint32 dosTime;
8087     clientchar_t *tidPathp;
8088     cm_req_t req;
8089     int created = 0;                    /* the file was new */
8090
8091     smb_InitReq(&req);
8092
8093     scp = NULL;
8094     excl = (inp->inCom == 0x03)? 0 : 1;
8095         
8096     attributes = smb_GetSMBParm(inp, 0);
8097     dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
8098         
8099     /* compute initial mode bits based on read-only flag in attributes */
8100     initialModeBits = 0666;
8101     if (attributes & SMB_ATTR_READONLY) 
8102         initialModeBits &= ~0222;
8103         
8104     tp = smb_GetSMBData(inp, NULL);
8105     pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
8106     if (!pathp)
8107         return CM_ERROR_BADSMB;
8108
8109     spacep = inp->spacep;
8110     /* smb_StripLastComponent will strip "::$DATA" if present */
8111     smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
8112
8113     if (!cm_IsValidClientString(pathp)) {
8114 #ifdef DEBUG
8115         clientchar_t * hexp;
8116
8117         hexp = cm_GetRawCharsAlloc(pathp, -1);
8118         osi_Log1(smb_logp, "CoreCreate rejecting invalid name. [%S]",
8119                  osi_LogSaveClientString(smb_logp, hexp));
8120         if (hexp)
8121             free(hexp);
8122 #else
8123         osi_Log0(smb_logp, "CoreCreate rejecting invalid name");
8124 #endif
8125         return CM_ERROR_BADNTFILENAME;
8126     }
8127
8128     userp = smb_GetUserFromVCP(vcp, inp);
8129
8130     caseFold = CM_FLAG_CASEFOLD;
8131
8132     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8133     if (code) {
8134         cm_ReleaseUser(userp);
8135         return CM_ERROR_NOSUCHPATH;
8136     }
8137     code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
8138                     userp, tidPathp, &req, &dscp);
8139
8140     if (code) {
8141         cm_ReleaseUser(userp);
8142         return code;
8143     }
8144         
8145 #ifdef DFS_SUPPORT
8146     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8147         int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8148         cm_ReleaseSCache(dscp);
8149         cm_ReleaseUser(userp);
8150         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8151             return CM_ERROR_PATH_NOT_COVERED;
8152         else
8153             return CM_ERROR_NOSUCHPATH;
8154     }
8155 #endif /* DFS_SUPPORT */
8156
8157     /* otherwise, scp points to the parent directory.  Do a lookup, and
8158      * truncate the file if we find it, otherwise we create the file.
8159      */
8160     if (!lastNamep) 
8161         lastNamep = pathp;
8162     else 
8163         lastNamep++;
8164
8165     if (!smb_IsLegalFilename(lastNamep))
8166         return CM_ERROR_BADNTFILENAME;
8167
8168     osi_Log1(smb_logp, "SMB receive create [%S]", osi_LogSaveClientString( smb_logp, pathp ));
8169 #ifdef DEBUG_VERBOSE
8170     {
8171         char *hexp;
8172         hexp = osi_HexifyString( lastNamep );
8173         DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
8174         free(hexp);
8175     }
8176 #endif    
8177
8178     code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
8179     if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8180         cm_ReleaseSCache(dscp);
8181         cm_ReleaseUser(userp);
8182         return code;
8183     }
8184         
8185     /* if we get here, if code is 0, the file exists and is represented by
8186      * scp.  Otherwise, we have to create it.
8187      */
8188     if (code == 0) {
8189         if (excl) {
8190             /* oops, file shouldn't be there */
8191             cm_ReleaseSCache(dscp);
8192             cm_ReleaseSCache(scp);
8193             cm_ReleaseUser(userp);
8194             return CM_ERROR_EXISTS;
8195         }
8196
8197         setAttr.mask = CM_ATTRMASK_LENGTH;
8198         setAttr.length.LowPart = 0;
8199         setAttr.length.HighPart = 0;
8200         code = cm_SetAttr(scp, &setAttr, userp, &req);
8201     }
8202     else {
8203         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8204         smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
8205         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
8206                          &req);
8207         if (code == 0) {
8208             created = 1;
8209             if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
8210                 smb_NotifyChange(FILE_ACTION_ADDED,     
8211                                  FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
8212                                  dscp, lastNamep, NULL, TRUE);
8213         } else if (!excl && code == CM_ERROR_EXISTS) {
8214             /* not an exclusive create, and someone else tried
8215              * creating it already, then we open it anyway.  We
8216              * don't bother retrying after this, since if this next
8217              * fails, that means that the file was deleted after
8218              * we started this call.
8219              */
8220             code = cm_Lookup(dscp, lastNamep, caseFold, userp,
8221                              &req, &scp);
8222             if (code == 0) {
8223                 setAttr.mask = CM_ATTRMASK_LENGTH;
8224                 setAttr.length.LowPart = 0;
8225                 setAttr.length.HighPart = 0;
8226                 code = cm_SetAttr(scp, &setAttr, userp, &req);
8227             }
8228         }
8229     }
8230         
8231     /* we don't need this any longer */
8232     cm_ReleaseSCache(dscp);
8233
8234     if (code) {
8235         /* something went wrong creating or truncating the file */
8236         if (scp) cm_ReleaseSCache(scp);
8237         cm_ReleaseUser(userp);
8238         return code;
8239     }
8240
8241     /* make sure we only open files */
8242     if (scp->fileType != CM_SCACHETYPE_FILE) {
8243         cm_ReleaseSCache(scp);
8244         cm_ReleaseUser(userp);
8245         return CM_ERROR_ISDIR;
8246     }
8247
8248     /* now all we have to do is open the file itself */
8249     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8250     osi_assertx(fidp, "null smb_fid_t");
8251         
8252     cm_HoldUser(userp);
8253
8254     lock_ObtainMutex(&fidp->mx);
8255     /* always create it open for read/write */
8256     fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
8257
8258     /* remember that the file was newly created */
8259     if (created)
8260         fidp->flags |= SMB_FID_CREATED;
8261
8262     osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
8263
8264     /* save a pointer to the vnode */
8265     fidp->scp = scp;
8266     lock_ObtainWrite(&scp->rw);
8267     scp->flags |= CM_SCACHEFLAG_SMB_FID;
8268     lock_ReleaseWrite(&scp->rw);
8269     
8270     /* and the user */
8271     fidp->userp = userp;
8272     lock_ReleaseMutex(&fidp->mx);
8273
8274     smb_SetSMBParm(outp, 0, fidp->fid);
8275     smb_SetSMBDataLength(outp, 0);
8276
8277     cm_Open(scp, 0, userp);
8278
8279     smb_ReleaseFID(fidp);
8280     cm_ReleaseUser(userp);
8281     /* leave scp held since we put it in fidp->scp */
8282     return 0;
8283 }
8284
8285 /* SMB_COM_SEEK */
8286 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8287 {
8288     long code = 0;
8289     osi_hyper_t new_offset;
8290     long offset;
8291     int whence;
8292     unsigned short fd;
8293     smb_fid_t *fidp;
8294     cm_scache_t *scp;
8295     cm_user_t *userp;
8296     cm_req_t req;
8297
8298     smb_InitReq(&req);
8299         
8300     fd = smb_GetSMBParm(inp, 0);
8301     whence = smb_GetSMBParm(inp, 1);
8302     offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
8303         
8304     /* try to find the file descriptor */
8305     fd = smb_ChainFID(fd, inp);
8306     fidp = smb_FindFID(vcp, fd, 0);
8307     if (!fidp) {
8308         osi_Log2(smb_logp, "smb_ReceiveCoreSeek Unknown SMB Fid vcp 0x%p fid %d",
8309                  vcp, fd);
8310         return CM_ERROR_BADFD;
8311     }
8312     lock_ObtainMutex(&fidp->mx);
8313     if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
8314         lock_ReleaseMutex(&fidp->mx);
8315         smb_ReleaseFID(fidp);
8316         return CM_ERROR_BADFD;
8317     }
8318
8319     if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
8320         lock_ReleaseMutex(&fidp->mx);
8321         smb_CloseFID(vcp, fidp, NULL, 0);
8322         smb_ReleaseFID(fidp);
8323         return CM_ERROR_NOSUCHFILE;
8324     }
8325
8326     lock_ReleaseMutex(&fidp->mx);
8327
8328     userp = smb_GetUserFromVCP(vcp, inp);
8329
8330     lock_ObtainMutex(&fidp->mx);
8331     scp = fidp->scp;
8332     cm_HoldSCache(scp);
8333     lock_ReleaseMutex(&fidp->mx);
8334     lock_ObtainWrite(&scp->rw);
8335     code = cm_SyncOp(scp, NULL, userp, &req, 0,
8336                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8337     if (code == 0) {
8338         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8339         if (whence == 1) {
8340             /* offset from current offset */
8341             new_offset = LargeIntegerAdd(fidp->offset,
8342                                          ConvertLongToLargeInteger(offset));
8343         }
8344         else if (whence == 2) {
8345             /* offset from current EOF */
8346             new_offset = LargeIntegerAdd(scp->length,
8347                                          ConvertLongToLargeInteger(offset));
8348         } else {
8349             new_offset = ConvertLongToLargeInteger(offset);
8350         }
8351
8352         fidp->offset = new_offset;
8353         smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
8354         smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
8355         smb_SetSMBDataLength(outp, 0);
8356     }
8357     lock_ReleaseWrite(&scp->rw);
8358     smb_ReleaseFID(fidp);
8359     cm_ReleaseSCache(scp);
8360     cm_ReleaseUser(userp);
8361     return code;
8362 }
8363
8364 /* dispatch all of the requests received in a packet.  Due to chaining, this may
8365  * be more than one request.
8366  */
8367 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
8368                         NCB *ncbp, raw_write_cont_t *rwcp)
8369 {
8370     smb_dispatch_t *dp;
8371     smb_t *smbp;
8372     unsigned long code = 0;
8373     unsigned char *outWctp;
8374     int nparms;                 /* # of bytes of parameters */
8375     char tbuffer[200];
8376     int nbytes;                 /* bytes of data, excluding count */
8377     int temp;
8378     unsigned char *tp;
8379     unsigned short errCode;
8380     unsigned long NTStatus;
8381     int noSend;
8382     unsigned char errClass;
8383     unsigned int oldGen;
8384     DWORD oldTime, newTime;
8385
8386     /* get easy pointer to the data */
8387     smbp = (smb_t *) inp->data;
8388
8389     if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
8390         /* setup the basic parms for the initial request in the packet */
8391         inp->inCom = smbp->com;
8392         inp->wctp = &smbp->wct;
8393         inp->inCount = 0;
8394         inp->ncb_length = ncbp->ncb_length;
8395     }
8396     noSend = 0;
8397
8398     /* Sanity check */
8399     if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
8400         /* log it and discard it */
8401         LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT, 
8402                  __FILE__, __LINE__, ncbp->ncb_length);
8403         osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
8404         return;
8405     }
8406
8407     /* We are an ongoing op */
8408     thrd_Increment(&ongoingOps);
8409
8410     /* set up response packet for receiving output */
8411     if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
8412         smb_FormatResponsePacket(vcp, inp, outp);
8413     outWctp = outp->wctp;
8414
8415     /* Remember session generation number and time */
8416     oldGen = sessionGen;
8417     oldTime = GetTickCount();
8418
8419     while (inp->inCom != 0xff) {
8420         dp = &smb_dispatchTable[inp->inCom];
8421
8422         if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
8423             outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
8424             code = outp->resumeCode;
8425             goto resume;
8426         }
8427
8428         /* process each request in the packet; inCom, wctp and inCount
8429          * are already set up.
8430          */
8431         osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
8432                   ncbp->ncb_lsn);
8433
8434         /* now do the dispatch */
8435         /* start by formatting the response record a little, as a default */
8436         if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
8437             outWctp[0] = 2;
8438             outWctp[1] = 0xff;  /* no operation */
8439             outWctp[2] = 0;             /* padding */
8440             outWctp[3] = 0;
8441             outWctp[4] = 0;
8442         }
8443         else {
8444             /* not a chained request, this is a more reasonable default */
8445             outWctp[0] = 0;     /* wct of zero */
8446             outWctp[1] = 0;     /* and bcc (word) of zero */
8447             outWctp[2] = 0;
8448         }   
8449
8450         /* once set, stays set.  Doesn't matter, since we never chain
8451          * "no response" calls.
8452          */
8453         if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
8454             noSend = 1;
8455
8456         if (dp->procp) {
8457             /* we have a recognized operation */
8458             char * opName = myCrt_Dispatch(inp->inCom);
8459             smb_t *smbp;
8460
8461             smbp = (smb_t *) inp;
8462
8463             osi_Log5(smb_logp,"Dispatch %s mid 0x%x vcp 0x%p lana %d lsn %d",
8464                       opName, smbp->mid, vcp, vcp->lana, vcp->lsn);
8465             if (inp->inCom == 0x1d) {
8466                 /* Raw Write */
8467                 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
8468             } else {
8469                 code = (*(dp->procp)) (vcp, inp, outp);
8470             }   
8471             osi_Log5(smb_logp,"Dispatch return code 0x%x mid 0x%x vcp 0x%p lana %d lsn %d",
8472                       code, smbp->mid, vcp, vcp->lana, vcp->lsn);
8473
8474             newTime = GetTickCount();
8475             osi_Log3(smb_logp, "Dispatch %s mid 0x%x duration %d ms", 
8476                      opName, smbp->mid, newTime - oldTime);
8477
8478 #ifdef LOG_PACKET
8479             if ( code == CM_ERROR_BADSMB ||
8480                  code == CM_ERROR_BADOP )
8481                 smb_LogPacket(inp);
8482 #endif /* LOG_PACKET */
8483
8484             /* ReceiveV3Tran2A handles its own logging */
8485             if (inp->inCom != 0x32 && newTime - oldTime > 45000) {
8486                 smb_user_t *uidp;
8487                 smb_fid_t *fidp;
8488                 clientchar_t *treepath = NULL;  /* do not free */
8489                 clientchar_t *pathname = NULL;
8490                 cm_fid_t afid = {0,0,0,0,0};
8491
8492                 uidp = smb_FindUID(vcp, smbp->uid, 0);
8493                 smb_LookupTIDPath(vcp, smbp->tid, &treepath);
8494                 fidp = smb_FindFID(vcp, inp->fid, 0);
8495
8496                 if (fidp) {
8497                     lock_ObtainMutex(&fidp->mx);
8498                     if (fidp->NTopen_pathp)
8499                         pathname = fidp->NTopen_pathp;
8500                     if (fidp->scp)
8501                         afid = fidp->scp->fid;
8502                 } else {
8503                     if (inp->stringsp->wdata)
8504                         pathname = inp->stringsp->wdata;
8505                 }
8506
8507                 afsi_log("Request %s duration %d ms user 0x%x \"%S\" pid 0x%x mid 0x%x tid 0x%x \"%S\" path? \"%S\" afid (%d.%d.%d.%d)", 
8508                           opName, newTime - oldTime, 
8509                           smbp->uid, uidp ? uidp->unp->name : NULL,
8510                           smbp->pid, smbp->mid, smbp->tid,
8511                           treepath,
8512                           pathname, 
8513                           afid.cell, afid.volume, afid.vnode, afid.unique);
8514
8515                 if (fidp)
8516                     lock_ReleaseMutex(&fidp->mx);
8517
8518                 if (uidp)
8519                     smb_ReleaseUID(uidp);
8520                 if (fidp)
8521                     smb_ReleaseFID(fidp);
8522             }
8523
8524             if (oldGen != sessionGen) {
8525                 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION, 
8526                          newTime - oldTime, ncbp->ncb_length);
8527                 osi_Log3(smb_logp, "Request %s straddled session startup, "
8528                           "took %d ms, ncb length %d", opName, newTime - oldTime, ncbp->ncb_length);
8529             }
8530
8531             FreeSMBStrings(inp);
8532         } else {
8533             /* bad opcode, fail the request, after displaying it */
8534             osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
8535 #ifdef LOG_PACKET
8536             smb_LogPacket(inp);
8537 #endif  /* LOG_PACKET */
8538
8539             if (showErrors) {
8540                 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
8541                 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
8542                                       MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
8543                 if (code == IDCANCEL) 
8544                     showErrors = 0;
8545             }
8546             code = CM_ERROR_BADOP;
8547         }
8548
8549         /* catastrophic failure:  log as much as possible */
8550         if (code == CM_ERROR_BADSMB) {
8551             LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID, 
8552                      ncbp->ncb_length);
8553 #ifdef LOG_PACKET
8554             smb_LogPacket(inp);
8555 #endif /* LOG_PACKET */
8556             osi_Log1(smb_logp, "Invalid SMB message, length %d",
8557                      ncbp->ncb_length);
8558
8559             code = CM_ERROR_INVAL;
8560         }
8561
8562         if (outp->flags & SMB_PACKETFLAG_NOSEND) {
8563             thrd_Decrement(&ongoingOps);
8564             return;
8565         }
8566
8567       resume:
8568         /* now, if we failed, turn the current response into an empty
8569          * one, and fill in the response packet's error code.
8570          */
8571         if (code) {
8572             if (vcp->flags & SMB_VCFLAG_STATUS32) {
8573                 smb_MapNTError(code, &NTStatus);
8574                 outWctp = outp->wctp;
8575                 smbp = (smb_t *) &outp->data;
8576                 if (code != CM_ERROR_PARTIALWRITE
8577                      && code != CM_ERROR_BUFFERTOOSMALL 
8578                      && code != CM_ERROR_GSSCONTINUE) {
8579                     /* nuke wct and bcc.  For a partial
8580                      * write or an in-process authentication handshake, 
8581                      * assume they're OK.
8582                      */
8583                     *outWctp++ = 0;
8584                     *outWctp++ = 0;
8585                     *outWctp++ = 0;
8586                 }
8587                 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8588                 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8589                 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8590                 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8591                 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8592                 break;
8593             }
8594             else {
8595                 smb_MapCoreError(code, vcp, &errCode, &errClass);
8596                 outWctp = outp->wctp;
8597                 smbp = (smb_t *) &outp->data;
8598                 if (code != CM_ERROR_PARTIALWRITE) {
8599                     /* nuke wct and bcc.  For a partial
8600                      * write, assume they're OK.
8601                      */
8602                     *outWctp++ = 0;
8603                     *outWctp++ = 0;
8604                     *outWctp++ = 0;
8605                 }
8606                 smbp->errLow = (unsigned char) (errCode & 0xff);
8607                 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8608                 smbp->rcls = errClass;
8609                 break;
8610             }
8611         }       /* error occurred */
8612
8613         /* if we're here, we've finished one request.  Look to see if
8614          * this is a chained opcode.  If it is, setup things to process
8615          * the chained request, and setup the output buffer to hold the
8616          * chained response.  Start by finding the next input record.
8617          */
8618         if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
8619             break;              /* not a chained req */
8620         tp = inp->wctp;         /* points to start of last request */
8621         /* in a chained request, the first two
8622          * parm fields are required, and are
8623          * AndXCommand/AndXReserved and
8624          * AndXOffset. */
8625         if (tp[0] < 2) break;   
8626         if (tp[1] == 0xff) break;       /* no more chained opcodes */
8627         inp->inCom = tp[1];
8628         inp->wctp = inp->data + tp[3] + (tp[4] << 8);
8629         inp->inCount++;
8630
8631         /* and now append the next output request to the end of this
8632          * last request.  Begin by finding out where the last response
8633          * ends, since that's where we'll put our new response.
8634          */
8635         outWctp = outp->wctp;           /* ptr to out parameters */
8636         osi_assert (outWctp[0] >= 2);   /* need this for all chained requests */
8637         nparms = outWctp[0] << 1;
8638         tp = outWctp + nparms + 1;      /* now points to bcc field */
8639         nbytes = tp[0] + (tp[1] << 8);  /* # of data bytes */
8640         tp += 2 /* for the count itself */ + nbytes;
8641         /* tp now points to the new output record; go back and patch the
8642          * second parameter (off2) to point to the new record.
8643          */
8644         temp = (unsigned int)(tp - outp->data);
8645         outWctp[3] = (unsigned char) (temp & 0xff);
8646         outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
8647         outWctp[2] = 0; /* padding */
8648         outWctp[1] = inp->inCom;        /* next opcode */
8649
8650         /* finally, setup for the next iteration */
8651         outp->wctp = tp;
8652         outWctp = tp;
8653     }   /* while loop over all requests in the packet */
8654
8655     /* now send the output packet, and return */
8656     if (!noSend)
8657         smb_SendPacket(vcp, outp);
8658     thrd_Decrement(&ongoingOps);
8659
8660     return;
8661 }
8662
8663 /* Wait for Netbios() calls to return, and make the results available to server
8664  * threads.  Note that server threads can't wait on the NCBevents array
8665  * themselves, because NCB events are manual-reset, and the servers would race
8666  * each other to reset them.
8667  */
8668 void smb_ClientWaiter(void *parmp)
8669 {
8670     DWORD code;
8671     int   idx;
8672
8673     while (smbShutdownFlag == 0) {
8674         code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
8675                                                  FALSE, INFINITE);
8676         if (code == WAIT_OBJECT_0)
8677             continue;
8678
8679         /* error checking */
8680         if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8681         {
8682             int abandonIdx = code - WAIT_ABANDONED_0;
8683             osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8684         }
8685
8686         if (code == WAIT_IO_COMPLETION)
8687         {
8688             osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
8689             continue;
8690         }
8691         
8692         if (code == WAIT_TIMEOUT)
8693         {
8694             osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
8695         }
8696
8697         if (code == WAIT_FAILED)
8698         {
8699             osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
8700         }
8701
8702         idx = code - WAIT_OBJECT_0;
8703  
8704         /* check idx range! */
8705         if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
8706         {
8707             /* this is fatal - log as much as possible */
8708             osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
8709             osi_assertx(0, "invalid index");
8710         }
8711         
8712         thrd_ResetEvent(NCBevents[idx]);
8713         thrd_SetEvent(NCBreturns[0][idx]);
8714     }
8715 }
8716
8717 /*
8718  * Try to have one NCBRECV request waiting for every live session.  Not more
8719  * than one, because if there is more than one, it's hard to handle Write Raw.
8720  */
8721 void smb_ServerWaiter(void *parmp)
8722 {
8723     DWORD code;
8724     int idx_session, idx_NCB;
8725     NCB *ncbp;
8726
8727     while (smbShutdownFlag == 0) {
8728         /* Get a session */
8729         code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
8730                                                  FALSE, INFINITE);
8731         if (code == WAIT_OBJECT_0)
8732             continue;
8733
8734         if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
8735         {
8736             int abandonIdx = code - WAIT_ABANDONED_0;
8737             osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8738         }
8739         
8740         if (code == WAIT_IO_COMPLETION)
8741         {
8742             osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
8743             continue;
8744         }
8745         
8746         if (code == WAIT_TIMEOUT)
8747         {
8748             osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
8749         }
8750         
8751         if (code == WAIT_FAILED)
8752         {
8753             osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
8754         }
8755         
8756         idx_session = code - WAIT_OBJECT_0;
8757
8758         /* check idx range! */
8759         if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
8760         {
8761             /* this is fatal - log as much as possible */
8762             osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
8763             osi_assertx(0, "invalid index");
8764         }
8765
8766                 /* Get an NCB */
8767       NCBretry:
8768         code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
8769                                                  FALSE, INFINITE);
8770         if (code == WAIT_OBJECT_0) {
8771             if (smbShutdownFlag == 1) 
8772                 break;
8773             else
8774                 goto NCBretry;
8775         }
8776
8777         /* error checking */
8778         if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8779         {
8780             int abandonIdx = code - WAIT_ABANDONED_0;
8781             osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8782         }
8783         
8784         if (code == WAIT_IO_COMPLETION)
8785         {
8786             osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
8787             continue;
8788         }
8789         
8790         if (code == WAIT_TIMEOUT)
8791         {
8792             osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
8793         }
8794         
8795         if (code == WAIT_FAILED)
8796         {
8797             osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
8798         }
8799                 
8800         idx_NCB = code - WAIT_OBJECT_0;
8801
8802         /* check idx range! */
8803         if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
8804         {
8805             /* this is fatal - log as much as possible */
8806             osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
8807             osi_assertx(0, "invalid index");
8808         }
8809
8810         /* Link them together */
8811         NCBsessions[idx_NCB] = idx_session;
8812
8813         /* Fire it up */
8814         ncbp = NCBs[idx_NCB];
8815         ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
8816         ncbp->ncb_command = NCBRECV | ASYNCH;
8817         ncbp->ncb_lana_num = lanas[idx_session];
8818         ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
8819         ncbp->ncb_event = NCBevents[idx_NCB];
8820         ncbp->ncb_length = SMB_PACKETSIZE;
8821         Netbios(ncbp);
8822     }
8823 }
8824
8825 /*
8826  * The top level loop for handling SMB request messages.  Each server thread
8827  * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
8828  * NCB and buffer for the incoming request are loaned to us.
8829  *
8830  * Write Raw trickery starts here.  When we get a Write Raw, we are supposed
8831  * to immediately send a request for the rest of the data.  This must come
8832  * before any other traffic for that session, so we delay setting the session
8833  * event until that data has come in.
8834  */
8835 void smb_Server(VOID *parmp)
8836 {
8837     INT_PTR myIdx = (INT_PTR) parmp;
8838     NCB *ncbp;
8839     NCB *outncbp;
8840     smb_packet_t *bufp;
8841     smb_packet_t *outbufp;
8842     DWORD code, rcode;
8843     int idx_NCB, idx_session;
8844     UCHAR rc;
8845     smb_vc_t *vcp = NULL;
8846     smb_t *smbp;
8847     extern void rx_StartClientThread(void);
8848
8849     rx_StartClientThread();
8850
8851     outncbp = smb_GetNCB();
8852     outbufp = smb_GetPacket();
8853     outbufp->ncbp = outncbp;
8854
8855     while (1) {
8856         if (vcp) {
8857             smb_ReleaseVC(vcp);
8858             vcp = NULL;
8859         }
8860
8861         cm_ResetServerPriority();
8862
8863         code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
8864                                                  FALSE, INFINITE);
8865
8866         /* terminate silently if shutdown flag is set */
8867         if (code == WAIT_OBJECT_0) {
8868             if (smbShutdownFlag == 1) {
8869                 thrd_SetEvent(smb_ServerShutdown[myIdx]);
8870                 break;
8871             } else
8872                 continue;
8873         }
8874
8875         /* error checking */
8876         if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8877         {
8878             int abandonIdx = code - WAIT_ABANDONED_0;
8879             osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
8880         }
8881         
8882         if (code == WAIT_IO_COMPLETION)
8883         {
8884             osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
8885             continue;
8886         }
8887         
8888         if (code == WAIT_TIMEOUT)
8889         {
8890             osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
8891         }
8892         
8893         if (code == WAIT_FAILED)
8894         {
8895             osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
8896         }
8897
8898         idx_NCB = code - WAIT_OBJECT_0;
8899         
8900         /* check idx range! */
8901         if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
8902         {
8903             /* this is fatal - log as much as possible */
8904             osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
8905             osi_assertx(0, "invalid index");
8906         }
8907
8908         ncbp = NCBs[idx_NCB];
8909         idx_session = NCBsessions[idx_NCB];
8910         rc = ncbp->ncb_retcode;
8911
8912         if (rc != NRC_PENDING && rc != NRC_GOODRET)
8913             osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
8914
8915         switch (rc) {
8916         case NRC_GOODRET: 
8917             vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8918             break;
8919
8920         case NRC_PENDING:
8921             /* Can this happen? Or is it just my UNIX paranoia? */
8922             osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
8923             continue;
8924
8925         case NRC_SNUMOUT:
8926         case NRC_SABORT:
8927             LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
8928             /* fallthrough */
8929         case NRC_SCLOSED:
8930             /* Client closed session */
8931             vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8932             if (vcp) {
8933                 lock_ObtainMutex(&vcp->mx);
8934                 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8935                     osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8936                              vcp, vcp->usersp);
8937                     vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8938                     lock_ReleaseMutex(&vcp->mx);
8939                     lock_ObtainWrite(&smb_globalLock);
8940                     dead_sessions[vcp->session] = TRUE;
8941                     lock_ReleaseWrite(&smb_globalLock);
8942                 } else {
8943                     lock_ReleaseMutex(&vcp->mx);
8944                 }
8945                 smb_CleanupDeadVC(vcp);
8946                 smb_ReleaseVC(vcp);
8947                 vcp = NULL;
8948             }
8949             goto doneWithNCB;
8950
8951         case NRC_INCOMP:
8952             /* Treat as transient error */
8953             LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE, 
8954                      ncbp->ncb_length);
8955             osi_Log1(smb_logp,
8956                      "dispatch smb recv failed, message incomplete, ncb_length %d",
8957                      ncbp->ncb_length);
8958             osi_Log1(smb_logp,
8959                      "SMB message incomplete, "
8960                      "length %d", ncbp->ncb_length);
8961
8962             /*
8963              * We used to discard the packet.
8964              * Instead, try handling it normally.
8965              *
8966              continue;
8967              */
8968             vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8969             break;
8970
8971         default:
8972             /* A weird error code.  Log it, sleep, and continue. */
8973             vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8974             if (vcp) {
8975                 lock_ObtainMutex(&vcp->mx);
8976                 if (vcp->errorCount++ > 3) {
8977                     osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
8978                     if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8979                         osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8980                                  vcp, vcp->usersp);
8981                         vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8982                         lock_ReleaseMutex(&vcp->mx);
8983                         lock_ObtainWrite(&smb_globalLock);
8984                         dead_sessions[vcp->session] = TRUE;
8985                         lock_ReleaseWrite(&smb_globalLock);
8986                     } else {
8987                         lock_ReleaseMutex(&vcp->mx);
8988                     }
8989                     smb_CleanupDeadVC(vcp);
8990                     smb_ReleaseVC(vcp);
8991                     vcp = NULL;
8992                     goto doneWithNCB;
8993                 }
8994                 else {
8995                     lock_ReleaseMutex(&vcp->mx);
8996                     smb_ReleaseVC(vcp);
8997                     vcp = NULL;
8998                     Sleep(10);
8999                     thrd_SetEvent(SessionEvents[idx_session]);
9000                 }
9001             }
9002             continue;
9003         }
9004
9005         /* Success, so now dispatch on all the data in the packet */
9006
9007         smb_concurrentCalls++;
9008         if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
9009             smb_maxObsConcurrentCalls = smb_concurrentCalls;
9010
9011         /*
9012          * If at this point vcp is NULL (implies that packet was invalid)
9013          * then we are in big trouble. This means either :
9014          *   a) we have the wrong NCB.
9015          *   b) Netbios screwed up the call.
9016          *   c) The VC was already marked dead before we were able to
9017          *      process the call
9018          * Obviously this implies that 
9019          *   ( LSNs[idx_session] != ncbp->ncb_lsn ||
9020          *   lanas[idx_session] != ncbp->ncb_lana_num )
9021          * Either way, we can't do anything with this packet.
9022          * Log, sleep and resume.
9023          */
9024         if (!vcp) {
9025             LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
9026                      LSNs[idx_session],
9027                      lanas[idx_session],
9028                      ncbp->ncb_lsn,
9029                      ncbp->ncb_lana_num);
9030
9031             /* Also log in the trace log. */
9032             osi_Log4(smb_logp, "Server: VCP does not exist!"
9033                       "LSNs[idx_session]=[%d],"
9034                       "lanas[idx_session]=[%d],"
9035                       "ncbp->ncb_lsn=[%d],"
9036                       "ncbp->ncb_lana_num=[%d]",
9037                       LSNs[idx_session],
9038                       lanas[idx_session],
9039                       ncbp->ncb_lsn,
9040                       ncbp->ncb_lana_num);
9041
9042             /* thrd_Sleep(1000); Don't bother sleeping */
9043             thrd_SetEvent(SessionEvents[idx_session]);
9044             smb_concurrentCalls--;
9045             continue;
9046         }
9047
9048         cm_SetRequestStartTime();
9049
9050         vcp->errorCount = 0;
9051         bufp = (struct smb_packet *) ncbp->ncb_buffer;
9052         smbp = (smb_t *)bufp->data;
9053         outbufp->flags = 0;
9054
9055 #ifndef NOTRACE
9056         __try
9057         {
9058 #endif
9059             if (smbp->com == 0x1d) {
9060                 /* Special handling for Write Raw */
9061                 raw_write_cont_t rwc;
9062             
9063                 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
9064                 if (rwc.code == 0) {
9065                     EVENT_HANDLE rwevent;
9066                     char eventName[MAX_PATH];
9067
9068                     snprintf(eventName, MAX_PATH, "smb_Server() rwevent %d", myIdx);
9069                     rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9070                     if ( GetLastError() == ERROR_ALREADY_EXISTS )
9071                         osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9072
9073                     ncbp->ncb_command = NCBRECV | ASYNCH;
9074                     ncbp->ncb_lsn = (unsigned char) vcp->lsn;
9075                     ncbp->ncb_lana_num = vcp->lana;
9076                     ncbp->ncb_buffer = rwc.buf;
9077                     ncbp->ncb_length = 65535;
9078                     ncbp->ncb_event = rwevent;
9079                     Netbios(ncbp);
9080                     rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
9081                     thrd_CloseHandle(rwevent);
9082                 }
9083                 thrd_SetEvent(SessionEvents[idx_session]);
9084                 if (rwc.code == 0)
9085                     smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
9086             } 
9087             else if (smbp->com == 0xa0) {
9088                 /* 
9089                  * Serialize the handling for NT Transact 
9090                  * (defect 11626)
9091                  */
9092                 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
9093                 thrd_SetEvent(SessionEvents[idx_session]);
9094             } else {
9095                 thrd_SetEvent(SessionEvents[idx_session]);
9096                 /* TODO: what else needs to be serialized? */
9097                 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
9098             }
9099 #ifndef NOTRACE        
9100         }
9101         __except( smb_ServerExceptionFilter() ) {
9102         }
9103 #endif
9104
9105         smb_concurrentCalls--;
9106
9107       doneWithNCB:
9108         thrd_SetEvent(NCBavails[idx_NCB]);
9109     }
9110     if (vcp)
9111         smb_ReleaseVC(vcp);
9112     if (outbufp)
9113         smb_FreePacket(outbufp);
9114     if (outncbp)
9115         smb_FreeNCB(outncbp);
9116 }
9117
9118 /*
9119  * Exception filter for the server threads.  If an exception occurs in the
9120  * dispatch routines, which is where exceptions are most common, then do a
9121  * force trace and give control to upstream exception handlers. Useful for
9122  * debugging.
9123  */
9124 DWORD smb_ServerExceptionFilter(void) {
9125     /* While this is not the best time to do a trace, if it succeeds, then
9126      * we have a trace (assuming tracing was enabled). Otherwise, this should
9127      * throw a second exception.
9128      */
9129     LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
9130     afsd_ForceTrace(TRUE);
9131     buf_ForceTrace(TRUE);
9132     return EXCEPTION_CONTINUE_SEARCH;
9133 }       
9134
9135 /*
9136  * Create a new NCB and associated events, packet buffer, and "space" buffer.
9137  * If the number of server threads is M, and the number of live sessions is
9138  * N, then the number of NCB's in use at any time either waiting for, or
9139  * holding, received messages is M + N, so that is how many NCB's get created.
9140  */
9141 void InitNCBslot(int idx)
9142 {
9143     struct smb_packet *bufp;
9144     EVENT_HANDLE retHandle;
9145     afs_uint32 i;
9146     char eventName[MAX_PATH];
9147
9148     osi_assertx( idx < (sizeof(NCBs) / sizeof(NCBs[0])), "invalid index" );
9149
9150     NCBs[idx] = smb_GetNCB();
9151     sprintf(eventName,"NCBavails[%d]", idx);
9152     NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9153     if ( GetLastError() == ERROR_ALREADY_EXISTS )
9154         osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9155     sprintf(eventName,"NCBevents[%d]", idx);
9156     NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
9157     if ( GetLastError() == ERROR_ALREADY_EXISTS )
9158         osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9159     sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
9160     retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9161     if ( GetLastError() == ERROR_ALREADY_EXISTS )
9162         osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9163     for (i=0; i<smb_NumServerThreads; i++)
9164         NCBreturns[i][idx] = retHandle;
9165     bufp = smb_GetPacket();
9166     bufp->spacep = cm_GetSpace();
9167     bufs[idx] = bufp;
9168 }
9169
9170 /* listen for new connections */
9171 void smb_Listener(void *parmp)
9172 {
9173     NCB *ncbp;
9174     long code = 0;
9175     long len;
9176     long i;
9177     afs_uint32  session, thread;
9178     smb_vc_t *vcp = NULL;
9179     int flags = 0;
9180     char rname[NCBNAMSZ+1];
9181     char cname[MAX_COMPUTERNAME_LENGTH+1];
9182     int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
9183     INT_PTR lana = (INT_PTR) parmp;
9184     char eventName[MAX_PATH];
9185     int bridgeCount = 0;
9186     int nowildCount = 0;
9187
9188     sprintf(eventName,"smb_Listener_lana_%d", (unsigned char)lana);
9189     ListenerShutdown[lana] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9190     if ( GetLastError() == ERROR_ALREADY_EXISTS )
9191         thrd_ResetEvent(ListenerShutdown[lana]);
9192
9193     ncbp = smb_GetNCB();
9194
9195     /* retrieve computer name */
9196     GetComputerName(cname, &cnamelen);
9197     _strupr(cname);
9198
9199     while (smb_ListenerState == SMB_LISTENER_STARTED) {
9200         memset(ncbp, 0, sizeof(NCB));
9201         flags = 0;
9202
9203         ncbp->ncb_command = NCBLISTEN;
9204         ncbp->ncb_rto = 0;      /* No receive timeout */
9205         ncbp->ncb_sto = 0;      /* No send timeout */
9206
9207         /* pad out with spaces instead of null termination */
9208         len = (long)strlen(smb_localNamep);
9209         strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9210         for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9211         
9212         strcpy(ncbp->ncb_callname, "*");
9213         for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
9214         
9215         ncbp->ncb_lana_num = (UCHAR)lana;
9216
9217         code = Netbios(ncbp);
9218
9219         if (code == NRC_NAMERR) {
9220           /* An smb shutdown or Vista resume must have taken place */
9221           osi_Log1(smb_logp,
9222                    "NCBLISTEN lana=%d failed with NRC_NAMERR.",
9223                    ncbp->ncb_lana_num);
9224           afsi_log("NCBLISTEN lana=%d failed with NRC_NAMERR.", ncbp->ncb_lana_num);
9225
9226             if (lock_TryMutex(&smb_StartedLock)) {
9227                 lana_list.lana[i] = LANA_INVALID;
9228                 lock_ReleaseMutex(&smb_StartedLock);
9229             }
9230             break;
9231         } else if (code ==  NRC_BRIDGE || code != 0) {
9232             int lanaRemaining = 0;
9233
9234             if (code == NRC_BRIDGE) {
9235                 if (++bridgeCount <= 5) {
9236                     afsi_log("NCBLISTEN lana=%d failed with NRC_BRIDGE, retrying ...", ncbp->ncb_lana_num);
9237                     continue;
9238                 }
9239             } else if (code == NRC_NOWILD) {
9240                 if (++nowildCount <= 5) {
9241                     afsi_log("NCBLISTEN lana=%d failed with NRC_NOWILD, retrying ...", ncbp->ncb_lana_num);
9242
9243                     if (bridgeCount > 0) {
9244                         memset(ncbp, 0, sizeof(*ncbp));
9245                         ncbp->ncb_command = NCBADDNAME;
9246                         ncbp->ncb_lana_num = (UCHAR)lana;
9247                         /* pad out with spaces instead of null termination */
9248                         len = (long)strlen(smb_localNamep);
9249                         strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9250                         for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9251                         code = Netbios(ncbp);
9252                     }
9253                     continue;
9254                 }
9255             }
9256
9257             while (!lock_TryMutex(&smb_StartedLock)) {
9258                 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9259                     goto exit_thread;
9260                 Sleep(50);
9261             }
9262  
9263             osi_Log2(smb_logp,
9264                       "NCBLISTEN lana=%d failed with %s.  Listener thread exiting.",
9265                       ncbp->ncb_lana_num, ncb_error_string(code));
9266             afsi_log("NCBLISTEN lana=%d failed with %s.  Listener thread exiting.",
9267                      ncbp->ncb_lana_num, ncb_error_string(code));
9268
9269             for (i = 0; i < lana_list.length; i++) {
9270                 if (lana_list.lana[i] == lana) {
9271                     smb_StopListener(ncbp, lana_list.lana[i], FALSE);
9272                     lana_list.lana[i] = LANA_INVALID;
9273                 }
9274                 if (lana_list.lana[i] != LANA_INVALID)
9275                     lanaRemaining++;
9276             }
9277
9278             if (lanaRemaining == 0) {
9279                 cm_VolStatus_Network_Stopped(cm_NetbiosName
9280 #ifdef _WIN64
9281                                              ,cm_NetbiosName
9282 #endif
9283                                               );
9284                 smb_ListenerState = SMB_LISTENER_STOPPED;
9285                 smb_LANadapter = LANA_INVALID;
9286                 lana_list.length = 0;
9287             }
9288             lock_ReleaseMutex(&smb_StartedLock);
9289             break;
9290         }
9291 #if 0
9292         else if (code != 0) {
9293             char tbuffer[AFSPATHMAX];
9294
9295             /* terminate silently if shutdown flag is set */
9296             while (!lock_TryMutex(&smb_StartedLock)) {
9297                 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9298                     goto exit_thread;
9299                 Sleep(50);
9300             }
9301
9302             osi_Log3(smb_logp, 
9303                      "NCBLISTEN lana=%d failed with code %d [%s]",
9304                      ncbp->ncb_lana_num, code, ncb_error_string(code));
9305             osi_Log0(smb_logp, 
9306                      "Client exiting due to network failure. Please restart client.\n");
9307
9308             sprintf(tbuffer, 
9309                      "Client exiting due to network failure.  Please restart client.\n"
9310                      "NCBLISTEN lana=%d failed with code %d [%s]",
9311                      ncbp->ncb_lana_num, code, ncb_error_string(code));
9312             if (showErrors)
9313                 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
9314                                       MB_OK|MB_SERVICE_NOTIFICATION);
9315             osi_panic(tbuffer, __FILE__, __LINE__);
9316
9317             lock_ReleaseMutex(&smb_StartedLock);
9318             break;
9319         }
9320 #endif /* 0 */
9321
9322         /* a successful packet received.  clear bridge error count */
9323         bridgeCount = 0;
9324         nowildCount = 0;
9325
9326         /* check for remote conns */
9327         /* first get remote name and insert null terminator */
9328         memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
9329         for (i=NCBNAMSZ; i>0; i--) {
9330             if (rname[i-1] != ' ' && rname[i-1] != 0) {
9331                 rname[i] = 0;
9332                 break;
9333             }
9334         }
9335
9336         /* compare with local name */
9337         if (!isGateway)
9338             if (strncmp(rname, cname, NCBNAMSZ) != 0)
9339                 flags |= SMB_VCFLAG_REMOTECONN;
9340
9341         /* lock */
9342         lock_ObtainMutex(&smb_ListenerLock);
9343
9344         osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
9345         osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
9346
9347         /* now ncbp->ncb_lsn is the connection ID */
9348         vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
9349         if (vcp->session == 0) {
9350             /* New generation */
9351             osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
9352             sessionGen++;
9353
9354             /* Log session startup */
9355 #ifdef NOTSERVICE
9356             fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9357                     ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9358 #endif /* NOTSERVICE */
9359             osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9360                      ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9361
9362             if (reportSessionStartups) {
9363                 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9364             }
9365             
9366             lock_ObtainMutex(&vcp->mx);
9367             cm_Utf8ToUtf16(rname, -1, vcp->rname, lengthof(vcp->rname));
9368             vcp->flags |= flags;
9369             lock_ReleaseMutex(&vcp->mx);
9370
9371             /* Allocate slot in session arrays */
9372             /* Re-use dead session if possible, otherwise add one more */
9373             /* But don't look at session[0], it is reserved */
9374             lock_ObtainWrite(&smb_globalLock);
9375             for (session = 1; session < numSessions; session++) {
9376                 if (dead_sessions[session]) {
9377                     osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
9378                     dead_sessions[session] = FALSE;
9379                     break;
9380                 }
9381             }
9382             lock_ReleaseWrite(&smb_globalLock);
9383         } else {
9384             /* We are re-using an existing VC because the lsn and lana 
9385              * were re-used */
9386             session = vcp->session;
9387
9388             osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
9389
9390             /* Log session startup */
9391 #ifdef NOTSERVICE
9392             fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9393                     ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9394 #endif /* NOTSERVICE */
9395             osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9396                      ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9397
9398             if (reportSessionStartups) {
9399                 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9400             }
9401         }
9402
9403         if (session >= SESSION_MAX - 1  || numNCBs >= NCB_MAX - 1) {
9404             unsigned long code = CM_ERROR_ALLBUSY;
9405             smb_packet_t * outp = smb_GetPacket();
9406             unsigned char *outWctp;
9407             smb_t *smbp;
9408             
9409             smb_FormatResponsePacket(vcp, NULL, outp);
9410             outp->ncbp = ncbp;
9411
9412             if (vcp->flags & SMB_VCFLAG_STATUS32) {
9413                 unsigned long NTStatus;
9414                 smb_MapNTError(code, &NTStatus);
9415                 outWctp = outp->wctp;
9416                 smbp = (smb_t *) &outp->data;
9417                 *outWctp++ = 0;
9418                 *outWctp++ = 0;
9419                 *outWctp++ = 0;
9420                 smbp->rcls = (unsigned char) (NTStatus & 0xff);
9421                 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
9422                 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
9423                 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
9424                 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9425             } else {
9426                 unsigned short errCode;
9427                 unsigned char errClass;
9428                 smb_MapCoreError(code, vcp, &errCode, &errClass);
9429                 outWctp = outp->wctp;
9430                 smbp = (smb_t *) &outp->data;
9431                 *outWctp++ = 0;
9432                 *outWctp++ = 0;
9433                 *outWctp++ = 0;
9434                 smbp->errLow = (unsigned char) (errCode & 0xff);
9435                 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
9436                 smbp->rcls = errClass;
9437             }
9438
9439             smb_SendPacket(vcp, outp);
9440             smb_FreePacket(outp);
9441
9442             lock_ObtainMutex(&vcp->mx);
9443             if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9444                 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9445                           vcp, vcp->usersp);
9446                 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9447                 lock_ReleaseMutex(&vcp->mx);
9448                 lock_ObtainWrite(&smb_globalLock);
9449                 dead_sessions[vcp->session] = TRUE;
9450                 lock_ReleaseWrite(&smb_globalLock);
9451                 smb_CleanupDeadVC(vcp);
9452             } else {
9453                 lock_ReleaseMutex(&vcp->mx);
9454             }
9455         } else {
9456             /* assert that we do not exceed the maximum number of sessions or NCBs.
9457              * we should probably want to wait for a session to be freed in case
9458              * we run out.
9459              */
9460             osi_assertx(session < SESSION_MAX - 1, "invalid session");
9461             osi_assertx(numNCBs < NCB_MAX - 1, "invalid numNCBs");   /* if we pass this test we can allocate one more */
9462
9463             lock_ObtainMutex(&vcp->mx);
9464             vcp->session   = session;
9465             lock_ReleaseMutex(&vcp->mx);
9466             lock_ObtainWrite(&smb_globalLock);
9467             LSNs[session]  = ncbp->ncb_lsn;
9468             lanas[session] = ncbp->ncb_lana_num;
9469             lock_ReleaseWrite(&smb_globalLock);
9470                 
9471             if (session == numSessions) {
9472                 /* Add new NCB for new session */
9473                 char eventName[MAX_PATH];
9474
9475                 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
9476
9477                 InitNCBslot(numNCBs);
9478                 lock_ObtainWrite(&smb_globalLock);
9479                 numNCBs++;
9480                 lock_ReleaseWrite(&smb_globalLock);
9481                 thrd_SetEvent(NCBavails[0]);
9482                 thrd_SetEvent(NCBevents[0]);
9483                 for (thread = 0; thread < smb_NumServerThreads; thread++)
9484                     thrd_SetEvent(NCBreturns[thread][0]);
9485                 /* Also add new session event */
9486                 sprintf(eventName, "SessionEvents[%d]", session);
9487                 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9488                 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9489                     osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9490                 lock_ObtainWrite(&smb_globalLock);
9491                 numSessions++;
9492                 lock_ReleaseWrite(&smb_globalLock);
9493                 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
9494                 thrd_SetEvent(SessionEvents[0]);
9495             } else {
9496                 thrd_SetEvent(SessionEvents[session]);
9497             }
9498         }
9499         smb_ReleaseVC(vcp);
9500
9501         /* unlock */
9502         lock_ReleaseMutex(&smb_ListenerLock);
9503     }   /* dispatch while loop */
9504
9505 exit_thread:
9506     smb_FreeNCB(ncbp);
9507     thrd_SetEvent(ListenerShutdown[lana]);
9508     return;
9509 }
9510
9511 static void
9512 configureBackConnectionHostNames(void)
9513 {
9514     /* On Windows XP SP2, Windows 2003 SP1, and all future Windows operating systems
9515      * there is a restriction on the use of SMB authentication on loopback connections.
9516      * There are two work arounds available:
9517      * 
9518      *   (1) We can disable the check for matching host names.  This does not
9519      *   require a reboot:
9520      *   [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa]
9521      *     "DisableLoopbackCheck"=dword:00000001
9522      *
9523      *   (2) We can add the AFS SMB/CIFS service name to an approved list.  This
9524      *   does require a reboot:
9525      *   [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0]
9526      *     "BackConnectionHostNames"=multi-sz
9527      *
9528      * The algorithm will be:
9529      *   (1) Check to see if cm_NetbiosName exists in the BackConnectionHostNames list
9530      *   (2a) If not, add it to the list.  (This will not take effect until the next reboot.)
9531      *   (2b1)    and check to see if DisableLoopbackCheck is set.
9532      *   (2b2)    If not set, set the DisableLoopbackCheck value to 0x1 
9533      *   (2b3)                and create HKLM\SOFTWARE\OpenAFS\Client  UnsetDisableLoopbackCheck
9534      *   (2c) else If cm_NetbiosName exists in the BackConnectionHostNames list,
9535      *             check for the UnsetDisableLoopbackCheck value.  
9536      *             If set, set the DisableLoopbackCheck flag to 0x0 
9537      *             and delete the UnsetDisableLoopbackCheck value
9538      *
9539      * Starting in Longhorn Beta 1, an entry in the BackConnectionHostNames value will
9540      * force Windows to use the loopback authentication mechanism for the specified 
9541      * services.
9542      * 
9543      * Do not permit the "DisableLoopbackCheck" value to be removed within the same
9544      * service session that set it.  
9545      */
9546     HKEY hkLsa;
9547     HKEY hkMSV10;
9548     HKEY hkClient;
9549     DWORD dwType;
9550     DWORD dwSize, dwAllocSize;
9551     DWORD dwValue;
9552     PBYTE pHostNames = NULL, pName = NULL;
9553     BOOL  bNameFound = FALSE;   
9554     static BOOL bLoopbackCheckDisabled = FALSE;
9555
9556     /* BackConnectionHostNames and DisableLoopbackCheck */
9557     if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, 
9558                        "SYSTEM\\CurrentControlSet\\Control\\Lsa\\MSV1_0",
9559                        0,
9560                        KEY_READ|KEY_WRITE,
9561                        &hkMSV10) == ERROR_SUCCESS )
9562     {
9563         if ((RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0, 
9564                              &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
9565             (dwType == REG_MULTI_SZ)) 
9566         {
9567             dwAllocSize += 1 /* in case the source string is not nul terminated */
9568                 + (DWORD)strlen(cm_NetbiosName) + 2;
9569             pHostNames = malloc(dwAllocSize);
9570             dwSize = dwAllocSize;
9571             if (RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0, &dwType, 
9572                                  pHostNames, &dwSize) == ERROR_SUCCESS) 
9573             {
9574                 for (pName = pHostNames; 
9575                      (pName - pHostNames < (int) dwSize) && *pName ; 
9576                      pName += strlen(pName) + 1)
9577                 {
9578                     if ( !stricmp(pName, cm_NetbiosName) ) {
9579                         bNameFound = TRUE;
9580                         break;
9581                     }   
9582                 }
9583             }
9584         }
9585              
9586         if ( !bNameFound ) {
9587             size_t size = strlen(cm_NetbiosName) + 2;
9588             if ( !pHostNames ) {
9589                 pHostNames = malloc(size);
9590                 pName = pHostNames;
9591             }
9592             StringCbCopyA(pName, size, cm_NetbiosName);
9593             pName += size - 1;
9594             *pName = '\0';  /* add a second nul terminator */
9595
9596             dwType = REG_MULTI_SZ;
9597             dwSize = (DWORD)(pName - pHostNames + 1);
9598             RegSetValueEx( hkMSV10, "BackConnectionHostNames", 0, dwType, pHostNames, dwSize);
9599
9600             if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, 
9601                                "SYSTEM\\CurrentControlSet\\Control\\Lsa",
9602                                0,
9603                                KEY_READ|KEY_WRITE,
9604                                &hkLsa) == ERROR_SUCCESS )
9605             {
9606                 dwSize = sizeof(DWORD);
9607                 if ( RegQueryValueEx( hkLsa, "DisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) != ERROR_SUCCESS ||
9608                      dwValue == 0 ) {
9609                     dwType = REG_DWORD;
9610                     dwSize = sizeof(DWORD);
9611                     dwValue = 1;
9612                     RegSetValueEx( hkLsa, "DisableLoopbackCheck", 0, dwType, (LPBYTE)&dwValue, dwSize);
9613
9614                     if (RegCreateKeyEx( HKEY_LOCAL_MACHINE, 
9615                                         AFSREG_CLT_OPENAFS_SUBKEY,
9616                                         0,
9617                                         NULL,
9618                                         REG_OPTION_NON_VOLATILE,
9619                                         KEY_READ|KEY_WRITE,
9620                                         NULL,
9621                                         &hkClient,
9622                                         NULL) == ERROR_SUCCESS) {
9623
9624                         dwType = REG_DWORD;
9625                         dwSize = sizeof(DWORD);
9626                         dwValue = 1;
9627                         RegSetValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, dwType, (LPBYTE)&dwValue, dwSize);
9628                         bLoopbackCheckDisabled = TRUE;
9629                         RegCloseKey(hkClient);
9630                     }
9631                     RegCloseKey(hkLsa);
9632                 }
9633             }
9634         } else if (!bLoopbackCheckDisabled) {
9635             if (RegCreateKeyEx( HKEY_LOCAL_MACHINE, 
9636                                 AFSREG_CLT_OPENAFS_SUBKEY,
9637                                 0,
9638                                 NULL,
9639                                 REG_OPTION_NON_VOLATILE,
9640                                 KEY_READ|KEY_WRITE,
9641                                 NULL,
9642                                 &hkClient,
9643                                 NULL) == ERROR_SUCCESS) {
9644
9645                 dwSize = sizeof(DWORD);
9646                 if ( RegQueryValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) == ERROR_SUCCESS &&
9647                      dwValue == 1 ) {
9648                     if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, 
9649                                        "SYSTEM\\CurrentControlSet\\Control\\Lsa",
9650                                        0,
9651                                        KEY_READ|KEY_WRITE,
9652                                        &hkLsa) == ERROR_SUCCESS )
9653                     {
9654                         RegDeleteValue(hkLsa, "DisableLoopbackCheck");
9655                         RegCloseKey(hkLsa);
9656                     }
9657                 }
9658                 RegDeleteValue(hkClient, "RemoveDisableLoopbackCheck");
9659                 RegCloseKey(hkClient);
9660             }
9661         }
9662
9663         if (pHostNames) {
9664             free(pHostNames);
9665             pHostNames = NULL;
9666         }
9667
9668         RegCloseKey(hkMSV10);
9669     }
9670 }
9671
9672
9673 static void
9674 configureExtendedSMBSessionTimeouts(void)
9675 {
9676     /*
9677      * In a Hot Fix to Windows 2003 SP2, the smb redirector was given the following
9678      * new functionality:
9679      *
9680      *  [HKLM\SYSTEM\CurrentControlSet\Services\LanManWorkstation\Parameters]
9681      *   "ReconnectableServers"            REG_MULTI_SZ
9682      *   "ExtendedSessTimeout"             REG_DWORD  (seconds)
9683      *   "ServersWithExtendedSessTimeout"  REG_MULTI_SZ 
9684      *  
9685      * These values can be used to prevent the smb redirector from timing out
9686      * smb connection to the afs smb server prematurely.
9687      */
9688     HKEY hkLanMan;
9689     DWORD dwType;
9690     DWORD dwSize, dwAllocSize;
9691     DWORD dwValue;
9692     PBYTE pHostNames = NULL, pName = NULL;
9693     BOOL  bNameFound = FALSE;   
9694
9695     if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, 
9696                        "SYSTEM\\CurrentControlSet\\Services\\LanManWorkstation\\Parameters",
9697                        0,
9698                        KEY_READ|KEY_WRITE,
9699                        &hkLanMan) == ERROR_SUCCESS )
9700     {
9701         if ((RegQueryValueEx( hkLanMan, "ReconnectableServers", 0, 
9702                              &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
9703             (dwType == REG_MULTI_SZ)) 
9704         {
9705             dwAllocSize += 1 /* in case the source string is not nul terminated */
9706                 + (DWORD)strlen(cm_NetbiosName) + 2;
9707             pHostNames = malloc(dwAllocSize);
9708             dwSize = dwAllocSize;
9709             if (RegQueryValueEx( hkLanMan, "ReconnectableServers", 0, &dwType, 
9710                                  pHostNames, &dwSize) == ERROR_SUCCESS) 
9711             {
9712                 for (pName = pHostNames; 
9713                      (pName - pHostNames < (int) dwSize) && *pName ; 
9714                      pName += strlen(pName) + 1)
9715                 {
9716                     if ( !stricmp(pName, cm_NetbiosName) ) {
9717                         bNameFound = TRUE;
9718                         break;
9719                     }   
9720                 }
9721             }
9722         }
9723              
9724         if ( !bNameFound ) {
9725             size_t size = strlen(cm_NetbiosName) + 2;
9726             if ( !pHostNames ) {
9727                 pHostNames = malloc(size);
9728                 pName = pHostNames;
9729             }
9730             StringCbCopyA(pName, size, cm_NetbiosName);
9731             pName += size - 1;
9732             *pName = '\0';  /* add a second nul terminator */
9733
9734             dwType = REG_MULTI_SZ;
9735             dwSize = (DWORD)(pName - pHostNames + 1);
9736             RegSetValueEx( hkLanMan, "ReconnectableServers", 0, dwType, pHostNames, dwSize);
9737         }
9738
9739         if (pHostNames) {
9740             free(pHostNames);
9741             pHostNames = NULL;
9742         }
9743         
9744         if ((RegQueryValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0, 
9745                              &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
9746             (dwType == REG_MULTI_SZ)) 
9747         {
9748             dwAllocSize += 1 /* in case the source string is not nul terminated */
9749                 + (DWORD)strlen(cm_NetbiosName) + 2;
9750             pHostNames = malloc(dwAllocSize);
9751             dwSize = dwAllocSize;
9752             if (RegQueryValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0, &dwType, 
9753                                  pHostNames, &dwSize) == ERROR_SUCCESS) 
9754             {
9755                 for (pName = pHostNames; 
9756                      (pName - pHostNames < (int) dwSize) && *pName ; 
9757                      pName += strlen(pName) + 1)
9758                 {
9759                     if ( !stricmp(pName, cm_NetbiosName) ) {
9760                         bNameFound = TRUE;
9761                         break;
9762                     }   
9763                 }
9764             }
9765         }
9766              
9767         if ( !bNameFound ) {
9768             size_t size = strlen(cm_NetbiosName) + 2;
9769             if ( !pHostNames ) {
9770                 pHostNames = malloc(size);
9771                 pName = pHostNames;
9772             }
9773             StringCbCopyA(pName, size, cm_NetbiosName);
9774             pName += size - 1;
9775             *pName = '\0';  /* add a second nul terminator */
9776
9777             dwType = REG_MULTI_SZ;
9778             dwSize = (DWORD)(pName - pHostNames + 1);
9779             RegSetValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0, dwType, pHostNames, dwSize);
9780         }
9781
9782         if (pHostNames) {
9783             free(pHostNames);
9784             pHostNames = NULL;
9785         }
9786
9787         if ((RegQueryValueEx( hkLanMan, "ExtendedSessTimeout", 0, 
9788                               &dwType, (LPBYTE)&dwValue, &dwAllocSize) != ERROR_SUCCESS) ||
9789              (dwType != REG_DWORD)) 
9790         {
9791             dwType = REG_DWORD;
9792             dwSize = sizeof(dwValue);
9793             dwValue = 300;      /* 5 minutes */
9794             RegSetValueEx( hkLanMan, "ExtendedSessTimeout", 0, dwType, (const BYTE *)&dwValue, dwSize);
9795         }
9796         RegCloseKey(hkLanMan);
9797     }
9798 }
9799
9800 static void
9801 smb_LanAdapterChangeThread(void *param)
9802 {
9803     /* 
9804      * Give the IPAddrDaemon thread a chance
9805      * to block before we trigger.
9806      */
9807     Sleep(30000);
9808     smb_LanAdapterChange(0);
9809 }
9810
9811 void smb_SetLanAdapterChangeDetected(void)
9812 {
9813     int lpid;
9814     thread_t phandle;
9815
9816     lock_ObtainMutex(&smb_StartedLock);
9817
9818     if (!powerStateSuspended) {
9819         phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_LanAdapterChangeThread,
9820                               NULL, 0, &lpid, "smb_LanAdapterChange");
9821         osi_assertx(phandle != NULL, "smb_LanAdapterChangeThread thread creation failure");
9822         thrd_CloseHandle(phandle);
9823     }
9824
9825     smb_LanAdapterChangeDetected = 1;
9826     lock_ReleaseMutex(&smb_StartedLock);
9827 }
9828
9829 void smb_LanAdapterChange(int locked) {
9830     lana_number_t lanaNum;
9831     BOOL          bGateway;
9832     char          NetbiosName[MAX_NB_NAME_LENGTH] = "";
9833     int           change = 0;
9834     LANA_ENUM     temp_list;           
9835     long          code;
9836     int           i;
9837
9838
9839     afsi_log("smb_LanAdapterChange");
9840
9841     if (!locked)
9842         lock_ObtainMutex(&smb_StartedLock);
9843     
9844     smb_LanAdapterChangeDetected = 0;
9845
9846     if (!powerStateSuspended && 
9847         SUCCEEDED(lana_GetUncServerNameEx(NetbiosName, &lanaNum, &bGateway, 
9848                                           LANA_NETBIOS_NAME_FULL)) &&
9849         lanaNum != LANA_INVALID && smb_LANadapter != lanaNum) {
9850         if ( isGateway != bGateway ) {
9851             afsi_log("Lan Adapter Change detected (%d != %d): gateway %d != %d",
9852                       smb_LANadapter, lanaNum, isGateway, bGateway);
9853             change = 1;
9854         } else if (strcmp(cm_NetbiosName, NetbiosName) ) {
9855             afsi_log("Lan Adapter Change detected (%d != %d): name %s != %s",
9856                       smb_LANadapter, lanaNum, cm_NetbiosName, NetbiosName);
9857             change = 1;
9858         } else {
9859             NCB *ncbp = smb_GetNCB();
9860             ncbp->ncb_command = NCBENUM;
9861             ncbp->ncb_buffer = (PUCHAR)&temp_list;
9862             ncbp->ncb_length = sizeof(temp_list);
9863             code = Netbios(ncbp);
9864             if (code == 0) {
9865                 if (temp_list.length != lana_list.length) {
9866                     afsi_log("Lan Adapter Change detected (%d != %d): lan list length changed %d != %d",
9867                               smb_LANadapter, lanaNum, temp_list.length, lana_list.length);
9868                     change = 1;
9869                 } else {
9870                     for (i=0; i<lana_list.length; i++) {
9871                         if ( temp_list.lana[i] != lana_list.lana[i] ) {
9872                             afsi_log("Lan Adapter Change detected (%d != %d): lana[%d] %d != %d",
9873                                       smb_LANadapter, lanaNum, i, temp_list.lana[i], lana_list.lana[i]);
9874                             change = 1;
9875                             break;
9876                         }
9877                     }
9878                 }
9879             }
9880             smb_FreeNCB(ncbp);
9881         }
9882     } 
9883
9884     if (change) {
9885         smb_StopListeners(1);
9886         smb_RestartListeners(1);
9887     }
9888     if (!locked)
9889         lock_ReleaseMutex(&smb_StartedLock);
9890 }
9891
9892 /* initialize Netbios */
9893 int smb_NetbiosInit(int locked)
9894 {
9895     NCB *ncbp;
9896     int i, lana, code, l;
9897     char s[100];
9898     int delname_tried=0;
9899     int len;
9900     int lana_found = 0;
9901     lana_number_t lanaNum;
9902
9903     if (!locked)
9904         lock_ObtainMutex(&smb_StartedLock);
9905
9906     if (smb_ListenerState != SMB_LISTENER_UNINITIALIZED &&
9907          smb_ListenerState != SMB_LISTENER_STOPPED) {
9908
9909         if (!locked)
9910             lock_ReleaseMutex(&smb_StartedLock);
9911         return 0;
9912     }
9913     /* setup the NCB system */
9914     ncbp = smb_GetNCB();
9915
9916     /* Call lanahelper to get Netbios name, lan adapter number and gateway flag */
9917     if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
9918         smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
9919
9920         if (smb_LANadapter != LANA_INVALID)
9921             afsi_log("LAN adapter number %d", smb_LANadapter);
9922         else
9923             afsi_log("LAN adapter number not determined");
9924
9925         if (isGateway)
9926             afsi_log("Set for gateway service");
9927
9928         afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
9929     } else {
9930         /* something went horribly wrong.  We can't proceed without a netbios name */
9931         char buf[128];
9932         StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
9933         osi_panic(buf, __FILE__, __LINE__);
9934     }
9935
9936     /* remember the name */
9937     len = (int)strlen(cm_NetbiosName);
9938     if (smb_localNamep)
9939         free(smb_localNamep);
9940     smb_localNamep = malloc(len+1);
9941     strcpy(smb_localNamep, cm_NetbiosName);
9942     afsi_log("smb_localNamep is >%s<", smb_localNamep);
9943
9944     /* Also copy the value to the client character encoded string */
9945     cm_Utf8ToClientString(cm_NetbiosName, -1, cm_NetbiosNameC, MAX_NB_NAME_LENGTH);
9946
9947     if (smb_LANadapter == LANA_INVALID) {
9948         ncbp->ncb_command = NCBENUM;
9949         ncbp->ncb_buffer = (PUCHAR)&lana_list;
9950         ncbp->ncb_length = sizeof(lana_list);
9951         code = Netbios(ncbp);
9952         if (code != 0) {
9953             afsi_log("Netbios NCBENUM error code %d", code);
9954             osi_panic(s, __FILE__, __LINE__);
9955         }
9956     }
9957     else {
9958         lana_list.length = 1;
9959         lana_list.lana[0] = smb_LANadapter;
9960     }
9961           
9962     for (i = 0; i < lana_list.length; i++) {
9963         /* reset the adaptor: in Win32, this is required for every process, and
9964          * acts as an init call, not as a real hardware reset.
9965          */
9966         ncbp->ncb_command = NCBRESET;
9967         ncbp->ncb_callname[0] = 100;
9968         ncbp->ncb_callname[2] = 100;
9969         ncbp->ncb_lana_num = lana_list.lana[i];
9970         code = Netbios(ncbp);
9971         if (code == 0) 
9972             code = ncbp->ncb_retcode;
9973         if (code != 0) {
9974             afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
9975             lana_list.lana[i] = LANA_INVALID;  /* invalid lana */
9976         } else {
9977             afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
9978         }
9979     }
9980
9981     /* and declare our name so we can receive connections */
9982     memset(ncbp, 0, sizeof(*ncbp));
9983     len=lstrlen(smb_localNamep);
9984     memset(smb_sharename,' ',NCBNAMSZ);
9985     memcpy(smb_sharename,smb_localNamep,len);
9986     afsi_log("lana_list.length %d", lana_list.length);
9987
9988     /* Keep the name so we can unregister it later */
9989     for (l = 0; l < lana_list.length; l++) {
9990         lana = lana_list.lana[l];
9991
9992         ncbp->ncb_command = NCBADDNAME;
9993         ncbp->ncb_lana_num = lana;
9994         memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9995         code = Netbios(ncbp);
9996           
9997         afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
9998                  lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
9999         {
10000             char name[NCBNAMSZ+1];
10001             name[NCBNAMSZ]=0;
10002             memcpy(name,ncbp->ncb_name,NCBNAMSZ);
10003             afsi_log("Netbios NCBADDNAME added new name >%s<",name);
10004         }
10005
10006         if (code == 0) 
10007             code = ncbp->ncb_retcode;
10008
10009         if (code == 0) {
10010             afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
10011         }
10012         else {
10013             afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
10014             if (code == NRC_BRIDGE) {    /* invalid LANA num */
10015                 lana_list.lana[l] = LANA_INVALID;
10016                 continue;
10017             }
10018             else if (code == NRC_DUPNAME) {
10019                 afsi_log("Name already exists; try to delete it");
10020                 memset(ncbp, 0, sizeof(*ncbp));
10021                 ncbp->ncb_command = NCBDELNAME;
10022                 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10023                 ncbp->ncb_lana_num = lana;
10024                 code = Netbios(ncbp);
10025                 if (code == 0) 
10026                     code = ncbp->ncb_retcode;
10027                 else {
10028                     afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
10029                 }
10030                 if (code != 0 || delname_tried) {
10031                     lana_list.lana[l] = LANA_INVALID;
10032                 }
10033                 else if (code == 0) {
10034                     if (!delname_tried) {
10035                         lana--;
10036                         delname_tried = 1;
10037                         continue;
10038                     }
10039                 }
10040             }
10041             else {
10042                 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
10043                 lana_list.lana[l] = LANA_INVALID;  /* invalid lana */
10044             }
10045         }
10046         if (code == 0) {
10047             smb_LANadapter = lana;
10048             lana_found = 1;   /* at least one worked */
10049         }
10050     }
10051
10052     osi_assertx(lana_list.length >= 0, "empty lana list");
10053     if (!lana_found) {
10054         afsi_log("No valid LANA numbers found!");
10055         lana_list.length = 0;
10056         smb_LANadapter = LANA_INVALID;
10057         smb_ListenerState = SMB_LISTENER_STOPPED;
10058         cm_VolStatus_Network_Stopped(cm_NetbiosName
10059 #ifdef _WIN64
10060                                       ,cm_NetbiosName
10061 #endif
10062                                       );
10063     }
10064         
10065     /* we're done with the NCB now */
10066     smb_FreeNCB(ncbp);
10067
10068     afsi_log("smb_NetbiosInit smb_LANadapter=%d",smb_LANadapter);
10069     if (lana_list.length > 0)
10070         osi_assert(smb_LANadapter != LANA_INVALID);
10071
10072     if (!locked)
10073         lock_ReleaseMutex(&smb_StartedLock);
10074
10075     return (lana_list.length > 0 ? 1 : 0);
10076 }
10077
10078 void smb_StartListeners(int locked)
10079 {
10080     int i;
10081     int lpid;
10082     thread_t phandle;
10083
10084     if (!locked)
10085         lock_ObtainMutex(&smb_StartedLock);
10086
10087     if (smb_ListenerState == SMB_LISTENER_STARTED) {
10088         if (!locked)
10089             lock_ReleaseMutex(&smb_StartedLock);
10090         return;
10091     }
10092
10093     afsi_log("smb_StartListeners");
10094     /* Ensure the AFS Netbios Name is registered to allow loopback access */
10095     configureBackConnectionHostNames();
10096
10097     /* Configure Extended SMB Session Timeouts */
10098     if (msftSMBRedirectorSupportsExtendedTimeouts()) {
10099         afsi_log("Microsoft SMB Redirector supports Extended Timeouts");
10100         configureExtendedSMBSessionTimeouts();
10101     }
10102
10103     smb_ListenerState = SMB_LISTENER_STARTED;
10104     cm_VolStatus_Network_Started(cm_NetbiosName
10105 #ifdef _WIN64
10106                                   , cm_NetbiosName
10107 #endif
10108                                   );
10109
10110     for (i = 0; i < lana_list.length; i++) {
10111         if (lana_list.lana[i] == LANA_INVALID) 
10112             continue;
10113         phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
10114                                (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
10115         osi_assertx(phandle != NULL, "smb_Listener thread creation failure");
10116         thrd_CloseHandle(phandle);
10117     }
10118     if (!locked)
10119         lock_ReleaseMutex(&smb_StartedLock);
10120 }
10121
10122 void smb_RestartListeners(int locked)
10123 {
10124     if (!locked)
10125         lock_ObtainMutex(&smb_StartedLock);
10126
10127     if (powerStateSuspended)
10128         afsi_log("smb_RestartListeners called while suspended");
10129
10130     if (!powerStateSuspended && smb_ListenerState != SMB_LISTENER_UNINITIALIZED) {
10131         if (smb_ListenerState == SMB_LISTENER_STOPPED) {
10132             if (smb_NetbiosInit(1))
10133                 smb_StartListeners(1);
10134         } else if (smb_LanAdapterChangeDetected) {
10135             smb_LanAdapterChange(1);
10136         }
10137     }
10138     if (!locked)
10139         lock_ReleaseMutex(&smb_StartedLock);
10140 }
10141
10142 void smb_StopListener(NCB *ncbp, int lana, int wait)
10143 {
10144     long code;
10145
10146     memset(ncbp, 0, sizeof(*ncbp));
10147     ncbp->ncb_command = NCBDELNAME;
10148     ncbp->ncb_lana_num = lana;
10149     memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10150     code = Netbios(ncbp);
10151           
10152     afsi_log("StopListener: Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
10153               lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
10154
10155     /* and then reset the LANA; this will cause the listener threads to exit */
10156     ncbp->ncb_command = NCBRESET;
10157     ncbp->ncb_callname[0] = 100;
10158     ncbp->ncb_callname[2] = 100;
10159     ncbp->ncb_lana_num = lana;
10160     code = Netbios(ncbp);
10161     if (code == 0) 
10162         code = ncbp->ncb_retcode;
10163     if (code != 0) {
10164         afsi_log("StopListener: Netbios NCBRESET lana %d error code %d", lana, code);
10165     } else {
10166         afsi_log("StopListener: Netbios NCBRESET lana %d succeeded", lana);
10167     }
10168
10169     if (wait)
10170         thrd_WaitForSingleObject_Event(ListenerShutdown[lana], INFINITE);
10171 }
10172
10173 void smb_StopListeners(int locked)
10174 {
10175     NCB *ncbp;
10176     int lana, l;
10177
10178     if (!locked)
10179         lock_ObtainMutex(&smb_StartedLock);
10180
10181     if (smb_ListenerState == SMB_LISTENER_STOPPED) {
10182         if (!locked)
10183             lock_ReleaseMutex(&smb_StartedLock);
10184         return;
10185     }
10186
10187     afsi_log("smb_StopListeners");
10188     smb_ListenerState = SMB_LISTENER_STOPPED;
10189     cm_VolStatus_Network_Stopped(cm_NetbiosName
10190 #ifdef _WIN64
10191                                   , cm_NetbiosName
10192 #endif
10193                                   );
10194
10195     ncbp = smb_GetNCB();
10196
10197     /* Unregister the SMB name */
10198     for (l = 0; l < lana_list.length; l++) {
10199         lana = lana_list.lana[l];
10200
10201         if (lana != LANA_INVALID) {
10202             smb_StopListener(ncbp, lana, TRUE);
10203
10204             /* mark the adapter invalid */
10205             lana_list.lana[l] = LANA_INVALID;  /* invalid lana */
10206         }
10207     }
10208
10209     /* force a re-evaluation of the network adapters */
10210     lana_list.length = 0;
10211     smb_LANadapter = LANA_INVALID;
10212     smb_FreeNCB(ncbp);
10213     if (!locked)
10214         lock_ReleaseMutex(&smb_StartedLock);
10215 }
10216
10217 void smb_Init(osi_log_t *logp, int useV3,
10218               int nThreads
10219               , void *aMBfunc
10220   )
10221
10222 {
10223     thread_t phandle;
10224     int lpid;
10225     INT_PTR i;
10226     struct tm myTime;
10227     EVENT_HANDLE retHandle;
10228     char eventName[MAX_PATH];
10229     int startListeners = 0;
10230
10231     smb_MBfunc = aMBfunc;
10232
10233     smb_useV3 = useV3;
10234
10235     /* Initialize smb_localZero */
10236     myTime.tm_isdst = -1;               /* compute whether on DST or not */
10237     myTime.tm_year = 70;
10238     myTime.tm_mon = 0;
10239     myTime.tm_mday = 1;
10240     myTime.tm_hour = 0;
10241     myTime.tm_min = 0;
10242     myTime.tm_sec = 0;
10243     smb_localZero = mktime(&myTime);
10244
10245 #ifdef AFS_FREELANCE_CLIENT
10246     /* Make sure the root.afs volume has the correct time */
10247     cm_noteLocalMountPointChange();
10248 #endif
10249
10250     /* initialize the remote debugging log */
10251     smb_logp = logp;
10252         
10253     /* and the global lock */
10254     lock_InitializeRWLock(&smb_globalLock, "smb global lock", LOCK_HIERARCHY_SMB_GLOBAL);
10255     lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock", LOCK_HIERARCHY_SMB_RCT_GLOBAL);
10256
10257     /* Raw I/O data structures */
10258     lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock", LOCK_HIERARCHY_SMB_RAWBUF);
10259
10260     lock_InitializeMutex(&smb_ListenerLock, "smb listener lock", LOCK_HIERARCHY_SMB_LISTENER);
10261     lock_InitializeMutex(&smb_StartedLock, "smb started lock", LOCK_HIERARCHY_SMB_STARTED);
10262         
10263     /* 4 Raw I/O buffers */
10264     smb_RawBufs = calloc(65536,1);
10265     *((char **)smb_RawBufs) = NULL;
10266     for (i=0; i<3; i++) {
10267         char *rawBuf = calloc(65536,1);
10268         *((char **)rawBuf) = smb_RawBufs;
10269         smb_RawBufs = rawBuf;
10270     }
10271
10272     /* global free lists */
10273     smb_ncbFreeListp = NULL;
10274     smb_packetFreeListp = NULL;
10275
10276     lock_ObtainMutex(&smb_StartedLock);
10277     startListeners = smb_NetbiosInit(1);
10278
10279     /* Initialize listener and server structures */
10280     numVCs = 0;
10281     memset(dead_sessions, 0, sizeof(dead_sessions));
10282     sprintf(eventName, "SessionEvents[0]");
10283     SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10284     if ( GetLastError() == ERROR_ALREADY_EXISTS )
10285         afsi_log("Event Object Already Exists: %s", eventName);
10286     numSessions = 1;
10287     smb_NumServerThreads = nThreads;
10288     sprintf(eventName, "NCBavails[0]");
10289     NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10290     if ( GetLastError() == ERROR_ALREADY_EXISTS )
10291         afsi_log("Event Object Already Exists: %s", eventName);
10292     sprintf(eventName, "NCBevents[0]");
10293     NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10294     if ( GetLastError() == ERROR_ALREADY_EXISTS )
10295         afsi_log("Event Object Already Exists: %s", eventName);
10296     NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
10297     sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
10298     retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10299     if ( GetLastError() == ERROR_ALREADY_EXISTS )
10300         afsi_log("Event Object Already Exists: %s", eventName);
10301     for (i = 0; i < smb_NumServerThreads; i++) {
10302         NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
10303         NCBreturns[i][0] = retHandle;
10304     }
10305
10306     smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
10307     for (i = 0; i < smb_NumServerThreads; i++) {
10308         sprintf(eventName, "smb_ServerShutdown[%d]", i);
10309         smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10310         if ( GetLastError() == ERROR_ALREADY_EXISTS )
10311             afsi_log("Event Object Already Exists: %s", eventName);
10312         InitNCBslot((int)(i+1));
10313     }
10314     numNCBs = smb_NumServerThreads + 1;
10315
10316     /* Initialize dispatch table */
10317     memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
10318     /* Prepare the table for unknown operations */
10319     for(i=0; i<= SMB_NOPCODES; i++) {
10320         smb_dispatchTable[i].procp = smb_SendCoreBadOp;
10321     }
10322     /* Fill in the ones we do know */
10323     smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
10324     smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
10325     smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
10326     smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
10327     smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
10328     smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
10329     smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
10330     smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
10331     smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
10332     smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
10333     smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
10334     smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
10335     smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
10336     smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
10337     smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
10338     smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
10339     smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
10340     smb_dispatchTable[0x11].procp = smb_SendCoreBadOp;  /* process exit */
10341     smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
10342     smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
10343     /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
10344     smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10345     smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
10346     smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
10347     smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
10348     smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
10349     smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
10350     smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
10351     smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10352     smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
10353     smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10354     smb_dispatchTable[0x29].procp = smb_SendCoreBadOp;  /* copy file */
10355     smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
10356     /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
10357     smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10358     smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
10359     smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
10360     smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
10361     smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
10362     smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
10363     smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
10364     smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A;        /* both are same */
10365     smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10366     smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
10367     smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10368     smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
10369     smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
10370     smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
10371     smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
10372     smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
10373     smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
10374     smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
10375     smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
10376     smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
10377     smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
10378     smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
10379     smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
10380     smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
10381     smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
10382     smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
10383     smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
10384     smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
10385     smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
10386     smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
10387     smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
10388     smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10389     smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
10390     smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp;  /* Open Print File */
10391     smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp;  /* Write Print File */
10392     smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp;  /* Close Print File */
10393     smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp;  /* Get Print Queue */
10394     smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp;  /* Read Bulk */
10395     smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp;  /* Write Bulk */
10396     smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp;  /* Write Bulk Data */
10397
10398     /* setup tran 2 dispatch table */
10399     smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
10400     smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir;        /* FindFirst */
10401     smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir;        /* FindNext */
10402     smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
10403     smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
10404     smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
10405     smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
10406     smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
10407     smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
10408     smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
10409     smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
10410     smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
10411     smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
10412     smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
10413     smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
10414     smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
10415     smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
10416     smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
10417
10418     /* setup the rap dispatch table */
10419     memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
10420     smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
10421     smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
10422     smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
10423     smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
10424
10425     smb3_Init();
10426
10427     /* if we are doing SMB authentication we have register outselves as a logon process */
10428     if (smb_authType != SMB_AUTH_NONE) {
10429         NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
10430         LSA_STRING afsProcessName;
10431         LSA_OPERATIONAL_MODE dummy; /*junk*/
10432
10433         afsProcessName.Buffer = "OpenAFSClientDaemon";
10434         afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
10435         afsProcessName.MaximumLength = afsProcessName.Length + 1;
10436
10437         nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
10438
10439         if (nts == STATUS_SUCCESS) {
10440             LSA_STRING packageName;
10441             /* we are registered. Find out the security package id */
10442             packageName.Buffer = MSV1_0_PACKAGE_NAME;
10443             packageName.Length = (USHORT)strlen(packageName.Buffer);
10444             packageName.MaximumLength = packageName.Length + 1;
10445             nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
10446             if (nts == STATUS_SUCCESS) {
10447                 /* BEGIN 
10448                  * This code forces Windows to authenticate against the Logon Cache 
10449                  * first instead of attempting to authenticate against the Domain 
10450                  * Controller.  When the Windows logon cache is enabled this improves
10451                  * performance by removing the network access and works around a bug
10452                  * seen at sites which are using a MIT Kerberos principal to login
10453                  * to machines joined to a non-root domain in a multi-domain forest.
10454                  * MsV1_0SetProcessOption was added in Windows XP.
10455                  */
10456                 PVOID pResponse = NULL;
10457                 ULONG cbResponse = 0;
10458                 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
10459
10460                 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
10461                 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
10462                 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST; 
10463                 OptionsRequest.DisableOptions = FALSE;
10464
10465                 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
10466                                                     smb_lsaSecPackage,
10467                                                     &OptionsRequest,
10468                                                     sizeof(OptionsRequest),
10469                                                     &pResponse,
10470                                                     &cbResponse,
10471                                                     &ntsEx
10472                                                     );
10473
10474                 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
10475                     osi_Log2(smb_logp, "MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
10476                              nts, ntsEx);
10477
10478                     afsi_log("MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x", nts, ntsEx);
10479                 } else {
10480                     osi_Log0(smb_logp, "MsV1_0SetProcessOption success");
10481                     afsi_log("MsV1_0SetProcessOption success");
10482                 }
10483                 /* END - code from Larry */
10484
10485                 smb_lsaLogonOrigin.Buffer = "OpenAFS";
10486                 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
10487                 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
10488             } else {
10489                 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
10490
10491                 /* something went wrong. We report the error and revert back to no authentication
10492                 because we can't perform any auth requests without a successful lsa handle
10493                 or sec package id. */
10494                 afsi_log("Reverting to NO SMB AUTH");
10495                 smb_authType = SMB_AUTH_NONE;
10496             }
10497         } else {
10498             afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
10499
10500             /* something went wrong. We report the error and revert back to no authentication
10501             because we can't perform any auth requests without a successful lsa handle
10502             or sec package id. */
10503             afsi_log("Reverting to NO SMB AUTH");
10504             smb_authType = SMB_AUTH_NONE;
10505         }
10506
10507 #ifdef COMMENT
10508         /* Don't fallback to SMB_AUTH_NTLM.  Apparently, allowing SPNEGO to be used each
10509          * time prevents the failure of authentication when logged into Windows with an
10510          * external Kerberos principal mapped to a local account.
10511          */
10512         else if ( smb_authType == SMB_AUTH_EXTENDED) {
10513             /* Test to see if there is anything to negotiate.  If SPNEGO is not going to be used 
10514              * then the only option is NTLMSSP anyway; so just fallback. 
10515              */
10516             void * secBlob;
10517             int secBlobLength;
10518
10519             smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
10520             if (secBlobLength == 0) {
10521                 smb_authType = SMB_AUTH_NTLM;
10522                 afsi_log("Reverting to SMB AUTH NTLM");
10523             } else
10524                 free(secBlob);
10525         }
10526 #endif
10527     }
10528
10529     {
10530         DWORD bufsize;
10531         /* Now get ourselves a domain name. */
10532         /* For now we are using the local computer name as the domain name.
10533          * It is actually the domain for local logins, and we are acting as
10534          * a local SMB server. 
10535          */
10536         bufsize = lengthof(smb_ServerDomainName) - 1;
10537         GetComputerNameW(smb_ServerDomainName, &bufsize);
10538         smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
10539         afsi_log("Setting SMB server domain name to [%S]", smb_ServerDomainName);
10540     }
10541
10542     /* Start listeners, waiters, servers, and daemons */
10543     if (startListeners)
10544         smb_StartListeners(1);
10545
10546     phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
10547                           NULL, 0, &lpid, "smb_ClientWaiter");
10548     osi_assertx(phandle != NULL, "smb_ClientWaiter thread creation failure");
10549     thrd_CloseHandle(phandle);
10550
10551     phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
10552                           NULL, 0, &lpid, "smb_ServerWaiter");
10553     osi_assertx(phandle != NULL, "smb_ServerWaiter thread creation failure");
10554     thrd_CloseHandle(phandle);
10555
10556     for (i=0; i<smb_NumServerThreads; i++) {
10557         phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
10558                               (void *) i, 0, &lpid, "smb_Server");
10559         osi_assertx(phandle != NULL, "smb_Server thread creation failure");
10560         thrd_CloseHandle(phandle);
10561     }
10562
10563     phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
10564                           NULL, 0, &lpid, "smb_Daemon");
10565     osi_assertx(phandle != NULL, "smb_Daemon thread creation failure");
10566     thrd_CloseHandle(phandle);
10567
10568     phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
10569                           NULL, 0, &lpid, "smb_WaitingLocksDaemon");
10570     osi_assertx(phandle != NULL, "smb_WaitingLocksDaemon thread creation failure");
10571     thrd_CloseHandle(phandle);
10572
10573     lock_ReleaseMutex(&smb_StartedLock);
10574     return;
10575 }
10576
10577 void smb_Shutdown(void)
10578 {
10579     NCB *ncbp;
10580     long code = 0;
10581     afs_uint32 i;
10582     smb_vc_t *vcp;
10583
10584     /*fprintf(stderr, "Entering smb_Shutdown\n");*/
10585         
10586     /* setup the NCB system */
10587     ncbp = smb_GetNCB();
10588
10589     /* Block new sessions by setting shutdown flag */
10590     smbShutdownFlag = 1;
10591
10592     /* Hang up all sessions */
10593     memset(ncbp, 0, sizeof(NCB));
10594     for (i = 1; i < numSessions; i++)
10595     {
10596         if (dead_sessions[i])
10597             continue;
10598       
10599         /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
10600         ncbp->ncb_command = NCBHANGUP;
10601         ncbp->ncb_lana_num = lanas[i];  /*smb_LANadapter;*/
10602         ncbp->ncb_lsn = (UCHAR)LSNs[i];
10603         code = Netbios(ncbp);
10604         /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
10605         if (code == 0) code = ncbp->ncb_retcode;
10606         if (code != 0) {
10607             osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
10608             fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
10609         }
10610     }
10611
10612     /* Trigger the shutdown of all SMB threads */                                
10613     for (i = 0; i < smb_NumServerThreads; i++)                                   
10614         thrd_SetEvent(NCBreturns[i][0]);                                         
10615                                                                                  
10616     thrd_SetEvent(NCBevents[0]);                                                 
10617     thrd_SetEvent(SessionEvents[0]);                                             
10618     thrd_SetEvent(NCBavails[0]);                                                 
10619                                                                                  
10620     for (i = 0;i < smb_NumServerThreads; i++) {                                  
10621         DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500); 
10622         if (code == WAIT_OBJECT_0) {                                             
10623             continue;                                                            
10624         } else {                                                                 
10625             afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);      
10626             thrd_SetEvent(NCBreturns[i--][0]);                                   
10627         }                                                                        
10628     }                                                                            
10629
10630     /* Delete Netbios name */
10631     memset(ncbp, 0, sizeof(NCB));
10632     for (i = 0; i < lana_list.length; i++) {
10633         if (lana_list.lana[i] == LANA_INVALID) continue;
10634         ncbp->ncb_command = NCBDELNAME;
10635         ncbp->ncb_lana_num = lana_list.lana[i];
10636         memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10637         code = Netbios(ncbp);
10638         if (code == 0) 
10639             code = ncbp->ncb_retcode;
10640         if (code != 0) {
10641             fprintf(stderr, "Shutdown: Netbios NCBDELNAME lana %d error code %d",
10642                      ncbp->ncb_lana_num, code);
10643         }       
10644         fflush(stderr);
10645     }
10646
10647     /* Release the reference counts held by the VCs */
10648     lock_ObtainWrite(&smb_rctLock);
10649     for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) 
10650     {
10651         smb_fid_t *fidp;
10652         smb_tid_t *tidp;
10653      
10654         if (vcp->magic != SMB_VC_MAGIC)
10655             osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp", 
10656                        __FILE__, __LINE__);
10657
10658         for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10659         {
10660             if (fidp->scp != NULL) {
10661                 cm_scache_t * scp;
10662
10663                 lock_ReleaseWrite(&smb_rctLock);
10664                 lock_ObtainMutex(&fidp->mx);
10665                 if (fidp->scp != NULL) {
10666                     scp = fidp->scp;
10667                     fidp->scp = NULL;
10668                     lock_ObtainWrite(&scp->rw);
10669                     scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
10670                     lock_ReleaseWrite(&scp->rw);
10671                     osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
10672                     cm_ReleaseSCache(scp);
10673                 }
10674                 lock_ReleaseMutex(&fidp->mx);
10675                 lock_ObtainWrite(&smb_rctLock);
10676             }
10677         }
10678
10679         for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10680             if (tidp->vcp)
10681                 smb_ReleaseVCNoLock(tidp->vcp);
10682             if (tidp->userp) {
10683                 cm_user_t *userp = tidp->userp;
10684                 tidp->userp = NULL;
10685                 cm_ReleaseUser(userp);
10686             }
10687         }
10688     }
10689     lock_ReleaseWrite(&smb_rctLock);
10690     smb_FreeNCB(ncbp);
10691 }
10692
10693 /* Get the UNC \\<servername>\<sharename> prefix. */
10694 char *smb_GetSharename()
10695 {
10696     char *name;
10697     size_t len;
10698
10699     /* Make sure we have been properly initialized. */
10700     if (smb_localNamep == NULL)
10701         return NULL;
10702
10703     /* Allocate space for \\<servername>\<sharename>, plus the
10704      * terminator.
10705      */
10706     len = (strlen(smb_localNamep) + strlen("ALL") + 4) * sizeof(char);
10707     name = malloc(len);
10708     snprintf(name, len, "\\\\%s\\%s", smb_localNamep, "ALL");
10709     return name;
10710 }
10711
10712
10713 #ifdef LOG_PACKET
10714 void smb_LogPacket(smb_packet_t *packet)
10715 {
10716     BYTE *vp, *cp;
10717     smb_t * smbp;
10718     unsigned length, paramlen, datalen, i, j;
10719     char buf[81];
10720     char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
10721
10722     if (!packet) return;
10723
10724     osi_Log0(smb_logp, "*** SMB packet dump ***");
10725
10726     smbp = (smb_t *) packet->data;
10727     vp = (BYTE *) packet->data;
10728
10729     paramlen = smbp->wct * 2;
10730     datalen = *((WORD *) (smbp->vdata + paramlen));
10731     length = sizeof(*smbp) + paramlen + 1 + datalen;
10732
10733     for (i=0;i < length; i+=16)
10734     {
10735         memset( buf, ' ', 80 );
10736         buf[80] = 0;
10737
10738         itoa( i, buf, 16 );
10739
10740         buf[strlen(buf)] = ' ';
10741
10742         cp = (BYTE*) buf + 7;
10743
10744         for (j=0;j < 16 && (i+j)<length; j++)
10745         {
10746             *(cp++) = hex[vp[i+j] >> 4];
10747             *(cp++) = hex[vp[i+j] & 0xf];
10748             *(cp++) = ' ';
10749
10750             if (j==7)
10751             {
10752                 *(cp++) = '-';
10753                 *(cp++) = ' ';
10754             }
10755         }
10756
10757         for (j=0;j < 16 && (i+j)<length;j++)
10758         {
10759             *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
10760             if (j==7)
10761             {
10762                 *(cp++) = ' ';
10763                 *(cp++) = '-';
10764                 *(cp++) = ' ';
10765             }
10766         }
10767
10768         *cp = 0;
10769
10770         osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
10771     }
10772
10773     osi_Log0(smb_logp, "*** End SMB packet dump ***");
10774 }
10775 #endif /* LOG_PACKET */
10776
10777
10778 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
10779 {
10780     int zilch;
10781     char output[4196];
10782   
10783     smb_vc_t *vcp;
10784     smb_username_t *unp;
10785     smb_waitingLockRequest_t *wlrp;
10786
10787     if (lock)
10788         lock_ObtainRead(&smb_rctLock);
10789   
10790     sprintf(output, "begin dumping smb_username_t\r\n");
10791     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10792     for (unp = usernamesp; unp; unp=unp->nextp) 
10793     {
10794         cm_ucell_t *ucellp;
10795
10796         sprintf(output, "%s -- smb_unp=0x%p, refCount=%d, cm_userp=0x%p, flags=0x%x, logoff=%u, name=%S, machine=%S\r\n", 
10797                 cookie, unp, unp->refCount, unp->userp, unp->flags, unp->last_logoff_t,
10798                 unp->name ? unp->name : _C("NULL"), 
10799                 unp->machine ? unp->machine : _C("NULL"));
10800         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10801
10802         sprintf(output, "  begin dumping cm_ucell_t\r\n");
10803         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10804
10805         for ( ucellp = unp->userp->cellInfop; ucellp; ucellp = ucellp->nextp ) {
10806             sprintf(output, "  %s -- ucellp=0x%p, cellp=0x%p, flags=0x%x, tktLen=%04u, kvno=%03u, expires=%I64u, gen=%d, name=%s, cellname=%s\r\n", 
10807                      cookie, ucellp, ucellp->cellp, ucellp->flags, ucellp->ticketLen, ucellp->kvno, 
10808                      ucellp->expirationTime, ucellp->gen, 
10809                      ucellp->userName,
10810                      ucellp->cellp->name);
10811             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10812         }
10813
10814         sprintf(output, "  done dumping cm_ucell_t\r\n");
10815         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10816
10817     }
10818     sprintf(output, "done dumping smb_username_t\r\n");
10819     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10820
10821
10822     sprintf(output, "begin dumping smb_waitingLockRequest_t\r\n");
10823     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10824
10825
10826     for ( wlrp = smb_allWaitingLocks; wlrp; wlrp = (smb_waitingLockRequest_t *) osi_QNext(&wlrp->q)) {
10827         smb_waitingLock_t *lockp;
10828
10829         sprintf(output, "%s wlrp=0x%p vcp=0x%p, scp=0x%p, type=0x%x, start_t=0x%I64u msTimeout=0x%x\r\n",
10830                  cookie, wlrp, wlrp->vcp, wlrp->scp, wlrp->lockType, wlrp->start_t, wlrp->msTimeout);
10831         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10832       
10833         sprintf(output, "  begin dumping smb_waitingLock_t\r\n");
10834         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10835         for (lockp = wlrp->locks; lockp; lockp = (smb_waitingLock_t *) osi_QNext(&lockp->q)) {
10836             sprintf(output, "  %s -- waitlockp=0x%p lockp=0x%p key=0x%I64x offset=0x%I64x length=0x%I64x state=0x%x\r\n", 
10837                     cookie, lockp, lockp->lockp, lockp->key, lockp->LOffset.QuadPart, lockp->LLength.QuadPart, lockp->state);
10838             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10839         }
10840         sprintf(output, "  done dumping smb_waitingLock_t\r\n");
10841         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10842     }
10843
10844     sprintf(output, "done dumping smb_waitingLockRequest_t\r\n");
10845     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10846
10847     sprintf(output, "begin dumping smb_vc_t\r\n");
10848     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10849
10850     for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) 
10851     {
10852         smb_fid_t *fidp;
10853         smb_tid_t *tidp;
10854         smb_user_t *userp;
10855       
10856         sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
10857                  cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
10858         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10859       
10860         sprintf(output, "  begin dumping smb_user_t\r\n");
10861         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10862         for (userp = vcp->usersp; userp; userp = userp->nextp) {
10863             sprintf(output, "  %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n", 
10864                     cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
10865             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10866         }
10867         sprintf(output, "  done dumping smb_user_t\r\n");
10868         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10869
10870         sprintf(output, "  begin dumping smb_tid_t\r\n");
10871         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10872         for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10873             sprintf(output, "  %s -- smb_tidp=0x%p, refCount=%d, tid=%d, vcp=0x%p, cm_userp=0x%p, flags=0x%x, delOk=%d, path=%S\r\n", 
10874                     cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
10875                     tidp->pathname ? tidp->pathname : _C("NULL"));
10876             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10877         }
10878         sprintf(output, "  done dumping smb_tid_t\r\n");
10879         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10880
10881         sprintf(output, "  begin dumping smb_fid_t\r\n");
10882         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10883
10884         for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10885         {
10886             sprintf(output, "  %s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, userp=0x%p, ioctlp=0x%p, flags=0x%x, delOk=%d, NTopen_pathp=%S, NTopen_wholepathp=%S\r\n", 
10887                     cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
10888                     fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"), 
10889                     fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
10890             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10891         }
10892       
10893         sprintf(output, "  done dumping smb_fid_t\r\n");
10894         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10895     }
10896
10897     sprintf(output, "done dumping smb_vc_t\r\n");
10898     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10899   
10900     sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
10901     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10902
10903     for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp) 
10904     {
10905         smb_fid_t *fidp;
10906         smb_tid_t *tidp;
10907         smb_user_t *userp;
10908
10909         sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
10910                 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
10911         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10912       
10913         sprintf(output, "  begin dumping smb_user_t\r\n");
10914         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10915         for (userp = vcp->usersp; userp; userp = userp->nextp) {
10916             sprintf(output, "  %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n", 
10917                     cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
10918             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10919         }
10920         sprintf(output, "  done dumping smb_user_t\r\n");
10921         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10922
10923         sprintf(output, "  begin dumping smb_tid_t\r\n");
10924         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10925         for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10926             sprintf(output, "  %s -- smb_tidp=0x%p, refCount=%d, tid=%d, vcp=0x%p, cm_userp=0x%p, flags=0x%x, delOk=%d, path=%S\r\n", 
10927                     cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
10928                     tidp->pathname ? tidp->pathname : _C("NULL"));
10929             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10930         }
10931         sprintf(output, "  done dumping smb_tid_t\r\n");
10932         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10933
10934         sprintf(output, "  begin dumping smb_fid_t\r\n");
10935         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10936
10937         for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10938         {
10939             sprintf(output, "  %s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, userp=0x%p, ioctlp=0x%p, flags=0x%x, delOk=%d, NTopen_pathp=%S, NTopen_wholepathp=%S\r\n", 
10940                     cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
10941                     fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"), 
10942                     fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
10943             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10944         }
10945       
10946         sprintf(output, "  done dumping smb_fid_t\r\n");
10947         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10948     }
10949
10950     sprintf(output, "done dumping DEAD smb_vc_t\r\n");
10951     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10952   
10953     if (lock)
10954         lock_ReleaseRead(&smb_rctLock);
10955     return 0;
10956 }
10957
10958 long smb_IsNetworkStarted(void)
10959 {
10960     long rc;
10961     lock_ObtainWrite(&smb_globalLock);
10962     rc = (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);
10963     lock_ReleaseWrite(&smb_globalLock);
10964     return rc;
10965 }