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