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