security-class-object-leak-20040301
[openafs.git] / src / WINNT / afsd / cm_ioctl.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 #else
16 #include <sys/socket.h>
17 #endif /* !DJGPP */
18 #include <errno.h>
19 #include <stdlib.h>
20 #include <malloc.h>
21 #include <string.h>
22 #include <stdio.h>
23 #include <time.h>
24
25 #include <osi.h>
26
27 #include "afsd.h"
28 #include "afsd_init.h"
29
30 #include "smb.h"
31
32 #ifndef DJGPP
33 #include <rx/rxkad.h>
34 #include "afsrpc.h"
35 #else
36 #include <rx/rxkad.h>
37 #include "afsrpc95.h"
38 #endif
39
40 #include "cm_rpc.h"
41
42 #ifdef _DEBUG
43 #include <crtdbg.h>
44 #endif
45
46 /* Copied from afs_tokens.h */
47 #define PIOCTL_LOGON    0x1
48 #define MAX_PATH 260
49
50 osi_mutex_t cm_Afsdsbmt_Lock;
51
52 extern afs_int32 cryptall;
53
54 void cm_InitIoctl(void)
55 {
56         lock_InitializeMutex(&cm_Afsdsbmt_Lock, "AFSDSBMT.INI Access Lock");
57 }
58
59 long cm_FlushFile(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
60 {
61         long code;
62
63         lock_ObtainWrite(&scp->bufCreateLock);
64         code = buf_FlushCleanPages(scp, userp, reqp);
65         
66         lock_ObtainMutex(&scp->mx);
67         scp->cbServerp = NULL;
68         scp->cbExpires = 0;
69         lock_ReleaseMutex(&scp->mx);
70
71         lock_ReleaseWrite(&scp->bufCreateLock);
72         cm_dnlcPurgedp(scp);
73
74         return code;
75 }
76
77 /*
78  * cm_ResetACLCache -- invalidate ACL info for a user that has just
79  *                      obtained or lost tokens
80  */
81 void cm_ResetACLCache(cm_user_t *userp)
82 {
83         cm_scache_t *scp;
84         int hash;
85
86         lock_ObtainWrite(&cm_scacheLock);
87         for (hash=0; hash < cm_hashTableSize; hash++) {
88                 for (scp=cm_hashTablep[hash]; scp; scp=scp->nextp) {
89                         scp->refCount++;
90                         lock_ReleaseWrite(&cm_scacheLock);
91                         lock_ObtainMutex(&scp->mx);
92                         cm_InvalidateACLUser(scp, userp);
93                         lock_ReleaseMutex(&scp->mx);
94                         lock_ObtainWrite(&cm_scacheLock);
95                         scp->refCount--;
96                 }
97         }
98         lock_ReleaseWrite(&cm_scacheLock);
99 }
100
101 /*
102  *  TranslateExtendedChars - This is a fix for TR 54482.
103  *
104  *  If an extended character (80 - FF) is entered into a file
105  *  or directory name in Windows, the character is translated
106  *  into the OEM character map before being passed to us.  Why
107  *  this occurs is unknown.  Our pioctl functions must match
108  *  this translation for paths given via our own commands (like
109  *  fs).  If we do not do this, then we will try to perform an
110  *  operation on a non-translated path, which we will fail to 
111  *  find, since the path was created with the translated chars.
112  *  This function performs the required translation.
113  */
114 void TranslateExtendedChars(char *str)
115 {
116 #ifdef DJGPP
117     char *p;
118 #endif
119
120     if (!str || !*str)
121         return;
122
123 #ifndef DJGPP
124     CharToOem(str, str);
125 #else
126     p = str;
127     while (*p) *p++ &= 0x7f;  /* turn off high bit; probably not right */
128 #endif
129 }
130         
131 /* parse the passed-in file name and do a namei on it.  If we fail,
132  * return an error code, otherwise return the vnode located in *scpp.
133  */
134 long cm_ParseIoctlPath(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
135         cm_scache_t **scpp)
136 {
137         long code;
138         cm_scache_t *substRootp;
139
140         /* This is usually the file name, but for StatMountPoint it is the path. */
141         TranslateExtendedChars(ioctlp->inDatap);
142
143         code = cm_NameI(cm_rootSCachep, ioctlp->prefix->data,
144                 CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
145                 userp, ioctlp->tidPathp, reqp, &substRootp);
146         if (code) return code;
147         
148         code = cm_NameI(substRootp, ioctlp->inDatap, CM_FLAG_FOLLOW,
149                 userp, NULL, reqp, scpp);
150         if (code) return code;
151         
152         /* # of bytes of path */
153         code = strlen(ioctlp->inDatap) + 1;
154         ioctlp->inDatap += code;
155
156         /* This is usually nothing, but for StatMountPoint it is the file name. */
157         TranslateExtendedChars(ioctlp->inDatap);
158
159         /* and return success */
160         return 0;
161 }
162
163 void cm_SkipIoctlPath(smb_ioctl_t *ioctlp)
164 {
165         long temp;
166         
167         temp = strlen(ioctlp->inDatap) + 1;
168         ioctlp->inDatap += temp;
169 }
170
171
172 /* format the specified path to look like "/afs/<cellname>/usr", by
173  * adding "/afs" (if necessary) in front, changing any \'s to /'s, and
174  * removing any trailing "/"'s. One weirdo caveat: "/afs" will be
175  * intentionally returned as "/afs/"--this makes submount manipulation
176  * easier (because we can always jump past the initial "/afs" to find
177  * the AFS path that should be written into afsdsbmt.ini).
178  */
179 void cm_NormalizeAfsPath (char *outpathp, char *inpathp)
180 {
181         char *cp;
182     char bslash_mountRoot[256];
183        
184     strncpy(bslash_mountRoot, cm_mountRoot, sizeof(bslash_mountRoot) - 1);
185     bslash_mountRoot[0] = '\\';
186        
187     if (!strnicmp (inpathp, cm_mountRoot, strlen(cm_mountRoot)))
188                 lstrcpy (outpathp, inpathp);
189        else if (!strnicmp (inpathp, bslash_mountRoot, strlen(bslash_mountRoot)))
190                 lstrcpy (outpathp, inpathp);
191         else if ((inpathp[0] == '/') || (inpathp[0] == '\\'))
192                sprintf (outpathp, "%s%s", cm_mountRoot, inpathp);
193         else // inpathp looks like "<cell>/usr"
194                sprintf (outpathp, "%s/%s", cm_mountRoot, inpathp);
195
196         for (cp = outpathp; *cp != 0; ++cp) {
197                 if (*cp == '\\')
198                         *cp = '/';
199         }
200
201         if (strlen(outpathp) && (outpathp[strlen(outpathp)-1] == '/')) {
202            outpathp[strlen(outpathp)-1] = 0;
203         }
204
205         if (!strcmpi (outpathp, cm_mountRoot)) {
206         strcpy (outpathp, cm_mountRoot);
207         }
208 }
209
210 /* parse the passed-in file name and do a namei on its parent.  If we fail,
211  * return an error code, otherwise return the vnode located in *scpp.
212  */
213 long cm_ParseIoctlParent(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
214                          cm_scache_t **scpp, char *leafp)
215 {
216         long code;
217         char tbuffer[1024];
218         char *tp, *jp;
219         cm_scache_t *substRootp;
220
221         strcpy(tbuffer, ioctlp->inDatap);
222         tp = strrchr(tbuffer, '\\');
223         jp = strrchr(tbuffer, '/');
224         if (!tp)
225                 tp = jp;
226         else if (jp && (tp - tbuffer) < (jp - tbuffer))
227                 tp = jp;
228         if (!tp) {
229                 strcpy(tbuffer, "\\");
230                 if (leafp) strcpy(leafp, ioctlp->inDatap);
231         }
232         else {
233                 *tp = 0;
234                 if (leafp) strcpy(leafp, tp+1);
235         }
236
237         code = cm_NameI(cm_rootSCachep, ioctlp->prefix->data,
238                 CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
239                 userp, ioctlp->tidPathp, reqp, &substRootp);
240         if (code) return code;
241
242         code = cm_NameI(substRootp, tbuffer, CM_FLAG_FOLLOW,
243                 userp, NULL, reqp, scpp);
244         if (code) return code;
245         
246         /* # of bytes of path */
247         code = strlen(ioctlp->inDatap) + 1;
248         ioctlp->inDatap += code;
249
250         /* and return success */
251         return 0;
252 }
253
254 long cm_IoctlGetACL(smb_ioctl_t *ioctlp, cm_user_t *userp)
255 {
256         cm_conn_t *connp;
257         cm_scache_t *scp;
258         AFSOpaque acl;
259         AFSFetchStatus fileStatus;
260         AFSVolSync volSync;
261         long code;
262         AFSFid fid;
263         int tlen;
264         cm_req_t req;
265
266         cm_InitReq(&req);
267
268         code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
269         if (code) return code;
270         
271         /* now make the get acl call */
272         fid.Volume = scp->fid.volume;
273         fid.Vnode = scp->fid.vnode;
274         fid.Unique = scp->fid.unique;
275         do {
276                 acl.AFSOpaque_val = ioctlp->outDatap;
277                 acl.AFSOpaque_len = 0;
278                 code = cm_Conn(&scp->fid, userp, &req, &connp);
279                 if (code) continue;
280                 
281                 code = RXAFS_FetchACL(connp->callp, &fid, &acl, &fileStatus, &volSync);
282         } while (cm_Analyze(connp, userp, &req, &scp->fid,
283                             &volSync, NULL, code));
284         code = cm_MapRPCError(code, &req);
285         cm_ReleaseSCache(scp);
286         
287         if (code) return code;
288         
289         /* skip over return data */
290         tlen = strlen(ioctlp->outDatap) + 1;
291         ioctlp->outDatap += tlen;
292
293         /* and return success */
294         return 0;
295 }
296
297 long cm_IoctlGetFileCellName(struct smb_ioctl *ioctlp, struct cm_user *userp)
298 {
299         long code;
300         cm_scache_t *scp;
301         cm_cell_t *cellp;
302         cm_req_t req;
303
304         cm_InitReq(&req);
305
306         code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
307         if (code) return code;
308         
309         cellp = cm_FindCellByID(scp->fid.cell);
310         if (cellp) {
311                 strcpy(ioctlp->outDatap, cellp->namep);
312                 ioctlp->outDatap += strlen(ioctlp->outDatap) + 1;
313                 code = 0;
314         }
315         else code = CM_ERROR_NOSUCHCELL;
316         
317         cm_ReleaseSCache(scp);
318         return code;
319 }
320
321 long cm_IoctlSetACL(struct smb_ioctl *ioctlp, struct cm_user *userp)
322 {
323         cm_conn_t *connp;
324         cm_scache_t *scp;
325         AFSOpaque acl;
326         AFSFetchStatus fileStatus;
327         AFSVolSync volSync;
328         long code;
329         AFSFid fid;
330         cm_req_t req;
331
332         cm_InitReq(&req);
333
334         code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
335         if (code) return code;
336         
337         /* now make the get acl call */
338         fid.Volume = scp->fid.volume;
339         fid.Vnode = scp->fid.vnode;
340         fid.Unique = scp->fid.unique;
341         do {
342                 acl.AFSOpaque_val = ioctlp->inDatap;
343                 acl.AFSOpaque_len = strlen(ioctlp->inDatap)+1;
344                 code = cm_Conn(&scp->fid, userp, &req, &connp);
345                 if (code) continue;
346                 
347                 code = RXAFS_StoreACL(connp->callp, &fid, &acl, &fileStatus, &volSync);
348         } while (cm_Analyze(connp, userp, &req, &scp->fid,
349                             &volSync, NULL, code));
350         code = cm_MapRPCError(code, &req);
351
352         /* invalidate cache info, since we just trashed the ACL cache */
353         lock_ObtainMutex(&scp->mx);
354         cm_DiscardSCache(scp);
355         lock_ReleaseMutex(&scp->mx);
356
357         cm_ReleaseSCache(scp);
358         
359         return code;
360 }
361
362 long cm_IoctlFlushVolume(struct smb_ioctl *ioctlp, struct cm_user *userp)
363 {
364         long code;
365         cm_scache_t *scp;
366         unsigned long volume;
367         int i;
368         cm_req_t req;
369
370         cm_InitReq(&req);
371
372         code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
373         if (code) return code;
374         
375         volume = scp->fid.volume;
376         cm_ReleaseSCache(scp);
377
378         lock_ObtainWrite(&cm_scacheLock);
379         for(i=0; i<cm_hashTableSize; i++) {
380                 for(scp = cm_hashTablep[i]; scp; scp = scp->nextp) {
381                         if (scp->fid.volume == volume) {
382                                 scp->refCount++;
383                                 lock_ReleaseWrite(&cm_scacheLock);
384
385                                 /* now flush the file */
386                                 cm_FlushFile(scp, userp, &req);
387
388                                 lock_ObtainWrite(&cm_scacheLock);
389                                 scp->refCount--;
390                         }
391                 }
392         }
393         lock_ReleaseWrite(&cm_scacheLock);
394
395         return code;
396 }
397
398 long cm_IoctlFlushFile(struct smb_ioctl *ioctlp, struct cm_user *userp)
399 {
400         long code;
401         cm_scache_t *scp;
402         cm_req_t req;
403
404         cm_InitReq(&req);
405
406         code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
407         if (code) return code;
408         
409         cm_FlushFile(scp, userp, &req);
410         cm_ReleaseSCache(scp);
411
412         return 0;
413 }
414
415 long cm_IoctlSetVolumeStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
416 {
417         cm_scache_t *scp;
418         char volName[32];
419         char offLineMsg[256];
420         char motd[256];
421         cm_conn_t *tcp;
422         long code;
423         AFSFetchVolumeStatus volStat;
424         AFSStoreVolumeStatus storeStat;
425         cm_volume_t *tvp;
426         char *cp;
427         cm_cell_t *cellp;
428         cm_req_t req;
429
430         cm_InitReq(&req);
431
432         code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
433         if (code) return code;
434
435         cellp = cm_FindCellByID(scp->fid.cell);
436         osi_assert(cellp);
437
438         if (scp->flags & CM_SCACHEFLAG_RO) {
439                 cm_ReleaseSCache(scp);
440                 return CM_ERROR_READONLY;
441         }
442
443         code = cm_GetVolumeByID(cellp, scp->fid.volume, userp, &req, &tvp);
444         if (code) {
445                 cm_ReleaseSCache(scp);
446                 return code;
447         }
448
449         /* Copy the junk out, using cp as a roving pointer. */
450         cp = ioctlp->inDatap;
451         memcpy((char *)&volStat, cp, sizeof(AFSFetchVolumeStatus));
452         cp += sizeof(AFSFetchVolumeStatus);
453         strcpy(volName, cp);
454         cp += strlen(volName)+1;
455         strcpy(offLineMsg, cp);
456         cp +=  strlen(offLineMsg)+1;
457         strcpy(motd, cp);
458         storeStat.Mask = 0;
459         if (volStat.MinQuota != -1) {
460                 storeStat.MinQuota = volStat.MinQuota;
461                 storeStat.Mask |= AFS_SETMINQUOTA;
462         }
463         if (volStat.MaxQuota != -1) {
464                 storeStat.MaxQuota = volStat.MaxQuota;
465                 storeStat.Mask |= AFS_SETMAXQUOTA;
466         }
467
468         do {
469                 code = cm_Conn(&scp->fid, userp, &req, &tcp);
470                 if (code) continue;
471
472                 code = RXAFS_SetVolumeStatus(tcp->callp, scp->fid.volume,
473                         &storeStat, volName, offLineMsg, motd);
474         } while (cm_Analyze(tcp, userp, &req, &scp->fid, NULL, NULL, code));
475         code = cm_MapRPCError(code, &req);
476
477         /* return on failure */
478         cm_ReleaseSCache(scp);
479         if (code) {
480                 return code;
481         }
482
483         /* we are sending parms back to make compat. with prev system.  should
484          * change interface later to not ask for current status, just set
485          * new status
486          */
487         cp = ioctlp->outDatap;
488         memcpy(cp, (char *)&volStat, sizeof(VolumeStatus));
489         cp += sizeof(VolumeStatus);
490         strcpy(cp, volName);
491         cp += strlen(volName)+1;
492         strcpy(cp, offLineMsg);
493         cp += strlen(offLineMsg)+1;
494         strcpy(cp, motd);
495         cp += strlen(motd)+1;
496
497         /* now return updated return data pointer */
498         ioctlp->outDatap = cp;
499
500         return 0;
501 }
502
503 long cm_IoctlGetVolumeStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
504 {
505         char volName[32];
506         cm_scache_t *scp;
507         char offLineMsg[256];
508         char motd[256];
509         cm_conn_t *tcp;
510         register long code;
511         AFSFetchVolumeStatus volStat;
512         register char *cp;
513         char *Name;
514         char *OfflineMsg;
515         char *MOTD;
516         cm_req_t req;
517
518         cm_InitReq(&req);
519
520         code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
521         if (code) return code;
522
523         Name = volName;
524         OfflineMsg = offLineMsg;
525         MOTD = motd;
526         do {
527                 code = cm_Conn(&scp->fid, userp, &req, &tcp);
528                 if (code) continue;
529
530                 code = RXAFS_GetVolumeStatus(tcp->callp, scp->fid.volume,
531                         &volStat, &Name, &OfflineMsg, &MOTD);
532         } while (cm_Analyze(tcp, userp, &req, &scp->fid, NULL, NULL, code));
533         code = cm_MapRPCError(code, &req);
534
535         cm_ReleaseSCache(scp);
536         if (code) return code;
537
538         /* Copy all this junk into msg->im_data, keeping track of the lengths. */
539         cp = ioctlp->outDatap;
540         memcpy(cp, (char *)&volStat, sizeof(AFSFetchVolumeStatus));
541         cp += sizeof(AFSFetchVolumeStatus);
542         strcpy(cp, volName);
543         cp += strlen(volName)+1;
544         strcpy(cp, offLineMsg);
545         cp += strlen(offLineMsg)+1;
546         strcpy(cp, motd);
547         cp += strlen(motd)+1;
548
549         /* return new size */
550         ioctlp->outDatap = cp;
551
552         return 0;
553 }
554
555 long cm_IoctlWhereIs(struct smb_ioctl *ioctlp, struct cm_user *userp)
556 {
557         long code;
558         cm_scache_t *scp;
559         cm_cell_t *cellp;
560         cm_volume_t *tvp;
561         cm_serverRef_t *tsrp;
562         cm_server_t *tsp;
563         unsigned long volume;
564         char *cp;
565         cm_req_t req;
566
567         cm_InitReq(&req);
568
569         code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
570         if (code) return code;
571         
572         volume = scp->fid.volume;
573
574         cellp = cm_FindCellByID(scp->fid.cell);
575         osi_assert(cellp);
576
577         cm_ReleaseSCache(scp);
578
579         code = cm_GetVolumeByID(cellp, volume, userp, &req, &tvp);
580         if (code) return code;
581         
582         cp = ioctlp->outDatap;
583         
584         lock_ObtainMutex(&tvp->mx);
585         tsrp = cm_GetVolServers(tvp, volume);
586         lock_ObtainRead(&cm_serverLock);
587         while(tsrp) {
588                 tsp = tsrp->server;
589                 memcpy(cp, (char *)&tsp->addr.sin_addr.s_addr, sizeof(long));
590                 cp += sizeof(long);
591                 tsrp = tsrp->next;
592         }
593         lock_ReleaseRead(&cm_serverLock);
594         lock_ReleaseMutex(&tvp->mx);
595
596         /* still room for terminating NULL, add it on */
597         volume = 0;     /* reuse vbl */
598         memcpy(cp, (char *)&volume, sizeof(long));
599         cp += sizeof(long);
600
601         ioctlp->outDatap = cp;
602         cm_PutVolume(tvp);
603         return 0;
604 }
605
606 long cm_IoctlStatMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
607 {
608         long code;
609         cm_scache_t *dscp;
610         cm_scache_t *scp;
611         char *cp;
612         cm_req_t req;
613
614         cm_InitReq(&req);
615
616         code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp);
617         if (code) return code;
618         
619         cp = ioctlp->inDatap;
620
621         code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &req, &scp);
622         cm_ReleaseSCache(dscp);
623         if (code) return code;
624         
625         lock_ObtainMutex(&scp->mx);
626
627         /* now check that this is a real mount point */
628         if (scp->fileType != CM_SCACHETYPE_MOUNTPOINT) {
629                 lock_ReleaseMutex(&scp->mx);
630                 cm_ReleaseSCache(scp);
631                 return CM_ERROR_INVAL;
632         }
633         
634         code = cm_ReadMountPoint(scp, userp, &req);
635         if (code == 0) {
636                 cp = ioctlp->outDatap;
637                 strcpy(cp, scp->mountPointStringp);
638                 cp += strlen(cp) + 1;
639                 ioctlp->outDatap = cp;
640         }
641         lock_ReleaseMutex(&scp->mx);
642         cm_ReleaseSCache(scp);
643
644         return code;
645 }
646
647 long cm_IoctlDeleteMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
648 {
649         long code;
650         cm_scache_t *dscp;
651         cm_scache_t *scp;
652         char *cp;
653         cm_req_t req;
654
655         cm_InitReq(&req);
656
657         code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp);
658         if (code) return code;
659         
660         cp = ioctlp->inDatap;
661
662         code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &req, &scp);
663         
664         /* if something went wrong, bail out now */
665         if (code) {
666                 goto done;
667         }
668         
669         lock_ObtainMutex(&scp->mx);
670         code = cm_SyncOp(scp, NULL, userp, &req, 0,
671                 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
672         if (code) {
673                 lock_ReleaseMutex(&scp->mx);
674                 cm_ReleaseSCache(scp);
675                 goto done;
676         }
677         
678         /* now check that this is a real mount point */
679         if (scp->fileType != CM_SCACHETYPE_MOUNTPOINT) {
680                 lock_ReleaseMutex(&scp->mx);
681                 cm_ReleaseSCache(scp);
682                 code = CM_ERROR_INVAL;
683                 goto done;
684         }
685         
686         /* time to make the RPC, so drop the lock */
687         lock_ReleaseMutex(&scp->mx);
688         cm_ReleaseSCache(scp);
689         
690         /* easier to do it this way */
691         code = cm_Unlink(dscp, cp, userp, &req);
692         if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
693                 smb_NotifyChange(FILE_ACTION_REMOVED,
694                                  FILE_NOTIFY_CHANGE_DIR_NAME,
695                                  dscp, cp, NULL, TRUE);
696
697 done:
698         cm_ReleaseSCache(dscp);
699         return code;
700 }
701
702 long cm_IoctlCheckServers(struct smb_ioctl *ioctlp, struct cm_user *userp)
703 {
704         cm_cell_t *cellp;
705         chservinfo_t csi;
706         char *tp;
707         char *cp;
708         long temp;
709         cm_server_t *tsp;
710         int haveCell;
711         
712         cm_SkipIoctlPath(ioctlp);       /* we don't care about the path */
713         tp = ioctlp->inDatap;
714         haveCell = 0;
715
716         memcpy(&temp, tp, sizeof(temp));
717         if (temp == 0x12345678) {       /* For afs3.3 version */
718                 memcpy(&csi, tp, sizeof(csi));
719                 if (csi.tinterval >= 0) {
720                         cp = ioctlp->outDatap;
721                         memcpy(cp, (char *)&cm_daemonCheckInterval, sizeof(long));
722                         ioctlp->outDatap += sizeof(long);
723                         if (csi.tinterval > 0) {
724                                 if (!smb_SUser(userp))
725                                         return CM_ERROR_NOACCESS;
726                                 cm_daemonCheckInterval = csi.tinterval;
727                         }
728                         return 0;
729                 }
730                 if (csi.tsize)
731                         haveCell = 1;
732                 temp = csi.tflags;
733                 cp = csi.tbuffer;
734         } else {        /* For pre afs3.3 versions */
735                 memcpy((char *)&temp, ioctlp->inDatap, sizeof(long));
736                 ioctlp->inDatap = cp = ioctlp->inDatap + sizeof(long);
737                 if (cp - ioctlp->inAllocp < ioctlp->inCopied)   /* still more data available */
738                         haveCell = 1;
739         }
740
741         /* 
742          * 1: fast check, don't contact servers.
743          * 2: local cell only.
744          */
745         if (haveCell) {
746                 /* have cell name, too */
747                 cellp = cm_GetCell(cp, 0);
748                 if (!cellp) return CM_ERROR_NOSUCHCELL;
749         }
750         else cellp = (cm_cell_t *) 0;
751         if (!cellp && (temp & 2)) {
752                 /* use local cell */
753                 cellp = cm_FindCellByID(1);
754         }
755         if (!(temp & 1)) {      /* if not fast, call server checker routine */
756                 /* check down servers */
757                 cm_CheckServers(CM_FLAG_CHECKDOWNSERVERS | CM_FLAG_CHECKUPSERVERS,
758                         cellp);
759         }
760
761         /* now return the current down server list */
762         cp = ioctlp->outDatap;
763         lock_ObtainRead(&cm_serverLock);
764         for(tsp = cm_allServersp; tsp; tsp=tsp->allNextp) {
765                 if (cellp && tsp->cellp != cellp) continue;     /* cell spec'd and wrong */
766                 if ((tsp->flags & CM_SERVERFLAG_DOWN)
767                         && tsp->type == CM_SERVER_FILE) {
768                         memcpy(cp, (char *)&tsp->addr.sin_addr.s_addr, sizeof(long));
769                         cp += sizeof(long);
770                 }
771         }
772         lock_ReleaseRead(&cm_serverLock);
773
774         ioctlp->outDatap = cp;
775         return 0;
776 }
777
778 long cm_IoctlGag(struct smb_ioctl *ioctlp, struct cm_user *userp)
779 {
780         /* we don't print anything superfluous, so we don't support the gag call */
781         return CM_ERROR_INVAL;
782 }
783
784 long cm_IoctlCheckVolumes(struct smb_ioctl *ioctlp, struct cm_user *userp)
785 {
786         cm_CheckVolumes();
787         return 0;
788 }
789
790 long cm_IoctlSetCacheSize(struct smb_ioctl *ioctlp, struct cm_user *userp)
791 {
792         long temp;
793         long code;
794         
795         cm_SkipIoctlPath(ioctlp);
796
797         memcpy(&temp, ioctlp->inDatap, sizeof(temp));
798         if (temp == 0) temp = buf_nOrigBuffers;
799         else {
800                 /* temp is in 1K units, convert to # of buffers */
801                 temp = temp / (buf_bufferSize / 1024);
802         }
803
804         /* now adjust the cache size */
805         code = buf_SetNBuffers(temp);
806
807         return code;
808 }
809
810 long cm_IoctlTraceControl(struct smb_ioctl *ioctlp, struct cm_user *userp)
811 {
812         long inValue;
813         
814         cm_SkipIoctlPath(ioctlp);
815         
816         memcpy(&inValue, ioctlp->inDatap, sizeof(long));
817
818         /* print trace */
819         if (inValue & 8) {
820                 afsd_ForceTrace(FALSE);
821         }
822         
823         if (inValue & 2) {
824                 /* set tracing value to low order bit */
825                 if ((inValue & 1) == 0) {
826                         /* disable tracing */
827                         osi_LogDisable(afsd_logp);
828                 }
829                 else {
830                         /* enable tracing */
831                         osi_LogEnable(afsd_logp);
832                 }
833         }
834
835         /* see if we're supposed to do a reset, too */
836         if (inValue & 4) {
837                 osi_LogReset(afsd_logp);
838         }
839
840         /* and copy out tracing flag */
841         inValue = afsd_logp->enabled;   /* use as a temp vbl */
842         memcpy(ioctlp->outDatap, &inValue, sizeof(long));
843         ioctlp->outDatap += sizeof(long);
844         return 0;
845 }
846
847 long cm_IoctlGetCacheParms(struct smb_ioctl *ioctlp, struct cm_user *userp)
848 {
849         cm_cacheParms_t parms;
850         
851         memset(&parms, 0, sizeof(parms));
852
853         /* first we get, in 1K units, the cache size */
854         parms.parms[0] = buf_nbuffers * (buf_bufferSize / 1024);
855         
856         /* and then the actual # of buffers in use (not in the free list, I guess,
857          * will be what we do).
858          */
859         parms.parms[1] = (buf_nbuffers - buf_CountFreeList()) * (buf_bufferSize / 1024);
860         
861         memcpy(ioctlp->outDatap, &parms, sizeof(parms));
862         ioctlp->outDatap += sizeof(parms);
863
864         return 0;
865 }
866
867 long cm_IoctlGetCell(struct smb_ioctl *ioctlp, struct cm_user *userp)
868 {
869         long whichCell;
870         long magic = 0;
871         cm_cell_t *tcellp;
872         cm_serverRef_t *serverRefp;
873         cm_server_t *serverp;
874         long i;
875         char *cp;
876         char *tp;
877         char *basep;
878
879         cm_SkipIoctlPath(ioctlp);
880
881         tp = ioctlp->inDatap;
882
883         memcpy((char *)&whichCell, tp, sizeof(long));
884         tp += sizeof(long);
885         
886         /* see if more than one long passed in, ignoring the null pathname (the -1) */
887         if (ioctlp->inCopied-1 > sizeof(long)) {
888                 memcpy((char *)&magic, tp, sizeof(long));
889         }
890
891         lock_ObtainRead(&cm_cellLock);
892         for(tcellp = cm_allCellsp; tcellp; tcellp = tcellp->nextp) {
893                 if (whichCell == 0) break;
894                 whichCell--;
895         }
896         lock_ReleaseRead(&cm_cellLock);
897         if (tcellp) {
898                 int max = 8;
899
900                 cp = ioctlp->outDatap;
901
902                 if (magic == 0x12345678) {
903                         memcpy(cp, (char *)&magic, sizeof(long));
904                         max = 13;
905                 }
906                 memset(cp, 0, max * sizeof(long));
907                 basep = cp;
908                 lock_ObtainRead(&cm_serverLock);        /* for going down server list */
909                 serverRefp = tcellp->vlServersp;
910                 for(i=0; i<max; i++) {
911                         if (!serverRefp) break;
912                         serverp = serverRefp->server;
913                         memcpy(cp, &serverp->addr.sin_addr.s_addr, sizeof(long));
914                         cp += sizeof(long);
915                         serverRefp = serverRefp->next;
916                 }
917                 lock_ReleaseRead(&cm_serverLock);
918                 cp = basep + max * sizeof(afs_int32);
919                 strcpy(cp, tcellp->namep);
920                 cp += strlen(tcellp->namep)+1;
921                 ioctlp->outDatap = cp;
922         }
923
924         if (tcellp) return 0;
925         else return CM_ERROR_NOMORETOKENS;      /* mapped to EDOM */
926 }
927
928 extern long cm_AddCellProc(void *rockp, struct sockaddr_in *addrp, char *namep);
929
930 long cm_IoctlNewCell(struct smb_ioctl *ioctlp, struct cm_user *userp)
931 {
932     /* NT cache manager will read cell information from afsdcell.ini each time
933      * cell is accessed. So, this call is necessary only if list of server for a cell 
934      * changes (or IP addresses of cell servers changes).
935      * All that needs to be done is to refresh server information for all cells that 
936      * are already loaded.
937   
938      * cell list will be cm_CellLock and cm_ServerLock will be held for write.
939     */  
940   
941     cm_cell_t *tcellp;
942   
943     cm_SkipIoctlPath(ioctlp);
944     lock_ObtainWrite(&cm_cellLock);
945   
946     for(tcellp = cm_allCellsp; tcellp; tcellp=tcellp->nextp) 
947     {
948         /* delete all previous server lists - cm_FreeServerList will ask for write on cm_ServerLock*/
949         cm_FreeServerList(&tcellp->vlServersp);
950         tcellp->vlServersp = NULL;
951         cm_SearchCellFile(tcellp->namep, tcellp->namep, cm_AddCellProc, tcellp);
952         cm_RandomizeServer(&tcellp->vlServersp);
953     }
954     
955     lock_ReleaseWrite(&cm_cellLock);
956     return 0;       
957 }
958
959 long cm_IoctlGetWsCell(smb_ioctl_t *ioctlp, cm_user_t *userp)
960 {
961         /* if we don't know our default cell, return failure */
962         if (cm_rootCellp == NULL) {
963                 return CM_ERROR_NOSUCHCELL;
964         }
965
966         /* return the default cellname to the caller */
967         strcpy(ioctlp->outDatap, cm_rootCellp->namep);
968         ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
969         
970         /* done: success */
971         return 0;
972 }
973
974 long cm_IoctlSysName(struct smb_ioctl *ioctlp, struct cm_user *userp)
975 {
976         long setSysName;
977         char *cp;
978         
979         cm_SkipIoctlPath(ioctlp);
980
981         memcpy(&setSysName, ioctlp->inDatap, sizeof(long));
982         ioctlp->inDatap += sizeof(long);
983         
984         if (setSysName) {
985                 strcpy(cm_sysName, ioctlp->inDatap);
986         }
987         else {
988                 /* return the sysname to the caller */
989                 setSysName = 1; /* really means "found sys name */
990                 cp = ioctlp->outDatap;
991                 memcpy(cp, &setSysName, sizeof(long));
992                 cp += sizeof(long);     /* skip found flag */
993                 strcpy(cp, cm_sysName);
994                 cp += strlen(cp) + 1;   /* skip name and terminating null char */
995                 ioctlp->outDatap = cp;
996         }
997         
998         /* done: success */
999         return 0;
1000 }
1001
1002 long cm_IoctlGetCellStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
1003 {
1004         long temp;
1005         cm_cell_t *cellp;
1006
1007         cm_SkipIoctlPath(ioctlp);
1008
1009         cellp = cm_GetCell(ioctlp->inDatap, 0);
1010         if (!cellp) return CM_ERROR_NOSUCHCELL;
1011
1012         temp = 0;
1013         lock_ObtainMutex(&cellp->mx);
1014         if (cellp->flags & CM_CELLFLAG_SUID)
1015                 temp |= CM_SETCELLFLAG_SUID;
1016         lock_ReleaseMutex(&cellp->mx);
1017         
1018         /* now copy out parm */
1019         memcpy(ioctlp->outDatap, &temp, sizeof(long));
1020         ioctlp->outDatap += sizeof(long);
1021
1022         return 0;
1023 }
1024
1025 long cm_IoctlSetCellStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
1026 {
1027         long temp;
1028         cm_cell_t *cellp;
1029
1030         cm_SkipIoctlPath(ioctlp);
1031
1032         cellp = cm_GetCell(ioctlp->inDatap + 2*sizeof(long), 0);
1033         if (!cellp) return CM_ERROR_NOSUCHCELL;
1034
1035         memcpy((char *)&temp, ioctlp->inDatap, sizeof(long));
1036
1037         lock_ObtainMutex(&cellp->mx);
1038         if (temp & CM_SETCELLFLAG_SUID)
1039                 cellp->flags |= CM_CELLFLAG_SUID;
1040         else
1041                 cellp->flags &= ~CM_CELLFLAG_SUID;
1042         lock_ReleaseMutex(&cellp->mx);
1043
1044         return 0;
1045 }
1046
1047 long cm_IoctlSetSPrefs(struct smb_ioctl *ioctlp, struct cm_user *userp)
1048 {
1049         cm_SSetPref_t     *spin; /* input */
1050         cm_SPref_t        *srvin;   /* one input component */
1051         cm_server_t       *tsp;
1052         int               i, vlonly, noServers, type;
1053         struct sockaddr_in      tmp;
1054         unsigned short    rank;
1055
1056         cm_SkipIoctlPath(ioctlp);       /* we don't care about the path */
1057
1058         spin       = (cm_SSetPref_t *)ioctlp->inDatap;
1059         noServers  = spin->num_servers;
1060         vlonly     = spin->flags;
1061         if ( vlonly )
1062                 type = CM_SERVER_VLDB;
1063         else    type = CM_SERVER_FILE;
1064
1065         for ( i=0; i < noServers; i++) 
1066         {
1067                 srvin          = &(spin->servers[i]);
1068                 rank           = srvin->rank + (rand() & 0x000f);
1069                 tmp.sin_addr   = srvin->host;
1070                 tmp.sin_family = AF_INET;
1071
1072                 tsp = cm_FindServer(&tmp, type);
1073                 if ( tsp )              /* an existing server */
1074                 {
1075                         tsp->ipRank = rank; /* no need to protect by mutex*/
1076
1077                         if ( type == CM_SERVER_FILE) /* fileserver */
1078                         {
1079                             /* find volumes which might have RO copy 
1080                             /* on server and change the ordering of 
1081                             ** their RO list */
1082                             cm_ChangeRankVolume(tsp);
1083                         }
1084                         else    
1085                         {
1086                             /* set preferences for an existing vlserver */
1087                             cm_ChangeRankCellVLServer(tsp);
1088                         }
1089                 }
1090                 else                    /* add a new server without a cell*/
1091                 {
1092                         tsp = cm_NewServer(&tmp, type, NULL);
1093                         tsp->ipRank = rank;
1094                 }
1095                 cm_PutServer(tsp);
1096         }
1097         return 0;
1098 }
1099
1100 long cm_IoctlGetSPrefs(struct smb_ioctl *ioctlp, struct cm_user *userp)
1101 {
1102         cm_SPrefRequest_t *spin; /* input */
1103         cm_SPrefInfo_t    *spout;   /* output */
1104         cm_SPref_t        *srvout;   /* one output component */
1105         cm_server_t       *tsp;
1106         int               i, vlonly, noServers;
1107
1108         cm_SkipIoctlPath(ioctlp);       /* we don't care about the path */
1109
1110         spin      = (cm_SPrefRequest_t *)ioctlp->inDatap;
1111         spout     = (cm_SPrefInfo_t *) ioctlp->outDatap;
1112         srvout    = spout->servers;
1113         noServers = spin->num_servers; 
1114         vlonly    = spin->flags & CM_SPREF_VLONLY;
1115         spout->num_servers = 0;
1116
1117         lock_ObtainRead(&cm_serverLock); /* get server lock */
1118
1119         for(tsp=cm_allServersp, i=0; tsp && noServers; tsp=tsp->allNextp,i++){
1120                 if (spin->offset > i) {
1121                         continue;    /* catch up to where we left off */
1122                 }
1123
1124                 if ( vlonly && (tsp->type == CM_SERVER_FILE) )
1125                         continue;   /* ignore fileserver for -vlserver option*/
1126                 if ( !vlonly && (tsp->type == CM_SERVER_VLDB) )
1127                         continue;   /* ignore vlservers */
1128
1129                 srvout->host = tsp->addr.sin_addr;
1130                 srvout->rank = tsp->ipRank;
1131                 srvout++;       
1132                 spout->num_servers++;
1133                 noServers--;
1134         }
1135         lock_ReleaseRead(&cm_serverLock); /* release server lock */
1136
1137         if ( tsp )      /* we ran out of space in the output buffer */
1138                 spout->next_offset = i;
1139         else    
1140                 spout->next_offset = 0; 
1141         ioctlp->outDatap += sizeof(cm_SPrefInfo_t) + 
1142                         (spout->num_servers -1 ) * sizeof(cm_SPref_t) ;
1143         return 0;
1144 }
1145
1146 long cm_IoctlStoreBehind(struct smb_ioctl *ioctlp, struct cm_user *userp)
1147 {
1148         /* we ignore default asynchrony since we only have one way
1149          * of doing this today.
1150          */
1151         return 0;
1152 }
1153
1154 long cm_IoctlCreateMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
1155 {
1156         char leaf[256];
1157         long code;
1158         cm_scache_t *dscp;
1159         cm_attr_t tattr;
1160         char *cp;
1161         cm_req_t req;
1162         char mpInfo[256];
1163         char fullCell[256];
1164         char volume[256];
1165         char cell[256];
1166         int ttl;
1167
1168         cm_InitReq(&req);
1169         
1170         code = cm_ParseIoctlParent(ioctlp, userp, &req, &dscp, leaf);
1171         if (code) return code;
1172
1173         /* Translate chars for the mount point name */
1174         TranslateExtendedChars(leaf);
1175
1176         /* 
1177          * The fs command allows the user to specify partial cell names on NT.  These must
1178          * be expanded to the full cell name for mount points so that the mount points will
1179          * work on UNIX clients.
1180          */
1181
1182         /* Extract the possibly partial cell name */
1183         strcpy(cell, ioctlp->inDatap + 1);      /* Skip the mp type character */
1184         
1185         if (cp = strchr(cell, ':')) {
1186                 /* Extract the volume name */
1187                 *cp = 0;
1188                 strcpy(volume,  cp + 1);
1189         
1190                 /* Get the full name for this cell */
1191                 code = cm_SearchCellFile(cell, fullCell, 0, 0);
1192 #ifdef AFS_AFSDB_ENV
1193                 if (code && cm_dnsEnabled)
1194                   code = cm_SearchCellByDNS(cell, fullCell, &ttl, 0, 0);
1195 #endif
1196                   if (code)
1197                         return CM_ERROR_NOSUCHCELL;
1198         
1199                 sprintf(mpInfo, "%c%s:%s", *ioctlp->inDatap, fullCell, volume);
1200         } else {
1201                 /* No cell name specified */
1202                 strcpy(mpInfo, ioctlp->inDatap);
1203         }
1204
1205 #ifdef AFS_FREELANCE_CLIENT
1206         if (cm_freelanceEnabled && dscp == cm_rootSCachep) {
1207           /* we are adding the mount point to the root dir., so call
1208              the freelance code to do the add. */
1209           code = cm_FreelanceAddMount(leaf, fullCell, volume, NULL);
1210           return code;
1211         }
1212 #endif
1213         /* create the symlink with mode 644.  The lack of X bits tells
1214          * us that it is a mount point.
1215          */
1216         tattr.mask = CM_ATTRMASK_UNIXMODEBITS | CM_ATTRMASK_CLIENTMODTIME;
1217         tattr.unixModeBits = 0644;
1218         tattr.clientModTime = time(NULL);
1219
1220         code = cm_SymLink(dscp, leaf, mpInfo, 0, &tattr, userp, &req);
1221         if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
1222                 smb_NotifyChange(FILE_ACTION_ADDED,
1223                                  FILE_NOTIFY_CHANGE_DIR_NAME,
1224                                  dscp, leaf, NULL, TRUE);
1225
1226         cm_ReleaseSCache(dscp);
1227
1228         return code;
1229 }
1230
1231 long cm_IoctlSymlink(struct smb_ioctl *ioctlp, struct cm_user *userp)
1232 {
1233         char leaf[256];
1234         long code;
1235         cm_scache_t *dscp;
1236         cm_attr_t tattr;
1237         char *cp;
1238         cm_req_t req;
1239
1240         cm_InitReq(&req);
1241
1242         code = cm_ParseIoctlParent(ioctlp, userp, &req, &dscp, leaf);
1243         if (code) return code;
1244
1245         /* Translate chars for the link name */
1246         TranslateExtendedChars(leaf);
1247
1248         /* Translate chars for the linked to name */
1249         TranslateExtendedChars(ioctlp->inDatap);
1250
1251         cp = ioctlp->inDatap;           /* contents of link */
1252
1253         /* Create symlink with mode 0755. */
1254         tattr.mask = CM_ATTRMASK_UNIXMODEBITS;
1255         tattr.unixModeBits = 0755;
1256
1257         code = cm_SymLink(dscp, leaf, cp, 0, &tattr, userp, &req);
1258         if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
1259                 smb_NotifyChange(FILE_ACTION_ADDED,
1260                                  FILE_NOTIFY_CHANGE_FILE_NAME
1261                                    | FILE_NOTIFY_CHANGE_DIR_NAME,
1262                                  dscp, leaf, NULL, TRUE);
1263
1264         cm_ReleaseSCache(dscp);
1265
1266         return code;
1267 }
1268
1269 extern long cm_AssembleLink(cm_scache_t *linkScp, char *pathSuffixp,
1270         cm_scache_t **newRootScpp, cm_space_t **newSpaceBufferp,
1271         cm_user_t *userp, cm_req_t *reqp);
1272
1273 long cm_IoctlListlink(struct smb_ioctl *ioctlp, struct cm_user *userp)
1274 {
1275         long code;
1276         cm_scache_t *dscp;
1277         cm_scache_t *scp;
1278         char *cp;
1279         cm_space_t *spacep;
1280         cm_scache_t *newRootScp;
1281         cm_req_t req;
1282
1283         cm_InitReq(&req);
1284
1285         code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp);
1286         if (code) return code;
1287
1288         cp = ioctlp->inDatap;
1289
1290         code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &req, &scp);
1291         cm_ReleaseSCache(dscp);
1292         if (code) return code;
1293
1294         /* Check that it's a real symlink */
1295         if (scp->fileType != CM_SCACHETYPE_SYMLINK){
1296                 cm_ReleaseSCache(scp);
1297                 return CM_ERROR_INVAL;
1298         }
1299
1300         code = cm_AssembleLink(scp, "", &newRootScp, &spacep, userp, &req);
1301         cm_ReleaseSCache(scp);
1302         if (code == 0) {
1303                 cp = ioctlp->outDatap;
1304                 if (newRootScp != NULL) {
1305             strcpy(cp, cm_mountRoot);
1306             strcat(cp, "/");
1307                         cp += strlen(cp);
1308                 }
1309                 strcpy(cp, spacep->data);
1310                 cp += strlen(cp) + 1;
1311                 ioctlp->outDatap = cp;
1312                 cm_FreeSpace(spacep);
1313                 if (newRootScp != NULL)
1314                         cm_ReleaseSCache(newRootScp);
1315         }
1316
1317         return code;
1318 }
1319
1320 long cm_IoctlIslink(struct smb_ioctl *ioctlp, struct cm_user *userp)
1321 {/*CHECK FOR VALID SYMLINK*/
1322         long code;
1323         cm_scache_t *dscp;
1324         cm_scache_t *scp;
1325         char *cp;
1326         cm_req_t req;
1327
1328         cm_InitReq(&req);
1329
1330         code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp);
1331         if (code) return code;
1332
1333         cp = ioctlp->inDatap;
1334         osi_LogEvent("cm_IoctlListlink",NULL," name[%s]",cp);
1335
1336         code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &req, &scp);
1337         cm_ReleaseSCache(dscp);
1338         if (code) return code;
1339
1340         /* Check that it's a real symlink */
1341         if (scp->fileType != CM_SCACHETYPE_SYMLINK)
1342                 code = CM_ERROR_INVAL;
1343         cm_ReleaseSCache(scp);
1344         return code;
1345 }
1346
1347 long cm_IoctlDeletelink(struct smb_ioctl *ioctlp, struct cm_user *userp)
1348 {
1349         long code;
1350         cm_scache_t *dscp;
1351         cm_scache_t *scp;
1352         char *cp;
1353         cm_req_t req;
1354
1355         cm_InitReq(&req);
1356
1357         code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp);
1358         if (code) return code;
1359
1360         cp = ioctlp->inDatap;
1361
1362         code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &req, &scp);
1363         
1364         /* if something went wrong, bail out now */
1365         if (code) {
1366                 goto done;
1367         }
1368         
1369         lock_ObtainMutex(&scp->mx);
1370         code = cm_SyncOp(scp, NULL, userp, &req, 0,
1371                 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1372         if (code) {
1373                 lock_ReleaseMutex(&scp->mx);
1374                 cm_ReleaseSCache(scp);
1375                 goto done;
1376         }
1377         
1378         /* now check that this is a real symlink */
1379         if (scp->fileType != CM_SCACHETYPE_SYMLINK) {
1380                 lock_ReleaseMutex(&scp->mx);
1381                 cm_ReleaseSCache(scp);
1382                 code = CM_ERROR_INVAL;
1383                 goto done;
1384         }
1385         
1386         /* time to make the RPC, so drop the lock */
1387         lock_ReleaseMutex(&scp->mx);
1388         cm_ReleaseSCache(scp);
1389         
1390         /* easier to do it this way */
1391         code = cm_Unlink(dscp, cp, userp, &req);
1392         if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
1393                 smb_NotifyChange(FILE_ACTION_REMOVED,
1394                                  FILE_NOTIFY_CHANGE_FILE_NAME
1395                                    | FILE_NOTIFY_CHANGE_DIR_NAME,
1396                                  dscp, cp, NULL, TRUE);
1397
1398 done:
1399         cm_ReleaseSCache(dscp);
1400         return code;
1401 }
1402
1403 long cm_IoctlSetToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
1404 {
1405         char *saveDataPtr;
1406         char *tp;
1407         int ticketLen;
1408         char *ticket;
1409         int ctSize;
1410         struct ClearToken ct;
1411         cm_cell_t *cellp;
1412         cm_ucell_t *ucellp;
1413         char *uname = NULL;
1414         afs_uuid_t uuid;
1415         int flags;
1416         char sessionKey[8];
1417         char *smbname;
1418
1419         saveDataPtr = ioctlp->inDatap;
1420
1421         cm_SkipIoctlPath(ioctlp);
1422
1423         tp = ioctlp->inDatap;
1424
1425         /* ticket length */
1426         memcpy(&ticketLen, tp, sizeof(ticketLen));
1427         tp += sizeof(ticketLen);
1428         if (ticketLen < MINKTCTICKETLEN || ticketLen > MAXKTCTICKETLEN)
1429                 return CM_ERROR_INVAL;
1430
1431         /* remember ticket and skip over it for now */
1432         ticket = tp;
1433         tp += ticketLen;
1434
1435         /* clear token size */
1436         memcpy(&ctSize, tp, sizeof(ctSize));
1437         tp += sizeof(ctSize);
1438         if (ctSize != sizeof(struct ClearToken))
1439                 return CM_ERROR_INVAL;
1440
1441         /* clear token */
1442         memcpy(&ct, tp, ctSize);
1443         tp += ctSize;
1444         if (ct.AuthHandle == -1)
1445                 ct.AuthHandle = 999;    /* more rxvab compat stuff */
1446
1447         /* more stuff, if any */
1448         if (ioctlp->inCopied > tp - saveDataPtr) {
1449                 /* flags:  logon flag */
1450                 memcpy(&flags, tp, sizeof(int));
1451                 tp += sizeof(int);
1452
1453                 /* cell name */
1454                 cellp = cm_GetCell(tp, CM_FLAG_CREATE);
1455                 if (!cellp) return CM_ERROR_NOSUCHCELL;
1456                 tp += strlen(tp) + 1;
1457
1458                 /* user name */
1459                 uname = tp;
1460                 tp += strlen(tp) + 1;
1461
1462         if (flags & PIOCTL_LOGON) {
1463                   /* SMB user name with which to associate tokens */
1464                   smbname = tp;
1465                   fprintf(stderr, "SMB name = %s\n", smbname);
1466                   tp += strlen(tp) + 1;
1467         }
1468
1469 #ifndef DJGPP   /* for win95, session key is back in pioctl */
1470                 /* uuid */
1471                 memcpy(&uuid, tp, sizeof(uuid));
1472                 if (!cm_FindTokenEvent(uuid, sessionKey))
1473                         return CM_ERROR_INVAL;
1474 #endif /* !DJGPP */
1475         } else
1476                 cellp = cm_rootCellp;
1477
1478         if (flags & PIOCTL_LOGON) {
1479           userp = smb_FindCMUserByName(smbname, ioctlp->fidp->vcp->rname);
1480         }
1481         
1482         /* store the token */
1483         lock_ObtainMutex(&userp->mx);
1484         ucellp = cm_GetUCell(userp, cellp);
1485         ucellp->ticketLen = ticketLen;
1486         if (ucellp->ticketp)
1487                 free(ucellp->ticketp);  /* Discard old token if any */
1488         ucellp->ticketp = malloc(ticketLen);
1489         memcpy(ucellp->ticketp, ticket, ticketLen);
1490 #ifndef DJGPP
1491         /*
1492          * Get the session key from the RPC, rather than from the pioctl.
1493          */
1494         /*
1495         memcpy(&ucellp->sessionKey, ct.HandShakeKey, sizeof(ct.HandShakeKey));
1496          */
1497         memcpy(ucellp->sessionKey.data, sessionKey, sizeof(sessionKey));
1498 #else
1499         /* for win95, we are getting the session key from the pioctl */
1500         memcpy(&ucellp->sessionKey, ct.HandShakeKey, sizeof(ct.HandShakeKey));
1501 #endif /* !DJGPP */
1502         ucellp->kvno = ct.AuthHandle;
1503         ucellp->expirationTime = ct.EndTimestamp;
1504         ucellp->gen++;
1505         if (uname) strcpy(ucellp->userName, uname);
1506         ucellp->flags |= CM_UCELLFLAG_RXKAD;
1507         lock_ReleaseMutex(&userp->mx);
1508
1509         if (flags & PIOCTL_LOGON) {
1510                 ioctlp->flags |= SMB_IOCTLFLAG_LOGON;
1511         }
1512
1513         cm_ResetACLCache(userp);
1514
1515         return 0;
1516 }
1517
1518 long cm_IoctlGetTokenIter(struct smb_ioctl *ioctlp, struct cm_user *userp)
1519 {
1520         char *tp, *cp;
1521         int iterator;
1522         int temp;
1523         cm_ucell_t *ucellp;
1524         struct ClearToken ct;
1525
1526         cm_SkipIoctlPath(ioctlp);
1527
1528         tp = ioctlp->inDatap;
1529         cp = ioctlp->outDatap;
1530
1531         /* iterator */
1532         memcpy(&iterator, tp, sizeof(iterator));
1533         tp += sizeof(iterator);
1534
1535         lock_ObtainMutex(&userp->mx);
1536
1537         /* look for token */
1538         for (;;iterator++) {
1539                 ucellp = cm_FindUCell(userp, iterator);
1540                 if (!ucellp) {
1541                         lock_ReleaseMutex(&userp->mx);
1542                         return CM_ERROR_NOMORETOKENS;
1543                 }
1544                 if (ucellp->flags & CM_UCELLFLAG_RXKAD)
1545                         break;
1546         }
1547
1548         /* new iterator */
1549         temp = ucellp->iterator + 1;
1550         memcpy(cp, &temp, sizeof(temp));
1551         cp += sizeof(temp);
1552
1553         /* ticket length */
1554         memcpy(cp, &ucellp->ticketLen, sizeof(ucellp->ticketLen));
1555         cp += sizeof(ucellp->ticketLen);
1556
1557         /* ticket */
1558         memcpy(cp, ucellp->ticketp, ucellp->ticketLen);
1559         cp += ucellp->ticketLen;
1560
1561         /* clear token size */
1562         temp = sizeof(ct);
1563         memcpy(cp, &temp, sizeof(temp));
1564         cp += sizeof(temp);
1565
1566         /* clear token */
1567         ct.AuthHandle = ucellp->kvno;
1568 #ifndef DJGPP
1569         /*
1570          * Don't give out a real session key here
1571          */
1572         /*
1573         memcpy(ct.HandShakeKey, &ucellp->sessionKey, sizeof(ct.HandShakeKey));
1574          */
1575         memset(ct.HandShakeKey, 0, sizeof(ct.HandShakeKey));
1576 #else
1577         memcpy(ct.HandShakeKey, &ucellp->sessionKey, sizeof(ct.HandShakeKey));
1578 #endif /* !DJGPP */
1579         ct.ViceId = 37;                 /* XXX */
1580         ct.BeginTimestamp = 0;          /* XXX */
1581         ct.EndTimestamp = ucellp->expirationTime;
1582         memcpy(cp, &ct, sizeof(ct));
1583         cp += sizeof(ct);
1584
1585         /* Primary flag (unused) */
1586         temp = 0;
1587         memcpy(cp, &temp, sizeof(temp));
1588         cp += sizeof(temp);
1589
1590         /* cell name */
1591         strcpy(cp, ucellp->cellp->namep);
1592         cp += strlen(cp) + 1;
1593
1594         /* user name */
1595         strcpy(cp, ucellp->userName);
1596         cp += strlen(cp) + 1;
1597
1598         ioctlp->outDatap = cp;
1599
1600         lock_ReleaseMutex(&userp->mx);
1601
1602         return 0;
1603 }
1604
1605 long cm_IoctlGetToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
1606 {
1607         char *cp;
1608         int temp;
1609         cm_cell_t *cellp;
1610         cm_ucell_t *ucellp;
1611         struct ClearToken ct;
1612         char *tp;
1613 #ifndef DJGPP
1614         afs_uuid_t uuid;
1615 #endif /* !DJGPP */
1616
1617         cm_SkipIoctlPath(ioctlp);
1618
1619         tp = ioctlp->inDatap;
1620
1621         cp = ioctlp->outDatap;
1622
1623         /* cell name is right here */
1624         cellp = cm_GetCell(tp, 0);
1625         if (!cellp) return CM_ERROR_NOSUCHCELL;
1626         tp += strlen(tp) + 1;
1627
1628 #ifndef DJGPP
1629         /* uuid */
1630         memcpy(&uuid, tp, sizeof(uuid));
1631 #endif /* !DJGPP */
1632
1633         lock_ObtainMutex(&userp->mx);
1634
1635         ucellp = cm_GetUCell(userp, cellp);
1636         if (!ucellp || !(ucellp->flags & CM_UCELLFLAG_RXKAD)) {
1637                 lock_ReleaseMutex(&userp->mx);
1638                 return CM_ERROR_NOMORETOKENS;
1639         }
1640
1641         /* ticket length */
1642         memcpy(cp, &ucellp->ticketLen, sizeof(ucellp->ticketLen));
1643         cp += sizeof(ucellp->ticketLen);
1644
1645         /* ticket */
1646         memcpy(cp, ucellp->ticketp, ucellp->ticketLen);
1647         cp += ucellp->ticketLen;
1648
1649         /* clear token size */
1650         temp = sizeof(ct);
1651         memcpy(cp, &temp, sizeof(temp));
1652         cp += sizeof(temp);
1653
1654         /* clear token */
1655         ct.AuthHandle = ucellp->kvno;
1656 #ifndef DJGPP
1657         /*
1658          * Don't give out a real session key here
1659          */
1660         /*
1661         memcpy(ct.HandShakeKey, &ucellp->sessionKey, sizeof(ct.HandShakeKey));
1662          */
1663         memset(ct.HandShakeKey, 0, sizeof(ct.HandShakeKey));
1664 #else
1665         memcpy(ct.HandShakeKey, &ucellp->sessionKey, sizeof(ct.HandShakeKey));
1666 #endif /* !DJGPP */
1667         ct.ViceId = 37;                 /* XXX */
1668         ct.BeginTimestamp = 0;          /* XXX */
1669         ct.EndTimestamp = ucellp->expirationTime;
1670         memcpy(cp, &ct, sizeof(ct));
1671         cp += sizeof(ct);
1672
1673         /* Primary flag (unused) */
1674         temp = 0;
1675         memcpy(cp, &temp, sizeof(temp));
1676         cp += sizeof(temp);
1677
1678         /* cell name */
1679         strcpy(cp, ucellp->cellp->namep);
1680         cp += strlen(cp) + 1;
1681
1682         /* user name */
1683         strcpy(cp, ucellp->userName);
1684         cp += strlen(cp) + 1;
1685
1686         ioctlp->outDatap = cp;
1687
1688         lock_ReleaseMutex(&userp->mx);
1689
1690 #ifndef DJGPP
1691         cm_RegisterNewTokenEvent(uuid, ucellp->sessionKey.data);
1692 #endif /* !DJGPP */
1693
1694         return 0;
1695 }
1696
1697 long cm_IoctlDelToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
1698 {
1699         char *cp;
1700         cm_cell_t *cellp;
1701         cm_ucell_t *ucellp;
1702
1703         cm_SkipIoctlPath(ioctlp);
1704
1705         cp = ioctlp->outDatap;
1706
1707         /* cell name is right here */
1708         cellp = cm_GetCell(ioctlp->inDatap, 0);
1709         if (!cellp) return CM_ERROR_NOSUCHCELL;
1710
1711         lock_ObtainMutex(&userp->mx);
1712
1713         ucellp = cm_GetUCell(userp, cellp);
1714         if (!ucellp) {
1715                 lock_ReleaseMutex(&userp->mx);
1716                 return CM_ERROR_NOMORETOKENS;
1717         }
1718
1719         if (ucellp->ticketp) {
1720                 free(ucellp->ticketp);
1721                 ucellp->ticketp = NULL;
1722         }
1723         ucellp->flags &= ~CM_UCELLFLAG_RXKAD;
1724         ucellp->gen++;
1725
1726         lock_ReleaseMutex(&userp->mx);
1727
1728         cm_ResetACLCache(userp);
1729
1730         return 0;
1731 }
1732
1733 long cm_IoctlDelAllToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
1734 {
1735         cm_ucell_t *ucellp;
1736
1737         lock_ObtainMutex(&userp->mx);
1738
1739         for (ucellp = userp->cellInfop; ucellp; ucellp = ucellp->nextp) {
1740                 ucellp->flags &= ~CM_UCELLFLAG_RXKAD;
1741                 ucellp->gen++;
1742         }
1743
1744         lock_ReleaseMutex(&userp->mx);
1745
1746         cm_ResetACLCache(userp);
1747
1748         return 0;
1749 }
1750
1751 long cm_IoctlMakeSubmount(smb_ioctl_t *ioctlp, cm_user_t *userp)
1752 {
1753         char afspath[MAX_PATH];
1754         char *submountreqp;
1755         int iteration;
1756         int submountDataSize;
1757         char *submountData;
1758         char *submountName;
1759         int nextAutoSubmount;
1760
1761         cm_SkipIoctlPath(ioctlp);
1762
1763         /* Serialize this one, to prevent simultaneous mods
1764          * to afsdsbmt.ini
1765          */
1766         lock_ObtainMutex(&cm_Afsdsbmt_Lock);
1767
1768         /* Parse the input parameters--first the required afs path,
1769          * then the requested submount name (which may be "").
1770          */
1771         cm_NormalizeAfsPath (afspath, ioctlp->inDatap);
1772         submountreqp = ioctlp->inDatap + (strlen(ioctlp->inDatap)+1);
1773
1774         /* If the caller supplied a suggested submount name, see if
1775          * that submount name is in use... if so, the submount's path
1776          * has to match our path.
1777          */
1778         if (submountreqp && *submountreqp) {
1779                 char submountPathNormalized[MAX_PATH];
1780                 char submountPath[MAX_PATH];
1781                 int submountPathLen;
1782
1783                 submountPathLen = GetPrivateProfileString("AFS Submounts",
1784                                         submountreqp, "", submountPath,
1785                                         sizeof(submountPath), "afsdsbmt.ini");
1786
1787                 if ((submountPathLen == 0) ||
1788                     (submountPathLen == sizeof(submountPath) - 1)) {
1789
1790                         /* The suggested submount name isn't in use now--
1791                          * so we can safely map the requested submount name
1792                          * to the supplied path. Remember not to write the
1793                          * leading "/afs" when writing out the submount.
1794                          */
1795                         WritePrivateProfileString("AFS Submounts",
1796                                         submountreqp, 
1797                                         (strlen(&afspath[strlen(cm_mountRoot)])) ?
1798                                                   &afspath[strlen(cm_mountRoot)]:"/",
1799                                         "afsdsbmt.ini");
1800
1801                         strcpy(ioctlp->outDatap, submountreqp);
1802                         ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
1803                         lock_ReleaseMutex(&cm_Afsdsbmt_Lock);
1804                         return 0;
1805                 }
1806
1807                 /* The suggested submount name is already in use--if the
1808                  * supplied path matches the submount's path, we can still
1809                  * use the suggested submount name.
1810                  */
1811                 cm_NormalizeAfsPath (submountPathNormalized, submountPath);
1812                 if (!strcmp (submountPathNormalized, afspath)) {
1813                         strcpy(ioctlp->outDatap, submountreqp);
1814                         ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
1815                         lock_ReleaseMutex(&cm_Afsdsbmt_Lock);
1816                         return 0;
1817                 }
1818         }
1819
1820         /* At this point, the user either didn't request a particular
1821          * submount name, or that submount name couldn't be used.
1822          * Look through afsdsbmt.ini to see if there are any submounts
1823          * already associated with the specified path. The first
1824          * step in doing that search is to load the AFS Submounts
1825          * section of afsdsbmt.ini into memory.
1826          */
1827
1828         submountDataSize = 1024;
1829         submountData = malloc (submountDataSize);
1830
1831         for (iteration = 0; iteration < 5; ++iteration) {
1832
1833                 int sectionSize;
1834                 sectionSize = GetPrivateProfileString("AFS Submounts",
1835                                         NULL, "", submountData,
1836                                         submountDataSize, "afsdsbmt.ini");
1837                 if (sectionSize < submountDataSize-2)
1838                         break;
1839
1840                 free (submountData);
1841                 submountDataSize *= 2;
1842                 submountData = malloc (submountDataSize);
1843         }
1844
1845         /* Having obtained a list of all available submounts, start
1846          * searching that list for a path which matches the requested
1847          * AFS path. We'll also keep track of the highest "auto15"/"auto47"
1848          * submount, in case we need to add a new one later.
1849          */
1850
1851         nextAutoSubmount = 1;
1852
1853         for (submountName = submountData;
1854                 submountName && *submountName;
1855                 submountName += 1+strlen(submountName)) {
1856
1857                 char submountPathNormalized[MAX_PATH];
1858                 char submountPath[MAX_PATH] = "";
1859                 int submountPathLen;
1860
1861                 /* If this is an Auto### submount, remember its ### value */
1862
1863                 if ((!strnicmp (submountName, "auto", 4)) &&
1864                     (isdigit (submountName[strlen("auto")]))) {
1865                         int thisAutoSubmount;
1866                         thisAutoSubmount = atoi (&submountName[strlen("auto")]);
1867                         nextAutoSubmount = max (nextAutoSubmount,
1868                                                 thisAutoSubmount+1);
1869                 }
1870
1871                 /* We have the name of a submount in the AFS Submounts
1872                  * section; read that entry to find out what path it
1873                  * maps to.
1874                  */
1875                 submountPathLen = GetPrivateProfileString("AFS Submounts",
1876                                         submountName, "", submountPath,
1877                                         sizeof(submountPath), "afsdsbmt.ini");
1878
1879                 if ((submountPathLen == 0) ||
1880                     (submountPathLen == sizeof(submountPath) - 1)) {
1881                         continue;
1882                 }
1883
1884                 /* See if the path for this submount matches the path
1885                  * that our caller specified. If so, we can return
1886                  * this submount.
1887                  */
1888                 cm_NormalizeAfsPath (submountPathNormalized, submountPath);
1889                 if (!strcmp (submountPathNormalized, afspath)) {
1890
1891                         strcpy(ioctlp->outDatap, submountName);
1892                         ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
1893                         free (submountData);
1894                         lock_ReleaseMutex(&cm_Afsdsbmt_Lock);
1895                         return 0;
1896
1897                 }
1898         }
1899
1900         free (submountData);
1901
1902         /* We've been through the entire list of existing submounts, and
1903          * didn't find any which matched the specified path. So, we'll
1904          * just have to add one. Remember not to write the leading "/afs"
1905          * when writing out the submount.
1906          */
1907
1908         sprintf(ioctlp->outDatap, "auto%ld", nextAutoSubmount);
1909
1910         WritePrivateProfileString("AFS Submounts", ioctlp->outDatap,
1911                                   (strlen(&afspath[lstrlen(cm_mountRoot)])) ? 
1912                                   &afspath[lstrlen(cm_mountRoot)]:"/",
1913                                   "afsdsbmt.ini");
1914
1915         ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
1916         lock_ReleaseMutex(&cm_Afsdsbmt_Lock);
1917         return 0;
1918 }
1919
1920 long cm_IoctlGetRxkcrypt(smb_ioctl_t *ioctlp, cm_user_t *userp)
1921 {
1922         memcpy(ioctlp->outDatap, &cryptall, sizeof(cryptall));
1923         ioctlp->outDatap += sizeof(cryptall);
1924
1925         return 0;
1926 }
1927
1928 long cm_IoctlSetRxkcrypt(smb_ioctl_t *ioctlp, cm_user_t *userp)
1929 {
1930         cm_SkipIoctlPath(ioctlp);
1931
1932         memcpy(&cryptall, ioctlp->inDatap, sizeof(cryptall));
1933
1934         return 0;
1935 }
1936
1937 #ifdef DJGPP
1938 extern int afsd_shutdown(int);
1939 extern int afs_shutdown;
1940
1941 long cm_IoctlShutdown(smb_ioctl_t *ioctlp, cm_user_t *userp) {
1942   afs_shutdown = 1;   /* flag to shut down */
1943   return 0;
1944 }
1945 #endif /* DJGPP */
1946
1947 long cm_IoctlGetSMBName(smb_ioctl_t *ioctlp, cm_user_t *userp)
1948 {
1949   smb_user_t *uidp = ioctlp->uidp;
1950
1951   if (uidp && uidp->unp) {
1952     memcpy(ioctlp->outDatap, uidp->unp->name, strlen(uidp->unp->name));
1953     ioctlp->outDatap += strlen(uidp->unp->name);
1954         }
1955
1956   return 0;
1957 }
1958
1959 /* 
1960  * functions to dump contents of various structures. 
1961  * In debug build (linked with crt debug library) will dump allocated but not freed memory
1962  */
1963 extern int cm_DumpSCache(FILE *outputFile, char *cookie);
1964 extern int cm_DumpBufHashTable(FILE *outputFile, char *cookie);
1965 extern int smb_DumpVCP(FILE *outputFile, char *cookie);
1966
1967 long cm_IoctlMemoryDump(struct smb_ioctl *ioctlp, struct cm_user *userp)
1968 {
1969     long inValue = 0;
1970     HANDLE hLogFile;
1971     char logfileName[MAX_PATH+1];
1972     char *cookie;
1973   
1974 #ifdef _DEBUG  
1975     static _CrtMemState memstate;
1976 #endif
1977   
1978     cm_SkipIoctlPath(ioctlp);
1979     memcpy(&inValue, ioctlp->inDatap, sizeof(long));
1980   
1981     GetWindowsDirectory(logfileName, sizeof(logfileName));
1982     strncat(logfileName, "\\afsd_alloc.log", sizeof(logfileName));
1983
1984     hLogFile = CreateFile(logfileName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1985   
1986     if (!hLogFile)
1987     {
1988       /* error */
1989       inValue = -1;
1990       memcpy(ioctlp->outDatap, &inValue, sizeof(long));
1991       ioctlp->outDatap += sizeof(long);
1992       
1993       return 0;               
1994     }
1995   
1996     SetFilePointer(hLogFile, 0, NULL, FILE_END);
1997   
1998     cookie = inValue ? "b" : "e";
1999   
2000 #ifdef _DEBUG  
2001   
2002     if (inValue)
2003     {
2004       _CrtMemCheckpoint(&memstate);           
2005     }
2006     else
2007     {
2008         _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2009         _CrtSetReportFile(_CRT_WARN, hLogFile);
2010         _CrtMemDumpAllObjectsSince(&memstate);
2011     }
2012 #endif
2013   
2014     /* dump all interesting data */
2015     cm_DumpSCache(hLogFile, cookie);
2016     cm_DumpBufHashTable(hLogFile, cookie);
2017     smb_DumpVCP(hLogFile, cookie);
2018
2019     CloseHandle(hLogFile);                          
2020   
2021     memcpy(ioctlp->outDatap, &inValue, sizeof(long));
2022     ioctlp->outDatap += sizeof(long);
2023   
2024     return 0;
2025 }