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