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