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