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