a5cfe6b5ee0e0947c72bfb03ebd7794ade8f884a
[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 = 2;      /* smb_allVCsp and caller */
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_ReleaseVCInternal(smb_vc_t *vcp)
937 {
938 #ifdef DEBUG
939     osi_assert(vcp->refCount-- != 0);
940 #else
941     vcp->refCount--;
942 #endif
943
944     if (vcp->refCount == 0) {
945         memset(vcp,0,sizeof(smb_vc_t));
946         free(vcp);
947     }
948 }
949
950 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
951 {
952     osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
953     smb_ReleaseVCInternal(vcp);
954 }       
955
956 void smb_ReleaseVC(smb_vc_t *vcp)
957 {
958     lock_ObtainWrite(&smb_rctLock);
959     osi_Log2(smb_logp,"smb_ReleaseVC       vcp %x ref %d",vcp, vcp->refCount);
960     smb_ReleaseVCInternal(vcp);
961     lock_ReleaseWrite(&smb_rctLock);
962 }       
963
964 void smb_HoldVCNoLock(smb_vc_t *vcp)
965 {
966     vcp->refCount++;
967     osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
968 }       
969
970 void smb_HoldVC(smb_vc_t *vcp)
971 {
972     lock_ObtainWrite(&smb_rctLock);
973     vcp->refCount++;
974     osi_Log2(smb_logp,"smb_HoldVC       vcp %x ref %d",vcp, vcp->refCount);
975     lock_ReleaseWrite(&smb_rctLock);
976 }       
977
978 void smb_CleanupDeadVC(smb_vc_t *vcp)
979 {
980     smb_fid_t *fidpIter;
981     smb_fid_t *fidpNext;
982     smb_fid_t *fidp;
983     unsigned short fid;
984     smb_tid_t *tidpIter;
985     smb_tid_t *tidpNext;
986     smb_tid_t *tidp;
987     unsigned short tid;
988     smb_user_t *userpIter;
989     smb_user_t *userpNext;
990     smb_user_t *userp;
991     unsigned short uid;
992     smb_vc_t **vcpp;
993
994     osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
995
996     lock_ObtainRead(&smb_rctLock);
997     for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
998         fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
999
1000         if (fidpIter->flags & SMB_FID_DELETE)
1001             continue;
1002
1003         fid = fidpIter->fid;
1004         osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1005         lock_ReleaseRead(&smb_rctLock);
1006
1007         fidp = smb_FindFID(vcp, fid, 0);
1008         osi_assert(fidp);
1009         smb_CloseFID(vcp, fidp, NULL, 0);
1010         smb_ReleaseFID(fidp);
1011
1012         lock_ObtainRead(&smb_rctLock);
1013     }
1014
1015     for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1016         tidpNext = tidpIter->nextp;
1017
1018         if (tidpIter->flags & SMB_TIDFLAG_DELETE)
1019             continue;
1020
1021         tid = tidpIter->tid;
1022         osi_Log2(smb_logp, "  Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1023         lock_ReleaseRead(&smb_rctLock);
1024
1025         tidp = smb_FindTID(vcp, tid, 0);
1026         osi_assert(tidp);
1027
1028         lock_ObtainMutex(&tidp->mx);
1029         tidp->flags |= SMB_TIDFLAG_DELETE;
1030         lock_ReleaseMutex(&tidp->mx);
1031
1032         smb_ReleaseTID(tidp);
1033
1034         lock_ObtainRead(&smb_rctLock);
1035     }
1036
1037     for (userpIter = vcp->usersp; userpIter; userpIter = userpNext) {
1038         userpNext = userpIter->nextp;
1039
1040         if (userpIter->flags & SMB_USERFLAG_DELETE)
1041             continue;
1042
1043         uid = userpIter->userID;
1044         osi_Log2(smb_logp, "  Cleanup UID %d (userp=0x%x)", uid, userpIter);
1045         lock_ReleaseRead(&smb_rctLock);
1046
1047         userp = smb_FindUID(vcp, uid, 0);
1048         osi_assert(userp);
1049
1050         lock_ObtainMutex(&userp->mx);
1051         userp->flags |= SMB_USERFLAG_DELETE;
1052         lock_ReleaseMutex(&userp->mx);
1053
1054         smb_ReleaseUID(userp);
1055
1056         lock_ObtainRead(&smb_rctLock);
1057     }
1058
1059     /* remove VCP from smb_allVCsp */
1060     for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
1061         if (*vcpp == vcp) {
1062             *vcpp = vcp->nextp;
1063             smb_ReleaseVCNoLock(vcp);
1064             break;
1065         }
1066     } 
1067     lock_ReleaseRead(&smb_rctLock);
1068     osi_Log0(smb_logp, "Done cleaning up dead vcp");
1069 }
1070
1071 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1072 {
1073     smb_tid_t *tidp;
1074
1075     lock_ObtainWrite(&smb_rctLock);
1076     for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1077         if (tid == tidp->tid) {
1078             tidp->refCount++;
1079             break;
1080         }       
1081     }
1082     if (!tidp && (flags & SMB_FLAG_CREATE)) {
1083         tidp = malloc(sizeof(*tidp));
1084         memset(tidp, 0, sizeof(*tidp));
1085         tidp->nextp = vcp->tidsp;
1086         tidp->refCount = 1;
1087         tidp->vcp = vcp;
1088         smb_HoldVCNoLock(vcp);
1089         vcp->tidsp = tidp;
1090         lock_InitializeMutex(&tidp->mx, "tid_t mutex");
1091         tidp->tid = tid;
1092     }
1093     lock_ReleaseWrite(&smb_rctLock);
1094     return tidp;
1095 }               
1096
1097 void smb_ReleaseTID(smb_tid_t *tidp)
1098 {
1099     smb_tid_t *tp;
1100     smb_tid_t **ltpp;
1101     cm_user_t *userp;
1102
1103     userp = NULL;
1104     lock_ObtainWrite(&smb_rctLock);
1105     osi_assert(tidp->refCount-- > 0);
1106     if (tidp->refCount == 0 && (tidp->flags & SMB_TIDFLAG_DELETE)) {
1107         ltpp = &tidp->vcp->tidsp;
1108         for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1109             if (tp == tidp) 
1110                 break;
1111         }
1112         osi_assert(tp != NULL);
1113         *ltpp = tp->nextp;
1114         lock_FinalizeMutex(&tidp->mx);
1115         userp = tidp->userp;    /* remember to drop ref later */
1116         tidp->userp = NULL;
1117         smb_ReleaseVCNoLock(tidp->vcp);
1118         tidp->vcp = 0;
1119     }
1120     lock_ReleaseWrite(&smb_rctLock);
1121     if (userp)
1122         cm_ReleaseUser(userp);
1123 }               
1124
1125 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1126 {
1127     smb_user_t *uidp = NULL;
1128
1129     lock_ObtainWrite(&smb_rctLock);
1130     for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1131         if (uid == uidp->userID) {
1132             uidp->refCount++;
1133             osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%s]",
1134                      vcp, uidp->userID, 
1135                      osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
1136             break;
1137         }
1138     }
1139     if (!uidp && (flags & SMB_FLAG_CREATE)) {
1140         uidp = malloc(sizeof(*uidp));
1141         memset(uidp, 0, sizeof(*uidp));
1142         uidp->nextp = vcp->usersp;
1143         uidp->refCount = 2; /* one for the vcp and one for the caller */
1144         uidp->vcp = vcp;
1145         smb_HoldVCNoLock(vcp);
1146         vcp->usersp = uidp;
1147         lock_InitializeMutex(&uidp->mx, "user_t mutex");
1148         uidp->userID = uid;
1149         osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%s]",
1150                  vcp, uidp->userID, 
1151                  osi_LogSaveString(smb_logp,uidp->unp ? uidp->unp->name : ""));
1152     }
1153     lock_ReleaseWrite(&smb_rctLock);
1154     return uidp;
1155 }               
1156
1157 smb_username_t *smb_FindUserByName(char *usern, char *machine, int flags)
1158 {
1159     smb_username_t *unp= NULL;
1160
1161     lock_ObtainWrite(&smb_rctLock);
1162     for(unp = usernamesp; unp; unp = unp->nextp) {
1163         if (stricmp(unp->name, usern) == 0 &&
1164              stricmp(unp->machine, machine) == 0) {
1165             unp->refCount++;
1166             break;
1167         }
1168     }
1169     if (!unp && (flags & SMB_FLAG_CREATE)) {
1170         unp = malloc(sizeof(*unp));
1171         memset(unp, 0, sizeof(*unp));
1172         unp->refCount = 1;
1173         unp->nextp = usernamesp;
1174         unp->name = strdup(usern);
1175         unp->machine = strdup(machine);
1176         usernamesp = unp;
1177         lock_InitializeMutex(&unp->mx, "username_t mutex");
1178     }
1179     lock_ReleaseWrite(&smb_rctLock);
1180     return unp;
1181 }       
1182
1183 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
1184 {
1185     smb_user_t *uidp= NULL;
1186
1187     lock_ObtainWrite(&smb_rctLock);
1188     for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1189         if (!uidp->unp) 
1190             continue;
1191         if (stricmp(uidp->unp->name, usern) == 0) {
1192             uidp->refCount++;
1193             osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%s]",
1194                      vcp,uidp->userID,osi_LogSaveString(smb_logp,usern));
1195             break;
1196         } else
1197             continue;
1198     }           
1199     lock_ReleaseWrite(&smb_rctLock);
1200     return uidp;
1201 }       
1202
1203 void smb_ReleaseUsername(smb_username_t *unp)
1204 {
1205     smb_username_t *up;
1206     smb_username_t **lupp;
1207     cm_user_t *userp = NULL;
1208
1209     lock_ObtainWrite(&smb_rctLock);
1210     osi_assert(unp->refCount-- > 0);
1211     if (unp->refCount == 0) {
1212         lupp = &usernamesp;
1213         for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1214             if (up == unp) 
1215                 break;
1216         }
1217         osi_assert(up != NULL);
1218         *lupp = up->nextp;
1219         lock_FinalizeMutex(&unp->mx);
1220         userp = unp->userp;
1221         free(unp->name);
1222         free(unp->machine);
1223         free(unp);
1224     }           
1225     lock_ReleaseWrite(&smb_rctLock);
1226
1227     if (userp) {
1228         cm_ReleaseUserVCRef(userp);
1229         cm_ReleaseUser(userp);
1230     }   
1231 }       
1232
1233 void smb_ReleaseUID(smb_user_t *uidp)
1234 {
1235     smb_user_t *up;
1236     smb_user_t **lupp;
1237     smb_username_t *unp = NULL;
1238
1239     lock_ObtainWrite(&smb_rctLock);
1240     osi_assert(uidp->refCount-- > 0);
1241     if (uidp->refCount == 0) {
1242         lupp = &uidp->vcp->usersp;
1243         for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1244             if (up == uidp) 
1245                 break;
1246         }
1247         osi_assert(up != NULL);
1248         *lupp = up->nextp;
1249         lock_FinalizeMutex(&uidp->mx);
1250         unp = uidp->unp;
1251         smb_ReleaseVCNoLock(uidp->vcp);
1252         free(uidp);
1253     }           
1254     lock_ReleaseWrite(&smb_rctLock);
1255
1256     if (unp)
1257         smb_ReleaseUsername(unp);
1258 }       
1259
1260 /* retrieve a held reference to a user structure corresponding to an incoming
1261  * request.
1262  * corresponding release function is cm_ReleaseUser.
1263  */
1264 cm_user_t *smb_GetUser(smb_vc_t *vcp, smb_packet_t *inp)
1265 {
1266     smb_user_t *uidp;
1267     cm_user_t *up = NULL;
1268     smb_t *smbp;
1269
1270     smbp = (smb_t *) inp;
1271     uidp = smb_FindUID(vcp, smbp->uid, 0);
1272     if (!uidp)
1273         return NULL;
1274     
1275     lock_ObtainMutex(&uidp->mx);
1276     if (uidp->unp) {
1277         up = uidp->unp->userp;
1278         cm_HoldUser(up);
1279     }
1280     lock_ReleaseMutex(&uidp->mx);
1281
1282     smb_ReleaseUID(uidp);
1283     return up;
1284 }
1285
1286 /*
1287  * Return a pointer to a pathname extracted from a TID structure.  The
1288  * TID structure is not held; assume it won't go away.
1289  */
1290 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1291 {
1292     smb_tid_t *tidp;
1293     long code = 0;
1294
1295     tidp = smb_FindTID(vcp, tid, 0);
1296     if (!tidp) {
1297         *treepath = NULL;
1298     } else {
1299         if (tidp->flags & SMB_TIDFLAG_IPC) {
1300             code = CM_ERROR_TIDIPC;
1301             /* tidp->pathname would be NULL, but that's fine */
1302         }
1303         *treepath = tidp->pathname;
1304         smb_ReleaseTID(tidp);
1305     }
1306     return code;
1307 }
1308
1309 /* check to see if we have a chained fid, that is, a fid that comes from an
1310  * OpenAndX message that ran earlier in this packet.  In this case, the fid
1311  * field in a read, for example, request, isn't set, since the value is
1312  * supposed to be inherited from the openAndX call.
1313  */
1314 int smb_ChainFID(int fid, smb_packet_t *inp)
1315 {
1316     if (inp->fid == 0 || inp->inCount == 0) 
1317         return fid;
1318     else 
1319         return inp->fid;
1320 }
1321
1322 /* are we a priv'd user?  What does this mean on NT? */
1323 int smb_SUser(cm_user_t *userp)
1324 {
1325     return 1;
1326 }
1327
1328 /* find a file ID.  If we pass in 0 we select an unused File ID.
1329  * If the SMB_FLAG_CREATE flag is set, we allocate a new  
1330  * smb_fid_t data structure if desired File ID cannot be found.
1331  */
1332 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1333 {
1334     smb_fid_t *fidp;
1335     int newFid = 0;
1336         
1337     if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1338         return NULL;
1339
1340     lock_ObtainWrite(&smb_rctLock);
1341     /* figure out if we need to allocate a new file ID */
1342     if (fid == 0) {
1343         newFid = 1;
1344         fid = vcp->fidCounter;
1345     }
1346
1347   retry:
1348     for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1349         if (fid == fidp->fid) {
1350             if (newFid) {
1351                 fid++;
1352                 if (fid == 0) {
1353                     osi_Log1(smb_logp,
1354                              "New FID number wraps on vcp 0x%x", vcp);
1355                     fid = 1;
1356                 }
1357                 goto retry;
1358             }
1359             fidp->refCount++;
1360             break;
1361         }
1362     }
1363
1364     if (!fidp && (flags & SMB_FLAG_CREATE)) {
1365         char eventName[MAX_PATH];
1366         EVENT_HANDLE event;
1367         sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1368         event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1369         if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1370             osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1371             thrd_CloseHandle(event);
1372             fid++;
1373             if (fid == 0) {
1374                 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1375                 fid = 1;
1376             }
1377             goto retry;
1378         }
1379
1380         fidp = malloc(sizeof(*fidp));
1381         memset(fidp, 0, sizeof(*fidp));
1382         osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1383         fidp->refCount = 1;
1384         fidp->vcp = vcp;
1385         smb_HoldVCNoLock(vcp);
1386         lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1387         fidp->fid = fid;
1388         fidp->curr_chunk = fidp->prev_chunk = -2;
1389         fidp->raw_write_event = event;
1390         if (newFid) {
1391             vcp->fidCounter = fid+1;
1392             if (vcp->fidCounter == 0) {
1393                 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1394                          vcp);
1395                 vcp->fidCounter = 1;
1396         }
1397     }
1398     }
1399
1400     lock_ReleaseWrite(&smb_rctLock);
1401     return fidp;
1402 }
1403
1404 void smb_ReleaseFID(smb_fid_t *fidp)
1405 {
1406     cm_scache_t *scp;
1407     cm_user_t *userp;
1408     smb_vc_t *vcp = NULL;
1409     smb_ioctl_t *ioctlp;
1410
1411     if (!fidp)
1412         return;
1413
1414     scp = NULL;
1415     userp = NULL;
1416     lock_ObtainWrite(&smb_rctLock);
1417     osi_assert(fidp->refCount-- > 0);
1418     if (fidp->refCount == 0 && (fidp->flags & SMB_FID_DELETE)) {
1419         vcp = fidp->vcp;
1420         fidp->vcp = NULL;
1421         scp = fidp->scp;    /* release after lock is released */
1422         fidp->scp = NULL;
1423         userp = fidp->userp;
1424         fidp->userp = NULL;
1425
1426         osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1427         thrd_CloseHandle(fidp->raw_write_event);
1428
1429         /* and see if there is ioctl stuff to free */
1430         ioctlp = fidp->ioctlp;
1431         if (ioctlp) {
1432             if (ioctlp->prefix)
1433                 cm_FreeSpace(ioctlp->prefix);
1434             if (ioctlp->inAllocp)
1435                 free(ioctlp->inAllocp);
1436             if (ioctlp->outAllocp)
1437                 free(ioctlp->outAllocp);
1438             free(ioctlp);
1439         }       
1440
1441         free(fidp);
1442
1443         smb_ReleaseVCNoLock(vcp);
1444     }
1445     lock_ReleaseWrite(&smb_rctLock);
1446
1447     /* now release the scache structure */
1448     if (scp) 
1449         cm_ReleaseSCache(scp);
1450
1451     if (userp)
1452         cm_ReleaseUser(userp);
1453 }       
1454
1455 /*
1456  * Case-insensitive search for one string in another;
1457  * used to find variable names in submount pathnames.
1458  */
1459 static char *smb_stristr(char *str1, char *str2)
1460 {
1461     char *cursor;
1462
1463     for (cursor = str1; *cursor; cursor++)
1464         if (stricmp(cursor, str2) == 0)
1465             return cursor;
1466
1467     return NULL;
1468 }
1469
1470 /*
1471  * Substitute a variable value for its name in a submount pathname.  Variable
1472  * name has been identified by smb_stristr() and is in substr.  Variable name
1473  * length (plus one) is in substr_size.  Variable value is in newstr.
1474  */
1475 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1476                       char *newstr)
1477 {
1478     char temp[1024];
1479
1480     strcpy(temp, substr + substr_size - 1);
1481     strcpy(substr, newstr);
1482     strcat(str1, temp);
1483 }       
1484
1485 char VNUserName[] = "%USERNAME%";
1486 char VNLCUserName[] = "%LCUSERNAME%";
1487 char VNComputerName[] = "%COMPUTERNAME%";
1488 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1489
1490 #ifdef DJGPP
1491 /* List available shares */
1492 int smb_ListShares()
1493 {
1494     char sbmtpath[256];
1495     char pathName[256];
1496     char shareBuf[4096];
1497     int num_shares=0;
1498     char *this_share;
1499     int len;
1500     char *p;
1501     int print_afs = 0;
1502     int code;
1503
1504     /*strcpy(shareNameList[num_shares], "all");
1505       strcpy(pathNameList[num_shares++], "/afs");*/
1506     fprintf(stderr, "The following shares are available:\n");
1507     fprintf(stderr, "Share Name (AFS Path)\n");
1508     fprintf(stderr, "---------------------\n");
1509     fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
1510
1511 #ifndef DJGPP
1512     code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1513     if (code == 0 || code > sizeof(sbmtpath)) return -1;
1514 #else
1515     strcpy(sbmtpath, cm_confDir);
1516 #endif /* !DJGPP */
1517     strcat(sbmtpath, "/afsdsbmt.ini");
1518     len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1519                                    shareBuf, sizeof(shareBuf),
1520                                    sbmtpath);
1521     if (len == 0) {
1522         return num_shares;
1523     }
1524
1525     this_share = shareBuf;
1526     do
1527     {
1528         print_afs = 0;
1529         /*strcpy(shareNameList[num_shares], this_share);*/
1530         len = GetPrivateProfileString("AFS Submounts", this_share,
1531                                        NULL,
1532                                        pathName, 256,
1533                                        sbmtpath);
1534         if (!len) 
1535             return num_shares;
1536         p = pathName;
1537         if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) != 0)
1538             print_afs = 1;
1539         while (*p) {
1540             if (*p == '\\') *p = '/';    /* change to / */
1541             p++;
1542         }
1543
1544         fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1545                  smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
1546                  pathName);
1547         num_shares++;
1548         while (*this_share != 0) this_share++;  /* find next NUL */
1549         this_share++;   /* skip past the NUL */
1550     } while (*this_share != 0);  /* stop at final NUL */
1551
1552     return num_shares;
1553 }
1554 #endif /* DJGPP */
1555
1556 typedef struct smb_findShare_rock {
1557     char * shareName;
1558     char * match;
1559     int matchType;
1560 } smb_findShare_rock_t;
1561
1562 #define SMB_FINDSHARE_EXACT_MATCH 1
1563 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1564
1565 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1566                        osi_hyper_t *offp)
1567 {
1568     int matchType = 0;
1569     smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1570     if (!strnicmp(dep->name, vrock->shareName, 12)) {
1571         if(!stricmp(dep->name, vrock->shareName))
1572             matchType = SMB_FINDSHARE_EXACT_MATCH;
1573         else
1574             matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1575         if(vrock->match) free(vrock->match);
1576         vrock->match = strdup(dep->name);
1577         vrock->matchType = matchType;
1578
1579         if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1580             return CM_ERROR_STOPNOW;
1581     }
1582     return 0;
1583 }
1584
1585
1586 /* find a shareName in the table of submounts */
1587 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1588         char **pathNamep)
1589 {
1590     DWORD len;
1591     char pathName[1024];
1592     char *var;
1593     char temp[1024];
1594     DWORD sizeTemp;
1595 #ifdef DJGPP
1596     char sbmtpath[MAX_PATH];
1597 #endif
1598     char *p, *q;
1599     HKEY parmKey;
1600     DWORD code;
1601     DWORD allSubmount = 1;
1602
1603     /* if allSubmounts == 0, only return the //mountRoot/all share 
1604      * if in fact it has been been created in the subMounts table.  
1605      * This is to allow sites that want to restrict access to the 
1606      * world to do so.
1607      */
1608     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1609                          0, KEY_QUERY_VALUE, &parmKey);
1610     if (code == ERROR_SUCCESS) {
1611         len = sizeof(allSubmount);
1612         code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1613                                 (BYTE *) &allSubmount, &len);
1614         if (code != ERROR_SUCCESS) {
1615             allSubmount = 1;
1616         }
1617         RegCloseKey (parmKey);
1618     }
1619
1620     if (allSubmount && _stricmp(shareName, "all") == 0) {
1621         *pathNamep = NULL;
1622         return 1;
1623     }
1624
1625     /* In case, the all share is disabled we need to still be able
1626      * to handle ioctl requests 
1627      */
1628     if (_stricmp(shareName, "ioctl$") == 0) {
1629         *pathNamep = strdup("/.__ioctl__");
1630         return 1;
1631     }
1632
1633     if (_stricmp(shareName, "IPC$") == 0 ||
1634         _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1635         _stricmp(shareName, "DESKTOP.INI") == 0
1636          ) {
1637         *pathNamep = NULL;
1638         return 0;
1639     }
1640
1641 #ifndef DJGPP
1642     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1643                          0, KEY_QUERY_VALUE, &parmKey);
1644     if (code == ERROR_SUCCESS) {
1645         len = sizeof(pathName);
1646         code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1647                                 (BYTE *) pathName, &len);
1648         if (code != ERROR_SUCCESS)
1649             len = 0;
1650         RegCloseKey (parmKey);
1651     } else {
1652         len = 0;
1653     }   
1654 #else /* DJGPP */
1655     strcpy(sbmtpath, cm_confDir);
1656     strcat(sbmtpath, "/afsdsbmt.ini");
1657     len = GetPrivateProfileString("AFS Submounts", shareName, "",
1658                                    pathName, sizeof(pathName), sbmtpath);
1659 #endif /* !DJGPP */
1660     if (len != 0 && len != sizeof(pathName) - 1) {
1661         /* We can accept either unix or PC style AFS pathnames.  Convert
1662          * Unix-style to PC style here for internal use. 
1663          */
1664         p = pathName;
1665         if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1666             p += strlen(cm_mountRoot);  /* skip mount path */
1667         q = p;
1668         while (*q) {
1669             if (*q == '/') *q = '\\';    /* change to \ */
1670             q++;
1671         }
1672
1673         while (1)
1674         {
1675             if (var = smb_stristr(p, VNUserName)) {
1676                 if (uidp && uidp->unp)
1677                     smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1678                 else
1679                     smb_subst(p, var, sizeof(VNUserName)," ");
1680             }
1681             else if (var = smb_stristr(p, VNLCUserName)) 
1682             {
1683                 if (uidp && uidp->unp)
1684                     strcpy(temp, uidp->unp->name);
1685                 else 
1686                     strcpy(temp, " ");
1687                 _strlwr(temp);
1688                 smb_subst(p, var, sizeof(VNLCUserName), temp);
1689             }
1690             else if (var = smb_stristr(p, VNComputerName)) 
1691             {
1692                 sizeTemp = sizeof(temp);
1693                 GetComputerName((LPTSTR)temp, &sizeTemp);
1694                 smb_subst(p, var, sizeof(VNComputerName), temp);
1695             }
1696             else if (var = smb_stristr(p, VNLCComputerName)) 
1697             {
1698                 sizeTemp = sizeof(temp);
1699                 GetComputerName((LPTSTR)temp, &sizeTemp);
1700                 _strlwr(temp);
1701                 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1702             }
1703             else     
1704                 break;
1705         }
1706         *pathNamep = strdup(p);
1707         return 1;
1708     } 
1709     else
1710     {
1711         /* First lookup shareName in root.afs */
1712         cm_req_t req;
1713         smb_findShare_rock_t vrock;
1714         osi_hyper_t thyper;
1715         char * p = shareName; 
1716         int rw = 0;
1717
1718         /*  attempt to locate a partial match in root.afs.  This is because
1719             when using the ANSI RAP calls, the share name is limited to 13 chars
1720             and hence is truncated. Of course we prefer exact matches. */
1721         cm_InitReq(&req);
1722         thyper.HighPart = 0;
1723         thyper.LowPart = 0;
1724
1725         vrock.shareName = shareName;
1726         vrock.match = NULL;
1727         vrock.matchType = 0;
1728
1729         cm_HoldSCache(cm_data.rootSCachep);
1730         code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1731             (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1732         cm_ReleaseSCache(cm_data.rootSCachep);
1733
1734         if (vrock.matchType) {
1735             sprintf(pathName,"/%s/",vrock.match);
1736             *pathNamep = strdup(strlwr(pathName));
1737             free(vrock.match);
1738             return 1;
1739         }
1740
1741         /* if we get here, there was no match for the share in root.afs */
1742         /* so try to create  \\<netbiosName>\<cellname>  */
1743         if ( *p == '.' ) {
1744             p++;
1745             rw = 1;
1746         }
1747         /* Get the full name for this cell */
1748         code = cm_SearchCellFile(p, temp, 0, 0);
1749 #ifdef AFS_AFSDB_ENV
1750         if (code && cm_dnsEnabled) {
1751             int ttl;
1752             code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1753         }
1754 #endif
1755         /* construct the path */
1756         if (code == 0) {     
1757             sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1758             *pathNamep = strdup(strlwr(pathName));
1759             return 1;
1760         }
1761     }
1762     /* failure */
1763     *pathNamep = NULL;
1764     return 0;
1765 }
1766
1767 /* Client-side offline caching policy types */
1768 #define CSC_POLICY_MANUAL 0
1769 #define CSC_POLICY_DOCUMENTS 1
1770 #define CSC_POLICY_PROGRAMS 2
1771 #define CSC_POLICY_DISABLE 3
1772
1773 int smb_FindShareCSCPolicy(char *shareName)
1774 {
1775     DWORD len;
1776     char policy[1024];
1777     DWORD dwType;
1778     HKEY hkCSCPolicy;
1779     int  retval = CSC_POLICY_MANUAL;
1780
1781     RegCreateKeyEx( HKEY_LOCAL_MACHINE, 
1782                     AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1783                     0, 
1784                     "AFS", 
1785                     REG_OPTION_NON_VOLATILE,
1786                     KEY_READ,
1787                     NULL, 
1788                     &hkCSCPolicy,
1789                     NULL );
1790
1791     len = sizeof(policy);
1792     if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1793          len == 0) {
1794         retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1795     }
1796     else if (stricmp(policy, "documents") == 0)
1797     {
1798         retval = CSC_POLICY_DOCUMENTS;
1799     }
1800     else if (stricmp(policy, "programs") == 0)
1801     {
1802         retval = CSC_POLICY_PROGRAMS;
1803     }
1804     else if (stricmp(policy, "disable") == 0)
1805     {
1806         retval = CSC_POLICY_DISABLE;
1807     }
1808         
1809     RegCloseKey(hkCSCPolicy);
1810     return retval;
1811 }
1812
1813 /* find a dir search structure by cookie value, and return it held.
1814  * Must be called with smb_globalLock held.
1815  */
1816 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
1817 {
1818     smb_dirSearch_t *dsp;
1819         
1820     for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1821         if (dsp->cookie == cookie) {
1822             if (dsp != smb_firstDirSearchp) {
1823                 /* move to head of LRU queue, too, if we're not already there */
1824                 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1825                     smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
1826                 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1827                 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1828                 if (!smb_lastDirSearchp)
1829                     smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1830             }
1831             lock_ObtainMutex(&dsp->mx);
1832             dsp->refCount++;
1833             lock_ReleaseMutex(&dsp->mx);
1834             break;
1835         }
1836     }
1837
1838     if (dsp == NULL) {
1839         osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
1840         for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1841             osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
1842         }
1843     }
1844     return dsp;
1845 }       
1846
1847 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1848 {
1849     lock_ObtainWrite(&smb_globalLock);
1850     lock_ObtainMutex(&dsp->mx);
1851     dsp->flags |= SMB_DIRSEARCH_DELETE;
1852     if (dsp->scp != NULL) {
1853         lock_ObtainMutex(&dsp->scp->mx);
1854         if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1855             dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1856             dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1857             dsp->scp->bulkStatProgress = hones;
1858         }       
1859         lock_ReleaseMutex(&dsp->scp->mx);
1860     }   
1861     lock_ReleaseMutex(&dsp->mx);
1862     lock_ReleaseWrite(&smb_globalLock);
1863 }               
1864
1865 /* Must be called with the smb_globalLock held */
1866 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
1867 {
1868     cm_scache_t *scp = NULL;
1869
1870     lock_ObtainMutex(&dsp->mx);
1871     osi_assert(dsp->refCount-- > 0);
1872     if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1873         if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1874             smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1875         osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1876         lock_ReleaseMutex(&dsp->mx);
1877         lock_FinalizeMutex(&dsp->mx);
1878         scp = dsp->scp;
1879         free(dsp);
1880     } else {
1881         lock_ReleaseMutex(&dsp->mx);
1882     }
1883     /* do this now to avoid spurious locking hierarchy creation */
1884     if (scp) 
1885         cm_ReleaseSCache(scp);
1886 }       
1887
1888 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1889 {
1890     lock_ObtainWrite(&smb_globalLock);
1891     smb_ReleaseDirSearchNoLock(dsp);
1892     lock_ReleaseWrite(&smb_globalLock);
1893 }       
1894
1895 /* find a dir search structure by cookie value, and return it held */
1896 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1897 {
1898     smb_dirSearch_t *dsp;
1899
1900     lock_ObtainWrite(&smb_globalLock);
1901     dsp = smb_FindDirSearchNoLock(cookie);
1902     lock_ReleaseWrite(&smb_globalLock);
1903     return dsp;
1904 }
1905
1906 /* GC some dir search entries, in the address space expected by the specific protocol.
1907  * Must be called with smb_globalLock held; release the lock temporarily.
1908  */
1909 #define SMB_DIRSEARCH_GCMAX     10      /* how many at once */
1910 void smb_GCDirSearches(int isV3)
1911 {
1912     smb_dirSearch_t *prevp;
1913     smb_dirSearch_t *tp;
1914     smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1915     int victimCount;
1916     int i;
1917         
1918     victimCount = 0;    /* how many have we got so far */
1919     for (tp = smb_lastDirSearchp; tp; tp=prevp) {
1920         /* we'll move tp from queue, so
1921          * do this early.
1922          */
1923         prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);  
1924         /* if no one is using this guy, and we're either in the new protocol,
1925          * or we're in the old one and this is a small enough ID to be useful
1926          * to the old protocol, GC this guy.
1927          */
1928         if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1929             /* hold and delete */
1930             tp->flags |= SMB_DIRSEARCH_DELETE;
1931             victimsp[victimCount++] = tp;
1932             tp->refCount++;
1933         }
1934
1935         /* don't do more than this */
1936         if (victimCount >= SMB_DIRSEARCH_GCMAX) 
1937             break;
1938     }
1939         
1940     /* now release them */
1941     for (i = 0; i < victimCount; i++) {
1942         smb_ReleaseDirSearchNoLock(victimsp[i]);
1943     }
1944 }
1945
1946 /* function for allocating a dir search entry.  We need these to remember enough context
1947  * since we don't get passed the path from call to call during a directory search.
1948  *
1949  * Returns a held dir search structure, and bumps the reference count on the vnode,
1950  * since it saves a pointer to the vnode.
1951  */
1952 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1953 {
1954     smb_dirSearch_t *dsp;
1955     int counter;
1956     int maxAllowed;
1957     int start;
1958     int wrapped = 0;
1959
1960     lock_ObtainWrite(&smb_globalLock);
1961     counter = 0;
1962
1963     /* what's the biggest ID allowed in this version of the protocol */
1964     maxAllowed = isV3 ? 65535 : 255;
1965     if (smb_dirSearchCounter > maxAllowed)
1966         smb_dirSearchCounter = 1;
1967
1968     start = smb_dirSearchCounter;
1969
1970     while (1) {
1971         /* twice so we have enough tries to find guys we GC after one pass;
1972          * 10 extra is just in case I mis-counted.
1973          */
1974         if (++counter > 2*maxAllowed+10) 
1975             osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
1976
1977         if (smb_dirSearchCounter > maxAllowed) {        
1978             smb_dirSearchCounter = 1;
1979         }
1980         if (smb_dirSearchCounter == start) {
1981             if (wrapped)
1982                 smb_GCDirSearches(isV3);
1983             wrapped++;
1984         }
1985         dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
1986         if (dsp) {
1987             /* don't need to watch for refcount zero and deleted, since
1988             * we haven't dropped the global lock.
1989             */
1990             lock_ObtainMutex(&dsp->mx);
1991             dsp->refCount--;
1992             lock_ReleaseMutex(&dsp->mx);
1993             ++smb_dirSearchCounter;
1994             continue;
1995         }       
1996
1997         dsp = malloc(sizeof(*dsp));
1998         memset(dsp, 0, sizeof(*dsp));
1999         dsp->cookie = smb_dirSearchCounter;
2000         ++smb_dirSearchCounter;
2001         dsp->refCount = 1;
2002         lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
2003         dsp->lastTime = osi_Time();
2004         osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2005         if (!smb_lastDirSearchp) 
2006             smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2007         break;
2008     }   
2009     lock_ReleaseWrite(&smb_globalLock);
2010     return dsp;
2011 }
2012
2013 static smb_packet_t *GetPacket(void)
2014 {
2015     smb_packet_t *tbp;
2016 #ifdef DJGPP
2017     unsigned int npar, seg, tb_sel;
2018 #endif
2019
2020     lock_ObtainWrite(&smb_globalLock);
2021     tbp = smb_packetFreeListp;
2022     if (tbp) 
2023         smb_packetFreeListp = tbp->nextp;
2024     lock_ReleaseWrite(&smb_globalLock);
2025     if (!tbp) {
2026 #ifndef DJGPP
2027         tbp = calloc(65540,1);
2028 #else /* DJGPP */
2029         tbp = malloc(sizeof(smb_packet_t));
2030 #endif /* !DJGPP */
2031         tbp->magic = SMB_PACKETMAGIC;
2032         tbp->ncbp = NULL;
2033         tbp->vcp = NULL;
2034         tbp->resumeCode = 0;
2035         tbp->inCount = 0;
2036         tbp->fid = 0;
2037         tbp->wctp = NULL;
2038         tbp->inCom = 0;
2039         tbp->oddByte = 0;
2040         tbp->ncb_length = 0;
2041         tbp->flags = 0;
2042         tbp->spacep = NULL;
2043         
2044 #ifdef DJGPP
2045         npar = SMB_PACKETSIZE >> 4;  /* number of paragraphs */
2046         {
2047             signed int retval =
2048                 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
2049             if (retval == -1) {
2050                 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS memory",
2051                           npar);
2052                 osi_panic("",__FILE__,__LINE__);
2053             }
2054             else {
2055                 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X",
2056                           npar, retval);
2057                 seg = retval;
2058             }
2059         }
2060         tbp->dos_pkt = (seg * 16) + 0;  /* DOS physical address */
2061         tbp->dos_pkt_sel = tb_sel;
2062 #endif /* DJGPP */
2063     }
2064     osi_assert(tbp->magic == SMB_PACKETMAGIC);
2065
2066     return tbp;
2067 }
2068
2069 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2070 {
2071     smb_packet_t *tbp;
2072     tbp = GetPacket();
2073     memcpy(tbp, pkt, sizeof(smb_packet_t));
2074     tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2075     if (tbp->vcp)
2076         smb_HoldVC(tbp->vcp);
2077     return tbp;
2078 }
2079
2080 static NCB *GetNCB(void)
2081 {
2082     smb_ncb_t *tbp;
2083     NCB *ncbp;
2084 #ifdef DJGPP
2085     unsigned int npar, seg, tb_sel;
2086 #endif /* DJGPP */
2087
2088     lock_ObtainWrite(&smb_globalLock);
2089     tbp = smb_ncbFreeListp;
2090     if (tbp) 
2091         smb_ncbFreeListp = tbp->nextp;
2092     lock_ReleaseWrite(&smb_globalLock);
2093     if (!tbp) {
2094 #ifndef DJGPP
2095         tbp = calloc(sizeof(*tbp),1);
2096 #else /* DJGPP */
2097         tbp = malloc(sizeof(*tbp));
2098         npar = (sizeof(NCB)+15) >> 4;  /* number of paragraphs */
2099         {
2100             signed int retval =
2101                 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
2102             if (retval == -1) {
2103                 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS mem in GetNCB",
2104                           npar);
2105                 osi_panic("",__FILE__,__LINE__);
2106             } else {
2107                 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
2108                           npar, retval);
2109                 seg = retval;
2110             }
2111         }
2112         tbp->dos_ncb = (seg * 16) + 0;  /* DOS physical address */
2113         tbp->dos_ncb_sel = tb_sel;
2114 #endif /* !DJGPP */
2115         tbp->magic = SMB_NCBMAGIC;
2116     }
2117         
2118     osi_assert(tbp->magic == SMB_NCBMAGIC);
2119
2120     memset(&tbp->ncb, 0, sizeof(NCB));
2121     ncbp = &tbp->ncb;
2122 #ifdef DJGPP
2123     dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
2124 #endif /* DJGPP */
2125     return ncbp;
2126 }
2127
2128 void smb_FreePacket(smb_packet_t *tbp)
2129 {
2130     smb_vc_t * vcp = NULL;
2131     osi_assert(tbp->magic == SMB_PACKETMAGIC);
2132         
2133     lock_ObtainWrite(&smb_globalLock);
2134     tbp->nextp = smb_packetFreeListp;
2135     smb_packetFreeListp = tbp;
2136     tbp->magic = SMB_PACKETMAGIC;
2137     tbp->ncbp = NULL;
2138     vcp = tbp->vcp;
2139     tbp->vcp = NULL;
2140     tbp->resumeCode = 0;
2141     tbp->inCount = 0;
2142     tbp->fid = 0;
2143     tbp->wctp = NULL;
2144     tbp->inCom = 0;
2145     tbp->oddByte = 0;
2146     tbp->ncb_length = 0;
2147     tbp->flags = 0;
2148     lock_ReleaseWrite(&smb_globalLock);
2149
2150     if (vcp)
2151         smb_ReleaseVC(vcp);
2152 }
2153
2154 static void FreeNCB(NCB *bufferp)
2155 {
2156     smb_ncb_t *tbp;
2157         
2158     tbp = (smb_ncb_t *) bufferp;
2159     osi_assert(tbp->magic == SMB_NCBMAGIC);
2160         
2161     lock_ObtainWrite(&smb_globalLock);
2162     tbp->nextp = smb_ncbFreeListp;
2163     smb_ncbFreeListp = tbp;
2164     lock_ReleaseWrite(&smb_globalLock);
2165 }
2166
2167 /* get a ptr to the data part of a packet, and its count */
2168 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2169 {
2170     int parmBytes;
2171     int dataBytes;
2172     unsigned char *afterParmsp;
2173
2174     parmBytes = *smbp->wctp << 1;
2175     afterParmsp = smbp->wctp + parmBytes + 1;
2176         
2177     dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2178     if (nbytesp) *nbytesp = dataBytes;
2179         
2180     /* don't forget to skip the data byte count, since it follows
2181      * the parameters; that's where the "2" comes from below.
2182      */
2183     return (unsigned char *) (afterParmsp + 2);
2184 }
2185
2186 /* must set all the returned parameters before playing around with the
2187  * data region, since the data region is located past the end of the
2188  * variable number of parameters.
2189  */
2190 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2191 {
2192     unsigned char *afterParmsp;
2193
2194     afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2195         
2196     *afterParmsp++ = dsize & 0xff;
2197     *afterParmsp = (dsize>>8) & 0xff;
2198 }       
2199
2200 /* return the parm'th parameter in the smbp packet */
2201 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
2202 {
2203     int parmCount;
2204     unsigned char *parmDatap;
2205
2206     parmCount = *smbp->wctp;
2207
2208     if (parm >= parmCount) {
2209         char s[100];
2210
2211         sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2212                 parm, parmCount, smbp->ncb_length);
2213         osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2214                  parm, parmCount, smbp->ncb_length);
2215 #ifndef DJGPP
2216         LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM, 
2217                  __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2218 #endif /* !DJGPP */
2219         osi_panic(s, __FILE__, __LINE__);
2220     }
2221     parmDatap = smbp->wctp + (2*parm) + 1;
2222         
2223     return parmDatap[0] + (parmDatap[1] << 8);
2224 }
2225
2226 /* return the parm'th parameter in the smbp packet */
2227 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2228 {
2229     int parmCount;
2230     unsigned char *parmDatap;
2231
2232     parmCount = *smbp->wctp;
2233
2234     if (parm * 2 + offset >= parmCount * 2) {
2235         char s[100];
2236
2237         sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2238                 parm, offset, parmCount, smbp->ncb_length);
2239 #ifndef DJGPP
2240         LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET, 
2241                  __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2242 #endif /* !DJGPP */
2243         osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2244                 parm, offset, parmCount, smbp->ncb_length);
2245         osi_panic(s, __FILE__, __LINE__);
2246     }
2247     parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2248         
2249     return parmDatap[0] + (parmDatap[1] << 8);
2250 }
2251
2252 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2253 {
2254     char *parmDatap;
2255
2256     /* make sure we have enough slots */
2257     if (*smbp->wctp <= slot) 
2258         *smbp->wctp = slot+1;
2259         
2260     parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2261     *parmDatap++ = parmValue & 0xff;
2262     *parmDatap = (parmValue>>8) & 0xff;
2263 }       
2264
2265 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2266 {
2267     char *parmDatap;
2268
2269     /* make sure we have enough slots */
2270     if (*smbp->wctp <= slot) 
2271         *smbp->wctp = slot+2;
2272
2273     parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2274     *parmDatap++ = parmValue & 0xff;
2275     *parmDatap++ = (parmValue>>8) & 0xff;
2276     *parmDatap++ = (parmValue>>16) & 0xff;
2277     *parmDatap++ = (parmValue>>24) & 0xff;
2278 }
2279
2280 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2281 {
2282     char *parmDatap;
2283     int i;
2284
2285     /* make sure we have enough slots */
2286     if (*smbp->wctp <= slot) 
2287         *smbp->wctp = slot+4;
2288
2289     parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2290     for (i=0; i<8; i++)
2291         *parmDatap++ = *parmValuep++;
2292 }       
2293
2294 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2295 {
2296     char *parmDatap;
2297
2298     /* make sure we have enough slots */
2299     if (*smbp->wctp <= slot) {
2300         if (smbp->oddByte) {
2301             smbp->oddByte = 0;
2302             *smbp->wctp = slot+1;
2303         } else
2304             smbp->oddByte = 1;
2305     }
2306
2307     parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2308     *parmDatap++ = parmValue & 0xff;
2309 }
2310
2311 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2312 {
2313     char *lastSlashp;
2314         
2315     lastSlashp = strrchr(inPathp, '\\');
2316     if (lastComponentp)
2317         *lastComponentp = lastSlashp;
2318     if (lastSlashp) {
2319         while (1) {
2320             if (inPathp == lastSlashp) 
2321                 break;
2322             *outPathp++ = *inPathp++;
2323         }
2324         *outPathp++ = 0;
2325     }
2326     else {
2327         *outPathp++ = 0;
2328     }
2329 }
2330
2331 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2332 {
2333     if (*inp++ != 0x4) 
2334         return NULL;
2335     if (chainpp) {
2336         *chainpp = inp + strlen(inp) + 1;       /* skip over null-terminated string */
2337     }
2338     return inp;
2339 }
2340
2341 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2342 {
2343     int tlen;
2344
2345     if (*inp++ != 0x5) 
2346         return NULL;
2347     tlen = inp[0] + (inp[1]<<8);
2348     inp += 2;           /* skip length field */
2349
2350     if (chainpp) {
2351         *chainpp = inp + tlen;
2352     }
2353         
2354     if (lengthp) 
2355         *lengthp = tlen;
2356         
2357     return inp;
2358 }       
2359
2360 /* format a packet as a response */
2361 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2362 {
2363     smb_t *outp;
2364     smb_t *inSmbp;
2365
2366     outp = (smb_t *) op;
2367         
2368     /* zero the basic structure through the smb_wct field, and zero the data
2369      * size field, assuming that wct stays zero; otherwise, you have to 
2370      * explicitly set the data size field, too.
2371      */
2372     inSmbp = (smb_t *) inp;
2373     memset(outp, 0, sizeof(smb_t)+2);
2374     outp->id[0] = 0xff;
2375     outp->id[1] = 'S';
2376     outp->id[2] = 'M';
2377     outp->id[3] = 'B';
2378     if (inp) {
2379         outp->com = inSmbp->com;
2380         outp->tid = inSmbp->tid;
2381         outp->pid = inSmbp->pid;
2382         outp->uid = inSmbp->uid;
2383         outp->mid = inSmbp->mid;
2384         outp->res[0] = inSmbp->res[0];
2385         outp->res[1] = inSmbp->res[1];
2386         op->inCom = inSmbp->com;
2387     }
2388     outp->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
2389     outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2390
2391     /* copy fields in generic packet area */
2392     op->wctp = &outp->wct;
2393 }       
2394
2395 /* send a (probably response) packet; vcp tells us to whom to send it.
2396  * we compute the length by looking at wct and bcc fields.
2397  */
2398 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2399 {
2400     NCB *ncbp;
2401     int extra;
2402     long code = 0;
2403     unsigned char *tp;
2404     int localNCB = 0;
2405 #ifdef DJGPP
2406     dos_ptr dos_ncb;
2407 #endif /* DJGPP */
2408         
2409     ncbp = inp->ncbp;
2410     if (ncbp == NULL) {
2411         ncbp = GetNCB();
2412         localNCB = 1;
2413     }
2414 #ifdef DJGPP
2415     dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2416 #endif /* DJGPP */
2417  
2418     memset((char *)ncbp, 0, sizeof(NCB));
2419
2420     extra = 2 * (*inp->wctp);   /* space used by parms, in bytes */
2421     tp = inp->wctp + 1+ extra;  /* points to count of data bytes */
2422     extra += tp[0] + (tp[1]<<8);
2423     extra += (unsigned int)(inp->wctp - inp->data);     /* distance to last wct field */
2424     extra += 3;                 /* wct and length fields */
2425         
2426     ncbp->ncb_length = extra;   /* bytes to send */
2427     ncbp->ncb_lsn = (unsigned char) vcp->lsn;   /* vc to use */
2428     ncbp->ncb_lana_num = vcp->lana;
2429     ncbp->ncb_command = NCBSEND;        /* op means send data */
2430 #ifndef DJGPP
2431     ncbp->ncb_buffer = (char *) inp;/* packet */
2432     code = Netbios(ncbp);
2433 #else /* DJGPP */
2434     ncbp->ncb_buffer = inp->dos_pkt;/* packet */
2435     ((smb_ncb_t*)ncbp)->orig_pkt = inp;
2436
2437     /* copy header information from virtual to DOS address space */
2438     dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
2439     code = Netbios(ncbp, dos_ncb);
2440 #endif /* !DJGPP */
2441         
2442     if (code != 0) {
2443         const char * s = ncb_error_string(code);
2444         osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2445 #ifndef DJGPP
2446         LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
2447 #endif /* !DJGPP */
2448
2449         osi_Log2(smb_logp, "setting dead_vcp 0x%x, user struct 0x%x",
2450                   vcp, vcp->usersp);
2451         smb_HoldVC(vcp);
2452         if (dead_vcp) {
2453             osi_Log1(smb_logp,"Previous dead_vcp %x", dead_vcp);
2454             smb_CleanupDeadVC(dead_vcp);
2455             smb_ReleaseVC(dead_vcp);
2456         }
2457         dead_vcp = vcp;
2458         vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2459     }
2460
2461     if (localNCB)
2462         FreeNCB(ncbp);
2463 }
2464
2465 void smb_MapNTError(long code, unsigned long *NTStatusp)
2466 {
2467     unsigned long NTStatus;
2468
2469     /* map CM_ERROR_* errors to NT 32-bit status codes */
2470     /* NT Status codes are listed in ntstatus.h not winerror.h */
2471     if (code == CM_ERROR_NOSUCHCELL) {
2472         NTStatus = 0xC000000FL; /* No such file */
2473     }
2474     else if (code == CM_ERROR_NOSUCHVOLUME) {
2475         NTStatus = 0xC000000FL; /* No such file */
2476     }
2477     else if (code == CM_ERROR_TIMEDOUT) {
2478 #ifdef COMMENT
2479         NTStatus = 0xC00000CFL; /* Sharing Paused */
2480 #else
2481         NTStatus = 0x00000102L; /* Timeout */
2482 #endif
2483     }
2484     else if (code == CM_ERROR_RETRY) {
2485         NTStatus = 0xC000022DL; /* Retry */
2486     }
2487     else if (code == CM_ERROR_NOACCESS) {
2488         NTStatus = 0xC0000022L; /* Access denied */
2489     }
2490     else if (code == CM_ERROR_READONLY) {
2491         NTStatus = 0xC00000A2L; /* Write protected */
2492     }
2493     else if (code == CM_ERROR_NOSUCHFILE) {
2494         NTStatus = 0xC000000FL; /* No such file */
2495     }
2496     else if (code == CM_ERROR_NOSUCHPATH) {
2497         NTStatus = 0xC000003AL; /* Object path not found */
2498     }           
2499     else if (code == CM_ERROR_TOOBIG) {
2500         NTStatus = 0xC000007BL; /* Invalid image format */
2501     }
2502     else if (code == CM_ERROR_INVAL) {
2503         NTStatus = 0xC000000DL; /* Invalid parameter */
2504     }
2505     else if (code == CM_ERROR_BADFD) {
2506         NTStatus = 0xC0000008L; /* Invalid handle */
2507     }
2508     else if (code == CM_ERROR_BADFDOP) {
2509         NTStatus = 0xC0000022L; /* Access denied */
2510     }
2511     else if (code == CM_ERROR_EXISTS) {
2512         NTStatus = 0xC0000035L; /* Object name collision */
2513     }
2514     else if (code == CM_ERROR_NOTEMPTY) {
2515         NTStatus = 0xC0000101L; /* Directory not empty */
2516     }   
2517     else if (code == CM_ERROR_CROSSDEVLINK) {
2518         NTStatus = 0xC00000D4L; /* Not same device */
2519     }
2520     else if (code == CM_ERROR_NOTDIR) {
2521         NTStatus = 0xC0000103L; /* Not a directory */
2522     }
2523     else if (code == CM_ERROR_ISDIR) {
2524         NTStatus = 0xC00000BAL; /* File is a directory */
2525     }
2526     else if (code == CM_ERROR_BADOP) {
2527 #ifdef COMMENT
2528         /* I have no idea where this comes from */
2529         NTStatus = 0xC09820FFL; /* SMB no support */
2530 #else
2531         NTStatus = 0xC00000BBL;     /* Not supported */
2532 #endif /* COMMENT */
2533     }
2534     else if (code == CM_ERROR_BADSHARENAME) {
2535         NTStatus = 0xC00000CCL; /* Bad network name */
2536     }
2537     else if (code == CM_ERROR_NOIPC) {
2538 #ifdef COMMENT
2539         NTStatus = 0xC0000022L; /* Access Denied */
2540 #else   
2541         NTStatus = 0xC000013DL; /* Remote Resources */
2542 #endif
2543     }
2544     else if (code == CM_ERROR_CLOCKSKEW) {
2545         NTStatus = 0xC0000133L; /* Time difference at DC */
2546     }
2547     else if (code == CM_ERROR_BADTID) {
2548         NTStatus = 0xC0982005L; /* SMB bad TID */
2549     }
2550     else if (code == CM_ERROR_USESTD) {
2551         NTStatus = 0xC09820FBL; /* SMB use standard */
2552     }
2553     else if (code == CM_ERROR_QUOTA) {
2554 #ifdef COMMENT
2555         NTStatus = 0xC0000044L; /* Quota exceeded */
2556 #else
2557         NTStatus = 0xC000007FL; /* Disk full */
2558 #endif
2559     }
2560     else if (code == CM_ERROR_SPACE) {
2561         NTStatus = 0xC000007FL; /* Disk full */
2562     }
2563     else if (code == CM_ERROR_ATSYS) {
2564         NTStatus = 0xC0000033L; /* Object name invalid */
2565     }
2566     else if (code == CM_ERROR_BADNTFILENAME) {
2567         NTStatus = 0xC0000033L; /* Object name invalid */
2568     }
2569     else if (code == CM_ERROR_WOULDBLOCK) {
2570         NTStatus = 0xC0000055L; /* Lock not granted */
2571     }
2572     else if (code == CM_ERROR_SHARING_VIOLATION) {
2573         NTStatus = 0xC0000043L; /* Sharing violation */
2574     }
2575     else if (code == CM_ERROR_LOCK_CONFLICT) {
2576         NTStatus = 0xC0000054L; /* Lock conflict */
2577     }
2578     else if (code == CM_ERROR_PARTIALWRITE) {
2579         NTStatus = 0xC000007FL; /* Disk full */
2580     }
2581     else if (code == CM_ERROR_BUFFERTOOSMALL) {
2582         NTStatus = 0xC0000023L; /* Buffer too small */
2583     }
2584     else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2585         NTStatus = 0xC0000035L; /* Object name collision */
2586     }   
2587     else if (code == CM_ERROR_BADPASSWORD) {
2588         NTStatus = 0xC000006DL; /* unknown username or bad password */
2589     }
2590     else if (code == CM_ERROR_BADLOGONTYPE) {
2591         NTStatus = 0xC000015BL; /* logon type not granted */
2592     }
2593     else if (code == CM_ERROR_GSSCONTINUE) {
2594         NTStatus = 0xC0000016L; /* more processing required */
2595     }
2596     else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2597 #ifdef COMMENT
2598         NTStatus = 0xC0000280L; /* reparse point not resolved */
2599 #else
2600         NTStatus = 0xC0000022L; /* Access Denied */
2601 #endif
2602     }
2603     else if (code == CM_ERROR_PATH_NOT_COVERED) {
2604         NTStatus = 0xC0000257L; /* Path Not Covered */
2605     } 
2606 #ifdef COMMENT
2607     else if (code == CM_ERROR_ALLBUSY) {
2608         NTStatus = 0xC00000BFL; /* Network Busy */
2609     } 
2610     else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
2611         NTStatus = 0xC0000350L; /* Remote Host Down */
2612     } 
2613 #else
2614     /* we do not want to be telling the SMB/CIFS client that
2615      * the AFS Client Service is busy or down.  
2616      */
2617     else if (code == CM_ERROR_ALLBUSY || 
2618              code == CM_ERROR_ALLOFFLINE ||
2619              code == CM_ERROR_ALLDOWN) {
2620         NTStatus = 0xC00000BEL; /* Bad Network Path */
2621     }
2622 #endif
2623     else if (code == RXKADUNKNOWNKEY) {
2624         NTStatus = 0xC0000322L; /* Bad Kerberos key */
2625     } else {
2626         NTStatus = 0xC0982001L; /* SMB non-specific error */
2627     }
2628
2629     *NTStatusp = NTStatus;
2630     osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2631 }       
2632
2633 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2634                       unsigned char *classp)
2635 {
2636     unsigned char class;
2637     unsigned short error;
2638
2639     /* map CM_ERROR_* errors to SMB errors */
2640     if (code == CM_ERROR_NOSUCHCELL) {
2641         class = 1;
2642         error = 3;      /* bad path */
2643     }
2644     else if (code == CM_ERROR_NOSUCHVOLUME) {
2645         class = 1;
2646         error = 3;      /* bad path */
2647     }
2648     else if (code == CM_ERROR_TIMEDOUT) {
2649         class = 2;
2650         error = 81;     /* server is paused */
2651     }
2652     else if (code == CM_ERROR_RETRY) {
2653         class = 2;      /* shouldn't happen */
2654         error = 1;
2655     }
2656     else if (code == CM_ERROR_NOACCESS) {
2657         class = 2;
2658         error = 4;      /* bad access */
2659     }
2660     else if (code == CM_ERROR_READONLY) {
2661         class = 3;
2662         error = 19;     /* read only */
2663     }
2664     else if (code == CM_ERROR_NOSUCHFILE) {
2665         class = 1;
2666         error = 2;      /* ENOENT! */
2667     }
2668     else if (code == CM_ERROR_NOSUCHPATH) {
2669         class = 1;
2670         error = 3;      /* Bad path */
2671     }
2672     else if (code == CM_ERROR_TOOBIG) {
2673         class = 1;
2674         error = 11;     /* bad format */
2675     }
2676     else if (code == CM_ERROR_INVAL) {
2677         class = 2;      /* server non-specific error code */
2678         error = 1;
2679     }
2680     else if (code == CM_ERROR_BADFD) {
2681         class = 1;
2682         error = 6;      /* invalid file handle */
2683     }
2684     else if (code == CM_ERROR_BADFDOP) {
2685         class = 1;      /* invalid op on FD */
2686         error = 5;
2687     }
2688     else if (code == CM_ERROR_EXISTS) {
2689         class = 1;
2690         error = 80;     /* file already exists */
2691     }
2692     else if (code == CM_ERROR_NOTEMPTY) {
2693         class = 1;
2694         error = 5;      /* delete directory not empty */
2695     }
2696     else if (code == CM_ERROR_CROSSDEVLINK) {
2697         class = 1;
2698         error = 17;     /* EXDEV */
2699     }
2700     else if (code == CM_ERROR_NOTDIR) {
2701         class = 1;      /* bad path */
2702         error = 3;
2703     }
2704     else if (code == CM_ERROR_ISDIR) {
2705         class = 1;      /* access denied; DOS doesn't have a good match */
2706         error = 5;
2707     }       
2708     else if (code == CM_ERROR_BADOP) {
2709         class = 2;
2710         error = 65535;
2711     }
2712     else if (code == CM_ERROR_BADSHARENAME) {
2713         class = 2;
2714         error = 6;
2715     }
2716     else if (code == CM_ERROR_NOIPC) {
2717         class = 2;
2718         error = 4; /* bad access */
2719     }
2720     else if (code == CM_ERROR_CLOCKSKEW) {
2721         class = 1;      /* invalid function */
2722         error = 1;
2723     }
2724     else if (code == CM_ERROR_BADTID) {
2725         class = 2;
2726         error = 5;
2727     }
2728     else if (code == CM_ERROR_USESTD) {
2729         class = 2;
2730         error = 251;
2731     }
2732     else if (code == CM_ERROR_REMOTECONN) {
2733         class = 2;
2734         error = 82;
2735     }
2736     else if (code == CM_ERROR_QUOTA) {
2737         if (vcp->flags & SMB_VCFLAG_USEV3) {
2738             class = 3;
2739             error = 39; /* disk full */
2740         }
2741         else {
2742             class = 1;
2743             error = 5;  /* access denied */
2744         }
2745     }
2746     else if (code == CM_ERROR_SPACE) {
2747         if (vcp->flags & SMB_VCFLAG_USEV3) {
2748             class = 3;
2749             error = 39; /* disk full */
2750         }
2751         else {
2752             class = 1;
2753             error = 5;  /* access denied */
2754         }
2755     }
2756     else if (code == CM_ERROR_PARTIALWRITE) {
2757         class = 3;
2758         error = 39;     /* disk full */
2759     }
2760     else if (code == CM_ERROR_ATSYS) {
2761         class = 1;
2762         error = 2;      /* ENOENT */
2763     }
2764     else if (code == CM_ERROR_WOULDBLOCK) {
2765         class = 1;
2766         error = 33;     /* lock conflict */
2767     }
2768     else if (code == CM_ERROR_LOCK_CONFLICT) {
2769         class = 1;
2770         error = 33;     /* lock conflict */
2771     }
2772     else if (code == CM_ERROR_SHARING_VIOLATION) {
2773         class = 1;
2774         error = 33;     /* lock conflict */
2775     }
2776     else if (code == CM_ERROR_NOFILES) {
2777         class = 1;
2778         error = 18;     /* no files in search */
2779     }
2780     else if (code == CM_ERROR_RENAME_IDENTICAL) {
2781         class = 1;
2782         error = 183;     /* Samba uses this */
2783     }
2784     else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2785         /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2786         class = 2;
2787         error = 2; /* bad password */
2788     }
2789     else if (code == CM_ERROR_PATH_NOT_COVERED) {
2790         class = 2;
2791         error = 3;     /* bad path */
2792     }
2793     else {
2794         class = 2;
2795         error = 1;
2796     }
2797
2798     *scodep = error;
2799     *classp = class;
2800     osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2801 }       
2802
2803 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2804 {
2805     osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2806     return CM_ERROR_BADOP;
2807 }
2808
2809 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2810 {
2811     unsigned short EchoCount, i;
2812     char *data, *outdata;
2813     int dataSize;
2814
2815     EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2816
2817     for (i=1; i<=EchoCount; i++) {
2818         data = smb_GetSMBData(inp, &dataSize);
2819         smb_SetSMBParm(outp, 0, i);
2820         smb_SetSMBDataLength(outp, dataSize);
2821         outdata = smb_GetSMBData(outp, NULL);
2822         memcpy(outdata, data, dataSize);
2823         smb_SendPacket(vcp, outp);
2824     }
2825
2826     return 0;
2827 }
2828
2829 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2830 {
2831     osi_hyper_t offset;
2832     long count, minCount, finalCount;
2833     unsigned short fd;
2834     unsigned pid;
2835     smb_fid_t *fidp;
2836     long code = 0;
2837     cm_user_t *userp = NULL;
2838     NCB *ncbp;
2839     int rc;
2840 #ifndef DJGPP
2841     char *rawBuf = NULL;
2842 #else
2843     dos_ptr rawBuf = NULL;
2844     dos_ptr dos_ncb;
2845 #endif /* DJGPP */
2846
2847     rawBuf = NULL;
2848     finalCount = 0;
2849
2850     fd = smb_GetSMBParm(inp, 0);
2851     count = smb_GetSMBParm(inp, 3);
2852     minCount = smb_GetSMBParm(inp, 4);
2853     offset.HighPart = 0;        /* too bad */
2854     offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2855
2856     osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2857              fd, offset.LowPart, count);
2858
2859     fidp = smb_FindFID(vcp, fd, 0);
2860     if (!fidp)
2861         goto send1;
2862
2863     pid = ((smb_t *) inp)->pid;
2864     {
2865         LARGE_INTEGER LOffset, LLength;
2866         cm_key_t key;
2867
2868         key = cm_GenerateKey(vcp->vcID, pid, fd);
2869
2870         LOffset.HighPart = 0;
2871         LOffset.LowPart = offset.LowPart;
2872         LLength.HighPart = 0;
2873         LLength.LowPart = count;
2874
2875         lock_ObtainMutex(&fidp->scp->mx);
2876         code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
2877         lock_ReleaseMutex(&fidp->scp->mx);
2878     }    
2879     if (code) {
2880         goto send1a;
2881     }
2882
2883     lock_ObtainMutex(&smb_RawBufLock);
2884     if (smb_RawBufs) {
2885         /* Get a raw buf, from head of list */
2886         rawBuf = smb_RawBufs;
2887 #ifndef DJGPP
2888         smb_RawBufs = *(char **)smb_RawBufs;
2889 #else /* DJGPP */
2890         smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2891 #endif /* !DJGPP */
2892     }
2893     lock_ReleaseMutex(&smb_RawBufLock);
2894     if (!rawBuf)
2895         goto send1a;
2896
2897     if (fidp->flags & SMB_FID_IOCTL)
2898     {
2899 #ifndef DJGPP
2900         rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2901 #else
2902         rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2903 #endif
2904         if (rawBuf) {
2905             /* Give back raw buffer */
2906             lock_ObtainMutex(&smb_RawBufLock);
2907 #ifndef DJGPP
2908             *((char **) rawBuf) = smb_RawBufs;
2909 #else /* DJGPP */
2910             _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2911 #endif /* !DJGPP */
2912             
2913             smb_RawBufs = rawBuf;
2914             lock_ReleaseMutex(&smb_RawBufLock);
2915         }
2916
2917         smb_ReleaseFID(fidp);
2918         return rc;
2919     }
2920         
2921     userp = smb_GetUser(vcp, inp);
2922
2923 #ifndef DJGPP
2924     code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2925 #else /* DJGPP */
2926     /* have to give ReadData flag so it will treat buffer as DOS mem. */
2927     code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2928                         userp, &finalCount, TRUE /* rawFlag */);
2929 #endif /* !DJGPP */
2930
2931     if (code != 0)
2932         goto send;
2933
2934   send:
2935     cm_ReleaseUser(userp);
2936
2937   send1a:
2938     smb_ReleaseFID(fidp);
2939
2940   send1:
2941     ncbp = outp->ncbp;
2942 #ifdef DJGPP
2943     dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2944 #endif /* DJGPP */
2945     memset((char *)ncbp, 0, sizeof(NCB));
2946
2947     ncbp->ncb_length = (unsigned short) finalCount;
2948     ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2949     ncbp->ncb_lana_num = vcp->lana;
2950     ncbp->ncb_command = NCBSEND;
2951     ncbp->ncb_buffer = rawBuf;
2952
2953 #ifndef DJGPP
2954     code = Netbios(ncbp);
2955 #else /* DJGPP */
2956     code = Netbios(ncbp, dos_ncb);
2957 #endif /* !DJGPP */
2958     if (code != 0)
2959         osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2960
2961     if (rawBuf) {
2962         /* Give back raw buffer */
2963         lock_ObtainMutex(&smb_RawBufLock);
2964 #ifndef DJGPP
2965         *((char **) rawBuf) = smb_RawBufs;
2966 #else /* DJGPP */
2967         _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2968 #endif /* !DJGPP */
2969
2970         smb_RawBufs = rawBuf;
2971         lock_ReleaseMutex(&smb_RawBufLock);
2972     }
2973
2974     return 0;
2975 }
2976
2977 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2978 {
2979     osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
2980                          ongoingOps - 1);
2981     return 0;
2982 }
2983
2984 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2985 {
2986     osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
2987                          ongoingOps - 1);
2988     return 0;
2989 }
2990
2991 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2992 {
2993     char *namep;
2994     char *datap;
2995     int coreProtoIndex;
2996     int v3ProtoIndex;
2997     int NTProtoIndex;
2998     int protoIndex;                             /* index we're using */
2999     int namex;
3000     int dbytes;
3001     int entryLength;
3002     int tcounter;
3003     char protocol_array[10][1024];  /* protocol signature of the client */
3004     int caps;                       /* capabilities */
3005     time_t unixTime;
3006     afs_uint32 dosTime;
3007     TIME_ZONE_INFORMATION tzi;
3008
3009     osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3010                          ongoingOps - 1);
3011     if (!isGateway) {
3012         if (active_vcp) {
3013             DWORD now = GetTickCount();
3014             if (now - last_msg_time >= 30000) {
3015                 smb_vc_t *avcp = active_vcp;
3016                 active_vcp = NULL;
3017                 osi_Log1(smb_logp,"Setting dead_vcp %x", avcp);
3018                 if (dead_vcp) {
3019                     osi_Log1(smb_logp,"Previous dead_vcp %x", dead_vcp);
3020                     smb_CleanupDeadVC(dead_vcp);
3021                     smb_ReleaseVC(dead_vcp);
3022                 }
3023                 smb_HoldVC(avcp);
3024                 dead_vcp = avcp;
3025                 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
3026                 smb_ReleaseVC(avcp);
3027             }
3028         }
3029     }
3030
3031     inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
3032
3033     namep = smb_GetSMBData(inp, &dbytes);
3034     namex = 0;
3035     tcounter = 0;
3036     coreProtoIndex = -1;                /* not found */
3037     v3ProtoIndex = -1;
3038     NTProtoIndex = -1;
3039     while(namex < dbytes) {
3040         osi_Log1(smb_logp, "Protocol %s",
3041                   osi_LogSaveString(smb_logp, namep+1));
3042         strcpy(protocol_array[tcounter], namep+1);
3043
3044         /* namep points at the first protocol, or really, a 0x02
3045          * byte preceding the null-terminated ASCII name.
3046          */
3047         if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3048             coreProtoIndex = tcounter;
3049         }       
3050         else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3051             v3ProtoIndex = tcounter;
3052         }
3053         else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3054             NTProtoIndex = tcounter;
3055         }
3056
3057         /* compute size of protocol entry */
3058         entryLength = (int)strlen(namep+1);
3059         entryLength += 2;       /* 0x02 bytes and null termination */
3060
3061         /* advance over this protocol entry */
3062         namex += entryLength;
3063         namep += entryLength;
3064         tcounter++;             /* which proto entry we're looking at */
3065     }
3066
3067     if (NTProtoIndex != -1) {
3068         protoIndex = NTProtoIndex;
3069         vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3070     }
3071     else if (v3ProtoIndex != -1) {
3072         protoIndex = v3ProtoIndex;
3073         vcp->flags |= SMB_VCFLAG_USEV3;
3074     }   
3075     else if (coreProtoIndex != -1) {
3076         protoIndex = coreProtoIndex;
3077         vcp->flags |= SMB_VCFLAG_USECORE;
3078     }   
3079     else protoIndex = -1;
3080
3081     if (protoIndex == -1)
3082         return CM_ERROR_INVAL;
3083     else if (NTProtoIndex != -1) {
3084         smb_SetSMBParm(outp, 0, protoIndex);
3085         if (smb_authType != SMB_AUTH_NONE) {
3086             smb_SetSMBParmByte(outp, 1,
3087                                NEGOTIATE_SECURITY_USER_LEVEL |
3088                                NEGOTIATE_SECURITY_CHALLENGE_RESPONSE);  /* user level security, challenge response */
3089         } else {
3090             smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3091         }
3092         smb_SetSMBParm(outp, 1, smb_maxMpxRequests);    /* max multiplexed requests */
3093         smb_SetSMBParm(outp, 2, smb_maxVCPerServer);    /* max VCs per consumer/server connection */
3094         smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE);    /* xmit buffer size */
3095         smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE);    /* raw buffer size */
3096         /* The session key is not a well documented field however most clients
3097          * will echo back the session key to the server.  Currently we are using
3098          * the same value for all sessions.  We should generate a random value
3099          * and store it into the vcp 
3100          */
3101         smb_SetSMBParm(outp, 7, 1);     /* next 2: session key */
3102         smb_SetSMBParm(outp, 8, 1);
3103         /* 
3104          * Tried changing the capabilities to support for W2K - defect 117695
3105          * Maybe something else needs to be changed here?
3106          */
3107         /*
3108         if (isWindows2000) 
3109         smb_SetSMBParmLong(outp, 9, 0x43fd);
3110         else 
3111         smb_SetSMBParmLong(outp, 9, 0x251);
3112         */
3113         /* Capabilities: *
3114          * 32-bit error codes *
3115          * and NT Find *
3116          * and NT SMB's *
3117          * and raw mode 
3118          * and DFS */
3119         caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3120 #ifdef DFS_SUPPORT
3121                NTNEGOTIATE_CAPABILITY_DFS |
3122 #endif
3123                NTNEGOTIATE_CAPABILITY_NTFIND |
3124                NTNEGOTIATE_CAPABILITY_RAWMODE |
3125                NTNEGOTIATE_CAPABILITY_NTSMB;
3126
3127         if ( smb_authType == SMB_AUTH_EXTENDED )
3128             caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3129
3130         smb_SetSMBParmLong(outp, 9, caps);
3131         time(&unixTime);
3132         smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3133         smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3134         smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3135
3136         GetTimeZoneInformation(&tzi);
3137         smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias);    /* server tzone */
3138
3139         if (smb_authType == SMB_AUTH_NTLM) {
3140             smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3141             smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3142             /* paste in encryption key */
3143             datap = smb_GetSMBData(outp, NULL);
3144             memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3145             /* and the faux domain name */
3146             strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
3147         } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3148             void * secBlob;
3149             int secBlobLength;
3150
3151             smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3152
3153             smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3154
3155             smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3156                         
3157             datap = smb_GetSMBData(outp, NULL);
3158             memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3159
3160             if (secBlob) {
3161                 datap += sizeof(smb_ServerGUID);
3162                 memcpy(datap, secBlob, secBlobLength);
3163                 free(secBlob);
3164             }
3165         } else {
3166             smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3167             smb_SetSMBDataLength(outp, 0);   /* Perhaps we should specify 8 bytes anyway */
3168         }
3169     }
3170     else if (v3ProtoIndex != -1) {
3171         smb_SetSMBParm(outp, 0, protoIndex);
3172
3173         /* NOTE: Extended authentication cannot be negotiated with v3
3174          * therefore we fail over to NTLM 
3175          */
3176         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3177             smb_SetSMBParm(outp, 1,
3178                            NEGOTIATE_SECURITY_USER_LEVEL |
3179                            NEGOTIATE_SECURITY_CHALLENGE_RESPONSE);      /* user level security, challenge response */
3180         } else {
3181             smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3182         }
3183         smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3184         smb_SetSMBParm(outp, 3, smb_maxMpxRequests);    /* max multiplexed requests */
3185         smb_SetSMBParm(outp, 4, smb_maxVCPerServer);    /* max VCs per consumer/server connection */
3186         smb_SetSMBParm(outp, 5, 0);     /* no support of block mode for read or write */
3187         smb_SetSMBParm(outp, 6, 1);     /* next 2: session key */
3188         smb_SetSMBParm(outp, 7, 1);
3189         time(&unixTime);
3190         smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3191         smb_SetSMBParm(outp, 8, LOWORD(dosTime));       /* server time */
3192         smb_SetSMBParm(outp, 9, HIWORD(dosTime));       /* server date */
3193
3194         GetTimeZoneInformation(&tzi);
3195         smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias);    /* server tzone */
3196
3197         /* NOTE: Extended authentication cannot be negotiated with v3
3198          * therefore we fail over to NTLM 
3199          */
3200         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3201             smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH);  /* encryption key length */
3202             smb_SetSMBParm(outp, 12, 0);        /* resvd */
3203             smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);   /* perhaps should specify 8 bytes anyway */
3204             datap = smb_GetSMBData(outp, NULL);
3205             /* paste in a new encryption key */
3206             memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3207             /* and the faux domain name */
3208             strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
3209         } else {
3210             smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3211             smb_SetSMBParm(outp, 12, 0); /* resvd */
3212             smb_SetSMBDataLength(outp, 0);
3213         }
3214     }
3215     else if (coreProtoIndex != -1) {     /* not really supported anymore */
3216         smb_SetSMBParm(outp, 0, protoIndex);
3217         smb_SetSMBDataLength(outp, 0);
3218     }
3219     return 0;
3220 }
3221
3222 void smb_Daemon(void *parmp)
3223 {
3224     afs_uint32 count = 0;
3225
3226     while(smbShutdownFlag == 0) {
3227         count++;
3228         thrd_Sleep(10000);
3229
3230         if (smbShutdownFlag == 1)
3231             break;
3232         
3233         if ((count % 72) == 0)  {       /* every five minutes */
3234             struct tm myTime;
3235             time_t old_localZero = smb_localZero;
3236                  
3237             /* Initialize smb_localZero */
3238             myTime.tm_isdst = -1;               /* compute whether on DST or not */
3239             myTime.tm_year = 70;
3240             myTime.tm_mon = 0;
3241             myTime.tm_mday = 1;
3242             myTime.tm_hour = 0;
3243             myTime.tm_min = 0;
3244             myTime.tm_sec = 0;
3245             smb_localZero = mktime(&myTime);
3246
3247 #ifndef USE_NUMERIC_TIME_CONV
3248             smb_CalculateNowTZ();
3249 #endif /* USE_NUMERIC_TIME_CONV */
3250 #ifdef AFS_FREELANCE
3251             if ( smb_localZero != old_localZero )
3252                 cm_noteLocalMountPointChange();
3253 #endif
3254         }
3255         /* XXX GC dir search entries */
3256     }
3257 }
3258
3259 void smb_WaitingLocksDaemon()
3260 {
3261     smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3262     smb_waitingLock_t *wl, *wlNext;
3263     int first;
3264     smb_vc_t *vcp;
3265     smb_packet_t *inp, *outp;
3266     NCB *ncbp;
3267     long code = 0;
3268
3269     while (smbShutdownFlag == 0) {
3270         lock_ObtainWrite(&smb_globalLock);
3271         nwlRequest = smb_allWaitingLocks;
3272         if (nwlRequest == NULL) {
3273             osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
3274             thrd_Sleep(1000);
3275             continue;
3276         } else {
3277             first = 1;
3278             osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
3279         }
3280
3281         do {
3282             if (first)
3283                 first = 0;
3284             else
3285                 lock_ObtainWrite(&smb_globalLock);
3286
3287             osi_Log1(smb_logp, "    Checking waiting lock request %p", nwlRequest);
3288
3289             wlRequest = nwlRequest;
3290             nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3291             lock_ReleaseWrite(&smb_globalLock);
3292
3293             code = 0;
3294
3295             for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3296                 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3297                     continue;
3298
3299                 osi_assert(wl->state != SMB_WAITINGLOCKSTATE_ERROR);
3300                 
3301                 /* wl->state is either _DONE or _WAITING.  _ERROR
3302                    would no longer be on the queue. */
3303                 code = cm_RetryLock( wl->lockp,
3304                                      !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3305
3306                 if (code == 0) {
3307                     wl->state = SMB_WAITINGLOCKSTATE_DONE;
3308                 } else if (code != CM_ERROR_WOULDBLOCK) {
3309                     wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3310                     break;
3311                 }
3312             }
3313
3314             if (code == CM_ERROR_WOULDBLOCK) {
3315
3316                 /* no progress */
3317                 if (wlRequest->timeRemaining != 0xffffffff
3318                      && (wlRequest->timeRemaining -= 1000) < 0)
3319                     goto endWait;
3320
3321                 continue;
3322             }
3323
3324           endWait:
3325
3326             if (code != 0) {
3327                 cm_scache_t * scp;
3328                 cm_req_t req;
3329
3330                 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
3331                          wlRequest);
3332
3333                 scp = wlRequest->scp;
3334
3335                 cm_InitReq(&req);
3336
3337                 lock_ObtainMutex(&scp->mx);
3338
3339                 for (wl = wlRequest->locks; wl; wl = wlNext) {
3340                     wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3341                     
3342                     cm_Unlock(scp, wlRequest->lockType, wl->LOffset, 
3343                               wl->LLength, wl->key, NULL, &req);
3344
3345                     osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3346
3347                     free(wl);
3348                 }
3349                 
3350                 lock_ReleaseMutex(&scp->mx);
3351
3352             } else {
3353
3354                 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
3355                          wlRequest);
3356
3357                 for (wl = wlRequest->locks; wl; wl = wlNext) {
3358                     wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3359                     osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3360                     free(wl);
3361                 }
3362             }
3363
3364             vcp = wlRequest->vcp;
3365             inp = wlRequest->inp;
3366             outp = wlRequest->outp;
3367             ncbp = GetNCB();
3368             ncbp->ncb_length = inp->ncb_length;
3369             inp->spacep = cm_GetSpace();
3370
3371             /* Remove waitingLock from list */
3372             lock_ObtainWrite(&smb_globalLock);
3373             osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3374                          &wlRequest->q);
3375             lock_ReleaseWrite(&smb_globalLock);
3376
3377             /* Resume packet processing */
3378             if (code == 0)
3379                 smb_SetSMBDataLength(outp, 0);
3380             outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3381             outp->resumeCode = code;
3382             outp->ncbp = ncbp;
3383             smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3384
3385             /* Clean up */
3386             cm_FreeSpace(inp->spacep);
3387             smb_FreePacket(inp);
3388             smb_FreePacket(outp);
3389             smb_ReleaseVC(vcp);
3390             cm_ReleaseSCache(wlRequest->scp);
3391             FreeNCB(ncbp);
3392             free(wlRequest);
3393         } while (nwlRequest && smbShutdownFlag == 0);
3394         thrd_Sleep(1000);
3395     }
3396 }
3397
3398 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3399 {
3400     osi_Log0(smb_logp, "SMB receive get disk attributes");
3401
3402     smb_SetSMBParm(outp, 0, 32000);
3403     smb_SetSMBParm(outp, 1, 64);
3404     smb_SetSMBParm(outp, 2, 1024);
3405     smb_SetSMBParm(outp, 3, 30000);
3406     smb_SetSMBParm(outp, 4, 0);
3407     smb_SetSMBDataLength(outp, 0);
3408     return 0;
3409 }
3410
3411 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3412 {
3413     smb_tid_t *tidp;
3414     smb_user_t *uidp;
3415     unsigned short newTid;
3416     char shareName[256];
3417     char *sharePath;
3418     int shareFound;
3419     char *tp;
3420     char *pathp;
3421     char *passwordp;
3422     cm_user_t *userp;
3423
3424     osi_Log0(smb_logp, "SMB receive tree connect");
3425
3426     /* parse input parameters */
3427     tp = smb_GetSMBData(inp, NULL);
3428     pathp = smb_ParseASCIIBlock(tp, &tp);
3429     if (smb_StoreAnsiFilenames)
3430         OemToChar(pathp,pathp);
3431     passwordp = smb_ParseASCIIBlock(tp, &tp);
3432     tp = strrchr(pathp, '\\');
3433     if (!tp)
3434         return CM_ERROR_BADSMB;
3435     strcpy(shareName, tp+1);
3436
3437     userp = smb_GetUser(vcp, inp);
3438
3439     lock_ObtainMutex(&vcp->mx);
3440     newTid = vcp->tidCounter++;
3441     lock_ReleaseMutex(&vcp->mx);
3442
3443     tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3444     uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3445     shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3446     if (uidp)
3447         smb_ReleaseUID(uidp);
3448     if (!shareFound) {
3449         smb_ReleaseTID(tidp);
3450         return CM_ERROR_BADSHARENAME;
3451     }
3452     lock_ObtainMutex(&tidp->mx);
3453     tidp->userp = userp;
3454     tidp->pathname = sharePath;
3455     lock_ReleaseMutex(&tidp->mx);
3456     smb_ReleaseTID(tidp);
3457
3458     smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3459     smb_SetSMBParm(rsp, 1, newTid);
3460     smb_SetSMBDataLength(rsp, 0);
3461
3462     osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3463     return 0;
3464 }
3465
3466 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3467 {
3468     int tlen;
3469
3470     if (*inp++ != 0x1) return NULL;
3471     tlen = inp[0] + (inp[1]<<8);
3472     inp += 2;           /* skip length field */
3473         
3474     if (chainpp) {
3475         *chainpp = inp + tlen;
3476     }   
3477
3478     if (lengthp) *lengthp = tlen;
3479         
3480     return inp;
3481 }
3482
3483 /* set maskp to the mask part of the incoming path.
3484  * Mask is 11 bytes long (8.3 with the dot elided).
3485  * Returns true if succeeds with a valid name, otherwise it does
3486  * its best, but returns false.
3487  */
3488 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3489 {
3490     char *tp;
3491     char *up;
3492     int i;
3493     int tc;
3494     int valid8Dot3;
3495
3496     /* starts off valid */
3497     valid8Dot3 = 1;
3498
3499     /* mask starts out all blanks */
3500     memset(maskp, ' ', 11);
3501
3502     /* find last backslash, or use whole thing if there is none */
3503     tp = strrchr(pathp, '\\');
3504     if (!tp) tp = pathp;
3505     else tp++;  /* skip slash */
3506         
3507     up = maskp;
3508
3509     /* names starting with a dot are illegal */
3510     if (*tp == '.') valid8Dot3 = 0;
3511
3512     for(i=0;; i++) {
3513         tc = *tp++;
3514         if (tc == 0) return valid8Dot3;
3515         if (tc == '.' || tc == '"') break;
3516         if (i < 8) *up++ = tc;
3517         else valid8Dot3 = 0;
3518     }
3519         
3520     /* if we get here, tp point after the dot */
3521     up = maskp+8;       /* ext goes here */
3522     for(i=0;;i++) {
3523         tc = *tp++;
3524         if (tc == 0) 
3525             return valid8Dot3;
3526
3527         /* too many dots */
3528         if (tc == '.' || tc == '"') 
3529             valid8Dot3 = 0;
3530
3531         /* copy extension if not too long */
3532         if (i < 3) 
3533             *up++ = tc;
3534         else 
3535             valid8Dot3 = 0;
3536     }   
3537
3538     /* unreachable */
3539 }
3540
3541 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3542 {
3543     char umask[11];
3544     int valid;
3545     int i;
3546     char tc1;
3547     char tc2;
3548     char *tp1;
3549     char *tp2;
3550
3551     /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3552
3553     valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3554     if (!valid) 
3555         return 0;
3556  
3557     /* otherwise, we have a valid 8.3 name; see if we have a match,
3558      * treating '?' as a wildcard in maskp (but not in the file name).
3559      */
3560     tp1 = umask;        /* real name, in mask format */
3561     tp2 = maskp;        /* mask, in mask format */
3562     for(i=0; i<11; i++) {
3563         tc1 = *tp1++;   /* char from real name */
3564         tc2 = *tp2++;   /* char from mask */
3565         tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3566         tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3567         if (tc1 == tc2) 
3568             continue;
3569         if (tc2 == '?' && tc1 != ' ') 
3570             continue;
3571         if (tc2 == '>') 
3572             continue;
3573         return 0;
3574     }
3575
3576     /* we got a match */
3577     return 1;
3578 }
3579
3580 char *smb_FindMask(char *pathp)
3581 {
3582     char *tp;
3583         
3584     tp = strrchr(pathp, '\\');  /* find last slash */
3585
3586     if (tp) 
3587         return tp+1;    /* skip the slash */
3588     else 
3589         return pathp;   /* no slash, return the entire path */
3590 }       
3591
3592 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3593 {
3594     unsigned char *pathp;
3595     unsigned char *tp;
3596     unsigned char mask[11];
3597     unsigned char *statBlockp;
3598     unsigned char initStatBlock[21];
3599     int statLen;
3600         
3601     osi_Log0(smb_logp, "SMB receive search volume");
3602
3603     /* pull pathname and stat block out of request */
3604     tp = smb_GetSMBData(inp, NULL);
3605     pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3606     osi_assert(pathp != NULL);
3607     if (smb_StoreAnsiFilenames)
3608         OemToChar(pathp,pathp);
3609     statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3610     osi_assert(statBlockp != NULL);
3611     if (statLen == 0) {
3612         statBlockp = initStatBlock;
3613         statBlockp[0] = 8;
3614     }
3615         
3616     /* for returning to caller */
3617     smb_Get8Dot3MaskFromPath(mask, pathp);
3618
3619     smb_SetSMBParm(outp, 0, 1);         /* we're returning one entry */
3620     tp = smb_GetSMBData(outp, NULL);
3621     *tp++ = 5;
3622     *tp++ = 43; /* bytes in a dir entry */
3623     *tp++ = 0;  /* high byte in counter */
3624
3625     /* now marshall the dir entry, starting with the search status */
3626     *tp++ = statBlockp[0];              /* Reserved */
3627     memcpy(tp, mask, 11); tp += 11;     /* FileName */
3628
3629     /* now pass back server use info, with 1st byte non-zero */
3630     *tp++ = 1;
3631     memset(tp, 0, 4); tp += 4;  /* reserved for server use */
3632
3633     memcpy(tp, statBlockp+17, 4); tp += 4;      /* reserved for consumer */
3634
3635     *tp++ = 0x8;                /* attribute: volume */
3636
3637     /* copy out time */
3638     *tp++ = 0;
3639     *tp++ = 0;
3640
3641     /* copy out date */
3642     *tp++ = 18;
3643     *tp++ = 178;
3644
3645     /* 4 byte file size */
3646     *tp++ = 0;
3647     *tp++ = 0;
3648     *tp++ = 0;
3649     *tp++ = 0;
3650
3651     /* finally, null-terminated 8.3 pathname, which we set to AFS */
3652     memset(tp, ' ', 13);
3653     strcpy(tp, "AFS");
3654
3655     /* set the length of the data part of the packet to 43 + 3, for the dir
3656      * entry plus the 5 and the length fields.
3657      */
3658     smb_SetSMBDataLength(outp, 46);
3659     return 0;
3660 }       
3661
3662 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3663                              cm_user_t *userp, cm_req_t *reqp)
3664 {
3665     long code = 0;
3666     cm_scache_t *scp;
3667     char *dptr;
3668     afs_uint32 dosTime;
3669     u_short shortTemp;
3670     char attr;
3671     smb_dirListPatch_t *patchp;
3672     smb_dirListPatch_t *npatchp;
3673
3674     for (patchp = *dirPatchespp; patchp; patchp =
3675          (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3676
3677         dptr = patchp->dptr;
3678
3679         code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3680         if (code) {
3681             if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3682                 *dptr++ = SMB_ATTR_HIDDEN;
3683             continue;
3684         }
3685         lock_ObtainMutex(&scp->mx);
3686         code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3687                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3688         if (code) {     
3689             lock_ReleaseMutex(&scp->mx);
3690             cm_ReleaseSCache(scp);
3691             if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3692                 *dptr++ = SMB_ATTR_HIDDEN;
3693             continue;
3694         }
3695
3696         attr = smb_Attributes(scp);
3697         /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3698         if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3699             attr |= SMB_ATTR_HIDDEN;
3700         *dptr++ = attr;
3701
3702         /* get dos time */
3703         smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3704                 
3705         /* copy out time */
3706         shortTemp = (unsigned short) (dosTime & 0xffff);
3707         *((u_short *)dptr) = shortTemp;
3708         dptr += 2;
3709
3710         /* and copy out date */
3711         shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3712         *((u_short *)dptr) = shortTemp;
3713         dptr += 2;
3714                 
3715         /* copy out file length */
3716         *((u_long *)dptr) = scp->length.LowPart;
3717         dptr += 4;
3718         lock_ReleaseMutex(&scp->mx);
3719         cm_ReleaseSCache(scp);
3720     }
3721         
3722     /* now free the patches */
3723     for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3724         npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3725         free(patchp);
3726     }   
3727         
3728     /* and mark the list as empty */
3729     *dirPatchespp = NULL;
3730
3731     return code;
3732 }
3733
3734 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3735 {
3736     int attribute;
3737     long nextCookie;
3738     char *tp;
3739     long code = 0;
3740     char *pathp;
3741     cm_dirEntry_t *dep;
3742     int maxCount;
3743     smb_dirListPatch_t *dirListPatchesp;
3744     smb_dirListPatch_t *curPatchp;
3745     int dataLength;
3746     cm_buf_t *bufferp;
3747     long temp;
3748     osi_hyper_t dirLength;
3749     osi_hyper_t bufferOffset;
3750     osi_hyper_t curOffset;
3751