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