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