windows-updates-20041016
[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 //#define NOTSERVICE 1
11 #define LOG_PACKET 1
12
13 #include <afs/param.h>
14 #include <afs/stds.h>
15
16 #ifndef DJGPP
17 #include <windows.h>
18 #else
19 #include <sys/timeb.h>
20 #include <tzfile.h>
21 #endif /* !DJGPP */
22 #include <stddef.h>
23 #include <stdlib.h>
24 #include <malloc.h>
25 #include <string.h>
26 #include <stdio.h>
27 #include <time.h>
28
29 #include <osi.h>
30 #include <ntstatus.h>
31
32 #include "afsd.h"
33
34 #include "smb.h"
35 #include "lanahelper.h"
36
37 /* These characters are illegal in Windows filenames */
38 static char *illegalChars = "\\/:*?\"<>|";
39 BOOL isWindows2000 = FALSE;
40
41 smb_vc_t *dead_vcp = NULL;
42 smb_vc_t *active_vcp = NULL;
43
44 /* TODO; logout mechanism needs to be thread-safe */
45 char *loggedOutName = NULL;
46 smb_user_t *loggedOutUserp = NULL;
47 time_t loggedOutTime;
48 int loggedOut = 0;
49 int smbShutdownFlag = 0;
50
51 int smb_LogoffTokenTransfer;
52 time_t smb_LogoffTransferTimeout;
53
54 DWORD last_msg_time = 0;
55
56 long ongoingOps = 0;
57
58 unsigned int sessionGen = 0;
59
60 extern void afsi_log(char *pattern, ...);
61 extern HANDLE afsi_file;
62
63 osi_hyper_t hzero = {0, 0};
64 osi_hyper_t hones = {0xFFFFFFFF, -1};
65
66 osi_log_t *  smb_logp;
67 osi_rwlock_t smb_globalLock;
68 osi_rwlock_t smb_rctLock;
69 osi_mutex_t  smb_ListenerLock;
70  
71 char smb_LANadapter;
72 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
73
74 /* for debugging */
75 long smb_maxObsConcurrentCalls=0;
76 long smb_concurrentCalls=0;
77
78 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
79
80 smb_packet_t *smb_packetFreeListp;
81 smb_ncb_t *smb_ncbFreeListp;
82
83 int smb_NumServerThreads;
84
85 int numNCBs, numSessions, numVCs;
86
87 int smb_maxVCPerServer;
88 int smb_maxMpxRequests;
89
90 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
91 HANDLE smb_lsaHandle;
92 ULONG smb_lsaSecPackage;
93 LSA_STRING smb_lsaLogonOrigin;
94
95 #define NCBmax MAXIMUM_WAIT_OBJECTS
96 EVENT_HANDLE NCBavails[NCBmax], NCBevents[NCBmax];
97 EVENT_HANDLE **NCBreturns;
98 DWORD NCBsessions[NCBmax];
99 NCB *NCBs[NCBmax];
100 struct smb_packet *bufs[NCBmax];
101
102 #define Sessionmax MAXIMUM_WAIT_OBJECTS - 4
103 EVENT_HANDLE SessionEvents[Sessionmax];
104 unsigned short LSNs[Sessionmax];
105 int lanas[Sessionmax];
106 BOOL dead_sessions[Sessionmax];
107 LANA_ENUM lana_list;
108
109 /* for raw I/O */
110 osi_mutex_t smb_RawBufLock;
111 #ifdef DJGPP
112 #define SMB_RAW_BUFS 4
113 dos_ptr smb_RawBufs;
114 int smb_RawBufSel[SMB_RAW_BUFS];
115 #else
116 char *smb_RawBufs;
117 #endif /* DJGPP */
118
119 #define SMB_MASKFLAG_TILDE 1
120 #define SMB_MASKFLAG_CASEFOLD 2
121
122 #define RAWTIMEOUT INFINITE
123
124 /* for raw write */
125 typedef struct raw_write_cont {
126         long code;
127         osi_hyper_t offset;
128         long count;
129 #ifndef DJGPP
130         char *buf;
131 #else
132         dos_ptr buf;
133 #endif /* DJGPP */
134         int writeMode;
135         long alreadyWritten;
136 } raw_write_cont_t;
137
138 /* dir search stuff */
139 long smb_dirSearchCounter = 1;
140 smb_dirSearch_t *smb_firstDirSearchp;
141 smb_dirSearch_t *smb_lastDirSearchp;
142
143 /* hide dot files? */
144 int smb_hideDotFiles;
145
146 /* global state about V3 protocols */
147 int smb_useV3;          /* try to negotiate V3 */
148
149 #ifndef DJGPP
150 static showErrors = 1;
151 /* MessageBox or something like it */
152 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
153 extern HANDLE WaitToTerminate;
154 #endif /* DJGPP */
155
156 /* GMT time info:
157  * Time in Unix format of midnight, 1/1/1970 local time.
158  * When added to dosUTime, gives Unix (AFS) time.
159  */
160 long smb_localZero = 0;
161
162 /* Time difference for converting to kludge-GMT */
163 int smb_NowTZ;
164
165 char *smb_localNamep = NULL;
166
167 smb_vc_t *smb_allVCsp;
168
169 smb_username_t *usernamesp = NULL;
170
171 smb_waitingLock_t *smb_allWaitingLocks;
172
173 /* forward decl */
174 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
175                                                 NCB *ncbp, raw_write_cont_t *rwcp);
176 void smb_NetbiosInit();
177 #ifdef DJGPP
178 #ifndef AFS_WIN95_ENV
179 DWORD smb_ServerExceptionFilter(void);
180 #endif
181
182 extern char cm_HostName[];
183 extern char cm_confDir[];
184 #endif
185
186 #ifdef DJGPP
187 #define LPTSTR char *
188 #define GetComputerName(str, sizep) \
189        strcpy((str), cm_HostName); \
190        *(sizep) = strlen(cm_HostName)
191 #endif /* DJGPP */
192
193 #ifdef LOG_PACKET
194 void smb_LogPacket(smb_packet_t *packet);
195 #endif /* LOG_PACKET */
196 extern char AFSConfigKeyName[];
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 char * myCrt_Dispatch(int i)
209 {
210     switch (i)
211     {
212     case 0x00:
213         return "(00)ReceiveCoreMakeDir";
214     case 0x01:
215         return "(01)ReceiveCoreRemoveDir";
216     case 0x02:
217         return "(02)ReceiveCoreOpen";
218     case 0x03:
219         return "(03)ReceiveCoreCreate";
220     case 0x04:
221         return "(04)ReceiveCoreClose";
222     case 0x05:
223         return "(05)ReceiveCoreFlush";
224     case 0x06:
225         return "(06)ReceiveCoreUnlink";
226     case 0x07:
227         return "(07)ReceiveCoreRename";
228     case 0x08:
229         return "(08)ReceiveCoreGetFileAttributes";
230     case 0x09:
231         return "(09)ReceiveCoreSetFileAttributes";
232     case 0x0a:
233         return "(0a)ReceiveCoreRead";
234     case 0x0b:
235         return "(0b)ReceiveCoreWrite";
236     case 0x0c:
237         return "(0c)ReceiveCoreLockRecord";
238     case 0x0d:
239         return "(0d)ReceiveCoreUnlockRecord";
240     case 0x0e:
241         return "(0e)SendCoreBadOp";
242     case 0x0f:
243         return "(0f)ReceiveCoreCreate";
244     case 0x10:
245         return "(10)ReceiveCoreCheckPath";
246     case 0x11:
247         return "(11)SendCoreBadOp";
248     case 0x12:
249         return "(12)ReceiveCoreSeek";
250     case 0x1a:
251         return "(1a)ReceiveCoreReadRaw";
252     case 0x1d:
253         return "(1d)ReceiveCoreWriteRawDummy";
254     case 0x22:
255         return "(22)ReceiveV3SetAttributes";
256     case 0x23:
257         return "(23)ReceiveV3GetAttributes";
258     case 0x24:
259         return "(24)ReceiveV3LockingX";
260     case 0x25:
261         return "(25)ReceiveV3Trans";
262     case 0x26:
263         return "(26)ReceiveV3Trans[aux]";
264     case 0x29:
265         return "(29)SendCoreBadOp";
266     case 0x2b:
267         return "(2b)ReceiveCoreEcho";
268     case 0x2d:
269         return "(2d)ReceiveV3OpenX";
270     case 0x2e:
271         return "(2e)ReceiveV3ReadX";
272     case 0x32:
273         return "(32)ReceiveV3Tran2A";
274     case 0x33:
275         return "(33)ReceiveV3Tran2A[aux]";
276     case 0x34:
277         return "(34)ReceiveV3FindClose";
278     case 0x35:
279         return "(35)ReceiveV3FindNotifyClose";
280     case 0x70:
281         return "(70)ReceiveCoreTreeConnect";
282     case 0x71:
283         return "(71)ReceiveCoreTreeDisconnect";
284     case 0x72:
285         return "(72)ReceiveNegotiate";
286     case 0x73:
287         return "(73)ReceiveV3SessionSetupX";
288     case 0x74:
289         return "(74)ReceiveV3UserLogoffX";
290     case 0x75:
291         return "(75)ReceiveV3TreeConnectX";
292     case 0x80:
293         return "(80)ReceiveCoreGetDiskAttributes";
294     case 0x81:
295         return "(81)ReceiveCoreSearchDir";
296     case 0x82:
297         return "(82)Find";
298     case 0x83:
299         return "(83)FindUnique";
300     case 0x84:
301         return "(84)FindClose";
302     case 0xA0:
303         return "(A0)ReceiveNTTransact";
304     case 0xA2:
305         return "(A2)ReceiveNTCreateX";
306     case 0xA4:
307         return "(A4)ReceiveNTCancel";
308     case 0xA5:
309         return "(A5)ReceiveNTRename";
310     case 0xc0:
311         return "(C0)OpenPrintFile";
312     case 0xc1:
313         return "(C1)WritePrintFile";
314     case 0xc2:
315         return "(C2)ClosePrintFile";
316     case 0xc3:
317         return "(C3)GetPrintQueue";
318     case 0xd8:
319         return "(D8)ReadBulk";
320     case 0xd9:
321         return "(D9)WriteBulk";
322     case 0xda:
323         return "(DA)WriteBulkData";
324     default:
325         return "unknown SMB op";
326     }
327 }       
328
329 char * myCrt_2Dispatch(int i)
330 {
331     switch (i)
332     {
333     default:
334         return "unknown SMB op-2";
335     case 0:
336         return "S(00)CreateFile";
337     case 1:
338         return "S(01)FindFirst";
339     case 2:
340         return "S(02)FindNext"; /* FindNext */
341     case 3:
342         return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
343     case 4:
344         return "S(04)??";
345     case 5:
346         return "S(05)QueryFileInfo_ReceiveTran2QPathInfo";
347     case 6:
348         return "S(06)SetFileInfo_ReceiveTran2SetPathInfo";
349     case 7:
350         return "S(07)SetInfoHandle_ReceiveTran2QFileInfo";
351     case 8:
352         return "S(08)??_ReceiveTran2SetFileInfo";
353     case 9:
354         return "S(09)??_ReceiveTran2FSCTL";
355     case 10:
356         return "S(0a)_ReceiveTran2IOCTL";
357     case 11:
358         return "S(0b)_ReceiveTran2FindNotifyFirst";
359     case 12:
360         return "S(0c)_ReceiveTran2FindNotifyNext";
361     case 13:
362         return "S(0d)_ReceiveTran2CreateDirectory";
363     case 14:
364         return "S(0e)_ReceiveTran2SessionSetup";
365     }
366 }       
367
368 char * myCrt_RapDispatch(int i)
369 {
370     switch(i)
371     {
372     default:
373         return "unknown RAP OP";
374     case 0:
375         return "RAP(0)NetShareEnum";
376     case 1:
377         return "RAP(1)NetShareGetInfo";
378     case 13:
379         return "RAP(13)NetServerGetInfo";
380     case 63:
381         return "RAP(63)NetWkStaGetInfo";
382     }
383 }       
384
385 /* scache must be locked */
386 unsigned int smb_Attributes(cm_scache_t *scp)
387 {
388     unsigned int attrs;
389
390     if (scp->fileType == CM_SCACHETYPE_DIRECTORY
391          || scp->fileType == CM_SCACHETYPE_MOUNTPOINT)
392         attrs = SMB_ATTR_DIRECTORY;
393     else
394         attrs = 0;
395
396     /*
397      * We used to mark a file RO if it was in an RO volume, but that
398      * turns out to be impolitic in NT.  See defect 10007.
399      */
400 #ifdef notdef
401     if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
402 #endif
403         if ((scp->unixModeBits & 0222) == 0)
404             attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
405
406     return attrs;
407 }
408
409 /* Check if the named file/dir is a dotfile/dotdir */
410 /* String pointed to by lastComp can have leading slashes, but otherwise should have
411    no other patch components */
412 unsigned int smb_IsDotFile(char *lastComp) {
413     char *s;
414     if(lastComp) {
415         /* skip over slashes */
416         for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
417     }
418     else
419         return 0;
420
421     /* nulls, curdir and parent dir doesn't count */
422     if (!*s) 
423         return 0;
424     if (*s == '.') {
425         if (!*(s + 1)) 
426             return 0;
427         if(*(s+1) == '.' && !*(s + 2)) 
428             return 0;
429         return 1;
430     }
431     return 0;
432 }
433
434 static int ExtractBits(WORD bits, short start, short len)
435 {
436     int end;
437     WORD num;
438
439     end = start + len;
440         
441     num = bits << (16 - end);
442     num = num >> ((16 - end) + start);
443
444     return (int)num;
445 }
446
447 #ifndef DJGPP
448 void ShowUnixTime(char *FuncName, time_t unixTime)
449 {
450     FILETIME ft;
451     WORD wDate, wTime;
452
453     smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
454
455     if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
456         osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
457     else {
458         int day, month, year, sec, min, hour;
459         char msg[256];
460
461         day = ExtractBits(wDate, 0, 5);
462         month = ExtractBits(wDate, 5, 4);
463         year = ExtractBits(wDate, 9, 7) + 1980;
464
465         sec = ExtractBits(wTime, 0, 5);
466         min = ExtractBits(wTime, 5, 6);
467         hour = ExtractBits(wTime, 11, 5);
468
469         sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
470         osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
471     }
472 }       
473 #endif /* DJGPP */
474
475 #ifndef DJGPP
476 /* Determine if we are observing daylight savings time */
477 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
478 {
479     TIME_ZONE_INFORMATION timeZoneInformation;
480     SYSTEMTIME utc, local, localDST;
481
482     /* Get the time zone info. NT uses this to calc if we are in DST. */
483     GetTimeZoneInformation(&timeZoneInformation);
484
485     /* Return the daylight bias */
486     *pDstBias = timeZoneInformation.DaylightBias;
487
488     /* Return the bias */
489     *pBias = timeZoneInformation.Bias;
490
491     /* Now determine if DST is being observed */
492
493     /* Get the UTC (GMT) time */
494     GetSystemTime(&utc);
495
496     /* Convert UTC time to local time using the time zone info.  If we are
497        observing DST, the calculated local time will include this. 
498      */
499     SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
500
501     /* Set the daylight bias to 0.  The daylight bias is the amount of change
502      * in time that we use for daylight savings time.  By setting this to 0
503      * we cause there to be no change in time during daylight savings time. 
504      */
505     timeZoneInformation.DaylightBias = 0;
506
507     /* Convert the utc time to local time again, but this time without any
508        adjustment for daylight savings time. 
509        */
510     SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
511
512     /* If the two times are different, then it means that the localDST that
513        we calculated includes the daylight bias, and therefore we are
514        observing daylight savings time.
515      */
516     *pDST = localDST.wHour != local.wHour;
517 }       
518 #else
519 /* Determine if we are observing daylight savings time */
520 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
521 {
522     struct timeb t;
523
524     ftime(&t);
525     *pDST = t.dstflag;
526     *pDstBias = -60;    /* where can this be different? */
527     *pBias = t.timezone;
528 }       
529 #endif /* DJGPP */
530  
531
532 void CompensateForSmbClientLastWriteTimeBugs(long *pLastWriteTime)
533 {
534     BOOL dst;       /* Will be TRUE if observing DST */
535     LONG dstBias;   /* Offset from local time if observing DST */
536     LONG bias;      /* Offset from GMT for local time */
537
538     /*
539      * This function will adjust the last write time to compensate
540      * for two bugs in the smb client:
541      *
542      *    1) During Daylight Savings Time, the LastWriteTime is ahead
543      *       in time by the DaylightBias (ignoring the sign - the
544      *       DaylightBias is always stored as a negative number).  If
545      *       the DaylightBias is -60, then the LastWriteTime will be
546      *       ahead by 60 minutes.
547      *
548      *    2) If the local time zone is a positive offset from GMT, then
549      *       the LastWriteTime will be the correct local time plus the
550      *       Bias (ignoring the sign - a positive offset from GMT is
551      *       always stored as a negative Bias).  If the Bias is -120,
552      *       then the LastWriteTime will be ahead by 120 minutes.
553      *
554      *    These bugs can occur at the same time.
555      */
556
557     GetTimeZoneInfo(&dst, &dstBias, &bias);
558
559     /* First adjust for DST */
560     if (dst)
561         *pLastWriteTime -= (-dstBias * 60);     /* Convert dstBias to seconds */
562
563     /* Now adjust for a positive offset from GMT (a negative bias). */
564     if (bias < 0)
565         *pLastWriteTime -= (-bias * 60);        /* Convert bias to seconds */
566 }                       
567
568 /*
569  * Calculate the difference (in seconds) between local time and GMT.
570  * This enables us to convert file times to kludge-GMT.
571  */
572 static void
573 smb_CalculateNowTZ()
574 {
575     time_t t;
576     struct tm gmt_tm, local_tm;
577     int days, hours, minutes, seconds;
578
579     t = time(NULL);
580     gmt_tm = *(gmtime(&t));
581     local_tm = *(localtime(&t));
582
583     days = local_tm.tm_yday - gmt_tm.tm_yday;
584     hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour
585 #ifdef COMMENT
586         /* There is a problem with DST immediately after the time change
587         * which may continue to exist until the machine is rebooted
588          */
589         - (local_tm.tm_isdst ? 1 : 0)
590 #endif /* COMMENT */
591             ;
592     minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min; 
593     seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
594
595     smb_NowTZ = seconds;
596 }
597
598 #ifndef DJGPP
599 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
600 {
601     struct tm *ltp;
602     SYSTEMTIME stm;
603     struct tm localJunk;
604     time_t ersatz_unixTime;
605
606     /*
607      * Must use kludge-GMT instead of real GMT.
608      * kludge-GMT is computed by adding time zone difference to localtime.
609      *
610      * real GMT would be:
611      * ltp = gmtime(&unixTime);
612      */
613     ersatz_unixTime = unixTime - smb_NowTZ;
614     ltp = localtime(&ersatz_unixTime);
615
616     /* if we fail, make up something */
617     if (!ltp) {
618         ltp = &localJunk;
619         localJunk.tm_year = 89 - 20;
620         localJunk.tm_mon = 4;
621         localJunk.tm_mday = 12;
622         localJunk.tm_hour = 0;
623         localJunk.tm_min = 0;
624         localJunk.tm_sec = 0;
625     }
626
627     stm.wYear = ltp->tm_year + 1900;
628     stm.wMonth = ltp->tm_mon + 1;
629     stm.wDayOfWeek = ltp->tm_wday;
630     stm.wDay = ltp->tm_mday;
631     stm.wHour = ltp->tm_hour;
632     stm.wMinute = ltp->tm_min;
633     stm.wSecond = ltp->tm_sec;
634     stm.wMilliseconds = 0;
635
636     SystemTimeToFileTime(&stm, largeTimep);
637 }
638 #else /* DJGPP */
639 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
640 {
641     /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
642     /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 ??? */
643     LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
644     LARGE_INTEGER ut;
645     int leap_years = 89;   /* leap years betw 1/1/1601 and 1/1/1970 */
646
647     /* set ft to number of 100ns intervals betw 1/1/1601 and 1/1/1970 GMT */
648     *ft = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years)
649                                      * 24 * 60);
650     *ft = LargeIntegerMultiplyByLong(*ft, 60);
651     *ft = LargeIntegerMultiplyByLong(*ft, 10000000);
652
653     /* add unix time */
654     ut = ConvertLongToLargeInteger(unixTime);
655     ut = LargeIntegerMultiplyByLong(ut, 10000000);
656     *ft = LargeIntegerAdd(*ft, ut);
657 }       
658 #endif /* !DJGPP */
659
660 #ifndef DJGPP
661 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
662 {
663     SYSTEMTIME stm;
664     struct tm lt;
665     long save_timezone;
666
667     FileTimeToSystemTime(largeTimep, &stm);
668
669     lt.tm_year = stm.wYear - 1900;
670     lt.tm_mon = stm.wMonth - 1;
671     lt.tm_wday = stm.wDayOfWeek;
672     lt.tm_mday = stm.wDay;
673     lt.tm_hour = stm.wHour;
674     lt.tm_min = stm.wMinute;
675     lt.tm_sec = stm.wSecond;
676     lt.tm_isdst = -1;
677
678     save_timezone = _timezone;
679     _timezone += smb_NowTZ;
680     *unixTimep = mktime(&lt);
681     _timezone = save_timezone;
682 }       
683 #else /* DJGPP */
684 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
685 {
686     /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
687     /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 GMT? */
688     LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
689     LARGE_INTEGER a;
690     int leap_years = 89;
691
692     /* set to number of 100ns intervals betw 1/1/1601 and 1/1/1970 */
693     a = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years) * 24 * 60);
694     a = LargeIntegerMultiplyByLong(a, 60);
695     a = LargeIntegerMultiplyByLong(a, 10000000);
696
697     /* subtract it from ft */
698     a = LargeIntegerSubtract(*ft, a);
699
700     /* divide down to seconds */
701     *unixTimep = LargeIntegerDivideByLong(a, 10000000);
702 }       
703 #endif /* !DJGPP */
704
705 void smb_SearchTimeFromUnixTime(long *dosTimep, time_t unixTime)
706 {
707     struct tm *ltp;
708     int dosDate;
709     int dosTime;
710     struct tm localJunk;
711     time_t t = unixTime;
712
713     ltp = localtime((time_t*) &t);
714
715     /* if we fail, make up something */
716     if (!ltp) {
717         ltp = &localJunk;
718         localJunk.tm_year = 89 - 20;
719         localJunk.tm_mon = 4;
720         localJunk.tm_mday = 12;
721         localJunk.tm_hour = 0;
722         localJunk.tm_min = 0;
723         localJunk.tm_sec = 0;
724     }   
725
726     dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
727     dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
728     *dosTimep = (dosDate<<16) | dosTime;
729 }       
730
731 void smb_UnixTimeFromSearchTime(time_t *unixTimep, time_t searchTime)
732 {
733     unsigned short dosDate;
734     unsigned short dosTime;
735     struct tm localTm;
736         
737     dosDate = searchTime & 0xffff;
738     dosTime = (searchTime >> 16) & 0xffff;
739
740     localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
741     localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1;        /* January is 0 in localTm */
742     localTm.tm_mday = (dosDate) & 0x1f;
743     localTm.tm_hour = (dosTime>>11) & 0x1f;
744     localTm.tm_min = (dosTime >> 5) & 0x3f;
745     localTm.tm_sec = (dosTime & 0x1f) * 2;
746     localTm.tm_isdst = -1;                              /* compute whether DST in effect */
747
748     *unixTimep = mktime(&localTm);
749 }
750
751 void smb_DosUTimeFromUnixTime(time_t *dosUTimep, time_t unixTime)
752 {
753     *dosUTimep = unixTime - smb_localZero;
754 }
755
756 void smb_UnixTimeFromDosUTime(time_t *unixTimep, time_t dosTime)
757 {
758 #ifndef DJGPP
759     *unixTimep = dosTime + smb_localZero;
760 #else /* DJGPP */
761     /* dosTime seems to be already adjusted for GMT */
762     *unixTimep = dosTime;
763 #endif /* !DJGPP */
764 }
765
766 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
767 {
768     smb_vc_t *vcp;
769
770     lock_ObtainWrite(&smb_rctLock);
771     for(vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
772         if (lsn == vcp->lsn && lana == vcp->lana) {
773             vcp->refCount++;
774             break;
775         }
776     }
777     if (!vcp && (flags & SMB_FLAG_CREATE)) {
778         vcp = malloc(sizeof(*vcp));
779         memset(vcp, 0, sizeof(*vcp));
780         vcp->vcID = numVCs++;
781         vcp->refCount = 1;
782         vcp->tidCounter = 1;
783         vcp->fidCounter = 1;
784         vcp->uidCounter = 1;  /* UID 0 is reserved for blank user */
785         vcp->nextp = smb_allVCsp;
786         smb_allVCsp = vcp;
787         lock_InitializeMutex(&vcp->mx, "vc_t mutex");
788         vcp->lsn = lsn;
789         vcp->lana = lana;
790         vcp->secCtx = NULL;
791
792         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
793             /* We must obtain a challenge for extended auth 
794              * in case the client negotiates smb v3 
795              */
796             NTSTATUS nts,ntsEx;
797             MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
798             PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp;
799             ULONG lsaRespSize;
800
801             lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
802
803             nts = LsaCallAuthenticationPackage( smb_lsaHandle,
804                                                 smb_lsaSecPackage,
805                                                 &lsaReq,
806                                                 sizeof(lsaReq),
807                                                 &lsaResp,
808                                                 &lsaRespSize,
809                                                 &ntsEx);
810             osi_assert(nts == STATUS_SUCCESS); /* this had better work! */
811
812             memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
813             LsaFreeReturnBuffer(lsaResp);
814         }
815         else
816             memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
817     }
818     lock_ReleaseWrite(&smb_rctLock);
819     return vcp;
820 }
821
822 int smb_IsStarMask(char *maskp)
823 {
824     int i;
825     char tc;
826         
827     for(i=0; i<11; i++) {
828         tc = *maskp++;
829         if (tc == '?' || tc == '*' || tc == '>') return 1;        
830     }   
831     return 0;
832 }
833
834 void smb_ReleaseVC(smb_vc_t *vcp)
835 {
836     lock_ObtainWrite(&smb_rctLock);
837     osi_assert(vcp->refCount-- > 0);
838     lock_ReleaseWrite(&smb_rctLock);
839 }       
840
841 void smb_HoldVC(smb_vc_t *vcp)
842 {
843     lock_ObtainWrite(&smb_rctLock);
844     vcp->refCount++;
845     lock_ReleaseWrite(&smb_rctLock);
846 }       
847
848 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
849 {
850     smb_tid_t *tidp;
851
852     lock_ObtainWrite(&smb_rctLock);
853     for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
854         if (tid == tidp->tid) {
855             tidp->refCount++;
856             break;
857         }       
858     }
859     if (!tidp && (flags & SMB_FLAG_CREATE)) {
860         tidp = malloc(sizeof(*tidp));
861         memset(tidp, 0, sizeof(*tidp));
862         tidp->nextp = vcp->tidsp;
863         tidp->refCount = 1;
864         tidp->vcp = vcp;
865         vcp->refCount++;
866         vcp->tidsp = tidp;
867         lock_InitializeMutex(&tidp->mx, "tid_t mutex");
868         tidp->tid = tid;
869     }
870     lock_ReleaseWrite(&smb_rctLock);
871     return tidp;
872 }               
873
874 void smb_ReleaseTID(smb_tid_t *tidp)
875 {
876     smb_tid_t *tp;
877     smb_tid_t **ltpp;
878     cm_user_t *userp;
879     smb_vc_t  *vcp;
880
881     userp = NULL;
882     vcp = NULL;
883     lock_ObtainWrite(&smb_rctLock);
884     osi_assert(tidp->refCount-- > 0);
885     if (tidp->refCount == 0 && (tidp->flags & SMB_TIDFLAG_DELETE)) {
886         ltpp = &tidp->vcp->tidsp;
887         for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
888             if (tp == tidp) break;
889         }
890         osi_assert(tp != NULL);
891         *ltpp = tp->nextp;
892         lock_FinalizeMutex(&tidp->mx);
893         userp = tidp->userp;    /* remember to drop ref later */
894         vcp = tidp->vcp;
895     }
896     lock_ReleaseWrite(&smb_rctLock);
897     if (userp) {
898         cm_ReleaseUser(userp);
899     }   
900     if (vcp) {
901         smb_ReleaseVC(vcp);
902     }   
903 }               
904
905 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
906 {
907     smb_user_t *uidp = NULL;
908
909     lock_ObtainWrite(&smb_rctLock);
910     for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
911         if (uid == uidp->userID) {
912             uidp->refCount++;
913             osi_LogEvent("AFS smb_FindUID (Find by UID)",NULL," VCP[%x] found-uid[%d] name[%s]",
914                           (int)vcp, uidp->userID, 
915                           osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
916             break;
917         }
918     }
919     if (!uidp && (flags & SMB_FLAG_CREATE)) {
920         uidp = malloc(sizeof(*uidp));
921         memset(uidp, 0, sizeof(*uidp));
922         uidp->nextp = vcp->usersp;
923         uidp->refCount = 1;
924         uidp->vcp = vcp;
925         vcp->refCount++;
926         vcp->usersp = uidp;
927         lock_InitializeMutex(&uidp->mx, "user_t mutex");
928         uidp->userID = uid;
929         osi_LogEvent("AFS smb_FindUID (Find by UID)",NULL,"VCP[%x] new-uid[%d] name[%s]",(int)vcp,uidp->userID,(uidp->unp ? uidp->unp->name : ""));
930     }
931     lock_ReleaseWrite(&smb_rctLock);
932     return uidp;
933 }               
934
935 smb_username_t *smb_FindUserByName(char *usern, char *machine, int flags)
936 {
937     smb_username_t *unp= NULL;
938
939     lock_ObtainWrite(&smb_rctLock);
940     for(unp = usernamesp; unp; unp = unp->nextp) {
941         if (stricmp(unp->name, usern) == 0 &&
942              stricmp(unp->machine, machine) == 0) {
943             unp->refCount++;
944             break;
945         }
946     }
947     if (!unp && (flags & SMB_FLAG_CREATE)) {
948         unp = malloc(sizeof(*unp));
949         memset(unp, 0, sizeof(*unp));
950         unp->refCount = 1;
951         unp->nextp = usernamesp;
952         unp->name = strdup(usern);
953         unp->machine = strdup(machine);
954         usernamesp = unp;
955         lock_InitializeMutex(&unp->mx, "username_t mutex");
956     }
957     lock_ReleaseWrite(&smb_rctLock);
958     return unp;
959 }       
960
961 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
962 {
963     smb_user_t *uidp= NULL;
964
965     lock_ObtainWrite(&smb_rctLock);
966     for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
967         if (!uidp->unp) 
968             continue;
969         if (stricmp(uidp->unp->name, usern) == 0) {
970             uidp->refCount++;
971             osi_LogEvent("AFS smb_FindUserByNameThisSession",NULL,"VCP[%x] uid[%d] match-name[%s]",(int)vcp,uidp->userID,usern);
972             break;
973         } else
974             continue;
975     }           
976     lock_ReleaseWrite(&smb_rctLock);
977     return uidp;
978 }       
979 void smb_ReleaseUID(smb_user_t *uidp)
980 {
981     smb_user_t *up;
982     smb_user_t **lupp;
983     cm_user_t *userp;
984     smb_vc_t  *vcp;
985
986     userp = NULL;
987     vcp = NULL;
988     lock_ObtainWrite(&smb_rctLock);
989     osi_assert(uidp->refCount-- > 0);
990     if (uidp->refCount == 0 && (uidp->flags & SMB_USERFLAG_DELETE)) {
991         lupp = &uidp->vcp->usersp;
992         for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
993             if (up == uidp) break;
994         }
995         osi_assert(up != NULL);
996         *lupp = up->nextp;
997         lock_FinalizeMutex(&uidp->mx);
998         if (uidp->unp) {
999             userp = uidp->unp->userp;   /* remember to drop ref later */
1000             uidp->unp->userp = NULL;
1001         }       
1002         vcp = uidp->vcp;
1003         uidp->vcp = NULL;
1004     }           
1005     lock_ReleaseWrite(&smb_rctLock);
1006     if (userp) {
1007         cm_ReleaseUserVCRef(userp);
1008         cm_ReleaseUser(userp);
1009     }   
1010     if (vcp) {
1011         smb_ReleaseVC(vcp);
1012     }
1013 }       
1014
1015 /* retrieve a held reference to a user structure corresponding to an incoming
1016  * request.
1017  * corresponding release function is cm_ReleaseUser.
1018  */
1019 cm_user_t *smb_GetUser(smb_vc_t *vcp, smb_packet_t *inp)
1020 {
1021     smb_user_t *uidp;
1022     cm_user_t *up;
1023     smb_t *smbp;
1024
1025     smbp = (smb_t *) inp;
1026     uidp = smb_FindUID(vcp, smbp->uid, 0);
1027     if ((!uidp) ||  (!uidp->unp))
1028         return NULL;
1029
1030     lock_ObtainMutex(&uidp->mx);
1031     up = uidp->unp->userp;
1032     cm_HoldUser(up);
1033     lock_ReleaseMutex(&uidp->mx);
1034
1035     smb_ReleaseUID(uidp);
1036
1037     return up;
1038 }
1039
1040 /*
1041  * Return a pointer to a pathname extracted from a TID structure.  The
1042  * TID structure is not held; assume it won't go away.
1043  */
1044 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1045 {
1046     smb_tid_t *tidp;
1047     long code = 0;
1048
1049     tidp = smb_FindTID(vcp, tid, 0);
1050     if (!tidp) {
1051         *treepath = NULL;
1052     } else {
1053         if(tidp->flags & SMB_TIDFLAG_IPC) {
1054             code = CM_ERROR_TIDIPC;
1055             /* tidp->pathname would be NULL, but that's fine */
1056         }
1057         *treepath = tidp->pathname;
1058         smb_ReleaseTID(tidp);
1059     }
1060     return code;
1061 }
1062
1063 /* check to see if we have a chained fid, that is, a fid that comes from an
1064  * OpenAndX message that ran earlier in this packet.  In this case, the fid
1065  * field in a read, for example, request, isn't set, since the value is
1066  * supposed to be inherited from the openAndX call.
1067  */
1068 int smb_ChainFID(int fid, smb_packet_t *inp)
1069 {
1070     if (inp->fid == 0 || inp->inCount == 0) 
1071         return fid;
1072     else 
1073         return inp->fid;
1074 }
1075
1076 /* are we a priv'd user?  What does this mean on NT? */
1077 int smb_SUser(cm_user_t *userp)
1078 {
1079     return 1;
1080 }
1081
1082 /* find a file ID.  If we pass in 0 we select an used File ID.
1083  * If the SMB_FLAG_CREATE flag is set, we allocate a new  
1084  * smb_fid_t data structure if desired File ID cannot be found.
1085  */
1086 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1087 {
1088     smb_fid_t *fidp;
1089     int newFid = 0;
1090         
1091     if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1092         return NULL;
1093
1094     lock_ObtainWrite(&smb_rctLock);
1095     /* figure out if we need to allocate a new file ID */
1096     if (fid == 0) {
1097         newFid = 1;
1098         fid = vcp->fidCounter;
1099     }
1100
1101   retry:
1102     for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1103         if (fid == fidp->fid) {
1104             if (newFid) {
1105                 fid++;
1106                 if (fid == 0) 
1107                     fid = 1;
1108                 goto retry;
1109             }
1110             fidp->refCount++;
1111             break;
1112         }
1113     }
1114     if (!fidp && (flags & SMB_FLAG_CREATE)) {
1115         char eventName[MAX_PATH];
1116         EVENT_HANDLE event;
1117         sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1118         event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1119         if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1120             osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1121             thrd_CloseHandle(event);
1122             fid++;
1123             if (fid == 0)
1124                 fid = 1;
1125             goto retry;
1126         }
1127
1128         fidp = malloc(sizeof(*fidp));
1129         memset(fidp, 0, sizeof(*fidp));
1130         osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1131         fidp->refCount = 1;
1132         fidp->vcp = vcp;
1133         vcp->refCount++;
1134         lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1135         fidp->fid = fid;
1136         fidp->curr_chunk = fidp->prev_chunk = -2;
1137         fidp->raw_write_event = event;
1138         if (newFid) {
1139             vcp->fidCounter = fid+1;
1140             if (vcp->fidCounter == 0) 
1141                 vcp->fidCounter = 1;
1142         }
1143     }
1144     lock_ReleaseWrite(&smb_rctLock);
1145     return fidp;
1146 }
1147
1148 void smb_ReleaseFID(smb_fid_t *fidp)
1149 {
1150     cm_scache_t *scp;
1151     smb_vc_t *vcp = NULL;
1152     smb_ioctl_t *ioctlp;
1153
1154     if (!fidp)
1155         return;
1156
1157     scp = NULL;
1158     lock_ObtainWrite(&smb_rctLock);
1159     osi_assert(fidp->refCount-- > 0);
1160     if (fidp->refCount == 0 && (fidp->flags & SMB_FID_DELETE)) {
1161         vcp = fidp->vcp;
1162         if (!(fidp->flags & SMB_FID_IOCTL))
1163             scp = fidp->scp;
1164         osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1165         thrd_CloseHandle(fidp->raw_write_event);
1166
1167         /* and see if there is ioctl stuff to free */
1168         ioctlp = fidp->ioctlp;
1169         if (ioctlp) {
1170             if (ioctlp->prefix) cm_FreeSpace(ioctlp->prefix);
1171             if (ioctlp->inAllocp) free(ioctlp->inAllocp);
1172             if (ioctlp->outAllocp) free(ioctlp->outAllocp);
1173             free(ioctlp);
1174         }       
1175
1176         free(fidp);
1177
1178         /* do not call smb_ReleaseVC() because we already have the lock */
1179         vcp->refCount--;
1180     }
1181     lock_ReleaseWrite(&smb_rctLock);
1182
1183     /* now release the scache structure */
1184     if (scp) 
1185         cm_ReleaseSCache(scp);
1186 }       
1187
1188 /*
1189  * Case-insensitive search for one string in another;
1190  * used to find variable names in submount pathnames.
1191  */
1192 static char *smb_stristr(char *str1, char *str2)
1193 {
1194     char *cursor;
1195
1196     for (cursor = str1; *cursor; cursor++)
1197         if (stricmp(cursor, str2) == 0)
1198             return cursor;
1199
1200     return NULL;
1201 }
1202
1203 /*
1204  * Substitute a variable value for its name in a submount pathname.  Variable
1205  * name has been identified by smb_stristr() and is in substr.  Variable name
1206  * length (plus one) is in substr_size.  Variable value is in newstr.
1207  */
1208 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1209                       char *newstr)
1210 {
1211     char temp[1024];
1212
1213     strcpy(temp, substr + substr_size - 1);
1214     strcpy(substr, newstr);
1215     strcat(str1, temp);
1216 }       
1217
1218 char VNUserName[] = "%USERNAME%";
1219 char VNLCUserName[] = "%LCUSERNAME%";
1220 char VNComputerName[] = "%COMPUTERNAME%";
1221 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1222
1223 #ifdef DJGPP
1224 /* List available shares */
1225 int smb_ListShares()
1226 {
1227     char sbmtpath[256];
1228     char pathName[256];
1229     char shareBuf[4096];
1230     int num_shares=0;
1231     char *this_share;
1232     int len;
1233     char *p;
1234     int print_afs = 0;
1235     int code;
1236
1237     /*strcpy(shareNameList[num_shares], "all");
1238       strcpy(pathNameList[num_shares++], "/afs");*/
1239     fprintf(stderr, "The following shares are available:\n");
1240     fprintf(stderr, "Share Name (AFS Path)\n");
1241     fprintf(stderr, "---------------------\n");
1242     fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
1243
1244 #ifndef DJGPP
1245     code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1246     if (code == 0 || code > sizeof(sbmtpath)) return -1;
1247 #else
1248     strcpy(sbmtpath, cm_confDir);
1249 #endif /* !DJGPP */
1250     strcat(sbmtpath, "/afsdsbmt.ini");
1251     len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1252                                    shareBuf, sizeof(shareBuf),
1253                                    sbmtpath);
1254     if (len == 0) {
1255         return num_shares;
1256     }
1257
1258     this_share = shareBuf;
1259     do
1260     {
1261         print_afs = 0;
1262         /*strcpy(shareNameList[num_shares], this_share);*/
1263         len = GetPrivateProfileString("AFS Submounts", this_share,
1264                                        NULL,
1265                                        pathName, 256,
1266                                        sbmtpath);
1267         if (!len) 
1268             return num_shares;
1269         p = pathName;
1270         if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) != 0)
1271             print_afs = 1;
1272         while (*p) {
1273             if (*p == '\\') *p = '/';    /* change to / */
1274             p++;
1275         }
1276
1277         fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1278                  smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
1279                  pathName);
1280         num_shares++;
1281         while (*this_share != 0) this_share++;  /* find next NUL */
1282         this_share++;   /* skip past the NUL */
1283     } while (*this_share != 0);  /* stop at final NUL */
1284
1285     return num_shares;
1286 }
1287 #endif /* DJGPP */
1288
1289 typedef struct smb_findShare_rock {
1290     char * shareName;
1291     char * match;
1292     int matchType;
1293 } smb_findShare_rock_t;
1294
1295 #define SMB_FINDSHARE_EXACT_MATCH 1
1296 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1297
1298 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1299                        osi_hyper_t *offp)
1300 {
1301     int matchType = 0;
1302     smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1303     if(!strnicmp(dep->name, vrock->shareName, 12)) {
1304         if(!stricmp(dep->name, vrock->shareName))
1305             matchType = SMB_FINDSHARE_EXACT_MATCH;
1306         else
1307             matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1308         if(vrock->match) free(vrock->match);
1309         vrock->match = strdup(dep->name);
1310         vrock->matchType = matchType;
1311
1312         if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1313             return CM_ERROR_STOPNOW;
1314     }
1315     return 0;
1316 }
1317
1318
1319 /* find a shareName in the table of submounts */
1320 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1321         char **pathNamep)
1322 {
1323     DWORD len;
1324     char pathName[1024];
1325     char *var;
1326     char temp[1024];
1327     DWORD sizeTemp;
1328 #ifdef DJGPP
1329     char sbmtpath[MAX_PATH];
1330 #endif
1331     char *p, *q;
1332     HKEY parmKey;
1333     DWORD code;
1334     DWORD allSubmount = 1;
1335
1336     /* if allSubmounts == 0, only return the //mountRoot/all share 
1337      * if in fact it has been been created in the subMounts table.  
1338      * This is to allow sites that want to restrict access to the 
1339      * world to do so.
1340      */
1341     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName,
1342                          0, KEY_QUERY_VALUE, &parmKey);
1343     if (code == ERROR_SUCCESS) {
1344         len = sizeof(allSubmount);
1345         code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1346                                 (BYTE *) &allSubmount, &len);
1347         if (code != ERROR_SUCCESS) {
1348             allSubmount = 1;
1349         }
1350         RegCloseKey (parmKey);
1351     }
1352
1353     if (allSubmount && _stricmp(shareName, "all") == 0) {
1354         *pathNamep = NULL;
1355         return 1;
1356     }
1357
1358     /* In case, the all share is disabled we need to still be able
1359      * to handle ioctl requests 
1360      */
1361     if (_stricmp(shareName, "ioctl$") == 0) {
1362         *pathNamep = strdup("/.__ioctl__");
1363         return 1;
1364     }
1365
1366     if (_stricmp(shareName, "IPC$") == 0 ||
1367         _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1368         _stricmp(shareName, "DESKTOP.INI") == 0
1369          ) {
1370         *pathNamep = NULL;
1371         return 0;
1372     }
1373
1374 #ifndef DJGPP
1375     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts",
1376                          0, KEY_QUERY_VALUE, &parmKey);
1377     if (code == ERROR_SUCCESS) {
1378         len = sizeof(pathName);
1379         code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1380                                 (BYTE *) pathName, &len);
1381         if (code != ERROR_SUCCESS)
1382             len = 0;
1383         RegCloseKey (parmKey);
1384     } else {
1385         len = 0;
1386     }   
1387 #else /* DJGPP */
1388     strcpy(sbmtpath, cm_confDir);
1389     strcat(sbmtpath, "/afsdsbmt.ini");
1390     len = GetPrivateProfileString("AFS Submounts", shareName, "",
1391                                    pathName, sizeof(pathName), sbmtpath);
1392 #endif /* !DJGPP */
1393     if (len != 0 && len != sizeof(pathName) - 1) {
1394         /* We can accept either unix or PC style AFS pathnames.  Convert
1395          * Unix-style to PC style here for internal use. 
1396          */
1397         p = pathName;
1398         if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1399             p += strlen(cm_mountRoot);  /* skip mount path */
1400         q = p;
1401         while (*q) {
1402             if (*q == '/') *q = '\\';    /* change to \ */
1403             q++;
1404         }
1405
1406         while (1)
1407         {
1408             if (var = smb_stristr(p, VNUserName)) {
1409                 if (uidp && uidp->unp)
1410                     smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1411                 else
1412                     smb_subst(p, var, sizeof(VNUserName)," ");
1413             }
1414             else if (var = smb_stristr(p, VNLCUserName)) 
1415             {
1416                 if (uidp && uidp->unp)
1417                     strcpy(temp, uidp->unp->name);
1418                 else 
1419                     strcpy(temp, " ");
1420                 _strlwr(temp);
1421                 smb_subst(p, var, sizeof(VNLCUserName), temp);
1422             }
1423             else if (var = smb_stristr(p, VNComputerName)) 
1424             {
1425                 sizeTemp = sizeof(temp);
1426                 GetComputerName((LPTSTR)temp, &sizeTemp);
1427                 smb_subst(p, var, sizeof(VNComputerName), temp);
1428             }
1429             else if (var = smb_stristr(p, VNLCComputerName)) 
1430             {
1431                 sizeTemp = sizeof(temp);
1432                 GetComputerName((LPTSTR)temp, &sizeTemp);
1433                 _strlwr(temp);
1434                 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1435             }
1436             else     
1437                 break;
1438         }
1439         *pathNamep = strdup(p);
1440         return 1;
1441     } 
1442     else
1443     {
1444         /* First lookup shareName in root.afs */
1445         cm_req_t req;
1446         smb_findShare_rock_t vrock;
1447         osi_hyper_t thyper;
1448         char * p = shareName; 
1449         int rw = 0;
1450
1451         /*  attempt to locate a partial match in root.afs.  This is because
1452             when using the ANSI RAP calls, the share name is limited to 13 chars
1453             and hence is truncated. Of course we prefer exact matches. */
1454         cm_InitReq(&req);
1455         thyper.HighPart = 0;
1456         thyper.LowPart = 0;
1457
1458         vrock.shareName = shareName;
1459         vrock.match = NULL;
1460         vrock.matchType = 0;
1461
1462         cm_HoldSCache(cm_rootSCachep);
1463         code = cm_ApplyDir(cm_rootSCachep, smb_FindShareProc, &vrock, &thyper,
1464             (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1465         cm_ReleaseSCache(cm_rootSCachep);
1466
1467         if(vrock.matchType) {
1468             sprintf(pathName,"/%s/",vrock.match);
1469             *pathNamep = strdup(strlwr(pathName));
1470             free(vrock.match);
1471             return 1;
1472         }
1473
1474         /* if we get here, there was no match for the share in root.afs */
1475         /* so try to create  \\<netbiosName>\<cellname>  */
1476         if ( *p == '.' ) {
1477             p++;
1478             rw = 1;
1479         }
1480         /* Get the full name for this cell */
1481         code = cm_SearchCellFile(p, temp, 0, 0);
1482 #ifdef AFS_AFSDB_ENV
1483                 if (code && cm_dnsEnabled) {
1484             int ttl;
1485             code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1486         }
1487 #endif
1488         /* construct the path */
1489         if (code == 0) {     
1490             sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1491             *pathNamep = strdup(strlwr(pathName));
1492             return 1;
1493         }
1494     }
1495     /* failure */
1496     *pathNamep = NULL;
1497     return 0;
1498 }
1499
1500 /* Client-side offline caching policy types */
1501 #define CSC_POLICY_MANUAL 0
1502 #define CSC_POLICY_DOCUMENTS 1
1503 #define CSC_POLICY_PROGRAMS 2
1504 #define CSC_POLICY_DISABLE 3
1505
1506 int smb_FindShareCSCPolicy(char *shareName)
1507 {
1508     DWORD len;
1509     char policy[1024];
1510     DWORD dwType;
1511     HKEY hkCSCPolicy;
1512     int  retval = CSC_POLICY_MANUAL;
1513
1514     RegCreateKeyEx( HKEY_LOCAL_MACHINE, 
1515                     "SOFTWARE\\OpenAFS\\Client\\CSCPolicy",
1516                     0, 
1517                     "AFS", 
1518                     REG_OPTION_NON_VOLATILE,
1519                     KEY_READ,
1520                     NULL, 
1521                     &hkCSCPolicy,
1522                     NULL );
1523
1524     len = sizeof(policy);
1525     if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1526          len == 0) {
1527         retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1528     }
1529     else if (stricmp(policy, "documents") == 0)
1530     {
1531         retval = CSC_POLICY_DOCUMENTS;
1532     }
1533     else if (stricmp(policy, "programs") == 0)
1534     {
1535         retval = CSC_POLICY_PROGRAMS;
1536     }
1537     else if (stricmp(policy, "disable") == 0)
1538     {
1539         retval = CSC_POLICY_DISABLE;
1540     }
1541         
1542     RegCloseKey(hkCSCPolicy);
1543     return retval;
1544 }
1545
1546 /* find a dir search structure by cookie value, and return it held.
1547  * Must be called with smb_globalLock held.
1548  */
1549 smb_dirSearch_t *smb_FindDirSearchNL(long cookie)
1550 {
1551     smb_dirSearch_t *dsp;
1552         
1553     for(dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1554         if (dsp->cookie == cookie) {
1555             if (dsp != smb_firstDirSearchp) {
1556                 /* move to head of LRU queue, too, if we're not already there */
1557                 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1558                     smb_lastDirSearchp = (smb_dirSearch_t *)
1559                         osi_QPrev(&dsp->q);
1560                 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1561                 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1562                 if (!smb_lastDirSearchp)
1563                     smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1564             }
1565             dsp->refCount++;
1566             break;
1567         }
1568     }
1569     return dsp;
1570 }       
1571
1572 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1573 {
1574     lock_ObtainWrite(&smb_globalLock);
1575     dsp->flags |= SMB_DIRSEARCH_DELETE;
1576     lock_ReleaseWrite(&smb_globalLock);
1577     lock_ObtainMutex(&dsp->mx);
1578     if(dsp->scp != NULL) {
1579         lock_ObtainMutex(&dsp->scp->mx);
1580         if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1581             dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1582             dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1583             dsp->scp->bulkStatProgress = hones;
1584         }       
1585         lock_ReleaseMutex(&dsp->scp->mx);
1586     }   
1587     lock_ReleaseMutex(&dsp->mx);
1588 }               
1589
1590 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1591 {
1592     cm_scache_t *scp;
1593         
1594     scp = NULL;
1595
1596     lock_ObtainWrite(&smb_globalLock);
1597     osi_assert(dsp->refCount-- > 0);
1598     if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1599         if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1600             smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1601         osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1602         lock_FinalizeMutex(&dsp->mx);
1603         scp = dsp->scp;
1604         free(dsp);
1605     }
1606     lock_ReleaseWrite(&smb_globalLock);
1607
1608     /* do this now to avoid spurious locking hierarchy creation */
1609     if (scp) cm_ReleaseSCache(scp);
1610 }       
1611
1612 /* find a dir search structure by cookie value, and return it held */
1613 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1614 {
1615     smb_dirSearch_t *dsp;
1616
1617     lock_ObtainWrite(&smb_globalLock);
1618     dsp = smb_FindDirSearchNL(cookie);
1619     lock_ReleaseWrite(&smb_globalLock);
1620     return dsp;
1621 }
1622
1623 /* GC some dir search entries, in the address space expected by the specific protocol.
1624  * Must be called with smb_globalLock held; release the lock temporarily.
1625  */
1626 #define SMB_DIRSEARCH_GCMAX     10      /* how many at once */
1627 void smb_GCDirSearches(int isV3)
1628 {
1629     smb_dirSearch_t *prevp;
1630     smb_dirSearch_t *tp;
1631     smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1632     int victimCount;
1633     int i;
1634         
1635     victimCount = 0;    /* how many have we got so far */
1636     for(tp = smb_lastDirSearchp; tp; tp=prevp) {
1637         /* we'll move tp from queue, so
1638          * do this early.
1639          */
1640         prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);  
1641         /* if no one is using this guy, and we're either in the new protocol,
1642          * or we're in the old one and this is a small enough ID to be useful
1643          * to the old protocol, GC this guy.
1644          */
1645         if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1646             /* hold and delete */
1647             tp->flags |= SMB_DIRSEARCH_DELETE;
1648             victimsp[victimCount++] = tp;
1649             tp->refCount++;
1650         }
1651
1652         /* don't do more than this */
1653         if (victimCount >= SMB_DIRSEARCH_GCMAX) break;
1654     }
1655         
1656     /* now release them */
1657     lock_ReleaseWrite(&smb_globalLock);
1658     for(i = 0; i < victimCount; i++) {
1659         smb_ReleaseDirSearch(victimsp[i]);
1660     }
1661     lock_ObtainWrite(&smb_globalLock);
1662 }
1663
1664 /* function for allocating a dir search entry.  We need these to remember enough context
1665  * since we don't get passed the path from call to call during a directory search.
1666  *
1667  * Returns a held dir search structure, and bumps the reference count on the vnode,
1668  * since it saves a pointer to the vnode.
1669  */
1670 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1671 {
1672     smb_dirSearch_t *dsp;
1673     int counter;
1674     int maxAllowed;
1675
1676     lock_ObtainWrite(&smb_globalLock);
1677     counter = 0;
1678
1679     /* what's the biggest ID allowed in this version of the protocol */
1680     if (isV3) maxAllowed = 65535;
1681     else maxAllowed = 255;
1682
1683     while(1) {
1684         /* twice so we have enough tries to find guys we GC after one pass;
1685          * 10 extra is just in case I mis-counted.
1686          */
1687         if (++counter > 2*maxAllowed+10) osi_panic("afsd: dir search cookie leak",
1688                                                     __FILE__, __LINE__);
1689         if (smb_dirSearchCounter > maxAllowed) {        
1690             smb_dirSearchCounter = 1;
1691             smb_GCDirSearches(isV3);    /* GC some (drops global lock) */
1692         }       
1693         dsp = smb_FindDirSearchNL(smb_dirSearchCounter);
1694         if (dsp) {
1695             /* don't need to watch for refcount zero and deleted, since
1696             * we haven't dropped the global lock.
1697             */
1698             dsp->refCount--;
1699             ++smb_dirSearchCounter;
1700             continue;
1701         }       
1702
1703         dsp = malloc(sizeof(*dsp));
1704         memset(dsp, 0, sizeof(*dsp));
1705         osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1706         if (!smb_lastDirSearchp) smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1707         dsp->cookie = smb_dirSearchCounter;
1708         ++smb_dirSearchCounter;
1709         dsp->refCount = 1;
1710         lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
1711         dsp->lastTime = osi_Time();
1712         break;
1713     }   
1714     lock_ReleaseWrite(&smb_globalLock);
1715     return dsp;
1716 }
1717
1718 static smb_packet_t *GetPacket(void)
1719 {
1720     smb_packet_t *tbp;
1721 #ifdef DJGPP
1722     unsigned int npar, seg, tb_sel;
1723 #endif
1724
1725     lock_ObtainWrite(&smb_globalLock);
1726     tbp = smb_packetFreeListp;
1727     if (tbp) 
1728         smb_packetFreeListp = tbp->nextp;
1729     lock_ReleaseWrite(&smb_globalLock);
1730     if (!tbp) {
1731 #ifndef DJGPP
1732         tbp = calloc(65540,1);
1733 #else /* DJGPP */
1734         tbp = malloc(sizeof(smb_packet_t));
1735 #endif /* !DJGPP */
1736         tbp->magic = SMB_PACKETMAGIC;
1737         tbp->ncbp = NULL;
1738         tbp->vcp = NULL;
1739         tbp->resumeCode = 0;
1740         tbp->inCount = 0;
1741         tbp->fid = 0;
1742         tbp->wctp = NULL;
1743         tbp->inCom = 0;
1744         tbp->oddByte = 0;
1745         tbp->ncb_length = 0;
1746         tbp->flags = 0;
1747         tbp->spacep = NULL;
1748         
1749 #ifdef DJGPP
1750         npar = SMB_PACKETSIZE >> 4;  /* number of paragraphs */
1751         {
1752             signed int retval =
1753                 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1754             if (retval == -1) {
1755                 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS memory",
1756                           npar);
1757                 osi_panic("",__FILE__,__LINE__);
1758             }
1759             else {
1760                 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X",
1761                           npar, retval);
1762                 seg = retval;
1763             }
1764         }
1765         tbp->dos_pkt = (seg * 16) + 0;  /* DOS physical address */
1766         tbp->dos_pkt_sel = tb_sel;
1767 #endif /* DJGPP */
1768     }
1769     osi_assert(tbp->magic == SMB_PACKETMAGIC);
1770
1771     return tbp;
1772 }
1773
1774 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
1775 {
1776     smb_packet_t *tbp;
1777     tbp = GetPacket();
1778     memcpy(tbp, pkt, sizeof(smb_packet_t));
1779     tbp->wctp = tbp->data + ((unsigned int)pkt->wctp - (unsigned int)pkt->data);
1780     return tbp;
1781 }
1782
1783 static NCB *GetNCB(void)
1784 {
1785     smb_ncb_t *tbp;
1786     NCB *ncbp;
1787 #ifdef DJGPP
1788     unsigned int npar, seg, tb_sel;
1789 #endif /* DJGPP */
1790
1791     lock_ObtainWrite(&smb_globalLock);
1792     tbp = smb_ncbFreeListp;
1793     if (tbp) 
1794         smb_ncbFreeListp = tbp->nextp;
1795     lock_ReleaseWrite(&smb_globalLock);
1796     if (!tbp) {
1797 #ifndef DJGPP
1798         tbp = calloc(sizeof(*tbp),1);
1799 #else /* DJGPP */
1800         tbp = malloc(sizeof(*tbp));
1801         npar = (sizeof(NCB)+15) >> 4;  /* number of paragraphs */
1802         {
1803             signed int retval =
1804                 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1805             if (retval == -1) {
1806                 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS mem in GetNCB",
1807                           npar);
1808                 osi_panic("",__FILE__,__LINE__);
1809             } else {
1810                 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
1811                           npar, retval);
1812                 seg = retval;
1813             }
1814         }
1815         tbp->dos_ncb = (seg * 16) + 0;  /* DOS physical address */
1816         tbp->dos_ncb_sel = tb_sel;
1817 #endif /* !DJGPP */
1818         tbp->magic = SMB_NCBMAGIC;
1819     }
1820         
1821     osi_assert(tbp->magic == SMB_NCBMAGIC);
1822
1823     memset(&tbp->ncb, 0, sizeof(NCB));
1824     ncbp = &tbp->ncb;
1825 #ifdef DJGPP
1826     dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
1827 #endif /* DJGPP */
1828     return ncbp;
1829 }
1830
1831 void smb_FreePacket(smb_packet_t *tbp)
1832 {
1833     osi_assert(tbp->magic == SMB_PACKETMAGIC);
1834         
1835     lock_ObtainWrite(&smb_globalLock);
1836     tbp->nextp = smb_packetFreeListp;
1837     smb_packetFreeListp = tbp;
1838     tbp->magic = SMB_PACKETMAGIC;
1839     tbp->ncbp = NULL;
1840     tbp->vcp = NULL;
1841     tbp->resumeCode = 0;
1842     tbp->inCount = 0;
1843     tbp->fid = 0;
1844     tbp->wctp = NULL;
1845     tbp->inCom = 0;
1846     tbp->oddByte = 0;
1847     tbp->ncb_length = 0;
1848     tbp->flags = 0;
1849     lock_ReleaseWrite(&smb_globalLock);
1850 }
1851
1852 static void FreeNCB(NCB *bufferp)
1853 {
1854     smb_ncb_t *tbp;
1855         
1856     tbp = (smb_ncb_t *) bufferp;
1857     osi_assert(tbp->magic == SMB_NCBMAGIC);
1858         
1859     lock_ObtainWrite(&smb_globalLock);
1860     tbp->nextp = smb_ncbFreeListp;
1861     smb_ncbFreeListp = tbp;
1862     lock_ReleaseWrite(&smb_globalLock);
1863 }
1864
1865 /* get a ptr to the data part of a packet, and its count */
1866 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
1867 {
1868     int parmBytes;
1869     int dataBytes;
1870     unsigned char *afterParmsp;
1871
1872     parmBytes = *smbp->wctp << 1;
1873     afterParmsp = smbp->wctp + parmBytes + 1;
1874         
1875     dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
1876     if (nbytesp) *nbytesp = dataBytes;
1877         
1878     /* don't forget to skip the data byte count, since it follows
1879      * the parameters; that's where the "2" comes from below.
1880      */
1881     return (unsigned char *) (afterParmsp + 2);
1882 }
1883
1884 /* must set all the returned parameters before playing around with the
1885  * data region, since the data region is located past the end of the
1886  * variable number of parameters.
1887  */
1888 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
1889 {
1890     unsigned char *afterParmsp;
1891
1892     afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
1893         
1894     *afterParmsp++ = dsize & 0xff;
1895     *afterParmsp = (dsize>>8) & 0xff;
1896 }       
1897
1898 /* return the parm'th parameter in the smbp packet */
1899 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
1900 {
1901     int parmCount;
1902     unsigned char *parmDatap;
1903
1904     parmCount = *smbp->wctp;
1905
1906     if (parm >= parmCount) {
1907         char s[100];
1908 #ifndef DJGPP
1909         HANDLE h;
1910         char *ptbuf[1];
1911         h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1912 #endif  
1913         sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
1914                  parm, parmCount, smbp->ncb_length);
1915 #ifndef DJGPP   
1916         ptbuf[0] = s;
1917         ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1918                      1, smbp->ncb_length, ptbuf, smbp);
1919         DeregisterEventSource(h);
1920 #endif
1921         osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
1922         osi_panic(s, __FILE__, __LINE__);
1923     }
1924     parmDatap = smbp->wctp + (2*parm) + 1;
1925         
1926     return parmDatap[0] + (parmDatap[1] << 8);
1927 }
1928
1929 /* return the parm'th parameter in the smbp packet */
1930 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
1931 {
1932     int parmCount;
1933     unsigned char *parmDatap;
1934
1935     parmCount = *smbp->wctp;
1936
1937     if (parm * 2 + offset >= parmCount * 2) {
1938         char s[100];
1939 #ifndef DJGPP
1940         HANDLE h;
1941         char *ptbuf[1];
1942         h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1943 #endif
1944         sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
1945                 parm, offset, parmCount, smbp->ncb_length);
1946 #ifndef DJGPP
1947         ptbuf[0] = s;
1948         ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1949                     1, smbp->ncb_length, ptbuf, smbp);
1950         DeregisterEventSource(h);
1951 #endif
1952         osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
1953         osi_panic(s, __FILE__, __LINE__);
1954     }
1955     parmDatap = smbp->wctp + (2*parm) + 1 + offset;
1956         
1957     return parmDatap[0] + (parmDatap[1] << 8);
1958 }
1959
1960 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
1961 {
1962     char *parmDatap;
1963
1964     /* make sure we have enough slots */
1965     if (*smbp->wctp <= slot) 
1966         *smbp->wctp = slot+1;
1967         
1968     parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1969     *parmDatap++ = parmValue & 0xff;
1970     *parmDatap = (parmValue>>8) & 0xff;
1971 }       
1972
1973 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
1974 {
1975     char *parmDatap;
1976
1977     /* make sure we have enough slots */
1978     if (*smbp->wctp <= slot) 
1979         *smbp->wctp = slot+2;
1980
1981     parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1982     *parmDatap++ = parmValue & 0xff;
1983     *parmDatap++ = (parmValue>>8) & 0xff;
1984     *parmDatap++ = (parmValue>>16) & 0xff;
1985     *parmDatap++ = (parmValue>>24) & 0xff;
1986 }
1987
1988 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
1989 {
1990     char *parmDatap;
1991     int i;
1992
1993     /* make sure we have enough slots */
1994     if (*smbp->wctp <= slot) 
1995         *smbp->wctp = slot+4;
1996
1997     parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1998     for (i=0; i<8; i++)
1999         *parmDatap++ = *parmValuep++;
2000 }       
2001
2002 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2003 {
2004     char *parmDatap;
2005
2006     /* make sure we have enough slots */
2007     if (*smbp->wctp <= slot) {
2008         if (smbp->oddByte) {
2009             smbp->oddByte = 0;
2010             *smbp->wctp = slot+1;
2011         } else
2012             smbp->oddByte = 1;
2013     }
2014
2015     parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2016     *parmDatap++ = parmValue & 0xff;
2017 }
2018
2019 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2020 {
2021     char *lastSlashp;
2022         
2023     lastSlashp = strrchr(inPathp, '\\');
2024     if (lastComponentp)
2025         *lastComponentp = lastSlashp;
2026     if (lastSlashp) {
2027         while (1) {
2028             if (inPathp == lastSlashp) 
2029                 break;
2030             *outPathp++ = *inPathp++;
2031         }
2032         *outPathp++ = 0;
2033     }
2034     else {
2035         *outPathp++ = 0;
2036     }
2037 }
2038
2039 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2040 {
2041     if (*inp++ != 0x4) 
2042         return NULL;
2043     if (chainpp) {
2044         *chainpp = inp + strlen(inp) + 1;       /* skip over null-terminated string */
2045     }
2046     return inp;
2047 }
2048
2049 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2050 {
2051     int tlen;
2052
2053     if (*inp++ != 0x5) 
2054         return NULL;
2055     tlen = inp[0] + (inp[1]<<8);
2056     inp += 2;           /* skip length field */
2057
2058     if (chainpp) {
2059         *chainpp = inp + tlen;
2060     }
2061         
2062     if (lengthp) 
2063         *lengthp = tlen;
2064         
2065     return inp;
2066 }       
2067
2068 /* format a packet as a response */
2069 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2070 {
2071     smb_t *outp;
2072     smb_t *inSmbp;
2073
2074     outp = (smb_t *) op;
2075         
2076     /* zero the basic structure through the smb_wct field, and zero the data
2077      * size field, assuming that wct stays zero; otherwise, you have to 
2078      * explicitly set the data size field, too.
2079      */
2080     inSmbp = (smb_t *) inp;
2081     memset(outp, 0, sizeof(smb_t)+2);
2082     outp->id[0] = 0xff;
2083     outp->id[1] = 'S';
2084     outp->id[2] = 'M';
2085     outp->id[3] = 'B';
2086     if (inp) {
2087         outp->com = inSmbp->com;
2088         outp->tid = inSmbp->tid;
2089         outp->pid = inSmbp->pid;
2090         outp->uid = inSmbp->uid;
2091         outp->mid = inSmbp->mid;
2092         outp->res[0] = inSmbp->res[0];
2093         outp->res[1] = inSmbp->res[1];
2094         op->inCom = inSmbp->com;
2095     }
2096     outp->reb = 0x80;   /* SERVER_RESP */
2097     outp->flg2 = 0x1;   /* KNOWS_LONG_NAMES */
2098
2099     /* copy fields in generic packet area */
2100     op->wctp = &outp->wct;
2101 }       
2102
2103 /* send a (probably response) packet; vcp tells us to whom to send it.
2104  * we compute the length by looking at wct and bcc fields.
2105  */
2106 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2107 {
2108     NCB *ncbp;
2109     int extra;
2110     long code = 0;
2111     unsigned char *tp;
2112     int localNCB = 0;
2113 #ifdef DJGPP
2114     dos_ptr dos_ncb;
2115 #endif /* DJGPP */
2116         
2117     ncbp = inp->ncbp;
2118     if (ncbp == NULL) {
2119         ncbp = GetNCB();
2120         localNCB = 1;
2121     }
2122 #ifdef DJGPP
2123     dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2124 #endif /* DJGPP */
2125  
2126     memset((char *)ncbp, 0, sizeof(NCB));
2127
2128     extra = 2 * (*inp->wctp);   /* space used by parms, in bytes */
2129     tp = inp->wctp + 1+ extra;  /* points to count of data bytes */
2130     extra += tp[0] + (tp[1]<<8);
2131     extra += ((unsigned int)inp->wctp - (unsigned int)inp->data);       /* distance to last wct field */
2132     extra += 3;                 /* wct and length fields */
2133         
2134     ncbp->ncb_length = extra;   /* bytes to send */
2135     ncbp->ncb_lsn = (unsigned char) vcp->lsn;   /* vc to use */
2136     ncbp->ncb_lana_num = vcp->lana;
2137     ncbp->ncb_command = NCBSEND;        /* op means send data */
2138 #ifndef DJGPP
2139     ncbp->ncb_buffer = (char *) inp;/* packet */
2140     code = Netbios(ncbp);
2141 #else /* DJGPP */
2142     ncbp->ncb_buffer = inp->dos_pkt;/* packet */
2143     ((smb_ncb_t*)ncbp)->orig_pkt = inp;
2144
2145     /* copy header information from virtual to DOS address space */
2146     dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
2147     code = Netbios(ncbp, dos_ncb);
2148 #endif /* !DJGPP */
2149         
2150     if (code != 0)
2151         osi_Log1(smb_logp, "SendPacket failure code %d", code);
2152
2153     if (localNCB)
2154         FreeNCB(ncbp);
2155 }
2156
2157 void smb_MapNTError(long code, unsigned long *NTStatusp)
2158 {
2159     unsigned long NTStatus;
2160
2161     /* map CM_ERROR_* errors to NT 32-bit status codes */
2162     /* NT Status codes are listed in ntstatus.h not winerror.h */
2163     if (code == CM_ERROR_NOSUCHCELL) {
2164         NTStatus = 0xC000000FL; /* No such file */
2165     }
2166     else if (code == CM_ERROR_NOSUCHVOLUME) {
2167         NTStatus = 0xC000000FL; /* No such file */
2168     }
2169     else if (code == CM_ERROR_TIMEDOUT) {
2170         NTStatus = 0xC00000CFL; /* Sharing Paused */
2171     }
2172     else if (code == CM_ERROR_RETRY) {
2173         NTStatus = 0xC000022DL; /* Retry */
2174     }
2175     else if (code == CM_ERROR_NOACCESS) {
2176         NTStatus = 0xC0000022L; /* Access denied */
2177     }
2178     else if (code == CM_ERROR_READONLY) {
2179         NTStatus = 0xC00000A2L; /* Write protected */
2180     }   
2181     else if (code == CM_ERROR_NOSUCHFILE) {
2182         NTStatus = 0xC000000FL; /* No such file */
2183     }
2184     else if (code == CM_ERROR_NOSUCHPATH) {
2185         NTStatus = 0xC000003AL; /* Object path not found */
2186     }           
2187     else if (code == CM_ERROR_TOOBIG) {
2188         NTStatus = 0xC000007BL; /* Invalid image format */
2189     }
2190     else if (code == CM_ERROR_INVAL) {
2191         NTStatus = 0xC000000DL; /* Invalid parameter */
2192     }
2193     else if (code == CM_ERROR_BADFD) {
2194         NTStatus = 0xC0000008L; /* Invalid handle */
2195     }
2196     else if (code == CM_ERROR_BADFDOP) {
2197         NTStatus = 0xC0000022L; /* Access denied */
2198     }
2199     else if (code == CM_ERROR_EXISTS) {
2200         NTStatus = 0xC0000035L; /* Object name collision */
2201     }
2202     else if (code == CM_ERROR_NOTEMPTY) {
2203         NTStatus = 0xC0000101L; /* Directory not empty */
2204     }   
2205     else if (code == CM_ERROR_CROSSDEVLINK) {
2206         NTStatus = 0xC00000D4L; /* Not same device */
2207     }
2208     else if (code == CM_ERROR_NOTDIR) {
2209         NTStatus = 0xC0000103L; /* Not a directory */
2210     }
2211     else if (code == CM_ERROR_ISDIR) {
2212         NTStatus = 0xC00000BAL; /* File is a directory */
2213     }
2214     else if (code == CM_ERROR_BADOP) {
2215 #ifdef COMMENT
2216         /* I have no idea where this comes from */
2217         NTStatus = 0xC09820FFL; /* SMB no support */
2218 #else
2219         NTStatus = 0xC00000BBL;     /* Not supported */
2220 #endif /* COMMENT */
2221     }
2222     else if (code == CM_ERROR_BADSHARENAME) {
2223         NTStatus = 0xC00000CCL; /* Bad network name */
2224     }
2225     else if (code == CM_ERROR_NOIPC) {
2226 #ifdef COMMENT
2227         NTStatus = 0xC0000022L; /* Access Denied */
2228 #else   
2229         NTStatus = 0xC000013DL; /* Remote Resources */
2230 #endif
2231     }
2232     else if (code == CM_ERROR_CLOCKSKEW) {
2233         NTStatus = 0xC0000133L; /* Time difference at DC */
2234     }
2235     else if (code == CM_ERROR_BADTID) {
2236         NTStatus = 0xC0982005L; /* SMB bad TID */
2237     }
2238     else if (code == CM_ERROR_USESTD) {
2239         NTStatus = 0xC09820FBL; /* SMB use standard */
2240     }
2241     else if (code == CM_ERROR_QUOTA) {
2242 #ifdef COMMENT
2243         NTStatus = 0xC0000044L; /* Quota exceeded */
2244 #else
2245         NTStatus = 0xC000007FL; /* Disk full */
2246 #endif
2247     }
2248     else if (code == CM_ERROR_SPACE) {
2249         NTStatus = 0xC000007FL; /* Disk full */
2250     }
2251     else if (code == CM_ERROR_ATSYS) {
2252         NTStatus = 0xC0000033L; /* Object name invalid */
2253     }
2254     else if (code == CM_ERROR_BADNTFILENAME) {
2255         NTStatus = 0xC0000033L; /* Object name invalid */
2256     }
2257     else if (code == CM_ERROR_WOULDBLOCK) {
2258         NTStatus = 0xC0000055L; /* Lock not granted */
2259     }
2260     else if (code == CM_ERROR_PARTIALWRITE) {
2261         NTStatus = 0xC000007FL; /* Disk full */
2262     }
2263     else if (code == CM_ERROR_BUFFERTOOSMALL) {
2264         NTStatus = 0xC0000023L; /* Buffer too small */
2265     }
2266     else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2267         NTStatus = 0xC0000035L; /* Object name collision */
2268     }   
2269     else if (code == CM_ERROR_BADPASSWORD) {
2270         NTStatus = 0xC000006DL; /* unknown username or bad password */
2271     }
2272     else if (code == CM_ERROR_BADLOGONTYPE) {
2273         NTStatus = 0xC000015BL; /* logon type not granted */
2274     }
2275     else if (code == CM_ERROR_GSSCONTINUE) {
2276         NTStatus = 0xC0000016L; /* more processing required */
2277     }
2278     else {
2279         NTStatus = 0xC0982001L; /* SMB non-specific error */
2280     }
2281
2282     *NTStatusp = NTStatus;
2283     osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2284 }       
2285
2286 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2287                       unsigned char *classp)
2288 {
2289     unsigned char class;
2290     unsigned short error;
2291
2292     /* map CM_ERROR_* errors to SMB errors */
2293     if (code == CM_ERROR_NOSUCHCELL) {
2294         class = 1;
2295         error = 3;      /* bad path */
2296     }
2297     else if (code == CM_ERROR_NOSUCHVOLUME) {
2298         class = 1;
2299         error = 3;      /* bad path */
2300     }
2301     else if (code == CM_ERROR_TIMEDOUT) {
2302         class = 2;
2303         error = 81;     /* server is paused */
2304     }
2305     else if (code == CM_ERROR_RETRY) {
2306         class = 2;      /* shouldn't happen */
2307         error = 1;
2308     }
2309     else if (code == CM_ERROR_NOACCESS) {
2310         class = 2;
2311         error = 4;      /* bad access */
2312     }
2313     else if (code == CM_ERROR_READONLY) {
2314         class = 3;
2315         error = 19;     /* read only */
2316     }
2317     else if (code == CM_ERROR_NOSUCHFILE) {
2318         class = 1;
2319         error = 2;      /* ENOENT! */
2320     }
2321     else if (code == CM_ERROR_NOSUCHPATH) {
2322         class = 1;
2323         error = 3;      /* Bad path */
2324     }
2325     else if (code == CM_ERROR_TOOBIG) {
2326         class = 1;
2327         error = 11;     /* bad format */
2328     }
2329     else if (code == CM_ERROR_INVAL) {
2330         class = 2;      /* server non-specific error code */
2331         error = 1;
2332     }
2333     else if (code == CM_ERROR_BADFD) {
2334         class = 1;
2335         error = 6;      /* invalid file handle */
2336     }
2337     else if (code == CM_ERROR_BADFDOP) {
2338         class = 1;      /* invalid op on FD */
2339         error = 5;
2340     }
2341     else if (code == CM_ERROR_EXISTS) {
2342         class = 1;
2343         error = 80;     /* file already exists */
2344     }
2345     else if (code == CM_ERROR_NOTEMPTY) {
2346         class = 1;
2347         error = 5;      /* delete directory not empty */
2348     }
2349     else if (code == CM_ERROR_CROSSDEVLINK) {
2350         class = 1;
2351         error = 17;     /* EXDEV */
2352     }
2353     else if (code == CM_ERROR_NOTDIR) {
2354         class = 1;      /* bad path */
2355         error = 3;
2356     }
2357     else if (code == CM_ERROR_ISDIR) {
2358         class = 1;      /* access denied; DOS doesn't have a good match */
2359         error = 5;
2360     }       
2361     else if (code == CM_ERROR_BADOP) {
2362         class = 2;
2363         error = 65535;
2364     }
2365     else if (code == CM_ERROR_BADSHARENAME) {
2366         class = 2;
2367         error = 6;
2368     }
2369     else if (code == CM_ERROR_NOIPC) {
2370         class = 2;
2371         error = 4; /* bad access */
2372     }
2373     else if (code == CM_ERROR_CLOCKSKEW) {
2374         class = 1;      /* invalid function */
2375         error = 1;
2376     }
2377     else if (code == CM_ERROR_BADTID) {
2378         class = 2;
2379         error = 5;
2380     }
2381     else if (code == CM_ERROR_USESTD) {
2382         class = 2;
2383         error = 251;
2384     }
2385     else if (code == CM_ERROR_REMOTECONN) {
2386         class = 2;
2387         error = 82;
2388     }
2389     else if (code == CM_ERROR_QUOTA) {
2390         if (vcp->flags & SMB_VCFLAG_USEV3) {
2391             class = 3;
2392             error = 39; /* disk full */
2393         }
2394         else {
2395             class = 1;
2396             error = 5;  /* access denied */
2397         }
2398     }
2399     else if (code == CM_ERROR_SPACE) {
2400         if (vcp->flags & SMB_VCFLAG_USEV3) {
2401             class = 3;
2402             error = 39; /* disk full */
2403         }
2404         else {
2405             class = 1;
2406             error = 5;  /* access denied */
2407         }
2408     }
2409     else if (code == CM_ERROR_PARTIALWRITE) {
2410         class = 3;
2411         error = 39;     /* disk full */
2412     }
2413     else if (code == CM_ERROR_ATSYS) {
2414         class = 1;
2415         error = 2;      /* ENOENT */
2416     }
2417     else if (code == CM_ERROR_WOULDBLOCK) {
2418         class = 1;
2419         error = 33;     /* lock conflict */
2420     }
2421     else if (code == CM_ERROR_NOFILES) {
2422         class = 1;
2423         error = 18;     /* no files in search */
2424     }
2425     else if (code == CM_ERROR_RENAME_IDENTICAL) {
2426         class = 1;
2427         error = 183;     /* Samba uses this */
2428     }
2429     else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2430         /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2431         class = 2;
2432         error = 2; /* bad password */
2433     }
2434     else {
2435         class = 2;
2436         error = 1;
2437     }
2438
2439     *scodep = error;
2440     *classp = class;
2441     osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2442 }       
2443
2444 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2445 {
2446     osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2447     return CM_ERROR_BADOP;
2448 }
2449
2450 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2451 {
2452     unsigned short EchoCount, i;
2453     char *data, *outdata;
2454     int dataSize;
2455
2456     EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2457
2458     for (i=1; i<=EchoCount; i++) {
2459         data = smb_GetSMBData(inp, &dataSize);
2460         smb_SetSMBParm(outp, 0, i);
2461         smb_SetSMBDataLength(outp, dataSize);
2462         outdata = smb_GetSMBData(outp, NULL);
2463         memcpy(outdata, data, dataSize);
2464         smb_SendPacket(vcp, outp);
2465     }
2466
2467     return 0;
2468 }
2469
2470 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2471 {
2472     osi_hyper_t offset;
2473     long count, minCount, finalCount;
2474     unsigned short fd;
2475     smb_fid_t *fidp;
2476     long code = 0;
2477     cm_user_t *userp = NULL;
2478     NCB *ncbp;
2479     int rc;
2480 #ifndef DJGPP
2481     char *rawBuf = NULL;
2482 #else
2483     dos_ptr rawBuf = NULL;
2484     dos_ptr dos_ncb;
2485 #endif /* DJGPP */
2486
2487     rawBuf = NULL;
2488     finalCount = 0;
2489
2490     fd = smb_GetSMBParm(inp, 0);
2491     count = smb_GetSMBParm(inp, 3);
2492     minCount = smb_GetSMBParm(inp, 4);
2493     offset.HighPart = 0;        /* too bad */
2494     offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2495
2496     osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2497              fd, offset.LowPart, count);
2498
2499     fidp = smb_FindFID(vcp, fd, 0);
2500     if (!fidp)
2501         goto send1;
2502
2503     lock_ObtainMutex(&smb_RawBufLock);
2504     if (smb_RawBufs) {
2505         /* Get a raw buf, from head of list */
2506         rawBuf = smb_RawBufs;
2507 #ifndef DJGPP
2508         smb_RawBufs = *(char **)smb_RawBufs;
2509 #else /* DJGPP */
2510         smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2511 #endif /* !DJGPP */
2512     }
2513     lock_ReleaseMutex(&smb_RawBufLock);
2514     if (!rawBuf)
2515         goto send1a;
2516
2517     if (fidp->flags & SMB_FID_IOCTL)
2518     {
2519 #ifndef DJGPP
2520         rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2521 #else
2522         rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2523 #endif
2524         if (rawBuf) {
2525             /* Give back raw buffer */
2526             lock_ObtainMutex(&smb_RawBufLock);
2527 #ifndef DJGPP
2528             *((char **) rawBuf) = smb_RawBufs;
2529 #else /* DJGPP */
2530             _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2531 #endif /* !DJGPP */
2532             
2533             smb_RawBufs = rawBuf;
2534             lock_ReleaseMutex(&smb_RawBufLock);
2535         }
2536
2537         smb_ReleaseFID(fidp);
2538         return rc;
2539     }
2540         
2541     userp = smb_GetUser(vcp, inp);
2542
2543 #ifndef DJGPP
2544     code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2545 #else /* DJGPP */
2546     /* have to give ReadData flag so it will treat buffer as DOS mem. */
2547     code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2548                         userp, &finalCount, TRUE /* rawFlag */);
2549 #endif /* !DJGPP */
2550
2551     if (code != 0)
2552         goto send;
2553
2554   send:
2555     cm_ReleaseUser(userp);
2556
2557   send1a:
2558     smb_ReleaseFID(fidp);
2559
2560   send1:
2561     ncbp = outp->ncbp;
2562 #ifdef DJGPP
2563     dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2564 #endif /* DJGPP */
2565     memset((char *)ncbp, 0, sizeof(NCB));
2566
2567     ncbp->ncb_length = (unsigned short) finalCount;
2568     ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2569     ncbp->ncb_lana_num = vcp->lana;
2570     ncbp->ncb_command = NCBSEND;
2571     ncbp->ncb_buffer = rawBuf;
2572
2573 #ifndef DJGPP
2574     code = Netbios(ncbp);
2575 #else /* DJGPP */
2576     code = Netbios(ncbp, dos_ncb);
2577 #endif /* !DJGPP */
2578     if (code != 0)
2579         osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2580
2581     if (rawBuf) {
2582         /* Give back raw buffer */
2583         lock_ObtainMutex(&smb_RawBufLock);
2584 #ifndef DJGPP
2585         *((char **) rawBuf) = smb_RawBufs;
2586 #else /* DJGPP */
2587         _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2588 #endif /* !DJGPP */
2589
2590         smb_RawBufs = rawBuf;
2591         lock_ReleaseMutex(&smb_RawBufLock);
2592     }
2593
2594     return 0;
2595 }
2596
2597 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2598 {
2599     osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
2600                          ongoingOps - 1);
2601     return 0;
2602 }
2603
2604 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2605 {
2606     osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
2607                          ongoingOps - 1);
2608     return 0;
2609 }
2610
2611 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2612 {
2613     char *namep;
2614     char *datap;
2615     int coreProtoIndex;
2616     int v3ProtoIndex;
2617     int NTProtoIndex;
2618     int protoIndex;                             /* index we're using */
2619     int namex;
2620     int dbytes;
2621     int entryLength;
2622     int tcounter;
2623     char protocol_array[10][1024];  /* protocol signature of the client */
2624     int caps;                       /* capabilities */
2625     time_t unixTime;
2626     time_t dosTime;
2627     TIME_ZONE_INFORMATION tzi;
2628
2629     osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2630                          ongoingOps - 1);
2631     if (!isGateway) {
2632         if (active_vcp) {
2633             DWORD now = GetCurrentTime();
2634             if (now - last_msg_time >= 30000
2635                  && now - last_msg_time <= 90000) {
2636                 osi_Log1(smb_logp,
2637                           "Setting dead_vcp %x", active_vcp);
2638                 if (dead_vcp) {
2639                     smb_ReleaseVC(dead_vcp);
2640                     osi_Log1(smb_logp,
2641                              "Previous dead_vcp %x", dead_vcp);
2642                 }
2643                 smb_HoldVC(active_vcp);
2644                 dead_vcp = active_vcp;
2645                 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2646             }
2647         }
2648     }
2649
2650     inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
2651
2652     namep = smb_GetSMBData(inp, &dbytes);
2653     namex = 0;
2654     tcounter = 0;
2655     coreProtoIndex = -1;                /* not found */
2656     v3ProtoIndex = -1;
2657     NTProtoIndex = -1;
2658     while(namex < dbytes) {
2659         osi_Log1(smb_logp, "Protocol %s",
2660                   osi_LogSaveString(smb_logp, namep+1));
2661         strcpy(protocol_array[tcounter], namep+1);
2662
2663         /* namep points at the first protocol, or really, a 0x02
2664          * byte preceding the null-terminated ASCII name.
2665          */
2666         if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2667             coreProtoIndex = tcounter;
2668         }       
2669         else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2670             v3ProtoIndex = tcounter;
2671         }
2672         else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
2673             NTProtoIndex = tcounter;
2674         }
2675
2676         /* compute size of protocol entry */
2677         entryLength = strlen(namep+1);
2678         entryLength += 2;       /* 0x02 bytes and null termination */
2679
2680         /* advance over this protocol entry */
2681         namex += entryLength;
2682         namep += entryLength;
2683         tcounter++;             /* which proto entry we're looking at */
2684     }
2685
2686     if (NTProtoIndex != -1) {
2687         protoIndex = NTProtoIndex;
2688         vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2689     }
2690     else if (v3ProtoIndex != -1) {
2691         protoIndex = v3ProtoIndex;
2692         vcp->flags |= SMB_VCFLAG_USEV3;
2693     }   
2694     else if (coreProtoIndex != -1) {
2695         protoIndex = coreProtoIndex;
2696         vcp->flags |= SMB_VCFLAG_USECORE;
2697     }   
2698     else protoIndex = -1;
2699
2700     if (protoIndex == -1)
2701         return CM_ERROR_INVAL;
2702     else if (NTProtoIndex != -1) {
2703         smb_SetSMBParm(outp, 0, protoIndex);
2704         if (smb_authType != SMB_AUTH_NONE) {
2705             smb_SetSMBParmByte(outp, 1,
2706                                NEGOTIATE_SECURITY_USER_LEVEL |
2707                                NEGOTIATE_SECURITY_CHALLENGE_RESPONSE);  /* user level security, challenge response */
2708         } else {
2709             smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
2710         }
2711         smb_SetSMBParm(outp, 1, smb_maxMpxRequests);    /* max multiplexed requests */
2712         smb_SetSMBParm(outp, 2, smb_maxVCPerServer);    /* max VCs per consumer/server connection */
2713         smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE);    /* xmit buffer size */
2714         smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE);    /* raw buffer size */
2715         /* The session key is not a well documented field however most clients
2716          * will echo back the session key to the server.  Currently we are using
2717          * the same value for all sessions.  We should generate a random value
2718          * and store it into the vcp 
2719          */
2720         smb_SetSMBParm(outp, 7, 1);     /* next 2: session key */
2721         smb_SetSMBParm(outp, 8, 1);
2722         /* 
2723          * Tried changing the capabilities to support for W2K - defect 117695
2724          * Maybe something else needs to be changed here?
2725          */
2726         /*
2727         if (isWindows2000) 
2728         smb_SetSMBParmLong(outp, 9, 0x43fd);
2729         else 
2730         smb_SetSMBParmLong(outp, 9, 0x251);
2731         */
2732         /* Capabilities: *
2733          * 32-bit error codes *
2734          * and NT Find *
2735          * and NT SMB's *
2736          * and raw mode */
2737         caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
2738                NTNEGOTIATE_CAPABILITY_NTFIND |
2739                NTNEGOTIATE_CAPABILITY_RAWMODE |
2740                NTNEGOTIATE_CAPABILITY_NTSMB;
2741
2742         if ( smb_authType == SMB_AUTH_EXTENDED )
2743             caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
2744
2745         smb_SetSMBParmLong(outp, 9, caps);
2746         time(&unixTime);
2747         smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2748         smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
2749         smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
2750
2751         GetTimeZoneInformation(&tzi);
2752         smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias);    /* server tzone */
2753
2754         if (smb_authType == SMB_AUTH_NTLM) {
2755             smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
2756             smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
2757             /* paste in encryption key */
2758             datap = smb_GetSMBData(outp, NULL);
2759             memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
2760             /* and the faux domain name */
2761             strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
2762         } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
2763             void * secBlob;
2764             int secBlobLength;
2765
2766             smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2767
2768             smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
2769
2770             smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
2771                         
2772             datap = smb_GetSMBData(outp, NULL);
2773             memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
2774
2775             if (secBlob) {
2776                 datap += sizeof(smb_ServerGUID);
2777                 memcpy(datap, secBlob, secBlobLength);
2778                 free(secBlob);
2779             }
2780         } else {
2781             smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2782             smb_SetSMBDataLength(outp, 0);   /* Perhaps we should specify 8 bytes anyway */
2783         }
2784     }
2785     else if (v3ProtoIndex != -1) {
2786         smb_SetSMBParm(outp, 0, protoIndex);
2787
2788         /* NOTE: Extended authentication cannot be negotiated with v3
2789          * therefore we fail over to NTLM 
2790          */
2791         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2792             smb_SetSMBParm(outp, 1,
2793                            NEGOTIATE_SECURITY_USER_LEVEL |
2794                            NEGOTIATE_SECURITY_CHALLENGE_RESPONSE);      /* user level security, challenge response */
2795         } else {
2796             smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
2797         }
2798         smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
2799         smb_SetSMBParm(outp, 3, smb_maxMpxRequests);    /* max multiplexed requests */
2800         smb_SetSMBParm(outp, 4, smb_maxVCPerServer);    /* max VCs per consumer/server connection */
2801         smb_SetSMBParm(outp, 5, 0);     /* no support of block mode for read or write */
2802         smb_SetSMBParm(outp, 6, 1);     /* next 2: session key */
2803         smb_SetSMBParm(outp, 7, 1);
2804         time(&unixTime);
2805         smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2806         smb_SetSMBParm(outp, 8, LOWORD(dosTime));       /* server time */
2807         smb_SetSMBParm(outp, 9, HIWORD(dosTime));       /* server date */
2808
2809         GetTimeZoneInformation(&tzi);
2810         smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias);    /* server tzone */
2811
2812         /* NOTE: Extended authentication cannot be negotiated with v3
2813          * therefore we fail over to NTLM 
2814          */
2815         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2816             smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH);  /* encryption key length */
2817             smb_SetSMBParm(outp, 12, 0);        /* resvd */
2818             smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);   /* perhaps should specify 8 bytes anyway */
2819             datap = smb_GetSMBData(outp, NULL);
2820             /* paste in a new encryption key */
2821             memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
2822             /* and the faux domain name */
2823             strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
2824         } else {
2825             smb_SetSMBParm(outp, 11, 0); /* encryption key length */
2826             smb_SetSMBParm(outp, 12, 0); /* resvd */
2827             smb_SetSMBDataLength(outp, 0);
2828         }
2829     }
2830     else if (coreProtoIndex != -1) {     /* not really supported anymore */
2831         smb_SetSMBParm(outp, 0, protoIndex);
2832         smb_SetSMBDataLength(outp, 0);
2833     }
2834     return 0;
2835 }
2836
2837 void smb_Daemon(void *parmp)
2838 {
2839     afs_uint32 count = 0;
2840
2841     while(1) {
2842         count++;
2843         thrd_Sleep(10000);
2844         if ((count % 72) == 0)  {       /* every five minutes */
2845             struct tm myTime;
2846             long old_localZero = smb_localZero;
2847                  
2848             /* Initialize smb_localZero */
2849             myTime.tm_isdst = -1;               /* compute whether on DST or not */
2850             myTime.tm_year = 70;
2851             myTime.tm_mon = 0;
2852             myTime.tm_mday = 1;
2853             myTime.tm_hour = 0;
2854             myTime.tm_min = 0;
2855             myTime.tm_sec = 0;
2856             smb_localZero = mktime(&myTime);
2857
2858             smb_CalculateNowTZ();
2859
2860 #ifdef AFS_FREELANCE
2861             if ( smb_localZero != old_localZero )
2862                 cm_noteLocalMountPointChange();
2863 #endif
2864         }
2865         /* XXX GC dir search entries */
2866     }
2867 }
2868
2869 void smb_WaitingLocksDaemon()
2870 {
2871     smb_waitingLock_t *wL, *nwL;
2872     int first;
2873     smb_vc_t *vcp;
2874     smb_packet_t *inp, *outp;
2875     NCB *ncbp;
2876     long code = 0;
2877
2878     while (1) {
2879         lock_ObtainWrite(&smb_globalLock);
2880         nwL = smb_allWaitingLocks;
2881         if (nwL == NULL) {
2882             osi_SleepW((long)&smb_allWaitingLocks, &smb_globalLock);
2883             thrd_Sleep(1000);
2884             continue;
2885         }
2886         else first = 1;
2887         do {
2888             if (first)
2889                 first = 0;
2890             else
2891                 lock_ObtainWrite(&smb_globalLock);
2892             wL = nwL;
2893             nwL = (smb_waitingLock_t *) osi_QNext(&wL->q);
2894             lock_ReleaseWrite(&smb_globalLock);
2895             code = cm_RetryLock((cm_file_lock_t *) wL->lockp,
2896                                  wL->vcp->flags & SMB_VCFLAG_ALREADYDEAD);
2897             if (code == CM_ERROR_WOULDBLOCK) {
2898                 /* no progress */
2899                 if (wL->timeRemaining != 0xffffffff
2900                      && (wL->timeRemaining -= 1000) < 0)
2901                     goto endWait;
2902                 continue;
2903             }
2904           endWait:
2905             vcp = wL->vcp;
2906             inp = wL->inp;
2907             outp = wL->outp;
2908             ncbp = GetNCB();
2909             ncbp->ncb_length = inp->ncb_length;
2910             inp->spacep = cm_GetSpace();
2911
2912             /* Remove waitingLock from list */
2913             lock_ObtainWrite(&smb_globalLock);
2914             osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
2915                          &wL->q);
2916             lock_ReleaseWrite(&smb_globalLock);
2917
2918             /* Resume packet processing */
2919             if (code == 0)
2920                 smb_SetSMBDataLength(outp, 0);
2921             outp->flags |= SMB_PACKETFLAG_SUSPENDED;
2922             outp->resumeCode = code;
2923             outp->ncbp = ncbp;
2924             smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
2925
2926             /* Clean up */
2927             cm_FreeSpace(inp->spacep);
2928             smb_FreePacket(inp);
2929             smb_FreePacket(outp);
2930             FreeNCB(ncbp);
2931             free(wL);
2932         } while (nwL);
2933         thrd_Sleep(1000);
2934     }
2935 }
2936
2937 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2938 {
2939     osi_Log0(smb_logp, "SMB receive get disk attributes");
2940
2941     smb_SetSMBParm(outp, 0, 32000);
2942     smb_SetSMBParm(outp, 1, 64);
2943     smb_SetSMBParm(outp, 2, 1024);
2944     smb_SetSMBParm(outp, 3, 30000);
2945     smb_SetSMBParm(outp, 4, 0);
2946     smb_SetSMBDataLength(outp, 0);
2947     return 0;
2948 }
2949
2950 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
2951 {
2952     smb_tid_t *tidp;
2953     smb_user_t *uidp;
2954     unsigned short newTid;
2955     char shareName[256];
2956     char *sharePath;
2957     int shareFound;
2958     char *tp;
2959     char *pathp;
2960     char *passwordp;
2961     cm_user_t *userp;
2962
2963     osi_Log0(smb_logp, "SMB receive tree connect");
2964
2965     /* parse input parameters */
2966     tp = smb_GetSMBData(inp, NULL);
2967     pathp = smb_ParseASCIIBlock(tp, &tp);
2968     passwordp = smb_ParseASCIIBlock(tp, &tp);
2969     tp = strrchr(pathp, '\\');
2970     if (!tp)
2971         return CM_ERROR_BADSMB;
2972     strcpy(shareName, tp+1);
2973
2974     userp = smb_GetUser(vcp, inp);
2975
2976     lock_ObtainMutex(&vcp->mx);
2977     newTid = vcp->tidCounter++;
2978     lock_ReleaseMutex(&vcp->mx);
2979
2980     tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
2981     uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
2982     shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
2983     if (uidp)
2984         smb_ReleaseUID(uidp);
2985     if (!shareFound) {
2986         smb_ReleaseTID(tidp);
2987         return CM_ERROR_BADSHARENAME;
2988     }
2989     lock_ObtainMutex(&tidp->mx);
2990     tidp->userp = userp;
2991     tidp->pathname = sharePath;
2992     lock_ReleaseMutex(&tidp->mx);
2993     smb_ReleaseTID(tidp);
2994
2995     smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
2996     smb_SetSMBParm(rsp, 1, newTid);
2997     smb_SetSMBDataLength(rsp, 0);
2998
2999     osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3000     return 0;
3001 }
3002
3003 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3004 {
3005     int tlen;
3006
3007     if (*inp++ != 0x1) return NULL;
3008     tlen = inp[0] + (inp[1]<<8);
3009     inp += 2;           /* skip length field */
3010         
3011     if (chainpp) {
3012         *chainpp = inp + tlen;
3013     }   
3014
3015     if (lengthp) *lengthp = tlen;
3016         
3017     return inp;
3018 }
3019
3020 /* set maskp to the mask part of the incoming path.
3021  * Mask is 11 bytes long (8.3 with the dot elided).
3022  * Returns true if succeeds with a valid name, otherwise it does
3023  * its best, but returns false.
3024  */
3025 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3026 {
3027     char *tp;
3028     char *up;
3029     int i;
3030     int tc;
3031     int valid8Dot3;
3032
3033     /* starts off valid */
3034     valid8Dot3 = 1;
3035
3036     /* mask starts out all blanks */
3037     memset(maskp, ' ', 11);
3038
3039     /* find last backslash, or use whole thing if there is none */
3040     tp = strrchr(pathp, '\\');
3041     if (!tp) tp = pathp;
3042     else tp++;  /* skip slash */
3043         
3044     up = maskp;
3045
3046     /* names starting with a dot are illegal */
3047     if (*tp == '.') valid8Dot3 = 0;
3048
3049     for(i=0;; i++) {
3050         tc = *tp++;
3051         if (tc == 0) return valid8Dot3;
3052         if (tc == '.' || tc == '"') break;
3053         if (i < 8) *up++ = tc;
3054         else valid8Dot3 = 0;
3055     }
3056         
3057     /* if we get here, tp point after the dot */
3058     up = maskp+8;       /* ext goes here */
3059     for(i=0;;i++) {
3060         tc = *tp++;
3061         if (tc == 0) 
3062             return valid8Dot3;
3063
3064         /* too many dots */
3065         if (tc == '.' || tc == '"') 
3066             valid8Dot3 = 0;
3067
3068         /* copy extension if not too long */
3069         if (i < 3) 
3070             *up++ = tc;
3071         else 
3072             valid8Dot3 = 0;
3073     }   
3074
3075     /* unreachable */
3076 }
3077
3078 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3079 {
3080     char umask[11];
3081     int valid;
3082     int i;
3083     char tc1;
3084     char tc2;
3085     char *tp1;
3086     char *tp2;
3087
3088     /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3089
3090     valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3091     if (!valid) 
3092         return 0;
3093  
3094     /* otherwise, we have a valid 8.3 name; see if we have a match,
3095      * treating '?' as a wildcard in maskp (but not in the file name).
3096      */
3097     tp1 = umask;        /* real name, in mask format */
3098     tp2 = maskp;        /* mask, in mask format */
3099     for(i=0; i<11; i++) {
3100         tc1 = *tp1++;   /* char from real name */
3101         tc2 = *tp2++;   /* char from mask */
3102         tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3103         tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3104         if (tc1 == tc2) 
3105             continue;
3106         if (tc2 == '?' && tc1 != ' ') 
3107             continue;
3108         if (tc2 == '>') 
3109             continue;
3110         return 0;
3111     }
3112
3113     /* we got a match */
3114     return 1;
3115 }
3116
3117 char *smb_FindMask(char *pathp)
3118 {
3119     char *tp;
3120         
3121     tp = strrchr(pathp, '\\');  /* find last slash */
3122
3123     if (tp) 
3124         return tp+1;    /* skip the slash */
3125     else 
3126         return pathp;   /* no slash, return the entire path */
3127 }       
3128
3129 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3130 {
3131     unsigned char *pathp;
3132     unsigned char *tp;
3133     unsigned char mask[11];
3134     unsigned char *statBlockp;
3135     unsigned char initStatBlock[21];
3136     int statLen;
3137         
3138     osi_Log0(smb_logp, "SMB receive search volume");
3139
3140     /* pull pathname and stat block out of request */
3141     tp = smb_GetSMBData(inp, NULL);
3142     pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3143     osi_assert(pathp != NULL);
3144     statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3145     osi_assert(statBlockp != NULL);
3146     if (statLen == 0) {
3147         statBlockp = initStatBlock;
3148         statBlockp[0] = 8;
3149     }
3150         
3151     /* for returning to caller */
3152     smb_Get8Dot3MaskFromPath(mask, pathp);
3153
3154     smb_SetSMBParm(outp, 0, 1);         /* we're returning one entry */
3155     tp = smb_GetSMBData(outp, NULL);
3156     *tp++ = 5;
3157     *tp++ = 43; /* bytes in a dir entry */
3158     *tp++ = 0;  /* high byte in counter */
3159
3160     /* now marshall the dir entry, starting with the search status */
3161     *tp++ = statBlockp[0];              /* Reserved */
3162     memcpy(tp, mask, 11); tp += 11;     /* FileName */
3163
3164     /* now pass back server use info, with 1st byte non-zero */
3165     *tp++ = 1;
3166     memset(tp, 0, 4); tp += 4;  /* reserved for server use */
3167
3168     memcpy(tp, statBlockp+17, 4); tp += 4;      /* reserved for consumer */
3169
3170     *tp++ = 0x8;                /* attribute: volume */
3171
3172     /* copy out time */
3173     *tp++ = 0;
3174     *tp++ = 0;
3175
3176     /* copy out date */
3177     *tp++ = 18;
3178     *tp++ = 178;
3179
3180     /* 4 byte file size */
3181     *tp++ = 0;
3182     *tp++ = 0;
3183     *tp++ = 0;
3184     *tp++ = 0;
3185
3186     /* finally, null-terminated 8.3 pathname, which we set to AFS */
3187     memset(tp, ' ', 13);
3188     strcpy(tp, "AFS");
3189
3190     /* set the length of the data part of the packet to 43 + 3, for the dir
3191      * entry plus the 5 and the length fields.
3192      */
3193     smb_SetSMBDataLength(outp, 46);
3194     return 0;
3195 }       
3196
3197 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3198                              cm_user_t *userp, cm_req_t *reqp)
3199 {
3200     long code = 0;
3201     cm_scache_t *scp;
3202     char *dptr;
3203     time_t dosTime;
3204     u_short shortTemp;
3205     char attr;
3206     smb_dirListPatch_t *patchp;
3207     smb_dirListPatch_t *npatchp;
3208
3209     for (patchp = *dirPatchespp; patchp; patchp =
3210          (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3211
3212         dptr = patchp->dptr;
3213
3214         code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3215         if (code) {
3216             if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3217                 *dptr++ = SMB_ATTR_HIDDEN;
3218             continue;
3219         }
3220         lock_ObtainMutex(&scp->mx);
3221         code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3222                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3223         if (code) {     
3224             lock_ReleaseMutex(&scp->mx);
3225             cm_ReleaseSCache(scp);
3226             if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3227                 *dptr++ = SMB_ATTR_HIDDEN;
3228             continue;
3229         }
3230
3231         attr = smb_Attributes(scp);
3232         /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3233         if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3234             attr |= SMB_ATTR_HIDDEN;
3235         *dptr++ = attr;
3236
3237         /* get dos time */
3238         smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3239                 
3240         /* copy out time */
3241         shortTemp = dosTime & 0xffff;
3242         *((u_short *)dptr) = shortTemp;
3243         dptr += 2;
3244
3245         /* and copy out date */
3246         shortTemp = (dosTime>>16) & 0xffff;
3247         *((u_short *)dptr) = shortTemp;
3248         dptr += 2;
3249                 
3250         /* copy out file length */
3251         *((u_long *)dptr) = scp->length.LowPart;
3252         dptr += 4;
3253         lock_ReleaseMutex(&scp->mx);
3254         cm_ReleaseSCache(scp);
3255     }
3256         
3257     /* now free the patches */
3258     for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3259         npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3260         free(patchp);
3261     }   
3262         
3263     /* and mark the list as empty */
3264     *dirPatchespp = NULL;
3265
3266     return code;
3267 }
3268
3269 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3270 {
3271     int attribute;
3272     long nextCookie;
3273     char *tp;
3274     long code = 0;
3275     char *pathp;
3276     cm_dirEntry_t *dep;
3277     int maxCount;
3278     smb_dirListPatch_t *dirListPatchesp;
3279     smb_dirListPatch_t *curPatchp;
3280     int dataLength;
3281     cm_buf_t *bufferp;
3282     long temp;
3283     osi_hyper_t dirLength;
3284     osi_hyper_t bufferOffset;
3285     osi_hyper_t curOffset;
3286     osi_hyper_t thyper;
3287     unsigned char *inCookiep;
3288     smb_dirSearch_t *dsp;
3289     cm_scache_t *scp;
3290     long entryInDir;
3291     long entryInBuffer;
3292     unsigned long clientCookie;
3293     cm_pageHeader_t *pageHeaderp;
3294     cm_user_t *userp = NULL;
3295     int slotInPage;
3296     char shortName[13];
3297     char *actualName;
3298     char *shortNameEnd;
3299     char mask[11];
3300     int returnedNames;
3301     long nextEntryCookie;
3302     int numDirChunks;           /* # of 32 byte dir chunks in this entry */
3303     char resByte;                       /* reserved byte from the cookie */
3304     char *op;                   /* output data ptr */
3305     char *origOp;                       /* original value of op */
3306     cm_space_t *spacep;         /* for pathname buffer */
3307     int starPattern;
3308     int rootPath = 0;
3309     int caseFold;
3310     char *tidPathp;
3311     cm_req_t req;
3312     cm_fid_t fid;
3313     int fileType;
3314
3315     cm_InitReq(&req);
3316
3317     maxCount = smb_GetSMBParm(inp, 0);
3318
3319     dirListPatchesp = NULL;
3320         
3321     caseFold = CM_FLAG_CASEFOLD;
3322
3323     tp = smb_GetSMBData(inp, NULL);
3324     pathp = smb_ParseASCIIBlock(tp, &tp);
3325     inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3326
3327     /* bail out if request looks bad */
3328     if (!tp || !pathp) {
3329         return CM_ERROR_BADSMB;
3330     }
3331
3332     /* We can handle long names */
3333     if (vcp->flags & SMB_VCFLAG_USENT)
3334         ((smb_t *)outp)->flg2 |= 0x40;  /* IS_LONG_NAME */
3335
3336     /* make sure we got a whole search status */
3337     if (dataLength < 21) {
3338         nextCookie = 0;         /* start at the beginning of the dir */
3339         resByte = 0;
3340         clientCookie = 0;
3341         attribute = smb_GetSMBParm(inp, 1);
3342
3343         /* handle volume info in another function */
3344         if (attribute & 0x8)
3345             return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3346
3347         osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3348                   maxCount, osi_LogSaveString(smb_logp, pathp));
3349
3350         if (*pathp == 0) {      /* null pathp, treat as root dir */
3351             if (!(attribute & SMB_ATTR_DIRECTORY))      /* exclude dirs */
3352                 return CM_ERROR_NOFILES;
3353             rootPath = 1;
3354         }
3355
3356         dsp = smb_NewDirSearch(0);
3357         dsp->attribute = attribute;
3358         smb_Get8Dot3MaskFromPath(mask, pathp);
3359         memcpy(dsp->mask, mask, 11);
3360
3361         /* track if this is likely to match a lot of entries */
3362         if (smb_IsStarMask(mask)) starPattern = 1;
3363         else starPattern = 0;
3364     }   
3365     else {
3366         /* pull the next cookie value out of the search status block */
3367         nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3368             + (inCookiep[16]<<24);
3369         dsp = smb_FindDirSearch(inCookiep[12]);
3370         if (!dsp) {
3371             /* can't find dir search status; fatal error */
3372             return CM_ERROR_BADFD;
3373         }
3374         attribute = dsp->attribute;
3375         resByte = inCookiep[0];
3376
3377         /* copy out client cookie, in host byte order.  Don't bother
3378          * interpreting it, since we're just passing it through, anyway.
3379          */
3380         memcpy(&clientCookie, &inCookiep[17], 4);
3381
3382         memcpy(mask, dsp->mask, 11);
3383
3384         /* assume we're doing a star match if it has continued for more
3385          * than one call.
3386          */
3387         starPattern = 1;
3388     }
3389
3390     osi_Log3(smb_logp, "SMB dir search cookie 0x%x, connection %d, attr 0x%x",
3391              nextCookie, dsp->cookie, attribute);
3392
3393     userp = smb_GetUser(vcp, inp);
3394
3395     /* try to get the vnode for the path name next */
3396     lock_ObtainMutex(&dsp->mx);
3397     if (dsp->scp) {
3398         scp = dsp->scp;
3399         cm_HoldSCache(scp);
3400         code = 0;
3401     }
3402     else {
3403         spacep = inp->spacep;
3404         smb_StripLastComponent(spacep->data, NULL, pathp);
3405         lock_ReleaseMutex(&dsp->mx);
3406         code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3407         if (code) {
3408             lock_ReleaseMutex(&dsp->mx);
3409             cm_ReleaseUser(userp);
3410             smb_DeleteDirSearch(dsp);
3411             smb_ReleaseDirSearch(dsp);
3412             return CM_ERROR_NOFILES;
3413         }
3414         code = cm_NameI(cm_rootSCachep, spacep->data,
3415                         caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3416         lock_ObtainMutex(&dsp->mx);
3417         if (code == 0) {
3418             if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
3419             dsp->scp = scp;
3420             /* we need one hold for the entry we just stored into,
3421              * and one for our own processing.  When we're done with this
3422              * function, we'll drop the one for our own processing.
3423              * We held it once from the namei call, and so we do another hold
3424              * now.
3425              */
3426             cm_HoldSCache(scp);
3427             lock_ObtainMutex(&scp->mx);
3428             if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3429                  && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3430                 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3431                 dsp->flags |= SMB_DIRSEARCH_BULKST;
3432             }
3433             lock_ReleaseMutex(&scp->mx);
3434         }
3435     }
3436     lock_ReleaseMutex(&dsp->mx);
3437     if (code) {
3438         cm_ReleaseUser(userp);
3439         smb_DeleteDirSearch(dsp);
3440         smb_ReleaseDirSearch(dsp);
3441         return code;
3442     }
3443
3444     /* reserves space for parameter; we'll adjust it again later to the
3445      * real count of the # of entries we returned once we've actually
3446      * assembled the directory listing.
3447      */
3448     smb_SetSMBParm(outp, 0, 0);
3449
3450     /* get the directory size */
3451     lock_ObtainMutex(&scp->mx);
3452     code = cm_SyncOp(scp, NULL, userp, &req, 0,
3453                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3454     if (code) {
3455         lock_ReleaseMutex(&scp->mx);
3456         cm_ReleaseSCache(scp);
3457         cm_ReleaseUser(userp);
3458         smb_DeleteDirSearch(dsp);
3459         smb_ReleaseDirSearch(dsp);
3460         return code;
3461     }
3462         
3463     dirLength = scp->length;
3464     bufferp = NULL;
3465     bufferOffset.LowPart = bufferOffset.HighPart = 0;
3466     curOffset.HighPart = 0;
3467     curOffset.LowPart = nextCookie;
3468     origOp = op = smb_GetSMBData(outp, NULL);
3469     /* and write out the basic header */
3470     *op++ = 5;          /* variable block */
3471     op += 2;            /* skip vbl block length; we'll fill it in later */
3472     code = 0;
3473     returnedNames = 0;
3474     while (1) {
3475         /* make sure that curOffset.LowPart doesn't point to the first
3476          * 32 bytes in the 2nd through last dir page, and that it doesn't
3477          * point at the first 13 32-byte chunks in the first dir page,
3478          * since those are dir and page headers, and don't contain useful
3479          * information.
3480          */
3481         temp = curOffset.LowPart & (2048-1);
3482         if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3483             /* we're in the first page */
3484             if (temp < 13*32) temp = 13*32;
3485         }
3486         else {
3487             /* we're in a later dir page */
3488             if (temp < 32) temp = 32;
3489         }
3490
3491         /* make sure the low order 5 bits are zero */
3492         temp &= ~(32-1);
3493
3494         /* now put temp bits back ito curOffset.LowPart */
3495         curOffset.LowPart &= ~(2048-1);
3496         curOffset.LowPart |= temp;
3497
3498         /* check if we've returned all the names that will fit in the
3499          * response packet.
3500          */
3501         if (returnedNames >= maxCount) 
3502             break;
3503                 
3504         /* check if we've passed the dir's EOF */
3505         if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
3506
3507         /* see if we can use the bufferp we have now; compute in which page
3508          * the current offset would be, and check whether that's the offset
3509          * of the buffer we have.  If not, get the buffer.
3510          */
3511         thyper.HighPart = curOffset.HighPart;
3512         thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
3513         if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3514             /* wrong buffer */
3515             if (bufferp) {
3516                 buf_Release(bufferp);
3517                 bufferp = NULL;
3518             }   
3519             lock_ReleaseMutex(&scp->mx);
3520             lock_ObtainRead(&scp->bufCreateLock);
3521             code = buf_Get(scp, &thyper, &bufferp);
3522             lock_ReleaseRead(&scp->bufCreateLock);
3523
3524             /* now, if we're doing a star match, do bulk fetching of all of 
3525              * the status info for files in the dir.
3526              */
3527             if (starPattern) {
3528                 smb_ApplyDirListPatches(&dirListPatchesp, userp,
3529                                          &req);
3530                 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
3531                      LargeIntegerGreaterThanOrEqualTo(thyper, 
3532                                                       scp->bulkStatProgress)) {
3533                     /* Don't bulk stat if risking timeout */
3534                     int now = GetCurrentTime();
3535                     if (now - req.startTime > 5000) {
3536                         scp->bulkStatProgress = thyper;
3537                         scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3538                         dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3539                     } else
3540                         cm_TryBulkStat(scp, &thyper, userp, &req);
3541                 }
3542             }
3543
3544             lock_ObtainMutex(&scp->mx);
3545             if (code) 
3546                 break;
3547             bufferOffset = thyper;
3548
3549             /* now get the data in the cache */
3550             while (1) {
3551                 code = cm_SyncOp(scp, bufferp, userp, &req,
3552                                  PRSFS_LOOKUP,
3553                                  CM_SCACHESYNC_NEEDCALLBACK |
3554                                  CM_SCACHESYNC_READ);
3555                 if (code) break;
3556                                 
3557                 if (cm_HaveBuffer(scp, bufferp, 0)) break;
3558
3559                 /* otherwise, load the buffer and try again */
3560                 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
3561                 if (code) break;
3562             }
3563             if (code) {
3564                 buf_Release(bufferp);
3565                 bufferp = NULL;
3566                 break;
3567             }
3568         }       /* if (wrong buffer) ... */
3569
3570         /* now we have the buffer containing the entry we're interested in; copy
3571          * it out if it represents a non-deleted entry.
3572          */
3573         entryInDir = curOffset.LowPart & (2048-1);
3574         entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
3575
3576         /* page header will help tell us which entries are free.  Page header
3577          * can change more often than once per buffer, since AFS 3 dir page size
3578          * may be less than (but not more than a buffer package buffer.
3579          */
3580         temp = curOffset.LowPart & (buf_bufferSize - 1);  /* only look intra-buffer */
3581         temp &= ~(2048 - 1);    /* turn off intra-page bits */
3582         pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3583
3584         /* now determine which entry we're looking at in the page.  If it is
3585          * free (there's a free bitmap at the start of the dir), we should
3586          * skip these 32 bytes.
3587          */
3588         slotInPage = (entryInDir & 0x7e0) >> 5;
3589         if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
3590             /* this entry is free */
3591             numDirChunks = 1;           /* only skip this guy */
3592             goto nextEntry;
3593         }
3594
3595         tp = bufferp->datap + entryInBuffer;
3596         dep = (cm_dirEntry_t *) tp;             /* now points to AFS3 dir entry */
3597
3598         /* while we're here, compute the next entry's location, too,
3599          * since we'll need it when writing out the cookie into the dir
3600          * listing stream.
3601          *
3602          * XXXX Probably should do more sanity checking.
3603          */
3604         numDirChunks = cm_NameEntries(dep->name, NULL);
3605
3606         /* compute the offset of the cookie representing the next entry */
3607         nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3608
3609         /* Compute 8.3 name if necessary */
3610         actualName = dep->name;
3611         if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
3612             cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3613             actualName = shortName;
3614         }
3615
3616         if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
3617             /* this is one of the entries to use: it is not deleted
3618              * and it matches the star pattern we're looking for.
3619              */
3620
3621             /* Eliminate entries that don't match requested
3622              * attributes */
3623
3624             /* no hidden files */
3625             if(smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName))
3626                 goto nextEntry;
3627
3628             if (!(dsp->attribute & SMB_ATTR_DIRECTORY))  /* no directories */
3629             {
3630                 /* We have already done the cm_TryBulkStat above */
3631                 fid.cell = scp->fid.cell;
3632                 fid.volume = scp->fid.volume;
3633                 fid.vnode = ntohl(dep->fid.vnode);
3634                 fid.unique = ntohl(dep->fid.unique);
3635                 fileType = cm_FindFileType(&fid);
3636                 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
3637                          "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
3638                           fileType);
3639                 if (fileType == CM_SCACHETYPE_DIRECTORY)
3640                     goto nextEntry;
3641             }
3642
3643             *op++ = resByte;
3644             memcpy(op, mask, 11); op += 11;
3645             *op++ = (char) dsp->cookie; /* they say it must be non-zero */
3646             *op++ = nextEntryCookie & 0xff;
3647             *op++ = (nextEntryCookie>>8) & 0xff;
3648             *op++ = (nextEntryCookie>>16) & 0xff;
3649             *op++ = (nextEntryCookie>>24) & 0xff;
3650             memcpy(op, &clientCookie, 4); op += 4;
3651
3652             /* now we emit the attribute.  This is sort of tricky,
3653              * since we need to really stat the file to find out
3654              * what type of entry we've got.  Right now, we're
3655              * copying out data from a buffer, while holding the
3656              * scp locked, so it isn't really convenient to stat
3657              * something now.  We'll put in a place holder now,
3658              * and make a second pass before returning this to get
3659              * the real attributes.  So, we just skip the data for
3660              * now, and adjust it later.  We allocate a patch
3661              * record to make it easy to find this point later.
3662              * The replay will happen at a time when it is safe to
3663              * unlock the directory.
3664              */
3665             curPatchp = malloc(sizeof(*curPatchp));
3666             osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
3667             curPatchp->dptr = op;
3668             curPatchp->fid.cell = scp->fid.cell;
3669             curPatchp->fid.volume = scp->fid.volume;
3670             curPatchp->fid.vnode = ntohl(dep->fid.vnode);
3671             curPatchp->fid.unique = ntohl(dep->fid.unique);
3672
3673             /* do hidden attribute here since name won't be around when applying
3674              * dir list patches
3675              */
3676
3677             if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
3678                 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
3679             else
3680                 curPatchp->flags = 0;
3681
3682             op += 9;    /* skip attr, time, date and size */
3683
3684             /* zero out name area.  The spec says to pad with
3685              * spaces, but Samba doesn't, and neither do we.
3686              */
3687             memset(op, 0, 13);
3688
3689             /* finally, we get to copy out the name; we know that
3690              * it fits in 8.3 or the pattern wouldn't match, but it
3691              * never hurts to be sure.
3692              */
3693             strncpy(op, actualName, 13);
3694
3695             /* Uppercase if requested by client */
3696             if ((((smb_t *)inp)->flg2 & 1) == 0)
3697                 _strupr(op);
3698
3699             op += 13;
3700
3701             /* now, adjust the # of entries copied */
3702             returnedNames++;
3703         }       /* if we're including this name */
3704
3705       nextEntry:
3706         /* and adjust curOffset to be where the new cookie is */
3707         thyper.HighPart = 0;
3708         thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
3709         curOffset = LargeIntegerAdd(thyper, curOffset);
3710     }           /* while copying data for dir listing */
3711
3712     /* release the mutex */
3713     lock_ReleaseMutex(&scp->mx);
3714     if (bufferp) buf_Release(bufferp);
3715
3716     /* apply and free last set of patches; if not doing a star match, this
3717      * will be empty, but better safe (and freeing everything) than sorry.
3718      */
3719