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