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