02c3ee30f1311012efd36a57d01a5f2fa96d9b58
[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 afs_uint32 cm_pioctlFollowMountPoint = 0;
57
58 void cm_InitIoctl(void)
59 {
60     lock_InitializeMutex(&cm_Afsdsbmt_Lock, "AFSDSBMT.INI Access Lock");
61 }
62
63 long cm_CleanFile(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
64 {
65     long code;
66
67     lock_ObtainWrite(&scp->bufCreateLock);
68     code = buf_CleanVnode(scp, userp, reqp);
69         
70     lock_ObtainMutex(&scp->mx);
71     cm_DiscardSCache(scp);
72     lock_ReleaseMutex(&scp->mx);
73
74     lock_ReleaseWrite(&scp->bufCreateLock);
75     osi_Log2(afsd_logp,"cm_CleanFile scp 0x%x returns error: [%x]",scp, code);
76     return code;
77 }
78
79 long cm_FlushFile(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
80 {
81     long code;
82
83 #ifdef AFS_FREELANCE_CLIENT
84     if ( scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID ) {
85         cm_noteLocalMountPointChange();
86         return 0;
87     }
88 #endif
89
90     lock_ObtainWrite(&scp->bufCreateLock);
91     code = buf_FlushCleanPages(scp, userp, reqp);
92         
93     lock_ObtainMutex(&scp->mx);
94     cm_DiscardSCache(scp);
95
96     lock_ReleaseMutex(&scp->mx);
97
98     lock_ReleaseWrite(&scp->bufCreateLock);
99     osi_Log2(afsd_logp,"cm_FlushFile scp 0x%x returns error: [%x]",scp, code);
100     return code;
101 }
102
103 long cm_FlushParent(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
104 {
105     long code = 0;
106     cm_scache_t * pscp;
107   
108     pscp = cm_FindSCacheParent(scp);
109   
110     /* now flush the file */
111     code = cm_FlushFile(pscp, userp, reqp);
112     cm_ReleaseSCache(pscp);
113
114     return code;
115 }
116
117
118 long cm_FlushVolume(cm_user_t *userp, cm_req_t *reqp, afs_uint32 cell, afs_uint32 volume)
119 {
120     long code = 0;
121     cm_scache_t *scp;
122     int i;
123
124 #ifdef AFS_FREELANCE_CLIENT
125     if ( cell == AFS_FAKE_ROOT_CELL_ID && volume == AFS_FAKE_ROOT_VOL_ID ) {
126         cm_noteLocalMountPointChange();
127         return 0;
128     }
129 #endif
130
131     lock_ObtainWrite(&cm_scacheLock);
132     for (i=0; i<cm_data.scacheHashTableSize; i++) {
133         for (scp = cm_data.scacheHashTablep[i]; scp; scp = scp->nextp) {
134             if (scp->fid.volume == volume && scp->fid.cell == cell) {
135                 cm_HoldSCacheNoLock(scp);
136                 lock_ReleaseWrite(&cm_scacheLock);
137
138                 /* now flush the file */
139                 code = cm_FlushFile(scp, userp, reqp);
140                 lock_ObtainWrite(&cm_scacheLock);
141                 cm_ReleaseSCacheNoLock(scp);
142             }
143         }
144     }
145     lock_ReleaseWrite(&cm_scacheLock);
146
147     return code;
148 }
149
150 /*
151  * cm_ResetACLCache -- invalidate ACL info for a user that has just
152  *                      obtained or lost tokens
153  */
154 void cm_ResetACLCache(cm_user_t *userp)
155 {
156     cm_scache_t *scp;
157     int hash;
158
159     lock_ObtainWrite(&cm_scacheLock);
160     for (hash=0; hash < cm_data.scacheHashTableSize; hash++) {
161         for (scp=cm_data.scacheHashTablep[hash]; scp; scp=scp->nextp) {
162             cm_HoldSCacheNoLock(scp);
163             lock_ReleaseWrite(&cm_scacheLock);
164             lock_ObtainMutex(&scp->mx);
165             cm_InvalidateACLUser(scp, userp);
166             lock_ReleaseMutex(&scp->mx);
167             lock_ObtainWrite(&cm_scacheLock);
168             cm_ReleaseSCacheNoLock(scp);
169         }
170     }
171     lock_ReleaseWrite(&cm_scacheLock);
172 }       
173
174 /*
175  *  TranslateExtendedChars - This is a fix for TR 54482.
176  *
177  *  If an extended character (80 - FF) is entered into a file
178  *  or directory name in Windows, the character is translated
179  *  into the OEM character map before being passed to us.  Why
180  *  this occurs is unknown.  Our pioctl functions must match
181  *  this translation for paths given via our own commands (like
182  *  fs).  If we do not do this, then we will try to perform an
183  *  operation on a non-translated path, which we will fail to 
184  *  find, since the path was created with the translated chars.
185  *  This function performs the required translation.
186  */
187 void TranslateExtendedChars(char *str)
188 {
189     if (!str || !*str)
190         return;
191
192     CharToOem(str, str);
193 }
194         
195 /* parse the passed-in file name and do a namei on it.  If we fail,
196  * return an error code, otherwise return the vnode located in *scpp.
197  */
198 long cm_ParseIoctlPath(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
199         cm_scache_t **scpp)
200 {
201     long code;
202 #ifndef AFSIFS
203     cm_scache_t *substRootp = NULL;
204     cm_scache_t *iscp = NULL;
205 #endif
206     char * relativePath;
207     char * lastComponent = NULL;
208     afs_uint32 follow = (cm_pioctlFollowMountPoint ? CM_FLAG_FOLLOW : CM_FLAG_NOMOUNTCHASE);
209
210     relativePath = ioctlp->inDatap;
211     /* setup the next data value for the caller to use */
212     ioctlp->inDatap += (long)strlen(ioctlp->inDatap) + 1;;
213
214     osi_Log1(afsd_logp, "cm_ParseIoctlPath %s", osi_LogSaveString(afsd_logp,relativePath));
215
216     /* This is usually the file name, but for StatMountPoint it is the path. */
217     /* ioctlp->inDatap can be either of the form:
218      *    \path\.
219      *    \path\file
220      *    \\netbios-name\submount\path\.
221      *    \\netbios-name\submount\path\file
222      */
223     TranslateExtendedChars(relativePath);
224
225     /* This is usually nothing, but for StatMountPoint it is the file name. */
226     TranslateExtendedChars(ioctlp->inDatap);
227
228 #ifdef AFSIFS
229     /* we have passed the whole path, including the afs prefix.
230        when the pioctl call is made, we perform an ioctl to afsrdr
231        and it returns the correct (full) path.  therefore, there is
232        no drive letter, and the path is absolute. */
233     code = cm_NameI(cm_data.rootSCachep, relativePath,
234                      CM_FLAG_CASEFOLD,
235                      userp, "", reqp, scpp);
236
237     if (code) {
238         osi_Log1(afsd_logp,"cm_ParseIoctlPath code 0x%x", code);
239         return code;
240     }
241 #else /* AFSIFS */
242
243     if (relativePath[0] == relativePath[1] &&
244          relativePath[1] == '\\' && 
245          !_strnicmp(cm_NetbiosName,relativePath+2,strlen(cm_NetbiosName))) 
246     {
247         char shareName[256];
248         char *sharePath;
249         int shareFound, i;
250
251         /* We may have found a UNC path. 
252          * If the first component is the NetbiosName,
253          * then throw out the second component (the submount)
254          * since it had better expand into the value of ioctl->tidPathp
255          */
256         char * p;
257         p = relativePath + 2 + strlen(cm_NetbiosName) + 1;                      /* buffer overflow vuln.? */
258         if ( !_strnicmp("all", p, 3) )
259             p += 4;
260
261         for (i = 0; *p && *p != '\\'; i++,p++ ) {
262             shareName[i] = *p;
263         }
264         p++;                    /* skip past trailing slash */
265         shareName[i] = 0;       /* terminate string */
266
267         shareFound = smb_FindShare(ioctlp->fidp->vcp, ioctlp->uidp, shareName, &sharePath);
268         if ( shareFound ) {
269             /* we found a sharename, therefore use the resulting path */
270             code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
271                              CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
272                              userp, sharePath, reqp, &substRootp);
273             free(sharePath);
274             if (code) {
275                 osi_Log1(afsd_logp,"cm_ParseIoctlPath [1] code 0x%x", code);
276                 return code;
277             }
278
279             lastComponent = strrchr(p, '\\');
280             if (lastComponent && (lastComponent - p) > 1 &&strlen(lastComponent) > 1) {
281                 *lastComponent = '\0';
282                 lastComponent++;
283
284                 code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
285                                  userp, NULL, reqp, &iscp);
286                 if (code == 0)
287                     code = cm_NameI(iscp, lastComponent, CM_FLAG_CASEFOLD | follow,
288                                     userp, NULL, reqp, scpp);
289                 if (iscp)
290                     cm_ReleaseSCache(iscp);
291             } else {
292                 code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD,
293                                 userp, NULL, reqp, scpp);
294             }
295             cm_ReleaseSCache(substRootp);
296             if (code) {
297                 osi_Log1(afsd_logp,"cm_ParseIoctlPath [2] code 0x%x", code);
298                 return code;
299             }
300         } else {
301             /* otherwise, treat the name as a cellname mounted off the afs root.
302              * This requires that we reconstruct the shareName string with 
303              * leading and trailing slashes.
304              */
305             p = relativePath + 2 + strlen(cm_NetbiosName) + 1;
306             if ( !_strnicmp("all", p, 3) )
307                 p += 4;
308
309             shareName[0] = '/';
310             for (i = 1; *p && *p != '\\'; i++,p++ ) {
311                 shareName[i] = *p;
312             }
313             p++;                    /* skip past trailing slash */
314             shareName[i++] = '/';       /* add trailing slash */
315             shareName[i] = 0;       /* terminate string */
316
317
318             code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
319                              CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
320                              userp, shareName, reqp, &substRootp);
321             if (code) {
322                 osi_Log1(afsd_logp,"cm_ParseIoctlPath [3] code 0x%x", code);
323                 return code;
324             }
325
326             lastComponent = strrchr(p, '\\');
327             if (lastComponent && (lastComponent - p) > 1 &&strlen(lastComponent) > 1) {
328                 *lastComponent = '\0';
329                 lastComponent++;
330
331                 code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
332                                  userp, NULL, reqp, &iscp);
333                 if (code == 0)
334                     code = cm_NameI(iscp, lastComponent, CM_FLAG_CASEFOLD | follow,
335                                     userp, NULL, reqp, scpp);
336                 if (iscp)
337                     cm_ReleaseSCache(iscp);
338             } else {
339                 code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD,
340                                 userp, NULL, reqp, scpp);
341             }
342
343             if (code) {
344                 cm_ReleaseSCache(substRootp);
345                 osi_Log1(afsd_logp,"cm_ParseIoctlPath code [4] 0x%x", code);
346                 return code;
347             }
348         }
349     } else {
350         code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
351                          CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
352                          userp, ioctlp->tidPathp, reqp, &substRootp);
353         if (code) {
354             osi_Log1(afsd_logp,"cm_ParseIoctlPath [6] code 0x%x", code);
355             return code;
356         }
357         
358         lastComponent = strrchr(relativePath, '\\');
359         if (lastComponent && (lastComponent - relativePath) > 1 && strlen(lastComponent) > 1) {
360             *lastComponent = '\0';
361             lastComponent++;
362
363             code = cm_NameI(substRootp, relativePath, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
364                              userp, NULL, reqp, &iscp);
365             if (code == 0)
366                 code = cm_NameI(iscp, lastComponent, CM_FLAG_CASEFOLD | follow,
367                                  userp, NULL, reqp, scpp);
368             if (iscp)
369                 cm_ReleaseSCache(iscp);
370         } else {
371             code = cm_NameI(substRootp, relativePath, CM_FLAG_CASEFOLD,
372                              userp, NULL, reqp, scpp);
373         }
374         if (code) {
375             cm_ReleaseSCache(substRootp);
376             osi_Log1(afsd_logp,"cm_ParseIoctlPath [7] code 0x%x", code);
377             return code;
378         }
379     }
380 #endif /* AFSIFS */
381
382     if (substRootp)
383         cm_ReleaseSCache(substRootp);
384
385     /* and return success */
386     osi_Log1(afsd_logp,"cm_ParseIoctlPath [8] code 0x%x", code);
387     return 0;
388 }
389
390 void cm_SkipIoctlPath(smb_ioctl_t *ioctlp)
391 {
392     long temp;
393         
394     temp = (long) strlen(ioctlp->inDatap) + 1;
395     ioctlp->inDatap += temp;
396 }       
397
398
399 /* format the specified path to look like "/afs/<cellname>/usr", by
400  * adding "/afs" (if necessary) in front, changing any \'s to /'s, and
401  * removing any trailing "/"'s. One weirdo caveat: "/afs" will be
402  * intentionally returned as "/afs/"--this makes submount manipulation
403  * easier (because we can always jump past the initial "/afs" to find
404  * the AFS path that should be written into afsdsbmt.ini).
405  */
406 void cm_NormalizeAfsPath(char *outpathp, long outlen, char *inpathp)
407 {
408     char *cp;
409     char bslash_mountRoot[256];
410        
411     strncpy(bslash_mountRoot, cm_mountRoot, sizeof(bslash_mountRoot) - 1);
412     bslash_mountRoot[0] = '\\';
413        
414     if (!strnicmp (inpathp, cm_mountRoot, strlen(cm_mountRoot)))
415         StringCbCopy(outpathp, outlen, inpathp);
416     else if (!strnicmp (inpathp, bslash_mountRoot, strlen(bslash_mountRoot)))
417         StringCbCopy(outpathp, outlen, inpathp);
418     else if ((inpathp[0] == '/') || (inpathp[0] == '\\'))
419         StringCbPrintfA(outpathp, outlen, "%s%s", cm_mountRoot, inpathp);
420     else // inpathp looks like "<cell>/usr"
421         StringCbPrintfA(outpathp, outlen, "%s/%s", cm_mountRoot, inpathp);
422
423     for (cp = outpathp; *cp != 0; ++cp) {
424         if (*cp == '\\')
425             *cp = '/';
426     }       
427
428     if (strlen(outpathp) && (outpathp[strlen(outpathp)-1] == '/')) {
429         outpathp[strlen(outpathp)-1] = 0;
430     }
431
432     if (!strcmpi (outpathp, cm_mountRoot)) {
433         StringCbCopy(outpathp, outlen, cm_mountRoot);
434     }
435 }
436
437 #define LEAF_SIZE 256
438 /* parse the passed-in file name and do a namei on its parent.  If we fail,
439  * return an error code, otherwise return the vnode located in *scpp.
440  */
441 long cm_ParseIoctlParent(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
442                          cm_scache_t **scpp, char *leafp)
443 {
444     long code;
445     char tbuffer[1024];
446     char *tp, *jp;
447     cm_scache_t *substRootp = NULL;
448
449     StringCbCopyA(tbuffer, sizeof(tbuffer), ioctlp->inDatap);
450     tp = strrchr(tbuffer, '\\');
451     jp = strrchr(tbuffer, '/');
452     if (!tp)
453         tp = jp;
454     else if (jp && (tp - tbuffer) < (jp - tbuffer))
455         tp = jp;
456     if (!tp) {
457         StringCbCopyA(tbuffer, sizeof(tbuffer), "\\");
458         if (leafp) 
459             StringCbCopyA(leafp, LEAF_SIZE, ioctlp->inDatap);
460     }
461     else {
462         *tp = 0;
463         if (leafp) 
464             StringCbCopyA(leafp, LEAF_SIZE, tp+1);
465     }   
466
467     if (tbuffer[0] == tbuffer[1] &&
468         tbuffer[1] == '\\' && 
469         !_strnicmp(cm_NetbiosName,tbuffer+2,strlen(cm_NetbiosName))) 
470     {
471         char shareName[256];
472         char *sharePath;
473         int shareFound, i;
474
475         /* We may have found a UNC path. 
476          * If the first component is the NetbiosName,
477          * then throw out the second component (the submount)
478          * since it had better expand into the value of ioctl->tidPathp
479          */
480         char * p;
481         p = tbuffer + 2 + strlen(cm_NetbiosName) + 1;
482         if ( !_strnicmp("all", p, 3) )
483             p += 4;
484
485         for (i = 0; *p && *p != '\\'; i++,p++ ) {
486             shareName[i] = *p;
487         }
488         p++;                    /* skip past trailing slash */
489         shareName[i] = 0;       /* terminate string */
490
491         shareFound = smb_FindShare(ioctlp->fidp->vcp, ioctlp->uidp, shareName, &sharePath);
492         if ( shareFound ) {
493             /* we found a sharename, therefore use the resulting path */
494             code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
495                              CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
496                              userp, sharePath, reqp, &substRootp);
497             free(sharePath);
498             if (code) return code;
499
500             code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
501                              userp, NULL, reqp, scpp);
502             cm_ReleaseSCache(substRootp);
503             if (code) return code;
504         } else {
505             /* otherwise, treat the name as a cellname mounted off the afs root.
506              * This requires that we reconstruct the shareName string with 
507              * leading and trailing slashes.
508              */
509             p = tbuffer + 2 + strlen(cm_NetbiosName) + 1;
510             if ( !_strnicmp("all", p, 3) )
511                 p += 4;
512
513             shareName[0] = '/';
514             for (i = 1; *p && *p != '\\'; i++,p++ ) {
515                 shareName[i] = *p;
516             }
517             p++;                    /* skip past trailing slash */
518             shareName[i++] = '/';       /* add trailing slash */
519             shareName[i] = 0;       /* terminate string */
520
521             code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
522                              CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
523                              userp, shareName, reqp, &substRootp);
524             if (code) return code;
525
526             code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
527                             userp, NULL, reqp, scpp);
528             cm_ReleaseSCache(substRootp);
529             if (code) return code;
530         }
531     } else {
532         code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
533                         CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
534                         userp, ioctlp->tidPathp, reqp, &substRootp);
535         if (code) return code;
536
537         code = cm_NameI(substRootp, tbuffer, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
538                         userp, NULL, reqp, scpp);
539         cm_ReleaseSCache(substRootp);
540         if (code) return code;
541     }
542
543     /* # of bytes of path */
544     code = (long)strlen(ioctlp->inDatap) + 1;
545     ioctlp->inDatap += code;
546
547     /* and return success */
548     return 0;
549 }
550
551 long cm_IoctlGetACL(smb_ioctl_t *ioctlp, cm_user_t *userp)
552 {
553     cm_conn_t *connp;
554     cm_scache_t *scp;
555     AFSOpaque acl;
556     AFSFetchStatus fileStatus;
557     AFSVolSync volSync;
558     long code;
559     AFSFid fid;
560     int tlen;
561     cm_req_t req;
562     struct rx_connection * callp;
563
564     cm_InitReq(&req);
565
566     code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
567     if (code) return code;
568
569     /* now make the get acl call */
570 #ifdef AFS_FREELANCE_CLIENT
571     if ( scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID ) {
572         code = 0;
573         ioctlp->outDatap[0] ='\0';
574     } else
575 #endif
576     {
577         fid.Volume = scp->fid.volume;
578         fid.Vnode = scp->fid.vnode;
579         fid.Unique = scp->fid.unique;
580         do {
581             acl.AFSOpaque_val = ioctlp->outDatap;
582             acl.AFSOpaque_len = 0;
583             code = cm_ConnFromFID(&scp->fid, userp, &req, &connp);
584             if (code) continue;
585
586             callp = cm_GetRxConn(connp);
587             code = RXAFS_FetchACL(callp, &fid, &acl, &fileStatus, &volSync);
588             rx_PutConnection(callp);
589
590         } while (cm_Analyze(connp, userp, &req, &scp->fid, &volSync, NULL, NULL, code));
591         code = cm_MapRPCError(code, &req);
592         cm_ReleaseSCache(scp);
593
594         if (code) return code;
595     }
596     /* skip over return data */
597     tlen = (int)strlen(ioctlp->outDatap) + 1;
598     ioctlp->outDatap += tlen;
599
600     /* and return success */
601     return 0;
602 }
603
604 long cm_IoctlGetFileCellName(struct smb_ioctl *ioctlp, struct cm_user *userp)
605 {
606     long code;
607     cm_scache_t *scp;
608     cm_cell_t *cellp;
609     cm_req_t req;
610
611     cm_InitReq(&req);
612
613     code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
614     if (code) return code;
615
616 #ifdef AFS_FREELANCE_CLIENT
617     if ( cm_freelanceEnabled && 
618          scp->fid.cell==AFS_FAKE_ROOT_CELL_ID &&
619          scp->fid.volume==AFS_FAKE_ROOT_VOL_ID &&
620          scp->fid.vnode==0x1 && scp->fid.unique==0x1 ) {
621         StringCbCopyA(ioctlp->outDatap, SMB_IOCTL_MAXDATA - (ioctlp->outDatap - ioctlp->outAllocp), "Freelance.Local.Root");
622         ioctlp->outDatap += strlen(ioctlp->outDatap) + 1;
623         code = 0;
624     } else 
625 #endif /* AFS_FREELANCE_CLIENT */
626     {
627         cellp = cm_FindCellByID(scp->fid.cell);
628         if (cellp) {
629             StringCbCopyA(ioctlp->outDatap, SMB_IOCTL_MAXDATA - (ioctlp->outDatap - ioctlp->outAllocp), cellp->name);
630             ioctlp->outDatap += strlen(ioctlp->outDatap) + 1;
631             code = 0;
632         }
633         else 
634             code = CM_ERROR_NOSUCHCELL;
635     }
636
637     cm_ReleaseSCache(scp);
638     return code;
639 }
640
641 long cm_IoctlSetACL(struct smb_ioctl *ioctlp, struct cm_user *userp)
642 {
643     cm_conn_t *connp;
644     cm_scache_t *scp;
645     AFSOpaque acl;
646     AFSFetchStatus fileStatus;
647     AFSVolSync volSync;
648     long code;
649     AFSFid fid;
650     cm_req_t req;
651     struct rx_connection * callp;
652
653     cm_InitReq(&req);
654
655     code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
656     if (code) return code;
657         
658 #ifdef AFS_FREELANCE_CLIENT
659     if ( scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID ) {
660         code = CM_ERROR_NOACCESS;
661     } else
662 #endif
663     {
664         /* now make the get acl call */
665         fid.Volume = scp->fid.volume;
666         fid.Vnode = scp->fid.vnode;
667         fid.Unique = scp->fid.unique;
668         do {
669             acl.AFSOpaque_val = ioctlp->inDatap;
670             acl.AFSOpaque_len = (u_int)strlen(ioctlp->inDatap)+1;
671             code = cm_ConnFromFID(&scp->fid, userp, &req, &connp);
672             if (code) continue;
673
674             callp = cm_GetRxConn(connp);
675             code = RXAFS_StoreACL(callp, &fid, &acl, &fileStatus, &volSync);
676             rx_PutConnection(callp);
677
678         } while (cm_Analyze(connp, userp, &req, &scp->fid, &volSync, NULL, NULL, code));
679         code = cm_MapRPCError(code, &req);
680
681         /* invalidate cache info, since we just trashed the ACL cache */
682         lock_ObtainMutex(&scp->mx);
683         cm_DiscardSCache(scp);
684         lock_ReleaseMutex(&scp->mx);
685     }
686     cm_ReleaseSCache(scp);
687
688     return code;
689 }
690
691
692
693 long cm_IoctlFlushAllVolumes(struct smb_ioctl *ioctlp, struct cm_user *userp)
694 {
695     long code;
696     cm_scache_t *scp;
697     int i;
698     cm_req_t req;
699
700     cm_InitReq(&req);
701
702     lock_ObtainWrite(&cm_scacheLock);
703     for (i=0; i<cm_data.scacheHashTableSize; i++) {
704         for (scp = cm_data.scacheHashTablep[i]; scp; scp = scp->nextp) {
705             cm_HoldSCacheNoLock(scp);
706             lock_ReleaseWrite(&cm_scacheLock);
707
708             /* now flush the file */
709             code = cm_FlushFile(scp, userp, &req);
710             lock_ObtainWrite(&cm_scacheLock);
711             cm_ReleaseSCacheNoLock(scp);
712         }
713     }
714     lock_ReleaseWrite(&cm_scacheLock);
715
716     return code;
717 }
718
719 long cm_IoctlFlushVolume(struct smb_ioctl *ioctlp, struct cm_user *userp)
720 {
721     long code;
722     cm_scache_t *scp;
723     unsigned long volume;
724     unsigned long cell;
725     cm_req_t req;
726
727     cm_InitReq(&req);
728
729     code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
730     if (code) return code;
731         
732 #ifdef AFS_FREELANCE_CLIENT
733     if ( scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID ) {
734         code = CM_ERROR_NOACCESS;
735     } else
736 #endif
737     {
738         volume = scp->fid.volume;
739         cell = scp->fid.cell;
740         cm_ReleaseSCache(scp);
741
742         code = cm_FlushVolume(userp, &req, cell, volume);
743     }
744     return code;
745 }
746
747 long cm_IoctlFlushFile(struct smb_ioctl *ioctlp, struct cm_user *userp)
748 {
749     long code;
750     cm_scache_t *scp;
751     cm_req_t req;
752
753     cm_InitReq(&req);
754
755     code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
756     if (code) return code;
757         
758 #ifdef AFS_FREELANCE_CLIENT
759     if ( scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID ) {
760         code = CM_ERROR_NOACCESS;
761     } else
762 #endif
763     {
764         cm_FlushFile(scp, userp, &req);
765     }
766     cm_ReleaseSCache(scp);
767
768     return 0;
769 }
770
771 long cm_IoctlSetVolumeStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
772 {
773     cm_scache_t *scp;
774     char volName[32];
775     char offLineMsg[256];
776     char motd[256];
777     cm_conn_t *tcp;
778     long code;
779     AFSFetchVolumeStatus volStat;
780     AFSStoreVolumeStatus storeStat;
781     cm_volume_t *tvp;
782     char *cp;
783     cm_cell_t *cellp;
784     cm_req_t req;
785     struct rx_connection * callp;
786
787     cm_InitReq(&req);
788
789     code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
790     if (code) return code;
791
792 #ifdef AFS_FREELANCE_CLIENT
793     if ( scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID ) {
794         code = CM_ERROR_NOACCESS;
795     } else
796 #endif
797     {
798         cellp = cm_FindCellByID(scp->fid.cell);
799         osi_assertx(cellp, "null cm_cell_t");
800
801         if (scp->flags & CM_SCACHEFLAG_RO) {
802             cm_ReleaseSCache(scp);
803             return CM_ERROR_READONLY;
804         }
805
806         code = cm_GetVolumeByID(cellp, scp->fid.volume, userp, &req, 
807                                  CM_GETVOL_FLAG_CREATE, &tvp);
808         if (code) {
809             cm_ReleaseSCache(scp);
810             return code;
811         }
812         cm_PutVolume(tvp);
813
814         /* Copy the junk out, using cp as a roving pointer. */
815         cp = ioctlp->inDatap;
816         memcpy((char *)&volStat, cp, sizeof(AFSFetchVolumeStatus));
817         cp += sizeof(AFSFetchVolumeStatus);
818         StringCbCopyA(volName, sizeof(volName), cp);
819         cp += strlen(volName)+1;
820         StringCbCopyA(offLineMsg, sizeof(offLineMsg), cp);
821         cp +=  strlen(offLineMsg)+1;
822         StringCbCopyA(motd, sizeof(motd), cp);
823         storeStat.Mask = 0;
824         if (volStat.MinQuota != -1) {
825             storeStat.MinQuota = volStat.MinQuota;
826             storeStat.Mask |= AFS_SETMINQUOTA;
827         }
828         if (volStat.MaxQuota != -1) {
829             storeStat.MaxQuota = volStat.MaxQuota;
830             storeStat.Mask |= AFS_SETMAXQUOTA;
831         }
832
833         do {
834             code = cm_ConnFromFID(&scp->fid, userp, &req, &tcp);
835             if (code) continue;
836
837             callp = cm_GetRxConn(tcp);
838             code = RXAFS_SetVolumeStatus(callp, scp->fid.volume,
839                                           &storeStat, volName, offLineMsg, motd);
840             rx_PutConnection(callp);
841
842         } while (cm_Analyze(tcp, userp, &req, &scp->fid, NULL, NULL, NULL, code));
843         code = cm_MapRPCError(code, &req);
844     }
845     
846     /* return on failure */
847     cm_ReleaseSCache(scp);
848     if (code) {
849         return code;
850     }
851
852     /* we are sending parms back to make compat. with prev system.  should
853      * change interface later to not ask for current status, just set
854      * new status
855      */
856     cp = ioctlp->outDatap;
857     memcpy(cp, (char *)&volStat, sizeof(VolumeStatus));
858     cp += sizeof(VolumeStatus);
859     StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), volName);
860     cp += strlen(volName)+1;
861     StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), offLineMsg);
862     cp += strlen(offLineMsg)+1;
863     StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), motd);
864     cp += strlen(motd)+1;
865
866     /* now return updated return data pointer */
867     ioctlp->outDatap = cp;
868
869     return 0;
870 }       
871
872 long cm_IoctlGetVolumeStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
873 {
874     char volName[32];
875     cm_scache_t *scp;
876     char offLineMsg[256];
877     char motd[256];
878     cm_conn_t *connp;
879     register long code;
880     AFSFetchVolumeStatus volStat;
881     register char *cp;
882     char *Name;
883     char *OfflineMsg;
884     char *MOTD;
885     cm_req_t req;
886     struct rx_connection * callp;
887
888     cm_InitReq(&req);
889
890     code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
891     if (code) return code;
892
893 #ifdef AFS_FREELANCE_CLIENT
894     if ( scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID ) {
895         code = 0;
896         strncpy(volName, "Freelance.Local.Root", sizeof(volName));
897         offLineMsg[0] = '\0';
898         strncpy(motd, "Freelance mode in use.", sizeof(motd));
899         volStat.Vid = scp->fid.volume;
900         volStat.MaxQuota = 0;
901         volStat.BlocksInUse = 100;
902         volStat.PartBlocksAvail = 0;
903         volStat.PartMaxBlocks = 100;
904     } else
905 #endif
906     {
907         Name = volName;
908         OfflineMsg = offLineMsg;
909         MOTD = motd;
910         do {
911             code = cm_ConnFromFID(&scp->fid, userp, &req, &connp);
912             if (code) continue;
913
914             callp = cm_GetRxConn(connp);
915             code = RXAFS_GetVolumeStatus(callp, scp->fid.volume,
916                                          &volStat, &Name, &OfflineMsg, &MOTD);
917             rx_PutConnection(callp);
918
919         } while (cm_Analyze(connp, userp, &req, &scp->fid, NULL, NULL, NULL, code));
920         code = cm_MapRPCError(code, &req);
921     }
922
923     cm_ReleaseSCache(scp);
924     if (code) return code;
925
926     /* Copy all this junk into msg->im_data, keeping track of the lengths. */
927     cp = ioctlp->outDatap;
928     memcpy(cp, (char *)&volStat, sizeof(AFSFetchVolumeStatus));
929     cp += sizeof(AFSFetchVolumeStatus);
930     StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), volName);
931     cp += strlen(volName)+1;
932     StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), offLineMsg);
933     cp += strlen(offLineMsg)+1;
934     StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), motd);
935     cp += strlen(motd)+1;
936
937     /* return new size */
938     ioctlp->outDatap = cp;
939
940     return 0;
941 }
942
943 long cm_IoctlGetFid(struct smb_ioctl *ioctlp, struct cm_user *userp)
944 {
945     cm_scache_t *scp;
946     register long code;
947     register char *cp;
948     cm_fid_t fid;
949     cm_req_t req;
950
951     cm_InitReq(&req);
952
953     code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
954     if (code) return code;
955
956     memset(&fid, 0, sizeof(cm_fid_t));
957     fid.volume = scp->fid.volume;
958     fid.vnode  = scp->fid.vnode;
959     fid.unique = scp->fid.unique;
960
961     cm_ReleaseSCache(scp);
962
963     /* Copy all this junk into msg->im_data, keeping track of the lengths. */
964     cp = ioctlp->outDatap;
965     memcpy(cp, (char *)&fid, sizeof(cm_fid_t));
966     cp += sizeof(cm_fid_t);
967
968     /* return new size */
969     ioctlp->outDatap = cp;
970
971     return 0;
972 }
973
974 long cm_IoctlGetOwner(struct smb_ioctl *ioctlp, struct cm_user *userp)
975 {
976     cm_scache_t *scp;
977     register long code;
978     register char *cp;
979     cm_req_t req;
980
981     cm_InitReq(&req);
982
983     code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
984     if (code) return code;
985
986     /* Copy all this junk into msg->im_data, keeping track of the lengths. */
987     cp = ioctlp->outDatap;
988     memcpy(cp, (char *)&scp->owner, sizeof(afs_uint32));
989     cp += sizeof(afs_uint32);
990     memcpy(cp, (char *)&scp->group, sizeof(afs_uint32));
991     cp += sizeof(afs_uint32);
992
993     /* return new size */
994     ioctlp->outDatap = cp;
995
996     cm_ReleaseSCache(scp);
997
998     return 0;
999 }
1000
1001 long cm_IoctlWhereIs(struct smb_ioctl *ioctlp, struct cm_user *userp)
1002 {
1003     long code;
1004     cm_scache_t *scp;
1005     cm_cell_t *cellp;
1006     cm_volume_t *tvp;
1007     cm_serverRef_t **tsrpp, *current;
1008     cm_server_t *tsp;
1009     unsigned long volume;
1010     char *cp;
1011     cm_req_t req;
1012
1013     cm_InitReq(&req);
1014
1015     code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
1016     if (code) return code;
1017         
1018     volume = scp->fid.volume;
1019
1020     cellp = cm_FindCellByID(scp->fid.cell);
1021
1022     cm_ReleaseSCache(scp);
1023
1024     if (!cellp)
1025         return CM_ERROR_NOSUCHCELL;
1026
1027     code = cm_GetVolumeByID(cellp, volume, userp, &req, CM_GETVOL_FLAG_CREATE, &tvp);
1028     if (code) 
1029         return code;
1030         
1031     cp = ioctlp->outDatap;
1032         
1033     lock_ObtainMutex(&tvp->mx);
1034     tsrpp = cm_GetVolServers(tvp, volume);
1035     lock_ObtainRead(&cm_serverLock);
1036     for (current = *tsrpp; current; current = current->next) {
1037         tsp = current->server;
1038         memcpy(cp, (char *)&tsp->addr.sin_addr.s_addr, sizeof(long));
1039         cp += sizeof(long);
1040     }
1041     lock_ReleaseRead(&cm_serverLock);
1042     cm_FreeServerList(tsrpp, 0);
1043     lock_ReleaseMutex(&tvp->mx);
1044
1045     /* still room for terminating NULL, add it on */
1046     volume = 0; /* reuse vbl */
1047     memcpy(cp, (char *)&volume, sizeof(long));
1048     cp += sizeof(long);
1049
1050     ioctlp->outDatap = cp;
1051     cm_PutVolume(tvp);
1052     return 0;
1053 }       
1054
1055 long cm_IoctlStatMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
1056 {
1057     long code;
1058     cm_scache_t *dscp;
1059     cm_scache_t *scp;
1060     char *cp;
1061     cm_req_t req;
1062
1063     cm_InitReq(&req);
1064
1065     code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp);
1066     if (code) return code;
1067
1068     cp = ioctlp->inDatap;
1069
1070     code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &req, &scp);
1071     cm_ReleaseSCache(dscp);
1072     if (code) return code;
1073         
1074     lock_ObtainMutex(&scp->mx);
1075
1076     /* now check that this is a real mount point */
1077     if (scp->fileType != CM_SCACHETYPE_MOUNTPOINT) {
1078         lock_ReleaseMutex(&scp->mx);
1079         cm_ReleaseSCache(scp);
1080         return CM_ERROR_INVAL;
1081     }
1082
1083     code = cm_ReadMountPoint(scp, userp, &req);
1084     if (code == 0) {
1085         cp = ioctlp->outDatap;
1086         StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), scp->mountPointStringp);
1087         cp += strlen(cp) + 1;
1088         ioctlp->outDatap = cp;
1089     }
1090     lock_ReleaseMutex(&scp->mx);
1091     cm_ReleaseSCache(scp);
1092
1093     return code;
1094 }       
1095
1096 long cm_IoctlDeleteMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
1097 {
1098     long code;
1099     cm_scache_t *dscp;
1100     cm_scache_t *scp;
1101     char *cp;
1102     cm_req_t req;
1103
1104     cm_InitReq(&req);
1105
1106     code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp);
1107     if (code) return code;
1108
1109     cp = ioctlp->inDatap;
1110
1111     code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &req, &scp);
1112         
1113     /* if something went wrong, bail out now */
1114     if (code) {
1115         goto done2;
1116     }
1117         
1118     lock_ObtainMutex(&scp->mx);
1119     code = cm_SyncOp(scp, NULL, userp, &req, 0,
1120                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1121     if (code) {     
1122         lock_ReleaseMutex(&scp->mx);
1123         cm_ReleaseSCache(scp);
1124         goto done2;
1125     }
1126
1127     /* now check that this is a real mount point */
1128     if (scp->fileType != CM_SCACHETYPE_MOUNTPOINT) {
1129         lock_ReleaseMutex(&scp->mx);
1130         cm_ReleaseSCache(scp);
1131         code = CM_ERROR_INVAL;
1132         goto done1;
1133     }
1134
1135     /* time to make the RPC, so drop the lock */
1136     lock_ReleaseMutex(&scp->mx);
1137     cm_ReleaseSCache(scp);
1138
1139     /* easier to do it this way */
1140     code = cm_Unlink(dscp, cp, userp, &req);
1141     if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
1142         smb_NotifyChange(FILE_ACTION_REMOVED,
1143                           FILE_NOTIFY_CHANGE_DIR_NAME,
1144                           dscp, cp, NULL, TRUE);
1145
1146   done1:
1147     lock_ObtainMutex(&scp->mx);
1148     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1149     lock_ReleaseMutex(&scp->mx);
1150
1151   done2:
1152     cm_ReleaseSCache(dscp);
1153     return code;
1154 }
1155
1156 long cm_IoctlCheckServers(struct smb_ioctl *ioctlp, struct cm_user *userp)
1157 {
1158     cm_cell_t *cellp;
1159     chservinfo_t csi;
1160     char *tp;
1161     char *cp;
1162     long temp;
1163     cm_server_t *tsp;
1164     int haveCell;
1165         
1166     cm_SkipIoctlPath(ioctlp);   /* we don't care about the path */
1167     tp = ioctlp->inDatap;
1168     haveCell = 0;
1169
1170     memcpy(&temp, tp, sizeof(temp));
1171     if (temp == 0x12345678) {   /* For afs3.3 version */
1172         memcpy(&csi, tp, sizeof(csi));
1173         if (csi.tinterval >= 0) {
1174             cp = ioctlp->outDatap;
1175             memcpy(cp, (char *)&cm_daemonCheckDownInterval, sizeof(long));
1176             ioctlp->outDatap += sizeof(long);
1177             if (csi.tinterval > 0) {
1178                 if (!smb_SUser(userp))
1179                     return CM_ERROR_NOACCESS;
1180                 cm_daemonCheckDownInterval = csi.tinterval;
1181             }
1182             return 0;
1183         }
1184         if (csi.tsize)
1185             haveCell = 1;
1186         temp = csi.tflags;
1187         cp = csi.tbuffer;
1188     } else {    /* For pre afs3.3 versions */
1189         memcpy((char *)&temp, ioctlp->inDatap, sizeof(long));
1190         ioctlp->inDatap = cp = ioctlp->inDatap + sizeof(long);
1191         if (cp - ioctlp->inAllocp < ioctlp->inCopied)   /* still more data available */
1192             haveCell = 1;
1193     }       
1194
1195     /* 
1196      * 1: fast check, don't contact servers.
1197      * 2: local cell only.
1198      */
1199     if (haveCell) {
1200         /* have cell name, too */
1201         cellp = cm_GetCell(cp, 0);
1202         if (!cellp) 
1203             return CM_ERROR_NOSUCHCELL;
1204     }
1205     else cellp = (cm_cell_t *) 0;
1206     if (!cellp && (temp & 2)) {
1207         /* use local cell */
1208         cellp = cm_FindCellByID(1);
1209     }
1210     if (!(temp & 1)) {  /* if not fast, call server checker routine */
1211         /* check down servers */
1212         cm_CheckServers(CM_FLAG_CHECKDOWNSERVERS | CM_FLAG_CHECKUPSERVERS,
1213                          cellp);
1214     }       
1215
1216     /* now return the current down server list */
1217     cp = ioctlp->outDatap;
1218     lock_ObtainRead(&cm_serverLock);
1219     for (tsp = cm_allServersp; tsp; tsp=tsp->allNextp) {
1220         if (cellp && tsp->cellp != cellp) continue;     /* cell spec'd and wrong */
1221         if ((tsp->flags & CM_SERVERFLAG_DOWN)
1222              && tsp->type == CM_SERVER_FILE) {
1223             memcpy(cp, (char *)&tsp->addr.sin_addr.s_addr, sizeof(long));
1224             cp += sizeof(long);
1225         }
1226     }
1227     lock_ReleaseRead(&cm_serverLock);
1228
1229     ioctlp->outDatap = cp;
1230     return 0;
1231 }
1232
1233 long cm_IoctlGag(struct smb_ioctl *ioctlp, struct cm_user *userp)
1234 {
1235     /* we don't print anything superfluous, so we don't support the gag call */
1236     return CM_ERROR_INVAL;
1237 }
1238
1239 long cm_IoctlCheckVolumes(struct smb_ioctl *ioctlp, struct cm_user *userp)
1240 {
1241     cm_RefreshVolumes();
1242     return 0;
1243 }       
1244
1245 long cm_IoctlSetCacheSize(struct smb_ioctl *ioctlp, struct cm_user *userp)
1246 {
1247     afs_uint64 temp;
1248     long code;
1249
1250     cm_SkipIoctlPath(ioctlp);
1251
1252     memcpy(&temp, ioctlp->inDatap, sizeof(temp));
1253     if (temp == 0) 
1254         temp = cm_data.buf_nOrigBuffers;
1255     else {
1256         /* temp is in 1K units, convert to # of buffers */
1257         temp = temp / (cm_data.buf_blockSize / 1024);
1258     }       
1259
1260     /* now adjust the cache size */
1261     code = buf_SetNBuffers(temp);
1262
1263     return code;
1264 }
1265
1266 long cm_IoctlTraceControl(struct smb_ioctl *ioctlp, struct cm_user *userp)
1267 {
1268     long inValue;
1269         
1270     cm_SkipIoctlPath(ioctlp);
1271         
1272     memcpy(&inValue, ioctlp->inDatap, sizeof(long));
1273
1274     /* print trace */
1275     if (inValue & 8) {
1276         afsd_ForceTrace(FALSE);
1277         buf_ForceTrace(FALSE);
1278     }
1279         
1280     if (inValue & 2) {
1281         /* set tracing value to low order bit */
1282         if ((inValue & 1) == 0) {
1283             /* disable tracing */
1284             osi_LogDisable(afsd_logp);
1285             rx_DebugOnOff(FALSE);
1286         }
1287         else {
1288             /* enable tracing */
1289             osi_LogEnable(afsd_logp);
1290             rx_DebugOnOff(TRUE);
1291         }
1292     }
1293
1294     /* see if we're supposed to do a reset, too */
1295     if (inValue & 4) {
1296         osi_LogReset(afsd_logp);
1297     }
1298
1299     /* and copy out tracing flag */
1300     inValue = afsd_logp->enabled;       /* use as a temp vbl */
1301     memcpy(ioctlp->outDatap, &inValue, sizeof(long));
1302     ioctlp->outDatap += sizeof(long);
1303     return 0;
1304 }       
1305
1306 long cm_IoctlGetCacheParms(struct smb_ioctl *ioctlp, struct cm_user *userp)
1307 {
1308     cm_cacheParms_t parms;
1309
1310     memset(&parms, 0, sizeof(parms));
1311
1312     /* first we get, in 1K units, the cache size */
1313     parms.parms[0] = cm_data.buf_nbuffers * (cm_data.buf_blockSize / 1024);
1314
1315     /* and then the actual # of buffers in use (not in the free list, I guess,
1316      * will be what we do).
1317      */
1318     parms.parms[1] = (cm_data.buf_nbuffers - buf_CountFreeList()) * (cm_data.buf_blockSize / 1024);
1319
1320     memcpy(ioctlp->outDatap, &parms, sizeof(parms));
1321     ioctlp->outDatap += sizeof(parms);
1322
1323     return 0;
1324 }
1325
1326 long cm_IoctlGetCell(struct smb_ioctl *ioctlp, struct cm_user *userp)
1327 {
1328     long whichCell;
1329     long magic = 0;
1330     cm_cell_t *tcellp;
1331     cm_serverRef_t *serverRefp;
1332     cm_server_t *serverp;
1333     long i;
1334     char *cp;
1335     char *tp;
1336     char *basep;
1337
1338     cm_SkipIoctlPath(ioctlp);
1339
1340     tp = ioctlp->inDatap;
1341
1342     memcpy((char *)&whichCell, tp, sizeof(long));
1343     tp += sizeof(long);
1344
1345     /* see if more than one long passed in, ignoring the null pathname (the -1) */
1346     if (ioctlp->inCopied-1 > sizeof(long)) {
1347         memcpy((char *)&magic, tp, sizeof(long));
1348     }
1349
1350     lock_ObtainRead(&cm_cellLock);
1351     for (tcellp = cm_data.allCellsp; tcellp; tcellp = tcellp->allNextp) {
1352         if (whichCell == 0) break;
1353         whichCell--;
1354     }
1355     lock_ReleaseRead(&cm_cellLock);
1356     if (tcellp) {
1357         int max = 8;
1358
1359         cp = ioctlp->outDatap;
1360
1361         if (magic == 0x12345678) {
1362             memcpy(cp, (char *)&magic, sizeof(long));
1363             max = 13;
1364         }
1365         memset(cp, 0, max * sizeof(long));
1366         basep = cp;
1367         lock_ObtainRead(&cm_serverLock);        /* for going down server list */
1368         /* jaltman - do the reference counts to serverRefp contents need to be increased? */
1369         serverRefp = tcellp->vlServersp;
1370         for (i=0; i<max; i++) {
1371             if (!serverRefp) break;
1372             serverp = serverRefp->server;
1373             memcpy(cp, &serverp->addr.sin_addr.s_addr, sizeof(long));
1374             cp += sizeof(long);
1375             serverRefp = serverRefp->next;
1376         }
1377         lock_ReleaseRead(&cm_serverLock);
1378         cp = basep + max * sizeof(afs_int32);
1379         StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), tcellp->name);
1380         cp += strlen(tcellp->name)+1;
1381         ioctlp->outDatap = cp;
1382     }
1383
1384     if (tcellp) 
1385         return 0;
1386     else 
1387         return CM_ERROR_NOMORETOKENS;   /* mapped to EDOM */
1388 }
1389
1390 extern long cm_AddCellProc(void *rockp, struct sockaddr_in *addrp, char *namep);
1391
1392 long cm_IoctlNewCell(struct smb_ioctl *ioctlp, struct cm_user *userp)
1393 {
1394     /* NT cache manager will read cell information from CellServDB each time
1395      * cell is accessed. So, this call is necessary only if list of server for a cell 
1396      * changes (or IP addresses of cell servers changes).
1397      * All that needs to be done is to refresh server information for all cells that 
1398      * are already loaded.
1399   
1400      * cell list will be cm_CellLock and cm_ServerLock will be held for write.
1401      */  
1402   
1403     cm_cell_t *cp;
1404   
1405     cm_SkipIoctlPath(ioctlp);
1406     lock_ObtainWrite(&cm_cellLock);
1407   
1408     for (cp = cm_data.allCellsp; cp; cp=cp->allNextp) 
1409     {
1410         long code;
1411         lock_ObtainMutex(&cp->mx);
1412         /* delete all previous server lists - cm_FreeServerList will ask for write on cm_ServerLock*/
1413         cm_FreeServerList(&cp->vlServersp, CM_FREESERVERLIST_DELETE);
1414         cp->vlServersp = NULL;
1415         code = cm_SearchCellFile(cp->name, cp->name, cm_AddCellProc, cp);
1416 #ifdef AFS_AFSDB_ENV
1417         if (code) {
1418             if (cm_dnsEnabled) {
1419                 int ttl;
1420                 code = cm_SearchCellByDNS(cp->name, cp->name, &ttl, cm_AddCellProc, cp);
1421                 if ( code == 0 ) { /* got cell from DNS */
1422                     cp->flags |= CM_CELLFLAG_DNS;
1423                     cp->flags &= ~CM_CELLFLAG_VLSERVER_INVALID;
1424                     cp->timeout = time(0) + ttl;
1425                 }
1426             }
1427         } 
1428         else {
1429             cp->flags &= ~CM_CELLFLAG_DNS;
1430         }
1431 #endif /* AFS_AFSDB_ENV */
1432         if (code) {
1433             cp->flags |= CM_CELLFLAG_VLSERVER_INVALID;
1434         }
1435         else {
1436             cp->flags &= ~CM_CELLFLAG_VLSERVER_INVALID;
1437             cm_RandomizeServer(&cp->vlServersp);
1438         }
1439         lock_ReleaseMutex(&cp->mx);
1440     }
1441     
1442     lock_ReleaseWrite(&cm_cellLock);
1443     return 0;       
1444 }
1445
1446 long cm_IoctlGetWsCell(smb_ioctl_t *ioctlp, cm_user_t *userp)
1447 {
1448         long code = 0;
1449
1450         if (cm_freelanceEnabled) {
1451             if (cm_GetRootCellName(ioctlp->outDatap))
1452                 StringCbCopyA(ioctlp->outDatap, SMB_IOCTL_MAXDATA - (ioctlp->outDatap - ioctlp->outAllocp), "Freelance.Local.Root");
1453             ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
1454         } else if (cm_data.rootCellp) {
1455             /* return the default cellname to the caller */
1456             StringCbCopyA(ioctlp->outDatap, SMB_IOCTL_MAXDATA - (ioctlp->outDatap - ioctlp->outAllocp), cm_data.rootCellp->name);
1457             ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
1458         } else {
1459             /* if we don't know our default cell, return failure */
1460             code = CM_ERROR_NOSUCHCELL;
1461     }
1462
1463     return code;
1464 }
1465
1466 long cm_IoctlSysName(struct smb_ioctl *ioctlp, struct cm_user *userp)
1467 {
1468     long setSysName, foundname = 0;
1469     char *cp, *cp2, inname[MAXSYSNAME], outname[MAXSYSNAME];
1470     int t, count, num = 0;
1471     char **sysnamelist[MAXSYSNAME];
1472         
1473     cm_SkipIoctlPath(ioctlp);
1474
1475     memcpy(&setSysName, ioctlp->inDatap, sizeof(long));
1476     ioctlp->inDatap += sizeof(long);
1477         
1478     if (setSysName) {
1479         /* check my args */
1480         if ( setSysName < 0 || setSysName > MAXNUMSYSNAMES )
1481             return EINVAL;
1482         cp2 = ioctlp->inDatap;
1483         for ( cp=ioctlp->inDatap, count = 0; count < setSysName; count++ ) {
1484             /* won't go past end of ioctlp->inDatap since maxsysname*num < ioctlp->inDatap length */
1485             t = (int)strlen(cp);
1486             if (t >= MAXSYSNAME || t <= 0)
1487                 return EINVAL;
1488             /* check for names that can shoot us in the foot */
1489             if (*cp == '.' && (cp[1] == 0 || (cp[1] == '.' && cp[2] == 0)))
1490                 return EINVAL;
1491             cp += t + 1;
1492         }
1493         /* args ok */
1494
1495         /* inname gets first entry in case we're being a translator */
1496         /* (we are never a translator) */
1497         t = (int)strlen(ioctlp->inDatap);
1498         memcpy(inname, ioctlp->inDatap, t + 1);
1499         ioctlp->inDatap += t + 1;
1500         num = count;
1501     }
1502
1503     /* Not xlating, so local case */
1504     if (!cm_sysName)
1505         osi_panic("cm_IoctlSysName: !cm_sysName\n", __FILE__, __LINE__);
1506
1507     if (!setSysName) {      /* user just wants the info */
1508         StringCbCopyA(outname, sizeof(outname), cm_sysName);
1509         foundname = cm_sysNameCount;
1510         *sysnamelist = cm_sysNameList;
1511     } else {        
1512         /* Local guy; only root can change sysname */
1513         /* clear @sys entries from the dnlc, once afs_lookup can
1514          * do lookups of @sys entries and thinks it can trust them */
1515         /* privs ok, store the entry, ... */
1516         StringCbCopyA(cm_sysName, sizeof(cm_sysName), inname);
1517         StringCbCopyA(cm_sysNameList[0], MAXSYSNAME, inname);
1518         if (setSysName > 1) {       /* ... or list */
1519             cp = ioctlp->inDatap;
1520             for (count = 1; count < setSysName; ++count) {
1521                 if (!cm_sysNameList[count])
1522                     osi_panic("cm_IoctlSysName: no cm_sysNameList entry to write\n",
1523                                __FILE__, __LINE__);
1524                 t = (int)strlen(cp);
1525                 StringCbCopyA(cm_sysNameList[count], MAXSYSNAME, cp);
1526                 cp += t + 1;
1527             }
1528         }
1529         cm_sysNameCount = setSysName;
1530     }
1531
1532     if (!setSysName) {
1533         /* return the sysname to the caller */
1534         cp = ioctlp->outDatap;
1535         memcpy(cp, (char *)&foundname, sizeof(afs_int32));
1536         cp += sizeof(afs_int32);        /* skip found flag */
1537         if (foundname) {
1538             StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), outname);
1539             cp += strlen(outname) + 1;  /* skip name and terminating null char */
1540             for ( count=1; count < foundname ; ++count) {   /* ... or list */
1541                 if ( !(*sysnamelist)[count] )
1542                     osi_panic("cm_IoctlSysName: no cm_sysNameList entry to read\n", 
1543                                __FILE__, __LINE__);
1544                 t = (int)strlen((*sysnamelist)[count]);
1545                 if (t >= MAXSYSNAME)
1546                     osi_panic("cm_IoctlSysName: sysname entry garbled\n", 
1547                                __FILE__, __LINE__);
1548                 StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), (*sysnamelist)[count]);
1549                 cp += t + 1;
1550             }
1551         }
1552         ioctlp->outDatap = cp;
1553     }
1554         
1555     /* done: success */
1556     return 0;
1557 }
1558
1559 long cm_IoctlGetCellStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
1560 {
1561     long temp;
1562     cm_cell_t *cellp;
1563
1564     cm_SkipIoctlPath(ioctlp);
1565
1566     cellp = cm_GetCell(ioctlp->inDatap, 0);
1567     if (!cellp) 
1568         return CM_ERROR_NOSUCHCELL;
1569
1570     temp = 0;
1571     lock_ObtainMutex(&cellp->mx);
1572     if (cellp->flags & CM_CELLFLAG_SUID)
1573         temp |= CM_SETCELLFLAG_SUID;
1574     lock_ReleaseMutex(&cellp->mx);
1575         
1576     /* now copy out parm */
1577     memcpy(ioctlp->outDatap, &temp, sizeof(long));
1578     ioctlp->outDatap += sizeof(long);
1579
1580     return 0;
1581 }
1582
1583 long cm_IoctlSetCellStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
1584 {
1585     long temp;
1586     cm_cell_t *cellp;
1587
1588     cm_SkipIoctlPath(ioctlp);
1589
1590     cellp = cm_GetCell(ioctlp->inDatap + 2*sizeof(long), 0);
1591     if (!cellp) 
1592         return CM_ERROR_NOSUCHCELL;
1593
1594     memcpy((char *)&temp, ioctlp->inDatap, sizeof(long));
1595
1596     lock_ObtainMutex(&cellp->mx);
1597     if (temp & CM_SETCELLFLAG_SUID)
1598         cellp->flags |= CM_CELLFLAG_SUID;
1599     else
1600         cellp->flags &= ~CM_CELLFLAG_SUID;
1601     lock_ReleaseMutex(&cellp->mx);
1602
1603     return 0;
1604 }
1605
1606 long cm_IoctlSetSPrefs(struct smb_ioctl *ioctlp, struct cm_user *userp)
1607 {
1608     cm_SSetPref_t         *spin; /* input */
1609     cm_SPref_t        *srvin;   /* one input component */
1610     cm_server_t       *tsp;
1611     int                   i, vlonly, noServers, type;
1612     struct sockaddr_in  tmp;
1613     unsigned short        rank;
1614
1615     cm_SkipIoctlPath(ioctlp);       /* we don't care about the path */
1616
1617     spin           = (cm_SSetPref_t *)ioctlp->inDatap;
1618     noServers  = spin->num_servers;
1619     vlonly     = spin->flags;
1620     if ( vlonly )
1621         type = CM_SERVER_VLDB;
1622     else    
1623         type = CM_SERVER_FILE;
1624
1625     for ( i=0; i < noServers; i++) 
1626     {
1627         srvin          = &(spin->servers[i]);
1628         rank           = srvin->rank + (rand() & 0x000f);
1629         tmp.sin_addr   = srvin->host;
1630         tmp.sin_family = AF_INET;
1631
1632         tsp = cm_FindServer(&tmp, type);
1633         if ( tsp )              /* an existing server - ref count increased */
1634         {
1635             tsp->ipRank = rank; /* no need to protect by mutex*/
1636
1637             if (type == CM_SERVER_FILE)
1638             {   /* fileserver */
1639                 /* find volumes which might have RO copy 
1640                 /* on server and change the ordering of 
1641                  * their RO list 
1642                  */
1643                 cm_ChangeRankVolume(tsp);
1644             }
1645             else        
1646             {
1647                 /* set preferences for an existing vlserver */
1648                 cm_ChangeRankCellVLServer(tsp);
1649             }
1650         }
1651         else    /* add a new server without a cell */
1652         {
1653             tsp = cm_NewServer(&tmp, type, NULL); /* refcount = 1 */
1654             tsp->ipRank = rank;
1655         }
1656         lock_ObtainMutex(&tsp->mx);
1657         tsp->flags |= CM_SERVERFLAG_PREF_SET;
1658         lock_ReleaseMutex(&tsp->mx);
1659         cm_PutServer(tsp);  /* decrease refcount */
1660     }
1661     return 0;
1662 }
1663
1664 long cm_IoctlGetSPrefs(struct smb_ioctl *ioctlp, struct cm_user *userp)
1665 {
1666     cm_SPrefRequest_t *spin; /* input */
1667     cm_SPrefInfo_t    *spout;   /* output */
1668     cm_SPref_t        *srvout;   /* one output component */
1669     cm_server_t       *tsp;
1670     int                   i, vlonly, noServers;
1671
1672     cm_SkipIoctlPath(ioctlp);       /* we don't care about the path */
1673
1674     spin      = (cm_SPrefRequest_t *)ioctlp->inDatap;
1675     spout     = (cm_SPrefInfo_t *) ioctlp->outDatap;
1676     srvout    = spout->servers;
1677     noServers = spin->num_servers; 
1678     vlonly    = spin->flags & CM_SPREF_VLONLY;
1679     spout->num_servers = 0;
1680
1681     lock_ObtainRead(&cm_serverLock); /* get server lock */
1682
1683     for (tsp=cm_allServersp, i=0; tsp && noServers; tsp=tsp->allNextp,i++){
1684         if (spin->offset > i) {
1685             continue;    /* catch up to where we left off */
1686         }
1687
1688         if ( vlonly && (tsp->type == CM_SERVER_FILE) )
1689             continue;   /* ignore fileserver for -vlserver option*/
1690         if ( !vlonly && (tsp->type == CM_SERVER_VLDB) )
1691             continue;   /* ignore vlservers */
1692
1693         srvout->host = tsp->addr.sin_addr;
1694         srvout->rank = tsp->ipRank;
1695         srvout++;       
1696         spout->num_servers++;
1697         noServers--;
1698     }
1699     lock_ReleaseRead(&cm_serverLock); /* release server lock */
1700
1701     if ( tsp )  /* we ran out of space in the output buffer */
1702         spout->next_offset = i;
1703     else    
1704         spout->next_offset = 0; 
1705     ioctlp->outDatap += sizeof(cm_SPrefInfo_t) + 
1706         (spout->num_servers -1 ) * sizeof(cm_SPref_t) ;
1707     return 0;
1708 }
1709
1710 long cm_IoctlStoreBehind(struct smb_ioctl *ioctlp, struct cm_user *userp)
1711 {
1712     /* we ignore default asynchrony since we only have one way
1713      * of doing this today.
1714      */
1715     return 0;
1716 }       
1717
1718 long cm_IoctlCreateMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
1719 {
1720     char leaf[LEAF_SIZE];
1721     long code;
1722     cm_scache_t *dscp;
1723     cm_attr_t tattr;
1724     char *cp;
1725     cm_req_t req;
1726     char mpInfo[256];
1727     char fullCell[256];
1728     char volume[256];
1729     char cell[256];
1730     int ttl;
1731
1732     cm_InitReq(&req);
1733         
1734     code = cm_ParseIoctlParent(ioctlp, userp, &req, &dscp, leaf);
1735     if (code) 
1736         return code;
1737
1738     /* Translate chars for the mount point name */
1739     TranslateExtendedChars(leaf);
1740
1741     /* 
1742      * The fs command allows the user to specify partial cell names on NT.  These must
1743      * be expanded to the full cell name for mount points so that the mount points will
1744      * work on UNIX clients.
1745      */
1746
1747     /* Extract the possibly partial cell name */
1748     StringCbCopyA(cell, sizeof(cell), ioctlp->inDatap + 1);      /* Skip the mp type character */
1749         
1750     if (cp = strchr(cell, ':')) {
1751         /* Extract the volume name */
1752         *cp = 0;
1753         StringCbCopyA(volume,  sizeof(volume), cp + 1);
1754         
1755         /* Get the full name for this cell */
1756         code = cm_SearchCellFile(cell, fullCell, 0, 0);
1757 #ifdef AFS_AFSDB_ENV
1758         if (code && cm_dnsEnabled)
1759             code = cm_SearchCellByDNS(cell, fullCell, &ttl, 0, 0);
1760 #endif
1761         if (code) {
1762             cm_ReleaseSCache(dscp);
1763             return CM_ERROR_NOSUCHCELL;
1764         }
1765         
1766         StringCbPrintfA(mpInfo, sizeof(mpInfo), "%c%s:%s", *ioctlp->inDatap, fullCell, volume);
1767     } else {
1768         /* No cell name specified */
1769         StringCbCopyA(mpInfo, sizeof(mpInfo), ioctlp->inDatap);
1770     }
1771
1772 #ifdef AFS_FREELANCE_CLIENT
1773     if (cm_freelanceEnabled && dscp == cm_data.rootSCachep) {
1774         /* we are adding the mount point to the root dir., so call
1775          * the freelance code to do the add. */
1776         osi_Log0(afsd_logp,"IoctlCreateMountPoint within Freelance root dir");
1777         code = cm_FreelanceAddMount(leaf, fullCell, volume, 
1778                                     *ioctlp->inDatap == '%', NULL);
1779         cm_ReleaseSCache(dscp);
1780         return code;
1781     }
1782 #endif
1783     /* create the symlink with mode 644.  The lack of X bits tells
1784      * us that it is a mount point.
1785      */
1786     tattr.mask = CM_ATTRMASK_UNIXMODEBITS | CM_ATTRMASK_CLIENTMODTIME;
1787     tattr.unixModeBits = 0644;
1788     tattr.clientModTime = time(NULL);
1789
1790     code = cm_SymLink(dscp, leaf, mpInfo, 0, &tattr, userp, &req);
1791     if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
1792         smb_NotifyChange(FILE_ACTION_ADDED,
1793                          FILE_NOTIFY_CHANGE_DIR_NAME,
1794                          dscp, leaf, NULL, TRUE);
1795
1796     cm_ReleaseSCache(dscp);
1797     return code;
1798 }
1799
1800 long cm_IoctlSymlink(struct smb_ioctl *ioctlp, struct cm_user *userp)
1801 {
1802     char leaf[LEAF_SIZE];
1803     long code;
1804     cm_scache_t *dscp;
1805     cm_attr_t tattr;
1806     char *cp;
1807     cm_req_t req;
1808
1809     cm_InitReq(&req);
1810
1811     code = cm_ParseIoctlParent(ioctlp, userp, &req, &dscp, leaf);
1812     if (code) return code;
1813
1814     /* Translate chars for the link name */
1815     TranslateExtendedChars(leaf);
1816
1817     /* Translate chars for the linked to name */
1818     TranslateExtendedChars(ioctlp->inDatap);
1819
1820     cp = ioctlp->inDatap;               /* contents of link */
1821
1822 #ifdef AFS_FREELANCE_CLIENT
1823     if (cm_freelanceEnabled && dscp == cm_data.rootSCachep) {
1824         /* we are adding the symlink to the root dir., so call
1825          * the freelance code to do the add. */
1826         if (cp[0] == cp[1] && cp[1] == '\\' && 
1827             !_strnicmp(cm_NetbiosName,cp+2,strlen(cm_NetbiosName))) 
1828         {
1829             /* skip \\AFS\ or \\AFS\all\ */
1830             char * p;
1831             p = cp + 2 + strlen(cm_NetbiosName) + 1;
1832             if ( !_strnicmp("all", p, 3) )
1833                 p += 4;
1834             cp = p;
1835         }
1836         osi_Log0(afsd_logp,"IoctlCreateSymlink within Freelance root dir");
1837         code = cm_FreelanceAddSymlink(leaf, cp, NULL);
1838         cm_ReleaseSCache(dscp);
1839         return code;
1840     }
1841 #endif
1842
1843     /* Create symlink with mode 0755. */
1844     tattr.mask = CM_ATTRMASK_UNIXMODEBITS;
1845     tattr.unixModeBits = 0755;
1846
1847     code = cm_SymLink(dscp, leaf, cp, 0, &tattr, userp, &req);
1848     if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
1849         smb_NotifyChange(FILE_ACTION_ADDED,
1850                           FILE_NOTIFY_CHANGE_FILE_NAME
1851                           | FILE_NOTIFY_CHANGE_DIR_NAME,
1852                           dscp, leaf, NULL, TRUE);
1853
1854     cm_ReleaseSCache(dscp);
1855
1856     return code;
1857 }
1858
1859
1860 long cm_IoctlListlink(struct smb_ioctl *ioctlp, struct cm_user *userp)
1861 {
1862     long code;
1863     cm_scache_t *dscp;
1864     cm_scache_t *scp;
1865     char *cp;
1866     cm_space_t *spacep;
1867     cm_scache_t *newRootScp;
1868     cm_req_t req;
1869
1870     cm_InitReq(&req);
1871
1872     code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp);
1873     if (code) return code;
1874
1875     cp = ioctlp->inDatap;
1876
1877     code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &req, &scp);
1878     cm_ReleaseSCache(dscp);
1879     if (code) return code;
1880
1881     /* Check that it's a real symlink */
1882     if (scp->fileType != CM_SCACHETYPE_SYMLINK &&
1883         scp->fileType != CM_SCACHETYPE_DFSLINK &&
1884         scp->fileType != CM_SCACHETYPE_INVALID) {
1885         cm_ReleaseSCache(scp);
1886         return CM_ERROR_INVAL;
1887     }
1888
1889     code = cm_AssembleLink(scp, "", &newRootScp, &spacep, userp, &req);
1890     cm_ReleaseSCache(scp);
1891     if (code == 0) {
1892         cp = ioctlp->outDatap;
1893         if (newRootScp != NULL) {
1894             StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), cm_mountRoot);
1895             StringCbCatA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), "/");
1896             cp += strlen(cp);
1897         }
1898         StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), spacep->data);
1899         cp += strlen(cp) + 1;
1900         ioctlp->outDatap = cp;
1901         cm_FreeSpace(spacep);
1902         if (newRootScp != NULL)
1903             cm_ReleaseSCache(newRootScp);
1904         code = 0;
1905     } else if (code == CM_ERROR_PATH_NOT_COVERED && 
1906                 scp->fileType == CM_SCACHETYPE_DFSLINK ||
1907                code == CM_ERROR_NOSUCHPATH &&
1908                 scp->fileType == CM_SCACHETYPE_INVALID) {
1909
1910         cp = ioctlp->outDatap;
1911         StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), scp->mountPointStringp);
1912         cp += strlen(cp) + 1;
1913         ioctlp->outDatap = cp;
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
2944 long cm_IoctlVolStatTest(struct smb_ioctl *ioctlp, struct cm_user *userp)
2945 {
2946     long code;
2947     cm_cell_t *cellp = NULL;
2948     cm_volume_t *volp;
2949     cm_vol_state_t *statep;
2950     struct VolStatTest * testp;
2951     cm_req_t req;
2952     afs_uint32 n;
2953     size_t len;
2954
2955     cm_InitReq(&req);
2956
2957     cm_SkipIoctlPath(ioctlp);   /* we don't care about the path */
2958     testp = (struct VolStatTest *)ioctlp->inDatap;
2959
2960 #ifdef AFS_FREELANCE_CLIENT
2961     if (testp->fid.cell == -1) 
2962         return CM_ERROR_NOACCESS;
2963 #endif
2964
2965     if (testp->flags & VOLSTAT_TEST_CHECK_VOLUME) {
2966         cm_CheckOfflineVolumes();
2967         return 0;
2968     }
2969
2970     if (testp->flags & VOLSTAT_TEST_NETWORK_UP) {
2971         cm_VolStatus_Network_Started(cm_NetbiosName
2972 #ifdef _WIN64
2973                                   , cm_NetbiosName
2974 #endif
2975                                   );
2976         return 0;
2977     }
2978
2979     if (testp->flags & VOLSTAT_TEST_NETWORK_DOWN) {
2980         cm_VolStatus_Network_Stopped(cm_NetbiosName
2981 #ifdef _WIN64
2982                                   , cm_NetbiosName
2983 #endif
2984                                   );
2985         return 0;
2986     }
2987
2988     if (testp->cellname[0]) {
2989         n = atoi(testp->cellname);
2990         if (n)
2991             testp->fid.cell = n;
2992         else
2993             cellp = cm_GetCell(testp->cellname, 0);
2994     }
2995
2996     if (testp->fid.cell > 0) {
2997         cellp = cm_FindCellByID(testp->fid.cell);
2998     }
2999
3000     if (!cellp)
3001         return CM_ERROR_NOSUCHCELL;
3002
3003     if (testp->volname[0]) {
3004         n = atoi(testp->volname);
3005         if (n)
3006             testp->fid.volume = n;
3007         else
3008             code = cm_GetVolumeByName(cellp, testp->volname, userp, &req, CM_GETVOL_FLAG_NO_LRU_UPDATE, &volp);
3009     }
3010
3011     if (testp->fid.volume > 0)
3012         code = cm_GetVolumeByID(cellp, testp->fid.volume, userp, &req, CM_GETVOL_FLAG_NO_LRU_UPDATE, &volp);
3013
3014     if (code)
3015         return code;
3016         
3017     if (testp->fid.volume) {
3018         if (testp->fid.volume == volp->rw.ID)
3019             statep = &volp->rw;
3020         else if (testp->fid.volume == volp->ro.ID)
3021             statep = &volp->ro;
3022         else
3023             statep = &volp->bk;
3024     } else {
3025         len = strlen(testp->volname);
3026
3027         if (stricmp(".readonly", &testp->volname[len-9]) == 0)
3028             statep = &volp->ro;
3029         else if (stricmp(".backup", &testp->volname[len-7]) == 0)
3030             statep = &volp->bk;
3031         else 
3032             statep = &volp->rw;
3033     }
3034
3035     if (statep) {
3036         statep->state = testp->state;
3037         code = cm_VolStatus_Change_Notification(cellp->cellID, statep->ID, testp->state);
3038     }
3039
3040     cm_PutVolume(volp);
3041
3042     return code;
3043 }       
3044
3045