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