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