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