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