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