cbb0fa96cb0ec80423d8130146701b28f158d30e
[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 #include <WINNT\afsreg.h>
30
31 #include "smb.h"
32 #include "cm_server.h"
33
34 #ifndef DJGPP
35 #include <rx/rxkad.h>
36 #include "afsrpc.h"
37 #else
38 #include <rx/rxkad.h>
39 #include "afsrpc95.h"
40 #endif
41
42 #include "cm_rpc.h"
43 #include <strsafe.h>
44 #include <winioctl.h>
45 #include <..\afsrdr\kif.h>
46 #include <rx\rx.h>
47
48 #ifdef _DEBUG
49 #include <crtdbg.h>
50 #endif
51
52 /* Copied from afs_tokens.h */
53 #define PIOCTL_LOGON    0x1
54 #define MAX_PATH 260
55
56 osi_mutex_t cm_Afsdsbmt_Lock;
57
58 extern afs_int32 cryptall;
59 extern char cm_NetbiosName[];
60
61 extern void afsi_log(char *pattern, ...);
62
63 void cm_InitIoctl(void)
64 {
65     lock_InitializeMutex(&cm_Afsdsbmt_Lock, "AFSDSBMT.INI Access Lock");
66 }
67
68 long cm_FlushFile(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
69 {
70     long code;
71
72     lock_ObtainWrite(&scp->bufCreateLock);
73     code = buf_FlushCleanPages(scp, userp, reqp);
74         
75     lock_ObtainMutex(&scp->mx);
76     scp->cbServerp = NULL;
77     scp->cbExpires = 0;
78     cm_dnlcPurgedp(scp);
79     cm_dnlcPurgevp(scp);
80     cm_FreeAllACLEnts(scp);
81
82     /* Force mount points and symlinks to be re-evaluated */
83     scp->mountPointStringp[0] = '\0';
84
85     lock_ReleaseMutex(&scp->mx);
86
87     lock_ReleaseWrite(&scp->bufCreateLock);
88     osi_Log2(afsd_logp,"cm_FlushFile scp 0x%x returns error: [%x]",scp, code);
89     return code;
90 }
91
92 long cm_FlushParent(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
93 {
94     long code = 0;
95     int i;
96     cm_fid_t    parent_fid;
97
98     lock_ObtainWrite(&cm_scacheLock);
99     cm_HoldSCacheNoLock(scp);
100     parent_fid = scp->fid;
101     parent_fid.vnode = scp->parentVnode;
102     parent_fid.unique = scp->parentUnique;
103     cm_ReleaseSCacheNoLock(scp);
104
105     for (i=0; i<cm_data.hashTableSize; i++) {
106         for (scp = cm_data.hashTablep[i]; scp; scp = scp->nextp) {
107             if (!cm_FidCmp(&scp->fid, &parent_fid)) {
108                 cm_HoldSCacheNoLock(scp);
109                 lock_ReleaseWrite(&cm_scacheLock);
110
111                 /* now flush the file */
112                 code = cm_FlushFile(scp, userp, reqp);
113                 lock_ObtainWrite(&cm_scacheLock);
114                 cm_ReleaseSCacheNoLock(scp);
115             }
116         }
117     }
118     lock_ReleaseWrite(&cm_scacheLock);
119
120     return code;
121 }
122
123
124 long cm_FlushVolume(cm_user_t *userp, cm_req_t *reqp, afs_uint32 cell, afs_uint32 volume)
125 {
126     long code = 0;
127     cm_scache_t *scp;
128     int i;
129
130     lock_ObtainWrite(&cm_scacheLock);
131     for (i=0; i<cm_data.hashTableSize; i++) {
132         for (scp = cm_data.hashTablep[i]; scp; scp = scp->nextp) {
133             if (scp->fid.volume == volume && scp->fid.cell == cell) {
134                 cm_HoldSCacheNoLock(scp);
135                 lock_ReleaseWrite(&cm_scacheLock);
136
137                 /* now flush the file */
138                 code = cm_FlushFile(scp, userp, reqp);
139                 lock_ObtainWrite(&cm_scacheLock);
140                 cm_ReleaseSCacheNoLock(scp);
141             }
142         }
143     }
144     lock_ReleaseWrite(&cm_scacheLock);
145
146     return code;
147 }
148
149 /*
150  * cm_ResetACLCache -- invalidate ACL info for a user that has just
151  *                      obtained or lost tokens
152  */
153 void cm_ResetACLCache(cm_user_t *userp)
154 {
155     cm_scache_t *scp;
156     int hash;
157
158     lock_ObtainWrite(&cm_scacheLock);
159     for (hash=0; hash < cm_data.hashTableSize; hash++) {
160         for (scp=cm_data.hashTablep[hash]; scp; scp=scp->nextp) {
161             cm_HoldSCacheNoLock(scp);
162             lock_ReleaseWrite(&cm_scacheLock);
163             lock_ObtainMutex(&scp->mx);
164             cm_InvalidateACLUser(scp, userp);
165             lock_ReleaseMutex(&scp->mx);
166             lock_ObtainWrite(&cm_scacheLock);
167             cm_ReleaseSCacheNoLock(scp);
168         }
169     }
170     lock_ReleaseWrite(&cm_scacheLock);
171 }       
172
173 /*
174  *  TranslateExtendedChars - This is a fix for TR 54482.
175  *
176  *  If an extended character (80 - FF) is entered into a file
177  *  or directory name in Windows, the character is translated
178  *  into the OEM character map before being passed to us.  Why
179  *  this occurs is unknown.  Our pioctl functions must match
180  *  this translation for paths given via our own commands (like
181  *  fs).  If we do not do this, then we will try to perform an
182  *  operation on a non-translated path, which we will fail to 
183  *  find, since the path was created with the translated chars.
184  *  This function performs the required translation.
185  */
186 void TranslateExtendedChars(char *str)
187 {
188 #ifdef DJGPP
189     char *p;
190 #endif
191
192     if (!str || !*str)
193         return;
194
195 #ifndef DJGPP
196     CharToOem(str, str);
197 #else
198     p = str;
199     while (*p) *p++ &= 0x7f;  /* turn off high bit; probably not right */
200 #endif
201 }
202         
203 /* parse the passed-in file name and do a namei on it.  If we fail,
204  * return an error code, otherwise return the vnode located in *scpp.
205  */
206 long cm_ParseIoctlPath(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
207         cm_scache_t **scpp)
208 {
209     long code;
210     cm_scache_t *substRootp;
211     char * relativePath = ioctlp->inDatap;
212 #ifdef AFSIFS
213     char * absRoot[MAX_PATH];
214     long length;
215     wchar_t absRoot_w[MAX_PATH];
216     HANDLE rootDir;
217 #endif
218     osi_Log1(afsd_logp, "cm_ParseIoctlPath %s", osi_LogSaveString(afsd_logp,relativePath));
219
220     /* This is usually the file name, but for StatMountPoint it is the path. */
221     /* ioctlp->inDatap can be either of the form:
222      *    \path\.
223      *    \path\file
224      *    \\netbios-name\submount\path\.
225      *    \\netbios-name\submount\path\file
226      */
227     TranslateExtendedChars(relativePath);
228
229 #ifdef AFSIFS
230     /* we have passed the whole path, including the afs prefix.
231            when the pioctl call is made, we perform an ioctl to afsrdr
232            and it returns the correct (full) path.  therefore, there is
233            no drive letter, and the path is absolute. */
234     code = cm_NameI(cm_data.rootSCachep, relativePath,
235                      CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
236                      userp, "", reqp, scpp);
237
238     if (code)
239         return code;
240
241     /* # of bytes of path */
242     code = strlen(ioctlp->inDatap) + 1;
243     ioctlp->inDatap += code;
244
245     /* This is usually nothing, but for StatMountPoint it is the file name. */
246     TranslateExtendedChars(ioctlp->inDatap);
247
248     return 0;
249 #endif /* AFSIFS */
250
251     if (relativePath[0] == relativePath[1] &&
252          relativePath[1] == '\\' && 
253          !_strnicmp(cm_NetbiosName,relativePath+2,strlen(cm_NetbiosName))) 
254     {
255         char shareName[256];
256         char *sharePath;
257         int shareFound, i;
258
259         /* We may have found a UNC path. 
260          * If the first component is the NetbiosName,
261          * then throw out the second component (the submount)
262          * since it had better expand into the value of ioctl->tidPathp
263          */
264         char * p;
265         p = relativePath + 2 + strlen(cm_NetbiosName) + 1;                      /* buffer overflow vuln.? */
266         if ( !_strnicmp("all", p, 3) )
267             p += 4;
268
269         for (i = 0; *p && *p != '\\'; i++,p++ ) {
270             shareName[i] = *p;
271         }
272         p++;                    /* skip past trailing slash */
273         shareName[i] = 0;       /* terminate string */
274
275         shareFound = smb_FindShare(ioctlp->fidp->vcp, ioctlp->uidp, shareName, &sharePath);
276         if ( shareFound ) {
277             /* we found a sharename, therefore use the resulting path */
278             code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
279                              CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
280                              userp, sharePath, reqp, &substRootp);
281             free(sharePath);
282             if (code) 
283                 return code;
284
285             code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
286                              userp, NULL, reqp, scpp);
287             if (code) 
288                 return code;
289         } else {
290             /* otherwise, treat the name as a cellname mounted off the afs root.
291              * This requires that we reconstruct the shareName string with 
292              * leading and trailing slashes.
293              */
294             p = relativePath + 2 + strlen(cm_NetbiosName) + 1;
295             if ( !_strnicmp("all", p, 3) )
296                 p += 4;
297
298             shareName[0] = '/';
299             for (i = 1; *p && *p != '\\'; i++,p++ ) {
300                 shareName[i] = *p;
301             }
302             p++;                    /* skip past trailing slash */
303             shareName[i++] = '/';       /* add trailing slash */
304             shareName[i] = 0;       /* terminate string */
305
306
307             code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
308                              CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
309                              userp, shareName, reqp, &substRootp);
310             if (code) 
311                 return code;
312
313             code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
314                             userp, NULL, reqp, scpp);
315             if (code) 
316                 return code;
317         }
318     } else {
319         code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
320                          CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
321                          userp, ioctlp->tidPathp, reqp, &substRootp);
322         if (code) 
323             return code;
324         
325         code = cm_NameI(substRootp, relativePath, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
326                          userp, NULL, reqp, scpp);
327         if (code) 
328             return code;
329     }
330
331     /* # of bytes of path */
332     code = (long)strlen(ioctlp->inDatap) + 1;
333     ioctlp->inDatap += code;
334
335     /* This is usually nothing, but for StatMountPoint it is the file name. */
336     TranslateExtendedChars(ioctlp->inDatap);
337
338     /* and return success */
339     return 0;
340 }
341
342 void cm_SkipIoctlPath(smb_ioctl_t *ioctlp)
343 {
344     long temp;
345         
346     temp = (long) strlen(ioctlp->inDatap) + 1;
347     ioctlp->inDatap += temp;
348 }       
349
350
351 /* format the specified path to look like "/afs/<cellname>/usr", by
352  * adding "/afs" (if necessary) in front, changing any \'s to /'s, and
353  * removing any trailing "/"'s. One weirdo caveat: "/afs" will be
354  * intentionally returned as "/afs/"--this makes submount manipulation
355  * easier (because we can always jump past the initial "/afs" to find
356  * the AFS path that should be written into afsdsbmt.ini).
357  */
358 void cm_NormalizeAfsPath(char *outpathp, long outlen, char *inpathp)
359 {
360     char *cp;
361     char bslash_mountRoot[256];
362        
363     strncpy(bslash_mountRoot, cm_mountRoot, sizeof(bslash_mountRoot) - 1);
364     bslash_mountRoot[0] = '\\';
365        
366     if (!strnicmp (inpathp, cm_mountRoot, strlen(cm_mountRoot)))
367         StringCbCopy(outpathp, outlen, inpathp);
368     else if (!strnicmp (inpathp, bslash_mountRoot, strlen(bslash_mountRoot)))
369         StringCbCopy(outpathp, outlen, inpathp);
370     else if ((inpathp[0] == '/') || (inpathp[0] == '\\'))
371         StringCbPrintfA(outpathp, outlen, "%s%s", cm_mountRoot, inpathp);
372     else // inpathp looks like "<cell>/usr"
373         StringCbPrintfA(outpathp, outlen, "%s/%s", cm_mountRoot, inpathp);
374
375     for (cp = outpathp; *cp != 0; ++cp) {
376         if (*cp == '\\')
377             *cp = '/';
378     }       
379
380     if (strlen(outpathp) && (outpathp[strlen(outpathp)-1] == '/')) {
381         outpathp[strlen(outpathp)-1] = 0;
382     }
383
384     if (!strcmpi (outpathp, cm_mountRoot)) {
385         StringCbCopy(outpathp, outlen, cm_mountRoot);
386     }
387 }
388
389 #define LEAF_SIZE 256
390 /* parse the passed-in file name and do a namei on its parent.  If we fail,
391  * return an error code, otherwise return the vnode located in *scpp.
392  */
393 long cm_ParseIoctlParent(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
394                          cm_scache_t **scpp, char *leafp)
395 {
396     long code;
397     char tbuffer[1024];
398     char *tp, *jp;
399     cm_scache_t *substRootp;
400
401     StringCbCopyA(tbuffer, sizeof(tbuffer), ioctlp->inDatap);
402     tp = strrchr(tbuffer, '\\');
403     jp = strrchr(tbuffer, '/');
404     if (!tp)
405         tp = jp;
406     else if (jp && (tp - tbuffer) < (jp - tbuffer))
407         tp = jp;
408     if (!tp) {
409         StringCbCopyA(tbuffer, sizeof(tbuffer), "\\");
410         if (leafp) 
411             StringCbCopyA(leafp, LEAF_SIZE, ioctlp->inDatap);
412     }
413     else {
414         *tp = 0;
415         if (leafp) 
416             StringCbCopyA(leafp, LEAF_SIZE, tp+1);
417     }   
418
419     if (tbuffer[0] == tbuffer[1] &&
420         tbuffer[1] == '\\' && 
421         !_strnicmp(cm_NetbiosName,tbuffer+2,strlen(cm_NetbiosName))) 
422     {
423         char shareName[256];
424         char *sharePath;
425         int shareFound, i;
426
427         /* We may have found a UNC path. 
428          * If the first component is the NetbiosName,
429          * then throw out the second component (the submount)
430          * since it had better expand into the value of ioctl->tidPathp
431          */
432         char * p;
433         p = tbuffer + 2 + strlen(cm_NetbiosName) + 1;
434         if ( !_strnicmp("all", p, 3) )
435             p += 4;
436
437         for (i = 0; *p && *p != '\\'; i++,p++ ) {
438             shareName[i] = *p;
439         }
440         p++;                    /* skip past trailing slash */
441         shareName[i] = 0;       /* terminate string */
442
443         shareFound = smb_FindShare(ioctlp->fidp->vcp, ioctlp->uidp, shareName, &sharePath);
444         if ( shareFound ) {
445             /* we found a sharename, therefore use the resulting path */
446             code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
447                              CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
448                              userp, sharePath, reqp, &substRootp);
449             free(sharePath);
450             if (code) return code;
451
452             code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
453                              userp, NULL, reqp, scpp);
454             if (code) return code;
455         } else {
456             /* otherwise, treat the name as a cellname mounted off the afs root.
457              * This requires that we reconstruct the shareName string with 
458              * leading and trailing slashes.
459              */
460             p = tbuffer + 2 + strlen(cm_NetbiosName) + 1;
461             if ( !_strnicmp("all", p, 3) )
462                 p += 4;
463
464             shareName[0] = '/';
465             for (i = 1; *p && *p != '\\'; i++,p++ ) {
466                 shareName[i] = *p;
467             }
468             p++;                    /* skip past trailing slash */
469             shareName[i++] = '/';       /* add trailing slash */
470             shareName[i] = 0;       /* terminate string */
471
472             code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
473                              CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
474                              userp, shareName, reqp, &substRootp);
475             if (code) return code;
476
477             code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
478                             userp, NULL, reqp, scpp);
479             if (code) return code;
480         }
481     } else {
482         code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
483                         CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
484                         userp, ioctlp->tidPathp, reqp, &substRootp);
485         if (code) return code;
486
487         code = cm_NameI(substRootp, tbuffer, CM_FLAG_FOLLOW,
488                         userp, NULL, reqp, scpp);
489         if (code) return code;
490     }
491
492     /* # of bytes of path */
493     code = (long)strlen(ioctlp->inDatap) + 1;
494     ioctlp->inDatap += code;
495
496     /* and return success */
497     return 0;
498 }
499
500 long cm_IoctlGetACL(smb_ioctl_t *ioctlp, cm_user_t *userp)
501 {
502     cm_conn_t *connp;
503     cm_scache_t *scp;
504     AFSOpaque acl;
505     AFSFetchStatus fileStatus;
506     AFSVolSync volSync;
507     long code;
508     AFSFid fid;
509     int tlen;
510     cm_req_t req;
511     struct rx_connection * callp;
512
513     cm_InitReq(&req);
514
515     code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
516     if (code) return code;
517
518     /* now make the get acl call */
519     fid.Volume = scp->fid.volume;
520     fid.Vnode = scp->fid.vnode;
521     fid.Unique = scp->fid.unique;
522     do {
523         acl.AFSOpaque_val = ioctlp->outDatap;
524         acl.AFSOpaque_len = 0;
525         code = cm_Conn(&scp->fid, userp, &req, &connp);
526         if (code) continue;
527
528         callp = cm_GetRxConn(connp);
529         code = RXAFS_FetchACL(callp, &fid, &acl, &fileStatus, &volSync);
530         rx_PutConnection(callp);
531
532     } while (cm_Analyze(connp, userp, &req, &scp->fid, &volSync, NULL, NULL, code));
533     code = cm_MapRPCError(code, &req);
534     cm_ReleaseSCache(scp);
535
536     if (code) return code;
537
538     /* skip over return data */
539     tlen = (int)strlen(ioctlp->outDatap) + 1;
540     ioctlp->outDatap += tlen;
541
542     /* and return success */
543     return 0;
544 }
545
546 long cm_IoctlGetFileCellName(struct smb_ioctl *ioctlp, struct cm_user *userp)
547 {
548     long code;
549     cm_scache_t *scp;
550     cm_cell_t *cellp;
551     cm_req_t req;
552
553     cm_InitReq(&req);
554
555     code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
556     if (code) return code;
557
558 #ifdef AFS_FREELANCE_CLIENT
559     if ( cm_freelanceEnabled && 
560          scp->fid.cell==AFS_FAKE_ROOT_CELL_ID &&
561          scp->fid.volume==AFS_FAKE_ROOT_VOL_ID &&
562          scp->fid.vnode==0x1 && scp->fid.unique==0x1 ) {
563         StringCbCopyA(ioctlp->outDatap, 999999, "Freelance.Local.Root");
564         ioctlp->outDatap += strlen(ioctlp->outDatap) + 1;
565         code = 0;
566     } else 
567 #endif /* AFS_FREELANCE_CLIENT */
568     {
569         cellp = cm_FindCellByID(scp->fid.cell);
570         if (cellp) {
571             StringCbCopyA(ioctlp->outDatap, 999999, cellp->name);
572             ioctlp->outDatap += strlen(ioctlp->outDatap) + 1;
573             code = 0;
574         }
575         else 
576             code = CM_ERROR_NOSUCHCELL;
577     }
578
579     cm_ReleaseSCache(scp);
580     return code;
581 }
582
583 long cm_IoctlSetACL(struct smb_ioctl *ioctlp, struct cm_user *userp)
584 {
585     cm_conn_t *connp;
586     cm_scache_t *scp;
587     AFSOpaque acl;
588     AFSFetchStatus fileStatus;
589     AFSVolSync volSync;
590     long code;
591     AFSFid fid;
592     cm_req_t req;
593     struct rx_connection * callp;
594
595     cm_InitReq(&req);
596
597     code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
598     if (code) return code;
599         
600     /* now make the get acl call */
601     fid.Volume = scp->fid.volume;
602     fid.Vnode = scp->fid.vnode;
603     fid.Unique = scp->fid.unique;
604     do {
605         acl.AFSOpaque_val = ioctlp->inDatap;
606         acl.AFSOpaque_len = (u_int)strlen(ioctlp->inDatap)+1;
607         code = cm_Conn(&scp->fid, userp, &req, &connp);
608         if (code) continue;
609
610         callp = cm_GetRxConn(connp);
611         code = RXAFS_StoreACL(callp, &fid, &acl, &fileStatus, &volSync);
612         rx_PutConnection(callp);
613
614     } while (cm_Analyze(connp, userp, &req, &scp->fid, &volSync, NULL, NULL, code));
615     code = cm_MapRPCError(code, &req);
616
617     /* invalidate cache info, since we just trashed the ACL cache */
618     lock_ObtainMutex(&scp->mx);
619     cm_DiscardSCache(scp);
620     lock_ReleaseMutex(&scp->mx);
621
622     cm_ReleaseSCache(scp);
623
624     return code;
625 }
626
627
628
629 long cm_IoctlFlushAllVolumes(struct smb_ioctl *ioctlp, struct cm_user *userp)
630 {
631     long code;
632     cm_scache_t *scp;
633     int i;
634     cm_req_t req;
635
636     cm_InitReq(&req);
637
638     lock_ObtainWrite(&cm_scacheLock);
639     for (i=0; i<cm_data.hashTableSize; i++) {
640         for (scp = cm_data.hashTablep[i]; scp; scp = scp->nextp) {
641             cm_HoldSCacheNoLock(scp);
642             lock_ReleaseWrite(&cm_scacheLock);
643
644             /* now flush the file */
645             code = cm_FlushFile(scp, userp, &req);
646             lock_ObtainWrite(&cm_scacheLock);
647             cm_ReleaseSCacheNoLock(scp);
648         }
649     }
650     lock_ReleaseWrite(&cm_scacheLock);
651
652     return code;
653 }
654
655 long cm_IoctlFlushVolume(struct smb_ioctl *ioctlp, struct cm_user *userp)
656 {
657     long code;
658     cm_scache_t *scp;
659     unsigned long volume;
660     unsigned long cell;
661     cm_req_t req;
662
663     cm_InitReq(&req);
664
665     code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
666     if (code) return code;
667         
668     volume = scp->fid.volume;
669     cell = scp->fid.cell;
670     cm_ReleaseSCache(scp);
671
672     code = cm_FlushVolume(userp, &req, cell, volume);
673
674     return code;
675 }
676
677 long cm_IoctlFlushFile(struct smb_ioctl *ioctlp, struct cm_user *userp)
678 {
679     long code;
680     cm_scache_t *scp;
681     cm_req_t req;
682
683     cm_InitReq(&req);
684
685     code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
686     if (code) return code;
687         
688     cm_FlushFile(scp, userp, &req);
689     cm_ReleaseSCache(scp);
690
691     return 0;
692 }
693
694 long cm_IoctlSetVolumeStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
695 {
696     cm_scache_t *scp;
697     char volName[32];
698     char offLineMsg[256];
699     char motd[256];
700     cm_conn_t *tcp;
701     long code;
702     AFSFetchVolumeStatus volStat;
703     AFSStoreVolumeStatus storeStat;
704     cm_volume_t *tvp;
705     char *cp;
706     cm_cell_t *cellp;
707     cm_req_t req;
708     struct rx_connection * callp;
709
710     cm_InitReq(&req);
711
712     code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
713     if (code) return code;
714
715     cellp = cm_FindCellByID(scp->fid.cell);
716     osi_assert(cellp);
717
718     if (scp->flags & CM_SCACHEFLAG_RO) {
719         cm_ReleaseSCache(scp);
720         return CM_ERROR_READONLY;
721     }
722
723     code = cm_GetVolumeByID(cellp, scp->fid.volume, userp, &req, &tvp);
724     if (code) {
725         cm_ReleaseSCache(scp);
726         return code;
727     }
728
729     /* Copy the junk out, using cp as a roving pointer. */
730     cp = ioctlp->inDatap;
731     memcpy((char *)&volStat, cp, sizeof(AFSFetchVolumeStatus));
732     cp += sizeof(AFSFetchVolumeStatus);
733     StringCbCopyA(volName, sizeof(volName), cp);
734     cp += strlen(volName)+1;
735     StringCbCopyA(offLineMsg, sizeof(offLineMsg), cp);
736     cp +=  strlen(offLineMsg)+1;
737     StringCbCopyA(motd, sizeof(motd), cp);
738     storeStat.Mask = 0;
739     if (volStat.MinQuota != -1) {
740         storeStat.MinQuota = volStat.MinQuota;
741         storeStat.Mask |= AFS_SETMINQUOTA;
742     }
743     if (volStat.MaxQuota != -1) {
744         storeStat.MaxQuota = volStat.MaxQuota;
745         storeStat.Mask |= AFS_SETMAXQUOTA;
746     }
747
748     do {
749         code = cm_Conn(&scp->fid, userp, &req, &tcp);
750         if (code) continue;
751
752         callp = cm_GetRxConn(tcp);
753         code = RXAFS_SetVolumeStatus(callp, scp->fid.volume,
754                                       &storeStat, volName, offLineMsg, motd);
755         rx_PutConnection(callp);
756
757     } while (cm_Analyze(tcp, userp, &req, &scp->fid, NULL, NULL, NULL, code));
758     code = cm_MapRPCError(code, &req);
759
760     /* return on failure */
761     cm_ReleaseSCache(scp);
762     if (code) {
763         return code;
764     }
765
766     /* we are sending parms back to make compat. with prev system.  should
767      * change interface later to not ask for current status, just set
768      * new status
769      */
770     cp = ioctlp->outDatap;
771     memcpy(cp, (char *)&volStat, sizeof(VolumeStatus));
772     cp += sizeof(VolumeStatus);
773     StringCbCopyA(cp, 999999, volName);
774     cp += strlen(volName)+1;
775     StringCbCopyA(cp, 999999, offLineMsg);
776     cp += strlen(offLineMsg)+1;
777     StringCbCopyA(cp, 999999, motd);
778     cp += strlen(motd)+1;
779
780     /* now return updated return data pointer */
781     ioctlp->outDatap = cp;
782
783     return 0;
784 }       
785
786 long cm_IoctlGetVolumeStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
787 {
788     char volName[32];
789     cm_scache_t *scp;
790     char offLineMsg[256];
791     char motd[256];
792     cm_conn_t *tcp;
793     register long code;
794     AFSFetchVolumeStatus volStat;
795     register char *cp;
796     char *Name;
797     char *OfflineMsg;
798     char *MOTD;
799     cm_req_t req;
800     struct rx_connection * callp;
801
802     cm_InitReq(&req);
803
804     code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
805     if (code) return code;
806
807     Name = volName;
808     OfflineMsg = offLineMsg;
809     MOTD = motd;
810     do {
811         code = cm_Conn(&scp->fid, userp, &req, &tcp);
812         if (code) continue;
813
814         callp = cm_GetRxConn(tcp);
815         code = RXAFS_GetVolumeStatus(callp, scp->fid.volume,
816                                       &volStat, &Name, &OfflineMsg, &MOTD);
817         rx_PutConnection(callp);
818
819     } while (cm_Analyze(tcp, userp, &req, &scp->fid, NULL, NULL, NULL, code));
820     code = cm_MapRPCError(code, &req);
821
822     cm_ReleaseSCache(scp);
823     if (code) return code;
824
825     /* Copy all this junk into msg->im_data, keeping track of the lengths. */
826     cp = ioctlp->outDatap;
827     memcpy(cp, (char *)&volStat, sizeof(AFSFetchVolumeStatus));
828     cp += sizeof(AFSFetchVolumeStatus);
829     StringCbCopyA(cp, 999999, volName);
830     cp += strlen(volName)+1;
831     StringCbCopyA(cp, 999999, offLineMsg);
832     cp += strlen(offLineMsg)+1;
833     StringCbCopyA(cp, 999999, motd);
834     cp += strlen(motd)+1;
835
836     /* return new size */
837     ioctlp->outDatap = cp;
838
839     return 0;
840 }
841
842 long cm_IoctlGetFid(struct smb_ioctl *ioctlp, struct cm_user *userp)
843 {
844     cm_scache_t *scp;
845     register long code;
846     register char *cp;
847     cm_fid_t fid;
848     cm_req_t req;
849
850     cm_InitReq(&req);
851
852     code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
853     if (code) return code;
854
855     memset(&fid, 0, sizeof(cm_fid_t));
856     fid.volume = scp->fid.volume;
857     fid.vnode  = scp->fid.vnode;
858     fid.unique = scp->fid.unique;
859
860     cm_ReleaseSCache(scp);
861
862     /* Copy all this junk into msg->im_data, keeping track of the lengths. */
863     cp = ioctlp->outDatap;
864     memcpy(cp, (char *)&fid, sizeof(cm_fid_t));
865     cp += sizeof(cm_fid_t);
866
867     /* return new size */
868     ioctlp->outDatap = cp;
869
870     return 0;
871 }
872
873 long cm_IoctlGetOwner(struct smb_ioctl *ioctlp, struct cm_user *userp)
874 {
875     cm_scache_t *scp;
876     register long code;
877     register char *cp;
878     cm_req_t req;
879
880     cm_InitReq(&req);
881
882     code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
883     if (code) return code;
884
885     /* Copy all this junk into msg->im_data, keeping track of the lengths. */
886     cp = ioctlp->outDatap;
887     memcpy(cp, (char *)&scp->owner, sizeof(afs_uint32));
888     cp += sizeof(afs_uint32);
889     memcpy(cp, (char *)&scp->group, sizeof(afs_uint32));
890     cp += sizeof(afs_uint32);
891
892     /* return new size */
893     ioctlp->outDatap = cp;
894
895     cm_ReleaseSCache(scp);
896
897     return 0;
898 }
899
900 long cm_IoctlWhereIs(struct smb_ioctl *ioctlp, struct cm_user *userp)
901 {
902     long code;
903     cm_scache_t *scp;
904     cm_cell_t *cellp;
905     cm_volume_t *tvp;
906     cm_serverRef_t **tsrpp, *current;
907     cm_server_t *tsp;
908     unsigned long volume;
909     char *cp;
910     cm_req_t req;
911
912     cm_InitReq(&req);
913
914     code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
915     if (code) return code;
916         
917     volume = scp->fid.volume;
918
919     cellp = cm_FindCellByID(scp->fid.cell);
920     osi_assert(cellp);
921
922     cm_ReleaseSCache(scp);
923
924     code = cm_GetVolumeByID(cellp, volume, userp, &req, &tvp);
925     if (code) return code;
926         
927     cp = ioctlp->outDatap;
928         
929     lock_ObtainMutex(&tvp->mx);
930     tsrpp = cm_GetVolServers(tvp, volume);
931     lock_ObtainRead(&cm_serverLock);
932     for (current = *tsrpp; current; current = current->next) {
933         tsp = current->server;
934         memcpy(cp, (char *)&tsp->addr.sin_addr.s_addr, sizeof(long));
935         cp += sizeof(long);
936     }
937     lock_ReleaseRead(&cm_serverLock);
938     cm_FreeServerList(tsrpp);
939     lock_ReleaseMutex(&tvp->mx);
940
941     /* still room for terminating NULL, add it on */
942     volume = 0; /* reuse vbl */
943     memcpy(cp, (char *)&volume, sizeof(long));
944     cp += sizeof(long);
945
946     ioctlp->outDatap = cp;
947     cm_PutVolume(tvp);
948     return 0;
949 }       
950
951 long cm_IoctlStatMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
952 {
953     long code;
954     cm_scache_t *dscp;
955     cm_scache_t *scp;
956     char *cp;
957     cm_req_t req;
958
959     cm_InitReq(&req);
960
961     code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp);
962     if (code) return code;
963
964     cp = ioctlp->inDatap;
965
966     code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &req, &scp);
967     cm_ReleaseSCache(dscp);
968     if (code) return code;
969         
970     lock_ObtainMutex(&scp->mx);
971
972     /* now check that this is a real mount point */
973     if (scp->fileType != CM_SCACHETYPE_MOUNTPOINT) {
974         lock_ReleaseMutex(&scp->mx);
975         cm_ReleaseSCache(scp);
976         return CM_ERROR_INVAL;
977     }
978
979     code = cm_ReadMountPoint(scp, userp, &req);
980     if (code == 0) {
981         cp = ioctlp->outDatap;
982         StringCbCopyA(cp, 999999, scp->mountPointStringp);
983         cp += strlen(cp) + 1;
984         ioctlp->outDatap = cp;
985     }
986     lock_ReleaseMutex(&scp->mx);
987     cm_ReleaseSCache(scp);
988
989     return code;
990 }       
991
992 long cm_IoctlDeleteMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
993 {
994     long code;
995     cm_scache_t *dscp;
996     cm_scache_t *scp;
997     char *cp;
998     cm_req_t req;
999
1000     cm_InitReq(&req);
1001
1002     code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp);
1003     if (code) return code;
1004
1005     cp = ioctlp->inDatap;
1006
1007     code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &req, &scp);
1008         
1009     /* if something went wrong, bail out now */
1010     if (code) {
1011         goto done;
1012     }
1013         
1014     lock_ObtainMutex(&scp->mx);
1015     code = cm_SyncOp(scp, NULL, userp, &req, 0,
1016                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1017     if (code) {     
1018         lock_ReleaseMutex(&scp->mx);
1019         cm_ReleaseSCache(scp);
1020         goto done;
1021     }
1022
1023     /* now check that this is a real mount point */
1024     if (scp->fileType != CM_SCACHETYPE_MOUNTPOINT) {
1025         lock_ReleaseMutex(&scp->mx);
1026         cm_ReleaseSCache(scp);
1027         code = CM_ERROR_INVAL;
1028         goto done;
1029     }
1030
1031     /* time to make the RPC, so drop the lock */
1032     lock_ReleaseMutex(&scp->mx);
1033     cm_ReleaseSCache(scp);
1034
1035     /* easier to do it this way */
1036     code = cm_Unlink(dscp, cp, userp, &req);
1037     if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
1038         smb_NotifyChange(FILE_ACTION_REMOVED,
1039                           FILE_NOTIFY_CHANGE_DIR_NAME,
1040                           dscp, cp, NULL, TRUE);
1041
1042   done:
1043     cm_ReleaseSCache(dscp);
1044     return code;
1045 }
1046
1047 long cm_IoctlCheckServers(struct smb_ioctl *ioctlp, struct cm_user *userp)
1048 {
1049     cm_cell_t *cellp;
1050     chservinfo_t csi;
1051     char *tp;
1052     char *cp;
1053     long temp;
1054     cm_server_t *tsp;
1055     int haveCell;
1056         
1057     cm_SkipIoctlPath(ioctlp);   /* we don't care about the path */
1058     tp = ioctlp->inDatap;
1059     haveCell = 0;
1060
1061     memcpy(&temp, tp, sizeof(temp));
1062     if (temp == 0x12345678) {   /* For afs3.3 version */
1063         memcpy(&csi, tp, sizeof(csi));
1064         if (csi.tinterval >= 0) {
1065             cp = ioctlp->outDatap;
1066             memcpy(cp, (char *)&cm_daemonCheckDownInterval, sizeof(long));
1067             ioctlp->outDatap += sizeof(long);
1068             if (csi.tinterval > 0) {
1069                 if (!smb_SUser(userp))
1070                     return CM_ERROR_NOACCESS;
1071                 cm_daemonCheckDownInterval = csi.tinterval;
1072             }
1073             return 0;
1074         }
1075         if (csi.tsize)
1076             haveCell = 1;
1077         temp = csi.tflags;
1078         cp = csi.tbuffer;
1079     } else {    /* For pre afs3.3 versions */
1080         memcpy((char *)&temp, ioctlp->inDatap, sizeof(long));
1081         ioctlp->inDatap = cp = ioctlp->inDatap + sizeof(long);
1082         if (cp - ioctlp->inAllocp < ioctlp->inCopied)   /* still more data available */
1083             haveCell = 1;
1084     }       
1085
1086     /* 
1087      * 1: fast check, don't contact servers.
1088      * 2: local cell only.
1089      */
1090     if (haveCell) {
1091         /* have cell name, too */
1092         cellp = cm_GetCell(cp, 0);
1093         if (!cellp) return CM_ERROR_NOSUCHCELL;
1094     }
1095     else cellp = (cm_cell_t *) 0;
1096     if (!cellp && (temp & 2)) {
1097         /* use local cell */
1098         cellp = cm_FindCellByID(1);
1099     }
1100     if (!(temp & 1)) {  /* if not fast, call server checker routine */
1101         /* check down servers */
1102         cm_CheckServers(CM_FLAG_CHECKDOWNSERVERS | CM_FLAG_CHECKUPSERVERS,
1103                          cellp);
1104     }       
1105
1106     /* now return the current down server list */
1107     cp = ioctlp->outDatap;
1108     lock_ObtainRead(&cm_serverLock);
1109     for (tsp = cm_allServersp; tsp; tsp=tsp->allNextp) {
1110         if (cellp && tsp->cellp != cellp) continue;     /* cell spec'd and wrong */
1111         if ((tsp->flags & CM_SERVERFLAG_DOWN)
1112              && tsp->type == CM_SERVER_FILE) {
1113             memcpy(cp, (char *)&tsp->addr.sin_addr.s_addr, sizeof(long));
1114             cp += sizeof(long);
1115         }
1116     }
1117     lock_ReleaseRead(&cm_serverLock);
1118
1119     ioctlp->outDatap = cp;
1120     return 0;
1121 }
1122
1123 long cm_IoctlGag(struct smb_ioctl *ioctlp, struct cm_user *userp)
1124 {
1125     /* we don't print anything superfluous, so we don't support the gag call */
1126     return CM_ERROR_INVAL;
1127 }
1128
1129 long cm_IoctlCheckVolumes(struct smb_ioctl *ioctlp, struct cm_user *userp)
1130 {
1131     cm_CheckVolumes();
1132     return 0;
1133 }       
1134
1135 long cm_IoctlSetCacheSize(struct smb_ioctl *ioctlp, struct cm_user *userp)
1136 {
1137     afs_uint64 temp;
1138     long code;
1139
1140     cm_SkipIoctlPath(ioctlp);
1141
1142     memcpy(&temp, ioctlp->inDatap, sizeof(temp));
1143     if (temp == 0) 
1144         temp = cm_data.buf_nOrigBuffers;
1145     else {
1146         /* temp is in 1K units, convert to # of buffers */
1147         temp = temp / (cm_data.buf_blockSize / 1024);
1148     }       
1149
1150     /* now adjust the cache size */
1151     code = buf_SetNBuffers(temp);
1152
1153     return code;
1154 }
1155
1156 long cm_IoctlTraceControl(struct smb_ioctl *ioctlp, struct cm_user *userp)
1157 {
1158     long inValue;
1159         
1160     cm_SkipIoctlPath(ioctlp);
1161         
1162     memcpy(&inValue, ioctlp->inDatap, sizeof(long));
1163
1164     /* print trace */
1165     if (inValue & 8) {
1166         afsd_ForceTrace(FALSE);
1167         buf_ForceTrace(FALSE);
1168     }
1169         
1170     if (inValue & 2) {
1171         /* set tracing value to low order bit */
1172         if ((inValue & 1) == 0) {
1173             /* disable tracing */
1174             osi_LogDisable(afsd_logp);
1175             rx_DebugOnOff(FALSE);
1176         }
1177         else {
1178             /* enable tracing */
1179             osi_LogEnable(afsd_logp);
1180             rx_DebugOnOff(TRUE);
1181         }
1182     }
1183
1184     /* see if we're supposed to do a reset, too */
1185     if (inValue & 4) {
1186         osi_LogReset(afsd_logp);
1187     }
1188
1189     /* and copy out tracing flag */
1190     inValue = afsd_logp->enabled;       /* use as a temp vbl */
1191     memcpy(ioctlp->outDatap, &inValue, sizeof(long));
1192     ioctlp->outDatap += sizeof(long);
1193     return 0;
1194 }       
1195
1196 long cm_IoctlGetCacheParms(struct smb_ioctl *ioctlp, struct cm_user *userp)
1197 {
1198     cm_cacheParms_t parms;
1199
1200     memset(&parms, 0, sizeof(parms));
1201
1202     /* first we get, in 1K units, the cache size */
1203     parms.parms[0] = cm_data.buf_nbuffers * (cm_data.buf_blockSize / 1024);
1204
1205     /* and then the actual # of buffers in use (not in the free list, I guess,
1206      * will be what we do).
1207      */
1208     parms.parms[1] = (cm_data.buf_nbuffers - buf_CountFreeList()) * (cm_data.buf_blockSize / 1024);
1209
1210     memcpy(ioctlp->outDatap, &parms, sizeof(parms));
1211     ioctlp->outDatap += sizeof(parms);
1212
1213     return 0;
1214 }
1215
1216 long cm_IoctlGetCell(struct smb_ioctl *ioctlp, struct cm_user *userp)
1217 {
1218     long whichCell;
1219     long magic = 0;
1220     cm_cell_t *tcellp;
1221     cm_serverRef_t *serverRefp;
1222     cm_server_t *serverp;
1223     long i;
1224     char *cp;
1225     char *tp;
1226     char *basep;
1227
1228     cm_SkipIoctlPath(ioctlp);
1229
1230     tp = ioctlp->inDatap;
1231
1232     memcpy((char *)&whichCell, tp, sizeof(long));
1233     tp += sizeof(long);
1234
1235     /* see if more than one long passed in, ignoring the null pathname (the -1) */
1236     if (ioctlp->inCopied-1 > sizeof(long)) {
1237         memcpy((char *)&magic, tp, sizeof(long));
1238     }
1239
1240     lock_ObtainRead(&cm_cellLock);
1241     for (tcellp = cm_data.allCellsp; tcellp; tcellp = tcellp->nextp) {
1242         if (whichCell == 0) break;
1243         whichCell--;
1244     }
1245     lock_ReleaseRead(&cm_cellLock);
1246     if (tcellp) {
1247         int max = 8;
1248
1249         cp = ioctlp->outDatap;
1250
1251         if (magic == 0x12345678) {
1252             memcpy(cp, (char *)&magic, sizeof(long));
1253             max = 13;
1254         }
1255         memset(cp, 0, max * sizeof(long));
1256         basep = cp;
1257         lock_ObtainRead(&cm_serverLock);        /* for going down server list */
1258         /* jaltman - do the reference counts to serverRefp contents need to be increased? */
1259         serverRefp = tcellp->vlServersp;
1260         for (i=0; i<max; i++) {
1261             if (!serverRefp) break;
1262             serverp = serverRefp->server;
1263             memcpy(cp, &serverp->addr.sin_addr.s_addr, sizeof(long));
1264             cp += sizeof(long);
1265             serverRefp = serverRefp->next;
1266         }
1267         lock_ReleaseRead(&cm_serverLock);
1268         cp = basep + max * sizeof(afs_int32);
1269         StringCbCopyA(cp, 999999, tcellp->name);
1270         cp += strlen(tcellp->name)+1;
1271         ioctlp->outDatap = cp;
1272     }
1273
1274     if (tcellp) 
1275         return 0;
1276     else 
1277         return CM_ERROR_NOMORETOKENS;   /* mapped to EDOM */
1278 }
1279
1280 extern long cm_AddCellProc(void *rockp, struct sockaddr_in *addrp, char *namep);
1281
1282 long cm_IoctlNewCell(struct smb_ioctl *ioctlp, struct cm_user *userp)
1283 {
1284     /* NT cache manager will read cell information from CellServDB each time
1285      * cell is accessed. So, this call is necessary only if list of server for a cell 
1286      * changes (or IP addresses of cell servers changes).
1287      * All that needs to be done is to refresh server information for all cells that 
1288      * are already loaded.
1289   
1290      * cell list will be cm_CellLock and cm_ServerLock will be held for write.
1291      */  
1292   
1293     cm_cell_t *cp;
1294   
1295     cm_SkipIoctlPath(ioctlp);
1296     lock_ObtainWrite(&cm_cellLock);
1297   
1298     for (cp = cm_data.allCellsp; cp; cp=cp->nextp) 
1299     {
1300         long code;
1301         /* delete all previous server lists - cm_FreeServerList will ask for write on cm_ServerLock*/
1302         cm_FreeServerList(&cp->vlServersp);
1303         cp->vlServersp = NULL;
1304         code = cm_SearchCellFile(cp->name, cp->name, cm_AddCellProc, cp);
1305 #ifdef AFS_AFSDB_ENV
1306         if (code) {
1307             if (cm_dnsEnabled) {
1308                 int ttl;
1309                 code = cm_SearchCellByDNS(cp->name, cp->name, &ttl, cm_AddCellProc, cp);
1310                 if ( code == 0 ) { /* got cell from DNS */
1311                     cp->flags |= CM_CELLFLAG_DNS;
1312                     cp->flags &= ~CM_CELLFLAG_VLSERVER_INVALID;
1313                     cp->timeout = time(0) + ttl;
1314                 }
1315             }
1316         } 
1317         else {
1318             cp->flags &= ~CM_CELLFLAG_DNS;
1319         }
1320 #endif /* AFS_AFSDB_ENV */
1321         if (code) {
1322             cp->flags |= CM_CELLFLAG_VLSERVER_INVALID;
1323         }
1324         else {
1325             cp->flags &= ~CM_CELLFLAG_VLSERVER_INVALID;
1326             cm_RandomizeServer(&cp->vlServersp);
1327         }
1328     }
1329     
1330     lock_ReleaseWrite(&cm_cellLock);
1331     return 0;       
1332 }
1333
1334 long cm_IoctlGetWsCell(smb_ioctl_t *ioctlp, cm_user_t *userp)
1335 {
1336         long code = 0;
1337
1338         if (cm_freelanceEnabled) {
1339             if (cm_GetRootCellName(ioctlp->outDatap))
1340                 StringCbCopyA(ioctlp->outDatap, 999999, "Freelance.Local.Root");
1341             ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
1342         } else if (cm_data.rootCellp) {
1343             /* return the default cellname to the caller */
1344             StringCbCopyA(ioctlp->outDatap, 999999, cm_data.rootCellp->name);
1345             ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
1346         } else {
1347             /* if we don't know our default cell, return failure */
1348             code = CM_ERROR_NOSUCHCELL;
1349     }
1350
1351     return code;
1352 }
1353
1354 long cm_IoctlSysName(struct smb_ioctl *ioctlp, struct cm_user *userp)
1355 {
1356     long setSysName, foundname = 0;
1357     char *cp, *cp2, inname[MAXSYSNAME], outname[MAXSYSNAME];
1358     int t, count, num = 0;
1359     char **sysnamelist[MAXSYSNAME];
1360         
1361     cm_SkipIoctlPath(ioctlp);
1362
1363     memcpy(&setSysName, ioctlp->inDatap, sizeof(long));
1364     ioctlp->inDatap += sizeof(long);
1365         
1366     if (setSysName) {
1367         /* check my args */
1368         if ( setSysName < 0 || setSysName > MAXNUMSYSNAMES )
1369             return EINVAL;
1370         cp2 = ioctlp->inDatap;
1371         for ( cp=ioctlp->inDatap, count = 0; count < setSysName; count++ ) {
1372             /* won't go past end of ioctlp->inDatap since maxsysname*num < ioctlp->inDatap length */
1373             t = (int)strlen(cp);
1374             if (t >= MAXSYSNAME || t <= 0)
1375                 return EINVAL;
1376             /* check for names that can shoot us in the foot */
1377             if (*cp == '.' && (cp[1] == 0 || (cp[1] == '.' && cp[2] == 0)))
1378                 return EINVAL;
1379             cp += t + 1;
1380         }
1381         /* args ok */
1382
1383         /* inname gets first entry in case we're being a translator */
1384         /* (we are never a translator) */
1385         t = (int)strlen(ioctlp->inDatap);
1386         memcpy(inname, ioctlp->inDatap, t + 1);
1387         ioctlp->inDatap += t + 1;
1388         num = count;
1389     }
1390
1391     /* Not xlating, so local case */
1392     if (!cm_sysName)
1393         osi_panic("cm_IoctlSysName: !cm_sysName\n", __FILE__, __LINE__);
1394
1395     if (!setSysName) {      /* user just wants the info */
1396         StringCbCopyA(outname, sizeof(outname), cm_sysName);
1397         foundname = cm_sysNameCount;
1398         *sysnamelist = cm_sysNameList;
1399     } else {        
1400         /* Local guy; only root can change sysname */
1401         /* clear @sys entries from the dnlc, once afs_lookup can
1402          * do lookups of @sys entries and thinks it can trust them */
1403         /* privs ok, store the entry, ... */
1404         StringCbCopyA(cm_sysName, sizeof(cm_sysName), inname);
1405         StringCbCopyA(cm_sysNameList[0], MAXSYSNAME, inname);
1406         if (setSysName > 1) {       /* ... or list */
1407             cp = ioctlp->inDatap;
1408             for (count = 1; count < setSysName; ++count) {
1409                 if (!cm_sysNameList[count])
1410                     osi_panic("cm_IoctlSysName: no cm_sysNameList entry to write\n",
1411                                __FILE__, __LINE__);
1412                 t = (int)strlen(cp);
1413                 StringCbCopyA(cm_sysNameList[count], MAXSYSNAME, cp);
1414                 cp += t + 1;
1415             }
1416         }
1417         cm_sysNameCount = setSysName;
1418     }
1419
1420     if (!setSysName) {
1421         /* return the sysname to the caller */
1422         cp = ioctlp->outDatap;
1423         memcpy(cp, (char *)&foundname, sizeof(afs_int32));
1424         cp += sizeof(afs_int32);        /* skip found flag */
1425         if (foundname) {
1426             StringCbCopyA(cp, 999999, outname);
1427             cp += strlen(outname) + 1;  /* skip name and terminating null char */
1428             for ( count=1; count < foundname ; ++count) {   /* ... or list */
1429                 if ( !(*sysnamelist)[count] )
1430                     osi_panic("cm_IoctlSysName: no cm_sysNameList entry to read\n", 
1431                                __FILE__, __LINE__);
1432                 t = (int)strlen((*sysnamelist)[count]);
1433                 if (t >= MAXSYSNAME)
1434                     osi_panic("cm_IoctlSysName: sysname entry garbled\n", 
1435                                __FILE__, __LINE__);
1436                 StringCbCopyA(cp, 999999, (*sysnamelist)[count]);
1437                 cp += t + 1;
1438             }
1439         }
1440         ioctlp->outDatap = cp;
1441     }
1442         
1443     /* done: success */
1444     return 0;
1445 }
1446
1447 long cm_IoctlGetCellStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
1448 {
1449     long temp;
1450     cm_cell_t *cellp;
1451
1452     cm_SkipIoctlPath(ioctlp);
1453
1454     cellp = cm_GetCell(ioctlp->inDatap, 0);
1455     if (!cellp) 
1456         return CM_ERROR_NOSUCHCELL;
1457
1458     temp = 0;
1459     lock_ObtainMutex(&cellp->mx);
1460     if (cellp->flags & CM_CELLFLAG_SUID)
1461         temp |= CM_SETCELLFLAG_SUID;
1462     lock_ReleaseMutex(&cellp->mx);
1463         
1464     /* now copy out parm */
1465     memcpy(ioctlp->outDatap, &temp, sizeof(long));
1466     ioctlp->outDatap += sizeof(long);
1467
1468     return 0;
1469 }
1470
1471 long cm_IoctlSetCellStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
1472 {
1473     long temp;
1474     cm_cell_t *cellp;
1475
1476     cm_SkipIoctlPath(ioctlp);
1477
1478     cellp = cm_GetCell(ioctlp->inDatap + 2*sizeof(long), 0);
1479     if (!cellp) 
1480         return CM_ERROR_NOSUCHCELL;
1481
1482     memcpy((char *)&temp, ioctlp->inDatap, sizeof(long));
1483
1484     lock_ObtainMutex(&cellp->mx);
1485     if (temp & CM_SETCELLFLAG_SUID)
1486         cellp->flags |= CM_CELLFLAG_SUID;
1487     else
1488         cellp->flags &= ~CM_CELLFLAG_SUID;
1489     lock_ReleaseMutex(&cellp->mx);
1490
1491     return 0;
1492 }
1493
1494 long cm_IoctlSetSPrefs(struct smb_ioctl *ioctlp, struct cm_user *userp)
1495 {
1496     cm_SSetPref_t         *spin; /* input */
1497     cm_SPref_t        *srvin;   /* one input component */
1498     cm_server_t       *tsp;
1499     int                   i, vlonly, noServers, type;
1500     struct sockaddr_in  tmp;
1501     unsigned short        rank;
1502
1503     cm_SkipIoctlPath(ioctlp);       /* we don't care about the path */
1504
1505     spin           = (cm_SSetPref_t *)ioctlp->inDatap;
1506     noServers  = spin->num_servers;
1507     vlonly     = spin->flags;
1508     if ( vlonly )
1509         type = CM_SERVER_VLDB;
1510     else    
1511         type = CM_SERVER_FILE;
1512
1513     for ( i=0; i < noServers; i++) 
1514     {
1515         srvin          = &(spin->servers[i]);
1516         rank           = srvin->rank + (rand() & 0x000f);
1517         tmp.sin_addr   = srvin->host;
1518         tmp.sin_family = AF_INET;
1519
1520         tsp = cm_FindServer(&tmp, type);
1521         if ( tsp )              /* an existing server - ref count increased */
1522         {
1523             tsp->ipRank = rank; /* no need to protect by mutex*/
1524
1525             if (type == CM_SERVER_FILE)
1526             {   /* fileserver */
1527                 /* find volumes which might have RO copy 
1528                 /* on server and change the ordering of 
1529                  * their RO list 
1530                  */
1531                 cm_ChangeRankVolume(tsp);
1532             }
1533             else        
1534             {
1535                 /* set preferences for an existing vlserver */
1536                 cm_ChangeRankCellVLServer(tsp);
1537             }
1538         }
1539         else    /* add a new server without a cell */
1540         {
1541             tsp = cm_NewServer(&tmp, type, NULL); /* refcount = 1 */
1542             tsp->ipRank = rank;
1543         }
1544         lock_ObtainMutex(&tsp->mx);
1545         tsp->flags |= CM_SERVERFLAG_PREF_SET;
1546         lock_ReleaseMutex(&tsp->mx);
1547         cm_PutServer(tsp);  /* decrease refcount */
1548     }
1549     return 0;
1550 }
1551
1552 long cm_IoctlGetSPrefs(struct smb_ioctl *ioctlp, struct cm_user *userp)
1553 {
1554     cm_SPrefRequest_t *spin; /* input */
1555     cm_SPrefInfo_t    *spout;   /* output */
1556     cm_SPref_t        *srvout;   /* one output component */
1557     cm_server_t       *tsp;
1558     int                   i, vlonly, noServers;
1559
1560     cm_SkipIoctlPath(ioctlp);       /* we don't care about the path */
1561
1562     spin      = (cm_SPrefRequest_t *)ioctlp->inDatap;
1563     spout     = (cm_SPrefInfo_t *) ioctlp->outDatap;
1564     srvout    = spout->servers;
1565     noServers = spin->num_servers; 
1566     vlonly    = spin->flags & CM_SPREF_VLONLY;
1567     spout->num_servers = 0;
1568
1569     lock_ObtainRead(&cm_serverLock); /* get server lock */
1570
1571     for (tsp=cm_allServersp, i=0; tsp && noServers; tsp=tsp->allNextp,i++){
1572         if (spin->offset > i) {
1573             continue;    /* catch up to where we left off */
1574         }
1575
1576         if ( vlonly && (tsp->type == CM_SERVER_FILE) )
1577             continue;   /* ignore fileserver for -vlserver option*/
1578         if ( !vlonly && (tsp->type == CM_SERVER_VLDB) )
1579             continue;   /* ignore vlservers */
1580
1581         srvout->host = tsp->addr.sin_addr;
1582         srvout->rank = tsp->ipRank;
1583         srvout++;       
1584         spout->num_servers++;
1585         noServers--;
1586     }
1587     lock_ReleaseRead(&cm_serverLock); /* release server lock */
1588
1589     if ( tsp )  /* we ran out of space in the output buffer */
1590         spout->next_offset = i;
1591     else    
1592         spout->next_offset = 0; 
1593     ioctlp->outDatap += sizeof(cm_SPrefInfo_t) + 
1594         (spout->num_servers -1 ) * sizeof(cm_SPref_t) ;
1595     return 0;
1596 }
1597
1598 long cm_IoctlStoreBehind(struct smb_ioctl *ioctlp, struct cm_user *userp)
1599 {
1600     /* we ignore default asynchrony since we only have one way
1601      * of doing this today.
1602      */
1603     return 0;
1604 }       
1605
1606 long cm_IoctlCreateMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
1607 {
1608     char leaf[LEAF_SIZE];
1609     long code;
1610     cm_scache_t *dscp;
1611     cm_attr_t tattr;
1612     char *cp;
1613     cm_req_t req;
1614     char mpInfo[256];
1615     char fullCell[256];
1616     char volume[256];
1617     char cell[256];
1618     int ttl;
1619
1620     cm_InitReq(&req);
1621         
1622     code = cm_ParseIoctlParent(ioctlp, userp, &req, &dscp, leaf);
1623     if (code) return code;
1624
1625     /* Translate chars for the mount point name */
1626     TranslateExtendedChars(leaf);
1627
1628     /* 
1629      * The fs command allows the user to specify partial cell names on NT.  These must
1630      * be expanded to the full cell name for mount points so that the mount points will
1631      * work on UNIX clients.
1632      */
1633
1634     /* Extract the possibly partial cell name */
1635     StringCbCopyA(cell, sizeof(cell), ioctlp->inDatap + 1);      /* Skip the mp type character */
1636         
1637     if (cp = strchr(cell, ':')) {
1638         /* Extract the volume name */
1639         *cp = 0;
1640         StringCbCopyA(volume,  sizeof(volume), cp + 1);
1641         
1642         /* Get the full name for this cell */
1643         code = cm_SearchCellFile(cell, fullCell, 0, 0);
1644 #ifdef AFS_AFSDB_ENV
1645         if (code && cm_dnsEnabled)
1646             code = cm_SearchCellByDNS(cell, fullCell, &ttl, 0, 0);
1647 #endif
1648         if (code)
1649             return CM_ERROR_NOSUCHCELL;
1650         
1651         StringCbPrintfA(mpInfo, sizeof(mpInfo), "%c%s:%s", *ioctlp->inDatap, fullCell, volume);
1652     } else {
1653         /* No cell name specified */
1654         StringCbCopyA(mpInfo, sizeof(mpInfo), ioctlp->inDatap);
1655     }
1656
1657 #ifdef AFS_FREELANCE_CLIENT
1658     if (cm_freelanceEnabled && dscp == cm_data.rootSCachep) {
1659         /* we are adding the mount point to the root dir., so call
1660          * the freelance code to do the add. */
1661         osi_Log0(afsd_logp,"IoctlCreateMountPoint within Freelance root dir");
1662         code = cm_FreelanceAddMount(leaf, fullCell, volume, 
1663                                     *ioctlp->inDatap == '%', NULL);
1664         return code;
1665     }
1666 #endif
1667     /* create the symlink with mode 644.  The lack of X bits tells
1668      * us that it is a mount point.
1669      */
1670     tattr.mask = CM_ATTRMASK_UNIXMODEBITS | CM_ATTRMASK_CLIENTMODTIME;
1671     tattr.unixModeBits = 0644;
1672     tattr.clientModTime = time(NULL);
1673
1674     code = cm_SymLink(dscp, leaf, mpInfo, 0, &tattr, userp, &req);
1675     if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
1676         smb_NotifyChange(FILE_ACTION_ADDED,
1677                          FILE_NOTIFY_CHANGE_DIR_NAME,
1678                          dscp, leaf, NULL, TRUE);
1679
1680     cm_ReleaseSCache(dscp);
1681     return code;
1682 }
1683
1684 long cm_IoctlSymlink(struct smb_ioctl *ioctlp, struct cm_user *userp)
1685 {
1686     char leaf[LEAF_SIZE];
1687     long code;
1688     cm_scache_t *dscp;
1689     cm_attr_t tattr;
1690     char *cp;
1691     cm_req_t req;
1692
1693     cm_InitReq(&req);
1694
1695     code = cm_ParseIoctlParent(ioctlp, userp, &req, &dscp, leaf);
1696     if (code) return code;
1697
1698     /* Translate chars for the link name */
1699     TranslateExtendedChars(leaf);
1700
1701     /* Translate chars for the linked to name */
1702     TranslateExtendedChars(ioctlp->inDatap);
1703
1704     cp = ioctlp->inDatap;               /* contents of link */
1705
1706 #ifdef AFS_FREELANCE_CLIENT
1707     if (cm_freelanceEnabled && dscp == cm_data.rootSCachep) {
1708         /* we are adding the symlink to the root dir., so call
1709          * the freelance code to do the add. */
1710         if (cp[0] == cp[1] && cp[1] == '\\' && 
1711             !_strnicmp(cm_NetbiosName,cp+2,strlen(cm_NetbiosName))) 
1712         {
1713             /* skip \\AFS\ or \\AFS\all\ */
1714             char * p;
1715             p = cp + 2 + strlen(cm_NetbiosName) + 1;
1716             if ( !_strnicmp("all", p, 3) )
1717                 p += 4;
1718             cp = p;
1719         }
1720         osi_Log0(afsd_logp,"IoctlCreateSymlink within Freelance root dir");
1721         code = cm_FreelanceAddSymlink(leaf, cp, NULL);
1722         return code;
1723     }
1724 #endif
1725
1726     /* Create symlink with mode 0755. */
1727     tattr.mask = CM_ATTRMASK_UNIXMODEBITS;
1728     tattr.unixModeBits = 0755;
1729
1730     code = cm_SymLink(dscp, leaf, cp, 0, &tattr, userp, &req);
1731     if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
1732         smb_NotifyChange(FILE_ACTION_ADDED,
1733                           FILE_NOTIFY_CHANGE_FILE_NAME
1734                           | FILE_NOTIFY_CHANGE_DIR_NAME,
1735                           dscp, leaf, NULL, TRUE);
1736
1737     cm_ReleaseSCache(dscp);
1738
1739     return code;
1740 }
1741
1742
1743 long cm_IoctlListlink(struct smb_ioctl *ioctlp, struct cm_user *userp)
1744 {
1745     long code;
1746     cm_scache_t *dscp;
1747     cm_scache_t *scp;
1748     char *cp;
1749     cm_space_t *spacep;
1750     cm_scache_t *newRootScp;
1751     cm_req_t req;
1752
1753     cm_InitReq(&req);
1754
1755     code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp);
1756     if (code) return code;
1757
1758     cp = ioctlp->inDatap;
1759
1760     code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &req, &scp);
1761     cm_ReleaseSCache(dscp);
1762     if (code) return code;
1763
1764     /* Check that it's a real symlink */
1765     if (scp->fileType != CM_SCACHETYPE_SYMLINK &&
1766         scp->fileType != CM_SCACHETYPE_DFSLINK &&
1767         scp->fileType != CM_SCACHETYPE_INVALID) {
1768         cm_ReleaseSCache(scp);
1769         return CM_ERROR_INVAL;
1770     }
1771
1772     code = cm_AssembleLink(scp, "", &newRootScp, &spacep, userp, &req);
1773     cm_ReleaseSCache(scp);
1774     if (code == 0) {
1775         cp = ioctlp->outDatap;
1776         if (newRootScp != NULL) {
1777             StringCbCopyA(cp, 999999, cm_mountRoot);
1778             StringCbCatA(cp, 999999, "/");
1779             cp += strlen(cp);
1780         }
1781         StringCbCopyA(cp, 999999, spacep->data);
1782         cp += strlen(cp) + 1;
1783         ioctlp->outDatap = cp;
1784         cm_FreeSpace(spacep);
1785         if (newRootScp != NULL)
1786             cm_ReleaseSCache(newRootScp);
1787         code = 0;
1788     } else if (code == CM_ERROR_PATH_NOT_COVERED && 
1789                 scp->fileType == CM_SCACHETYPE_DFSLINK ||
1790                code == CM_ERROR_NOSUCHPATH &&
1791                 scp->fileType == CM_SCACHETYPE_INVALID) {
1792         cp = ioctlp->outDatap;
1793         StringCbCopyA(cp, 999999, spacep->data);
1794         cp += strlen(cp) + 1;
1795         ioctlp->outDatap = cp;
1796         cm_FreeSpace(spacep);
1797         if (newRootScp != NULL)
1798             cm_ReleaseSCache(newRootScp);
1799         code = 0;
1800     }
1801
1802     return code;
1803 }
1804
1805 long cm_IoctlIslink(struct smb_ioctl *ioctlp, struct cm_user *userp)
1806 {/*CHECK FOR VALID SYMLINK*/
1807     long code;
1808     cm_scache_t *dscp;
1809     cm_scache_t *scp;
1810     char *cp;
1811     cm_req_t req;
1812
1813     cm_InitReq(&req);
1814
1815     code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp);
1816     if (code) return code;
1817
1818     cp = ioctlp->inDatap;
1819     osi_LogEvent("cm_IoctlListlink",NULL," name[%s]",cp);
1820
1821     code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &req, &scp);
1822     cm_ReleaseSCache(dscp);
1823     if (code) return code;
1824
1825     /* Check that it's a real symlink */
1826     if (scp->fileType != CM_SCACHETYPE_SYMLINK &&
1827         scp->fileType != CM_SCACHETYPE_DFSLINK &&
1828         scp->fileType != CM_SCACHETYPE_INVALID)
1829         code = CM_ERROR_INVAL;
1830     cm_ReleaseSCache(scp);
1831     return code;
1832 }
1833
1834 long cm_IoctlDeletelink(struct smb_ioctl *ioctlp, struct cm_user *userp)
1835 {
1836     long code;
1837     cm_scache_t *dscp;
1838     cm_scache_t *scp;
1839     char *cp;
1840     cm_req_t req;
1841
1842     cm_InitReq(&req);
1843
1844     code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp);
1845     if (code) return code;
1846
1847     cp = ioctlp->inDatap;
1848
1849 #ifdef AFS_FREELANCE_CLIENT
1850     if (cm_freelanceEnabled && dscp == cm_data.rootSCachep) {
1851         /* we are adding the mount point to the root dir., so call
1852          * the freelance code to do the add. */
1853         osi_Log0(afsd_logp,"IoctlDeletelink from Freelance root dir");
1854         code = cm_FreelanceRemoveSymlink(cp);
1855         return code;
1856     }
1857 #endif
1858
1859     code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &req, &scp);
1860         
1861     /* if something went wrong, bail out now */
1862     if (code) {
1863         goto done;
1864     }
1865         
1866     lock_ObtainMutex(&scp->mx);
1867     code = cm_SyncOp(scp, NULL, userp, &req, 0,
1868                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1869     if (code) {     
1870         lock_ReleaseMutex(&scp->mx);
1871         cm_ReleaseSCache(scp);
1872         goto done;
1873     }
1874         
1875     /* now check that this is a real symlink */
1876     if (scp->fileType != CM_SCACHETYPE_SYMLINK &&
1877         scp->fileType != CM_SCACHETYPE_DFSLINK &&
1878         scp->fileType != CM_SCACHETYPE_INVALID) {
1879         lock_ReleaseMutex(&scp->mx);
1880         cm_ReleaseSCache(scp);
1881         code = CM_ERROR_INVAL;
1882         goto done;
1883     }
1884         
1885     /* time to make the RPC, so drop the lock */
1886     lock_ReleaseMutex(&scp->mx);
1887     cm_ReleaseSCache(scp);
1888         
1889     /* easier to do it this way */
1890     code = cm_Unlink(dscp, cp, userp, &req);
1891     if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
1892         smb_NotifyChange(FILE_ACTION_REMOVED,
1893                           FILE_NOTIFY_CHANGE_FILE_NAME
1894                           | FILE_NOTIFY_CHANGE_DIR_NAME,
1895                           dscp, cp, NULL, TRUE);
1896
1897   done:
1898     cm_ReleaseSCache(dscp);
1899     return code;
1900 }
1901
1902 long cm_IoctlSetToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
1903 {
1904     char *saveDataPtr;
1905     char *tp;
1906     int ticketLen;
1907     char *ticket;
1908     int ctSize;
1909     struct ClearToken ct;
1910     cm_cell_t *cellp;
1911     cm_ucell_t *ucellp;
1912     char *uname = NULL;
1913     afs_uuid_t uuid;
1914     int flags;
1915     char sessionKey[8];
1916     char *smbname;
1917     int release_userp = 0;
1918
1919     saveDataPtr = ioctlp->inDatap;
1920
1921     cm_SkipIoctlPath(ioctlp);
1922
1923     tp = ioctlp->inDatap;
1924
1925     /* ticket length */
1926     memcpy(&ticketLen, tp, sizeof(ticketLen));
1927     tp += sizeof(ticketLen);
1928     if (ticketLen < MINKTCTICKETLEN || ticketLen > MAXKTCTICKETLEN)
1929         return CM_ERROR_INVAL;
1930
1931     /* remember ticket and skip over it for now */
1932     ticket = tp;
1933     tp += ticketLen;
1934
1935     /* clear token size */
1936     memcpy(&ctSize, tp, sizeof(ctSize));
1937     tp += sizeof(ctSize);
1938     if (ctSize != sizeof(struct ClearToken))
1939         return CM_ERROR_INVAL;
1940
1941     /* clear token */
1942     memcpy(&ct, tp, ctSize);
1943     tp += ctSize;
1944     if (ct.AuthHandle == -1)
1945         ct.AuthHandle = 999;    /* more rxvab compat stuff */
1946
1947     /* more stuff, if any */
1948     if (ioctlp->inCopied > tp - saveDataPtr) {
1949         /* flags:  logon flag */
1950         memcpy(&flags, tp, sizeof(int));
1951         tp += sizeof(int);
1952
1953         /* cell name */
1954         cellp = cm_GetCell(tp, CM_FLAG_CREATE);
1955         if (!cellp) return CM_ERROR_NOSUCHCELL;
1956         tp += strlen(tp) + 1;
1957
1958         /* user name */
1959         uname = tp;
1960         tp += strlen(tp) + 1;
1961
1962 #ifndef AFSIFS                  /* no SMB username, so we cannot log based on this */
1963         if (flags & PIOCTL_LOGON) {
1964             /* SMB user name with which to associate tokens */
1965             smbname = tp;
1966             osi_Log2(smb_logp,"cm_IoctlSetToken for user [%s] smbname [%s]",
1967                      osi_LogSaveString(smb_logp,uname), osi_LogSaveString(smb_logp,smbname));
1968             fprintf(stderr, "SMB name = %s\n", smbname);
1969             tp += strlen(tp) + 1;
1970         } else {
1971             osi_Log1(smb_logp,"cm_IoctlSetToken for user [%s]",
1972                      osi_LogSaveString(smb_logp,uname));
1973         }
1974 #endif
1975
1976 #ifndef DJGPP   /* for win95, session key is back in pioctl */
1977                 /* uuid */
1978         memcpy(&uuid, tp, sizeof(uuid));
1979         if (!cm_FindTokenEvent(uuid, sessionKey))
1980             return CM_ERROR_INVAL;
1981 #endif /* !DJGPP */
1982     } else {
1983         cellp = cm_data.rootCellp;
1984         osi_Log0(smb_logp,"cm_IoctlSetToken - no name specified");
1985     }
1986
1987     if (flags & PIOCTL_LOGON) {
1988         userp = smb_FindCMUserByName(smbname, ioctlp->fidp->vcp->rname);
1989         release_userp = 1;
1990     }
1991
1992     /* store the token */
1993     lock_ObtainMutex(&userp->mx);
1994     ucellp = cm_GetUCell(userp, cellp);
1995     osi_Log1(smb_logp,"cm_IoctlSetToken ucellp %lx", ucellp);
1996     ucellp->ticketLen = ticketLen;
1997     if (ucellp->ticketp)
1998         free(ucellp->ticketp);  /* Discard old token if any */
1999     ucellp->ticketp = malloc(ticketLen);
2000     memcpy(ucellp->ticketp, ticket, ticketLen);
2001 #ifndef DJGPP
2002     /*
2003      * Get the session key from the RPC, rather than from the pioctl.
2004      */
2005     /*
2006     memcpy(&ucellp->sessionKey, ct.HandShakeKey, sizeof(ct.HandShakeKey));
2007     */
2008     memcpy(ucellp->sessionKey.data, sessionKey, sizeof(sessionKey));
2009 #else
2010     /* for win95, we are getting the session key from the pioctl */
2011     memcpy(&ucellp->sessionKey, ct.HandShakeKey, sizeof(ct.HandShakeKey));
2012 #endif /* !DJGPP */
2013     ucellp->kvno = ct.AuthHandle;
2014     ucellp->expirationTime = ct.EndTimestamp;
2015     ucellp->gen++;
2016     if (uname) 
2017         StringCbCopyA(ucellp->userName, MAXKTCNAMELEN, uname);
2018     ucellp->flags |= CM_UCELLFLAG_RXKAD;
2019     lock_ReleaseMutex(&userp->mx);
2020
2021     if (flags & PIOCTL_LOGON) {
2022         ioctlp->flags |= SMB_IOCTLFLAG_LOGON;
2023     }
2024
2025     cm_ResetACLCache(userp);
2026
2027     if (release_userp)
2028         cm_ReleaseUser(userp);
2029
2030     return 0;
2031 }
2032
2033 long cm_IoctlGetTokenIter(struct smb_ioctl *ioctlp, struct cm_user *userp)
2034 {
2035     char *tp, *cp;
2036     int iterator;
2037     int temp;
2038     cm_ucell_t *ucellp;
2039     struct ClearToken ct;
2040
2041     cm_SkipIoctlPath(ioctlp);
2042
2043     tp = ioctlp->inDatap;
2044     cp = ioctlp->outDatap;
2045
2046     /* iterator */
2047     memcpy(&iterator, tp, sizeof(iterator));
2048     tp += sizeof(iterator);
2049
2050     lock_ObtainMutex(&userp->mx);
2051
2052     /* look for token */
2053     for (;;iterator++) {
2054         ucellp = cm_FindUCell(userp, iterator);
2055         if (!ucellp) {
2056             lock_ReleaseMutex(&userp->mx);
2057             return CM_ERROR_NOMORETOKENS;
2058         }
2059         if (ucellp->flags & CM_UCELLFLAG_RXKAD)
2060             break;
2061     }       
2062
2063     /* new iterator */
2064     temp = ucellp->iterator + 1;
2065     memcpy(cp, &temp, sizeof(temp));
2066     cp += sizeof(temp);
2067
2068     /* ticket length */
2069     memcpy(cp, &ucellp->ticketLen, sizeof(ucellp->ticketLen));
2070     cp += sizeof(ucellp->ticketLen);
2071
2072     /* ticket */
2073     memcpy(cp, ucellp->ticketp, ucellp->ticketLen);
2074     cp += ucellp->ticketLen;
2075
2076     /* clear token size */
2077     temp = sizeof(ct);
2078     memcpy(cp, &temp, sizeof(temp));
2079     cp += sizeof(temp);
2080
2081     /* clear token */
2082     ct.AuthHandle = ucellp->kvno;
2083 #ifndef DJGPP
2084     /*
2085      * Don't give out a real session key here
2086      */
2087     /*
2088     memcpy(ct.HandShakeKey, &ucellp->sessionKey, sizeof(ct.HandShakeKey));
2089     */
2090     memset(ct.HandShakeKey, 0, sizeof(ct.HandShakeKey));
2091 #else
2092     memcpy(ct.HandShakeKey, &ucellp->sessionKey, sizeof(ct.HandShakeKey));
2093 #endif /* !DJGPP */
2094     ct.ViceId = 37;                     /* XXX */
2095     ct.BeginTimestamp = 0;              /* XXX */
2096     ct.EndTimestamp = ucellp->expirationTime;
2097     memcpy(cp, &ct, sizeof(ct));
2098     cp += sizeof(ct);
2099
2100     /* Primary flag (unused) */
2101     temp = 0;
2102     memcpy(cp, &temp, sizeof(temp));
2103     cp += sizeof(temp);
2104
2105     /* cell name */
2106     StringCbCopyA(cp, 999999, ucellp->cellp->name);
2107     cp += strlen(cp) + 1;
2108
2109     /* user name */
2110     StringCbCopyA(cp, 999999, ucellp->userName);
2111     cp += strlen(cp) + 1;
2112
2113     ioctlp->outDatap = cp;
2114
2115     lock_ReleaseMutex(&userp->mx);
2116
2117     return 0;
2118 }
2119
2120 long cm_IoctlGetToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
2121 {
2122     char *cp;
2123     int temp;
2124     cm_cell_t *cellp;
2125     cm_ucell_t *ucellp;
2126     struct ClearToken ct;
2127     char *tp;
2128 #ifndef DJGPP
2129     afs_uuid_t uuid;
2130 #endif /* !DJGPP */
2131
2132     cm_SkipIoctlPath(ioctlp);
2133
2134     tp = ioctlp->inDatap;
2135
2136     cp = ioctlp->outDatap;
2137
2138     /* cell name is right here */
2139     cellp = cm_GetCell(tp, 0);
2140     if (!cellp) 
2141         return CM_ERROR_NOSUCHCELL;
2142     tp += strlen(tp) + 1;
2143
2144 #ifndef DJGPP
2145     /* uuid */
2146     memcpy(&uuid, tp, sizeof(uuid));
2147 #endif /* !DJGPP */
2148
2149     lock_ObtainMutex(&userp->mx);
2150
2151     ucellp = cm_GetUCell(userp, cellp);
2152     if (!ucellp || !(ucellp->flags & CM_UCELLFLAG_RXKAD)) {
2153         lock_ReleaseMutex(&userp->mx);
2154         return CM_ERROR_NOMORETOKENS;
2155     }
2156
2157     /* ticket length */
2158     memcpy(cp, &ucellp->ticketLen, sizeof(ucellp->ticketLen));
2159     cp += sizeof(ucellp->ticketLen);
2160
2161     /* ticket */
2162     memcpy(cp, ucellp->ticketp, ucellp->ticketLen);
2163     cp += ucellp->ticketLen;
2164
2165     /* clear token size */
2166     temp = sizeof(ct);
2167     memcpy(cp, &temp, sizeof(temp));
2168     cp += sizeof(temp);
2169
2170     /* clear token */
2171     ct.AuthHandle = ucellp->kvno;
2172 #ifndef DJGPP
2173     /*
2174      * Don't give out a real session key here
2175      */
2176     /*
2177     memcpy(ct.HandShakeKey, &ucellp->sessionKey, sizeof(ct.HandShakeKey));
2178     */
2179     memset(ct.HandShakeKey, 0, sizeof(ct.HandShakeKey));
2180 #else
2181     memcpy(ct.HandShakeKey, &ucellp->sessionKey, sizeof(ct.HandShakeKey));
2182 #endif /* !DJGPP */
2183     ct.ViceId = 37;                     /* XXX */
2184     ct.BeginTimestamp = 0;              /* XXX */
2185     ct.EndTimestamp = ucellp->expirationTime;
2186     memcpy(cp, &ct, sizeof(ct));
2187     cp += sizeof(ct);
2188
2189     /* Primary flag (unused) */
2190     temp = 0;
2191     memcpy(cp, &temp, sizeof(temp));
2192     cp += sizeof(temp);
2193
2194     /* cell name */
2195     StringCbCopyA(cp, 999999, ucellp->cellp->name);
2196     cp += strlen(cp) + 1;
2197
2198     /* user name */
2199     StringCbCopyA(cp, 999999, ucellp->userName);
2200     cp += strlen(cp) + 1;
2201
2202     ioctlp->outDatap = cp;
2203
2204     lock_ReleaseMutex(&userp->mx);
2205
2206 #ifndef DJGPP
2207     cm_RegisterNewTokenEvent(uuid, ucellp->sessionKey.data);
2208 #endif /* !DJGPP */
2209
2210     return 0;
2211 }
2212
2213 long cm_IoctlDelToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
2214 {
2215     char *cp;
2216     cm_cell_t *cellp;
2217     cm_ucell_t *ucellp;
2218
2219     cm_SkipIoctlPath(ioctlp);
2220
2221     cp = ioctlp->outDatap;
2222
2223     /* cell name is right here */
2224     cellp = cm_GetCell(ioctlp->inDatap, 0);
2225     if (!cellp) return CM_ERROR_NOSUCHCELL;
2226
2227     lock_ObtainMutex(&userp->mx);
2228
2229     ucellp = cm_GetUCell(userp, cellp);
2230     if (!ucellp) {
2231         lock_ReleaseMutex(&userp->mx);
2232         return CM_ERROR_NOMORETOKENS;
2233     }
2234
2235     osi_Log1(smb_logp,"cm_IoctlDelToken ucellp %lx", ucellp);
2236
2237     if (ucellp->ticketp) {
2238         free(ucellp->ticketp);
2239         ucellp->ticketp = NULL;
2240     }
2241     ucellp->flags &= ~CM_UCELLFLAG_RXKAD;
2242     ucellp->gen++;
2243
2244     lock_ReleaseMutex(&userp->mx);
2245
2246     cm_ResetACLCache(userp);
2247
2248     return 0;
2249 }
2250
2251 long cm_IoctlDelAllToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
2252 {
2253     cm_ucell_t *ucellp;
2254
2255     lock_ObtainMutex(&userp->mx);
2256
2257     for (ucellp = userp->cellInfop; ucellp; ucellp = ucellp->nextp) {
2258         osi_Log1(smb_logp,"cm_IoctlDelAllToken ucellp %lx", ucellp);
2259         ucellp->flags &= ~CM_UCELLFLAG_RXKAD;
2260         ucellp->gen++;
2261     }
2262
2263     lock_ReleaseMutex(&userp->mx);
2264
2265     cm_ResetACLCache(userp);
2266
2267     return 0;
2268 }
2269
2270 long cm_IoctlMakeSubmount(smb_ioctl_t *ioctlp, cm_user_t *userp)
2271 {
2272     char afspath[MAX_PATH];
2273     char *submountreqp;
2274     int nextAutoSubmount;
2275     HKEY hkSubmounts;
2276     DWORD dwType, dwSize;
2277     DWORD status;
2278     DWORD dwIndex;
2279     DWORD dwSubmounts;
2280
2281     cm_SkipIoctlPath(ioctlp);
2282
2283     /* Serialize this one, to prevent simultaneous mods
2284      * to afsdsbmt.ini
2285      */
2286     lock_ObtainMutex(&cm_Afsdsbmt_Lock);
2287
2288     /* Parse the input parameters--first the required afs path,
2289      * then the requested submount name (which may be "").
2290      */
2291     cm_NormalizeAfsPath (afspath, sizeof(afspath), ioctlp->inDatap);
2292     submountreqp = ioctlp->inDatap + (strlen(ioctlp->inDatap)+1);
2293
2294     /* If the caller supplied a suggested submount name, see if
2295      * that submount name is in use... if so, the submount's path
2296      * has to match our path.
2297      */
2298
2299     RegCreateKeyEx( HKEY_LOCAL_MACHINE, 
2300                     AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
2301                     0, 
2302                     "AFS", 
2303                     REG_OPTION_NON_VOLATILE,
2304                     KEY_READ|KEY_WRITE|KEY_QUERY_VALUE,
2305                     NULL, 
2306                     &hkSubmounts,
2307                     NULL );
2308
2309     if (submountreqp && *submountreqp) {
2310         char submountPathNormalized[MAX_PATH];
2311         char submountPath[MAX_PATH];
2312
2313         dwSize = sizeof(submountPath);
2314         status = RegQueryValueEx( hkSubmounts, submountreqp, 0,
2315                                   &dwType, submountPath, &dwSize);
2316
2317         if (status != ERROR_SUCCESS) {
2318
2319             /* The suggested submount name isn't in use now--
2320              * so we can safely map the requested submount name
2321              * to the supplied path. Remember not to write the
2322              * leading "/afs" when writing out the submount.
2323              */
2324             RegSetValueEx( hkSubmounts, submountreqp, 0,
2325                            REG_EXPAND_SZ, 
2326                            (strlen(&afspath[strlen(cm_mountRoot)])) ?
2327                            &afspath[strlen(cm_mountRoot)]:"/",
2328                            (strlen(&afspath[strlen(cm_mountRoot)])) ?
2329                            (DWORD)strlen(&afspath[strlen(cm_mountRoot)])+1:2);
2330
2331             RegCloseKey( hkSubmounts );
2332             StringCbCopyA(ioctlp->outDatap, 999999, submountreqp);
2333             ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
2334             lock_ReleaseMutex(&cm_Afsdsbmt_Lock);
2335             return 0;
2336         }
2337
2338         /* The suggested submount name is already in use--if the
2339          * supplied path matches the submount's path, we can still
2340          * use the suggested submount name.
2341          */
2342         cm_NormalizeAfsPath (submountPathNormalized, sizeof(submountPathNormalized), submountPath);
2343         if (!strcmp (submountPathNormalized, afspath)) {
2344             StringCbCopyA(ioctlp->outDatap, 999999, submountreqp);
2345             ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
2346             RegCloseKey( hkSubmounts );
2347             lock_ReleaseMutex(&cm_Afsdsbmt_Lock);
2348             return 0;
2349         }
2350     }
2351
2352     RegQueryInfoKey( hkSubmounts,
2353                      NULL,  /* lpClass */
2354                      NULL,  /* lpcClass */
2355                      NULL,  /* lpReserved */
2356                      NULL,  /* lpcSubKeys */
2357                      NULL,  /* lpcMaxSubKeyLen */
2358                      NULL,  /* lpcMaxClassLen */
2359                      &dwSubmounts, /* lpcValues */
2360                      NULL,  /* lpcMaxValueNameLen */
2361                      NULL,  /* lpcMaxValueLen */
2362                      NULL,  /* lpcbSecurityDescriptor */
2363                      NULL   /* lpftLastWriteTime */
2364                      );
2365
2366
2367     /* Having obtained a list of all available submounts, start
2368      * searching that list for a path which matches the requested
2369      * AFS path. We'll also keep track of the highest "auto15"/"auto47"
2370      * submount, in case we need to add a new one later.
2371      */
2372
2373     nextAutoSubmount = 1;
2374
2375     for ( dwIndex = 0; dwIndex < dwSubmounts; dwIndex ++ ) {
2376         char submountPathNormalized[MAX_PATH];
2377         char submountPath[MAX_PATH] = "";
2378         DWORD submountPathLen = sizeof(submountPath);
2379         char submountName[MAX_PATH];
2380         DWORD submountNameLen = sizeof(submountName);
2381
2382         dwType = 0;
2383         RegEnumValue( hkSubmounts, dwIndex, submountName, &submountNameLen, NULL,
2384                       &dwType, submountPath, &submountPathLen);
2385         if (dwType == REG_EXPAND_SZ) {
2386             char buf[MAX_PATH];
2387             StringCbCopyA(buf, MAX_PATH, submountPath);
2388             submountPathLen = ExpandEnvironmentStrings(buf, submountPath, MAX_PATH);
2389             if (submountPathLen > MAX_PATH)
2390                 continue;
2391         }
2392
2393         /* If this is an Auto### submount, remember its ### value */
2394         if ((!strnicmp (submountName, "auto", 4)) &&
2395              (isdigit (submountName[strlen("auto")]))) {
2396             int thisAutoSubmount;
2397             thisAutoSubmount = atoi (&submountName[strlen("auto")]);
2398             nextAutoSubmount = max (nextAutoSubmount,
2399                                      thisAutoSubmount+1);
2400         }       
2401
2402         if ((submountPathLen == 0) ||
2403              (submountPathLen == sizeof(submountPath) - 1)) {
2404             continue;
2405         }
2406
2407         /* See if the path for this submount matches the path
2408          * that our caller specified. If so, we can return
2409          * this submount.
2410          */
2411         cm_NormalizeAfsPath (submountPathNormalized, sizeof(submountPathNormalized), submountPath);
2412         if (!strcmp (submountPathNormalized, afspath)) {
2413             StringCbCopyA(ioctlp->outDatap, 999999, submountName);
2414             ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
2415             RegCloseKey(hkSubmounts);
2416             lock_ReleaseMutex(&cm_Afsdsbmt_Lock);
2417             return 0;
2418
2419         }
2420     }
2421
2422     /* We've been through the entire list of existing submounts, and
2423      * didn't find any which matched the specified path. So, we'll
2424      * just have to add one. Remember not to write the leading "/afs"
2425      * when writing out the submount.
2426      */
2427
2428     StringCbPrintfA(ioctlp->outDatap, 999999, "auto%ld", nextAutoSubmount);
2429
2430     RegSetValueEx( hkSubmounts, 
2431                    ioctlp->outDatap,
2432                    0,
2433                    REG_EXPAND_SZ, 
2434                    (strlen(&afspath[strlen(cm_mountRoot)])) ?
2435                    &afspath[strlen(cm_mountRoot)]:"/",
2436                    (strlen(&afspath[strlen(cm_mountRoot)])) ?
2437                    (DWORD)strlen(&afspath[strlen(cm_mountRoot)])+1:2);
2438
2439     ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
2440     RegCloseKey(hkSubmounts);
2441     lock_ReleaseMutex(&cm_Afsdsbmt_Lock);
2442     return 0;
2443 }
2444
2445 long cm_IoctlGetRxkcrypt(smb_ioctl_t *ioctlp, cm_user_t *userp)
2446 {
2447     memcpy(ioctlp->outDatap, &cryptall, sizeof(cryptall));
2448     ioctlp->outDatap += sizeof(cryptall);
2449
2450     return 0;
2451 }
2452
2453 long cm_IoctlSetRxkcrypt(smb_ioctl_t *ioctlp, cm_user_t *userp)
2454 {
2455     cm_SkipIoctlPath(ioctlp);
2456
2457     memcpy(&cryptall, ioctlp->inDatap, sizeof(cryptall));
2458
2459     return 0;
2460 }
2461
2462 long cm_IoctlRxStatProcess(struct smb_ioctl *ioctlp, struct cm_user *userp)
2463 {
2464     afs_int32 flags;
2465     int code = 0;
2466
2467     cm_SkipIoctlPath(ioctlp);
2468
2469     memcpy((char *)&flags, ioctlp->inDatap, sizeof(afs_int32));
2470     if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
2471         return -1;
2472     }
2473     if (flags & AFSCALL_RXSTATS_ENABLE) {
2474         rx_enableProcessRPCStats();
2475     }
2476     if (flags & AFSCALL_RXSTATS_DISABLE) {
2477         rx_disableProcessRPCStats();
2478     }
2479     if (flags & AFSCALL_RXSTATS_CLEAR) {
2480         rx_clearProcessRPCStats(AFS_RX_STATS_CLEAR_ALL);
2481     }
2482     return 0;
2483 }
2484
2485 long cm_IoctlRxStatPeer(struct smb_ioctl *ioctlp, struct cm_user *userp)
2486 {
2487     afs_int32 flags;
2488     int code = 0;
2489
2490     cm_SkipIoctlPath(ioctlp);
2491
2492     memcpy((char *)&flags, ioctlp->inDatap, sizeof(afs_int32));
2493     if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK)) {
2494         return -1;
2495     }
2496     if (flags & AFSCALL_RXSTATS_ENABLE) {
2497         rx_enablePeerRPCStats();
2498     }
2499     if (flags & AFSCALL_RXSTATS_DISABLE) {
2500         rx_disablePeerRPCStats();
2501     }
2502     if (flags & AFSCALL_RXSTATS_CLEAR) {
2503         rx_clearPeerRPCStats(AFS_RX_STATS_CLEAR_ALL);
2504     }
2505     return 0;
2506 }
2507
2508 #ifdef DJGPP
2509 extern int afsd_shutdown(int);
2510 extern int afs_shutdown;
2511
2512 long cm_IoctlShutdown(smb_ioctl_t *ioctlp, cm_user_t *userp) {
2513   afs_shutdown = 1;   /* flag to shut down */
2514   return 0;
2515 }
2516 #endif /* DJGPP */
2517
2518 long cm_IoctlGetSMBName(smb_ioctl_t *ioctlp, cm_user_t *userp)
2519 {
2520   smb_user_t *uidp = ioctlp->uidp;
2521
2522   if (uidp && uidp->unp) {
2523     memcpy(ioctlp->outDatap, uidp->unp->name, strlen(uidp->unp->name));
2524     ioctlp->outDatap += strlen(uidp->unp->name);
2525   }
2526
2527   return 0;
2528 }
2529
2530 /* 
2531  * functions to dump contents of various structures. 
2532  * In debug build (linked with crt debug library) will dump allocated but not freed memory
2533  */
2534 extern int cm_DumpSCache(FILE *outputFile, char *cookie, int lock);
2535 extern int cm_DumpBufHashTable(FILE *outputFile, char *cookie, int lock);
2536 extern int smb_DumpVCP(FILE *outputFile, char *cookie, int lock);
2537
2538 long cm_IoctlMemoryDump(struct smb_ioctl *ioctlp, struct cm_user *userp)
2539 {
2540     long inValue = 0;
2541     HANDLE hLogFile;
2542     char logfileName[MAX_PATH+1];
2543     char *cookie;
2544     DWORD dwSize;
2545   
2546 #ifdef _DEBUG  
2547     static _CrtMemState memstate;
2548 #endif
2549   
2550     cm_SkipIoctlPath(ioctlp);
2551     memcpy(&inValue, ioctlp->inDatap, sizeof(long));
2552   
2553     dwSize = GetEnvironmentVariable("TEMP", logfileName, sizeof(logfileName));
2554     if ( dwSize == 0 || dwSize > sizeof(logfileName) )
2555     {
2556         GetWindowsDirectory(logfileName, sizeof(logfileName));
2557     }
2558     strncat(logfileName, "\\afsd_alloc.log", sizeof(logfileName));
2559
2560     hLogFile = CreateFile(logfileName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2561   
2562     if (!hLogFile)
2563     {
2564       /* error */
2565       inValue = -1;
2566       memcpy(ioctlp->outDatap, &inValue, sizeof(long));
2567       ioctlp->outDatap += sizeof(long);
2568       
2569       return 0;               
2570     }
2571   
2572     SetFilePointer(hLogFile, 0, NULL, FILE_END);
2573   
2574     cookie = inValue ? "b" : "e";
2575   
2576 #ifdef _DEBUG  
2577   
2578     if (inValue)
2579     {
2580       _CrtMemCheckpoint(&memstate);           
2581     }
2582     else
2583     {
2584         _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2585         _CrtSetReportFile(_CRT_WARN, hLogFile);
2586         _CrtMemDumpAllObjectsSince(&memstate);
2587     }
2588 #endif
2589   
2590     /* dump all interesting data */
2591     cm_DumpSCache(hLogFile, cookie, 1);
2592     cm_DumpBufHashTable(hLogFile, cookie, 1);
2593     smb_DumpVCP(hLogFile, cookie, 1);
2594
2595     CloseHandle(hLogFile);                          
2596   
2597     memcpy(ioctlp->outDatap, &inValue, sizeof(long));
2598     ioctlp->outDatap += sizeof(long);
2599   
2600     return 0;
2601 }