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