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