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