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