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