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