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