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