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