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