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