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