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