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