2 * Copyright 2000, International Business Machines Corporation and others.
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
10 #include <afs/param.h>
16 #include <sys/socket.h>
28 #include "afsd_init.h"
29 #include <WINNT\afsreg.h>
32 #include "cm_server.h"
45 #include <..\afsrdr\kif.h>
51 /* Copied from afs_tokens.h */
52 #define PIOCTL_LOGON 0x1
55 osi_mutex_t cm_Afsdsbmt_Lock;
57 extern afs_int32 cryptall;
58 extern char cm_NetbiosName[];
60 extern void afsi_log(char *pattern, ...);
62 void cm_InitIoctl(void)
64 lock_InitializeMutex(&cm_Afsdsbmt_Lock, "AFSDSBMT.INI Access Lock");
67 long cm_FlushFile(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
71 lock_ObtainWrite(&scp->bufCreateLock);
72 code = buf_FlushCleanPages(scp, userp, reqp);
74 lock_ObtainMutex(&scp->mx);
75 scp->cbServerp = NULL;
79 cm_FreeAllACLEnts(scp);
80 lock_ReleaseMutex(&scp->mx);
82 lock_ReleaseWrite(&scp->bufCreateLock);
87 * cm_ResetACLCache -- invalidate ACL info for a user that has just
88 * obtained or lost tokens
90 void cm_ResetACLCache(cm_user_t *userp)
95 lock_ObtainWrite(&cm_scacheLock);
96 for (hash=0; hash < cm_data.hashTableSize; hash++) {
97 for (scp=cm_data.hashTablep[hash]; scp; scp=scp->nextp) {
98 cm_HoldSCacheNoLock(scp);
99 lock_ReleaseWrite(&cm_scacheLock);
100 lock_ObtainMutex(&scp->mx);
101 cm_InvalidateACLUser(scp, userp);
102 lock_ReleaseMutex(&scp->mx);
103 lock_ObtainWrite(&cm_scacheLock);
104 cm_ReleaseSCacheNoLock(scp);
107 lock_ReleaseWrite(&cm_scacheLock);
111 * TranslateExtendedChars - This is a fix for TR 54482.
113 * If an extended character (80 - FF) is entered into a file
114 * or directory name in Windows, the character is translated
115 * into the OEM character map before being passed to us. Why
116 * this occurs is unknown. Our pioctl functions must match
117 * this translation for paths given via our own commands (like
118 * fs). If we do not do this, then we will try to perform an
119 * operation on a non-translated path, which we will fail to
120 * find, since the path was created with the translated chars.
121 * This function performs the required translation.
123 void TranslateExtendedChars(char *str)
136 while (*p) *p++ &= 0x7f; /* turn off high bit; probably not right */
140 /* parse the passed-in file name and do a namei on it. If we fail,
141 * return an error code, otherwise return the vnode located in *scpp.
143 long cm_ParseIoctlPath(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
147 cm_scache_t *substRootp;
148 char * relativePath = ioctlp->inDatap, absRoot[MAX_PATH];
149 wchar_t absRoot_w[MAX_PATH];
152 /* This is usually the file name, but for StatMountPoint it is the path. */
153 /* ioctlp->inDatap can be either of the form:
156 * \\netbios-name\submount\path\.
157 * \\netbios-name\submount\path\file
159 TranslateExtendedChars(relativePath);
162 /* we have passed the whole path, including the afs prefix.
163 when the pioctl call is made, we perform an ioctl to afsrdr
164 and it returns the correct (full) path. therefore, there is
165 no drive letter, and the path is absolute. */
166 code = cm_NameI(cm_data.rootSCachep, relativePath,
167 CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
168 userp, "", reqp, scpp);
173 /* # of bytes of path */
174 code = strlen(ioctlp->inDatap) + 1;
175 ioctlp->inDatap += code;
177 /* This is usually nothing, but for StatMountPoint it is the file name. */
178 TranslateExtendedChars(ioctlp->inDatap);
183 if (relativePath[0] == relativePath[1] &&
184 relativePath[1] == '\\' &&
185 !_strnicmp(cm_NetbiosName,relativePath+2,strlen(cm_NetbiosName)))
191 /* We may have found a UNC path.
192 * If the first component is the NetbiosName,
193 * then throw out the second component (the submount)
194 * since it had better expand into the value of ioctl->tidPathp
197 p = relativePath + 2 + strlen(cm_NetbiosName) + 1; /* buffer overflow vuln.? */
198 if ( !_strnicmp("all", p, 3) )
201 for (i = 0; *p && *p != '\\'; i++,p++ ) {
204 p++; /* skip past trailing slash */
205 shareName[i] = 0; /* terminate string */
207 shareFound = smb_FindShare(ioctlp->fidp->vcp, ioctlp->uidp, shareName, &sharePath);
209 /* we found a sharename, therefore use the resulting path */
210 code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
211 CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
212 userp, sharePath, reqp, &substRootp);
217 code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
218 userp, NULL, reqp, scpp);
222 /* otherwise, treat the name as a cellname mounted off the afs root.
223 * This requires that we reconstruct the shareName string with
224 * leading and trailing slashes.
226 p = relativePath + 2 + strlen(cm_NetbiosName) + 1;
227 if ( !_strnicmp("all", p, 3) )
231 for (i = 1; *p && *p != '\\'; i++,p++ ) {
234 p++; /* skip past trailing slash */
235 shareName[i++] = '/'; /* add trailing slash */
236 shareName[i] = 0; /* terminate string */
239 code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
240 CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
241 userp, shareName, reqp, &substRootp);
245 code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
246 userp, NULL, reqp, scpp);
251 code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
252 CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
253 userp, ioctlp->tidPathp, reqp, &substRootp);
257 code = cm_NameI(substRootp, relativePath, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
258 userp, NULL, reqp, scpp);
263 /* # of bytes of path */
264 code = strlen(ioctlp->inDatap) + 1;
265 ioctlp->inDatap += code;
267 /* This is usually nothing, but for StatMountPoint it is the file name. */
268 TranslateExtendedChars(ioctlp->inDatap);
270 /* and return success */
274 void cm_SkipIoctlPath(smb_ioctl_t *ioctlp)
278 temp = strlen(ioctlp->inDatap) + 1;
279 ioctlp->inDatap += temp;
283 /* format the specified path to look like "/afs/<cellname>/usr", by
284 * adding "/afs" (if necessary) in front, changing any \'s to /'s, and
285 * removing any trailing "/"'s. One weirdo caveat: "/afs" will be
286 * intentionally returned as "/afs/"--this makes submount manipulation
287 * easier (because we can always jump past the initial "/afs" to find
288 * the AFS path that should be written into afsdsbmt.ini).
290 void cm_NormalizeAfsPath(char *outpathp, long outlen, char *inpathp)
293 char bslash_mountRoot[256];
295 strncpy(bslash_mountRoot, cm_mountRoot, sizeof(bslash_mountRoot) - 1);
296 bslash_mountRoot[0] = '\\';
298 if (!strnicmp (inpathp, cm_mountRoot, strlen(cm_mountRoot)))
299 StringCbCopy(outpathp, outlen, inpathp);
300 else if (!strnicmp (inpathp, bslash_mountRoot, strlen(bslash_mountRoot)))
301 StringCbCopy(outpathp, outlen, inpathp);
302 else if ((inpathp[0] == '/') || (inpathp[0] == '\\'))
303 StringCbPrintfA(outpathp, outlen, "%s%s", cm_mountRoot, inpathp);
304 else // inpathp looks like "<cell>/usr"
305 StringCbPrintfA(outpathp, outlen, "%s/%s", cm_mountRoot, inpathp);
307 for (cp = outpathp; *cp != 0; ++cp) {
312 if (strlen(outpathp) && (outpathp[strlen(outpathp)-1] == '/')) {
313 outpathp[strlen(outpathp)-1] = 0;
316 if (!strcmpi (outpathp, cm_mountRoot)) {
317 StringCbCopy(outpathp, outlen, cm_mountRoot);
321 #define LEAF_SIZE 256
322 /* parse the passed-in file name and do a namei on its parent. If we fail,
323 * return an error code, otherwise return the vnode located in *scpp.
325 long cm_ParseIoctlParent(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
326 cm_scache_t **scpp, char *leafp)
331 cm_scache_t *substRootp;
333 StringCbCopyA(tbuffer, sizeof(tbuffer), ioctlp->inDatap);
334 tp = strrchr(tbuffer, '\\');
335 jp = strrchr(tbuffer, '/');
338 else if (jp && (tp - tbuffer) < (jp - tbuffer))
341 StringCbCopyA(tbuffer, sizeof(tbuffer), "\\");
343 StringCbCopyA(leafp, LEAF_SIZE, ioctlp->inDatap);
348 StringCbCopyA(leafp, LEAF_SIZE, tp+1);
351 if (tbuffer[0] == tbuffer[1] &&
352 tbuffer[1] == '\\' &&
353 !_strnicmp(cm_NetbiosName,tbuffer+2,strlen(cm_NetbiosName)))
359 /* We may have found a UNC path.
360 * If the first component is the NetbiosName,
361 * then throw out the second component (the submount)
362 * since it had better expand into the value of ioctl->tidPathp
365 p = tbuffer + 2 + strlen(cm_NetbiosName) + 1;
366 if ( !_strnicmp("all", p, 3) )
369 for (i = 0; *p && *p != '\\'; i++,p++ ) {
372 p++; /* skip past trailing slash */
373 shareName[i] = 0; /* terminate string */
375 shareFound = smb_FindShare(ioctlp->fidp->vcp, ioctlp->uidp, shareName, &sharePath);
377 /* we found a sharename, therefore use the resulting path */
378 code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
379 CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
380 userp, sharePath, reqp, &substRootp);
382 if (code) return code;
384 code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
385 userp, NULL, reqp, scpp);
386 if (code) return code;
388 /* otherwise, treat the name as a cellname mounted off the afs root.
389 * This requires that we reconstruct the shareName string with
390 * leading and trailing slashes.
392 p = tbuffer + 2 + strlen(cm_NetbiosName) + 1;
393 if ( !_strnicmp("all", p, 3) )
397 for (i = 1; *p && *p != '\\'; i++,p++ ) {
400 p++; /* skip past trailing slash */
401 shareName[i++] = '/'; /* add trailing slash */
402 shareName[i] = 0; /* terminate string */
404 code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
405 CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
406 userp, shareName, reqp, &substRootp);
407 if (code) return code;
409 code = cm_NameI(substRootp, p, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
410 userp, NULL, reqp, scpp);
411 if (code) return code;
414 code = cm_NameI(cm_data.rootSCachep, ioctlp->prefix->data,
415 CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
416 userp, ioctlp->tidPathp, reqp, &substRootp);
417 if (code) return code;
419 code = cm_NameI(substRootp, tbuffer, CM_FLAG_FOLLOW,
420 userp, NULL, reqp, scpp);
421 if (code) return code;
424 /* # of bytes of path */
425 code = strlen(ioctlp->inDatap) + 1;
426 ioctlp->inDatap += code;
428 /* and return success */
432 long cm_IoctlGetACL(smb_ioctl_t *ioctlp, cm_user_t *userp)
437 AFSFetchStatus fileStatus;
443 struct rx_connection * callp;
447 code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
448 if (code) return code;
450 /* now make the get acl call */
451 fid.Volume = scp->fid.volume;
452 fid.Vnode = scp->fid.vnode;
453 fid.Unique = scp->fid.unique;
455 acl.AFSOpaque_val = ioctlp->outDatap;
456 acl.AFSOpaque_len = 0;
457 code = cm_Conn(&scp->fid, userp, &req, &connp);
460 callp = cm_GetRxConn(connp);
461 code = RXAFS_FetchACL(callp, &fid, &acl, &fileStatus, &volSync);
462 rx_PutConnection(callp);
464 } while (cm_Analyze(connp, userp, &req, &scp->fid, &volSync, NULL, NULL, code));
465 code = cm_MapRPCError(code, &req);
466 cm_ReleaseSCache(scp);
468 if (code) return code;
470 /* skip over return data */
471 tlen = strlen(ioctlp->outDatap) + 1;
472 ioctlp->outDatap += tlen;
474 /* and return success */
478 long cm_IoctlGetFileCellName(struct smb_ioctl *ioctlp, struct cm_user *userp)
487 code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
488 if (code) return code;
490 #ifdef AFS_FREELANCE_CLIENT
491 if ( cm_freelanceEnabled &&
492 scp->fid.cell==AFS_FAKE_ROOT_CELL_ID &&
493 scp->fid.volume==AFS_FAKE_ROOT_VOL_ID &&
494 scp->fid.vnode==0x1 && scp->fid.unique==0x1 ) {
495 StringCbCopyA(ioctlp->outDatap, 999999, "Freelance.Local.Root");
496 ioctlp->outDatap += strlen(ioctlp->outDatap) + 1;
499 #endif /* AFS_FREELANCE_CLIENT */
501 cellp = cm_FindCellByID(scp->fid.cell);
503 StringCbCopyA(ioctlp->outDatap, 999999, cellp->name);
504 ioctlp->outDatap += strlen(ioctlp->outDatap) + 1;
508 code = CM_ERROR_NOSUCHCELL;
511 cm_ReleaseSCache(scp);
515 long cm_IoctlSetACL(struct smb_ioctl *ioctlp, struct cm_user *userp)
520 AFSFetchStatus fileStatus;
525 struct rx_connection * callp;
529 code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
530 if (code) return code;
532 /* now make the get acl call */
533 fid.Volume = scp->fid.volume;
534 fid.Vnode = scp->fid.vnode;
535 fid.Unique = scp->fid.unique;
537 acl.AFSOpaque_val = ioctlp->inDatap;
538 acl.AFSOpaque_len = strlen(ioctlp->inDatap)+1;
539 code = cm_Conn(&scp->fid, userp, &req, &connp);
542 callp = cm_GetRxConn(connp);
543 code = RXAFS_StoreACL(callp, &fid, &acl, &fileStatus, &volSync);
544 rx_PutConnection(callp);
546 } while (cm_Analyze(connp, userp, &req, &scp->fid, &volSync, NULL, NULL, code));
547 code = cm_MapRPCError(code, &req);
549 /* invalidate cache info, since we just trashed the ACL cache */
550 lock_ObtainMutex(&scp->mx);
551 cm_DiscardSCache(scp);
552 lock_ReleaseMutex(&scp->mx);
554 cm_ReleaseSCache(scp);
559 long cm_IoctlFlushVolume(struct smb_ioctl *ioctlp, struct cm_user *userp)
563 unsigned long volume;
569 code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
570 if (code) return code;
572 volume = scp->fid.volume;
573 cm_ReleaseSCache(scp);
575 lock_ObtainWrite(&cm_scacheLock);
576 for (i=0; i<cm_data.hashTableSize; i++) {
577 for (scp = cm_data.hashTablep[i]; scp; scp = scp->nextp) {
578 if (scp->fid.volume == volume) {
579 cm_HoldSCacheNoLock(scp);
580 lock_ReleaseWrite(&cm_scacheLock);
582 /* now flush the file */
583 code = cm_FlushFile(scp, userp, &req);
585 afsi_log("cm_FlushFile returns error: [%x]",code);
586 lock_ObtainWrite(&cm_scacheLock);
587 cm_ReleaseSCacheNoLock(scp);
591 lock_ReleaseWrite(&cm_scacheLock);
596 long cm_IoctlFlushFile(struct smb_ioctl *ioctlp, struct cm_user *userp)
604 code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
605 if (code) return code;
607 cm_FlushFile(scp, userp, &req);
608 cm_ReleaseSCache(scp);
613 long cm_IoctlSetVolumeStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
617 char offLineMsg[256];
621 AFSFetchVolumeStatus volStat;
622 AFSStoreVolumeStatus storeStat;
627 struct rx_connection * callp;
631 code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
632 if (code) return code;
634 cellp = cm_FindCellByID(scp->fid.cell);
637 if (scp->flags & CM_SCACHEFLAG_RO) {
638 cm_ReleaseSCache(scp);
639 return CM_ERROR_READONLY;
642 code = cm_GetVolumeByID(cellp, scp->fid.volume, userp, &req, &tvp);
644 cm_ReleaseSCache(scp);
648 /* Copy the junk out, using cp as a roving pointer. */
649 cp = ioctlp->inDatap;
650 memcpy((char *)&volStat, cp, sizeof(AFSFetchVolumeStatus));
651 cp += sizeof(AFSFetchVolumeStatus);
652 StringCbCopyA(volName, sizeof(volName), cp);
653 cp += strlen(volName)+1;
654 StringCbCopyA(offLineMsg, sizeof(offLineMsg), cp);
655 cp += strlen(offLineMsg)+1;
656 StringCbCopyA(motd, sizeof(motd), cp);
658 if (volStat.MinQuota != -1) {
659 storeStat.MinQuota = volStat.MinQuota;
660 storeStat.Mask |= AFS_SETMINQUOTA;
662 if (volStat.MaxQuota != -1) {
663 storeStat.MaxQuota = volStat.MaxQuota;
664 storeStat.Mask |= AFS_SETMAXQUOTA;
668 code = cm_Conn(&scp->fid, userp, &req, &tcp);
671 callp = cm_GetRxConn(tcp);
672 code = RXAFS_SetVolumeStatus(callp, scp->fid.volume,
673 &storeStat, volName, offLineMsg, motd);
674 rx_PutConnection(callp);
676 } while (cm_Analyze(tcp, userp, &req, &scp->fid, NULL, NULL, NULL, code));
677 code = cm_MapRPCError(code, &req);
679 /* return on failure */
680 cm_ReleaseSCache(scp);
685 /* we are sending parms back to make compat. with prev system. should
686 * change interface later to not ask for current status, just set
689 cp = ioctlp->outDatap;
690 memcpy(cp, (char *)&volStat, sizeof(VolumeStatus));
691 cp += sizeof(VolumeStatus);
692 StringCbCopyA(cp, 999999, volName);
693 cp += strlen(volName)+1;
694 StringCbCopyA(cp, 999999, offLineMsg);
695 cp += strlen(offLineMsg)+1;
696 StringCbCopyA(cp, 999999, motd);
697 cp += strlen(motd)+1;
699 /* now return updated return data pointer */
700 ioctlp->outDatap = cp;
705 long cm_IoctlGetVolumeStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
709 char offLineMsg[256];
713 AFSFetchVolumeStatus volStat;
719 struct rx_connection * callp;
723 code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
724 if (code) return code;
727 OfflineMsg = offLineMsg;
730 code = cm_Conn(&scp->fid, userp, &req, &tcp);
733 callp = cm_GetRxConn(tcp);
734 code = RXAFS_GetVolumeStatus(callp, scp->fid.volume,
735 &volStat, &Name, &OfflineMsg, &MOTD);
736 rx_PutConnection(callp);
738 } while (cm_Analyze(tcp, userp, &req, &scp->fid, NULL, NULL, NULL, code));
739 code = cm_MapRPCError(code, &req);
741 cm_ReleaseSCache(scp);
742 if (code) return code;
744 /* Copy all this junk into msg->im_data, keeping track of the lengths. */
745 cp = ioctlp->outDatap;
746 memcpy(cp, (char *)&volStat, sizeof(AFSFetchVolumeStatus));
747 cp += sizeof(AFSFetchVolumeStatus);
748 StringCbCopyA(cp, 999999, volName);
749 cp += strlen(volName)+1;
750 StringCbCopyA(cp, 999999, offLineMsg);
751 cp += strlen(offLineMsg)+1;
752 StringCbCopyA(cp, 999999, motd);
753 cp += strlen(motd)+1;
755 /* return new size */
756 ioctlp->outDatap = cp;
761 long cm_IoctlWhereIs(struct smb_ioctl *ioctlp, struct cm_user *userp)
767 cm_serverRef_t **tsrpp, *current;
769 unsigned long volume;
775 code = cm_ParseIoctlPath(ioctlp, userp, &req, &scp);
776 if (code) return code;
778 volume = scp->fid.volume;
780 cellp = cm_FindCellByID(scp->fid.cell);
783 cm_ReleaseSCache(scp);
785 code = cm_GetVolumeByID(cellp, volume, userp, &req, &tvp);
786 if (code) return code;
788 cp = ioctlp->outDatap;
790 lock_ObtainMutex(&tvp->mx);
791 tsrpp = cm_GetVolServers(tvp, volume);
792 lock_ObtainRead(&cm_serverLock);
793 for (current = *tsrpp; current; current = current->next) {
794 tsp = current->server;
795 memcpy(cp, (char *)&tsp->addr.sin_addr.s_addr, sizeof(long));
798 lock_ReleaseRead(&cm_serverLock);
799 cm_FreeServerList(tsrpp);
800 lock_ReleaseMutex(&tvp->mx);
802 /* still room for terminating NULL, add it on */
803 volume = 0; /* reuse vbl */
804 memcpy(cp, (char *)&volume, sizeof(long));
807 ioctlp->outDatap = cp;
812 long cm_IoctlStatMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
822 code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp);
823 if (code) return code;
825 cp = ioctlp->inDatap;
827 code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &req, &scp);
828 cm_ReleaseSCache(dscp);
829 if (code) return code;
831 lock_ObtainMutex(&scp->mx);
833 /* now check that this is a real mount point */
834 if (scp->fileType != CM_SCACHETYPE_MOUNTPOINT) {
835 lock_ReleaseMutex(&scp->mx);
836 cm_ReleaseSCache(scp);
837 return CM_ERROR_INVAL;
840 code = cm_ReadMountPoint(scp, userp, &req);
842 cp = ioctlp->outDatap;
843 StringCbCopyA(cp, 999999, scp->mountPointStringp);
844 cp += strlen(cp) + 1;
845 ioctlp->outDatap = cp;
847 lock_ReleaseMutex(&scp->mx);
848 cm_ReleaseSCache(scp);
853 long cm_IoctlDeleteMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
863 code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp);
864 if (code) return code;
866 cp = ioctlp->inDatap;
868 code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &req, &scp);
870 /* if something went wrong, bail out now */
875 lock_ObtainMutex(&scp->mx);
876 code = cm_SyncOp(scp, NULL, userp, &req, 0,
877 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
879 lock_ReleaseMutex(&scp->mx);
880 cm_ReleaseSCache(scp);
884 /* now check that this is a real mount point */
885 if (scp->fileType != CM_SCACHETYPE_MOUNTPOINT) {
886 lock_ReleaseMutex(&scp->mx);
887 cm_ReleaseSCache(scp);
888 code = CM_ERROR_INVAL;
892 /* time to make the RPC, so drop the lock */
893 lock_ReleaseMutex(&scp->mx);
894 cm_ReleaseSCache(scp);
896 /* easier to do it this way */
897 code = cm_Unlink(dscp, cp, userp, &req);
898 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
899 smb_NotifyChange(FILE_ACTION_REMOVED,
900 FILE_NOTIFY_CHANGE_DIR_NAME,
901 dscp, cp, NULL, TRUE);
904 cm_ReleaseSCache(dscp);
908 long cm_IoctlCheckServers(struct smb_ioctl *ioctlp, struct cm_user *userp)
918 cm_SkipIoctlPath(ioctlp); /* we don't care about the path */
919 tp = ioctlp->inDatap;
922 memcpy(&temp, tp, sizeof(temp));
923 if (temp == 0x12345678) { /* For afs3.3 version */
924 memcpy(&csi, tp, sizeof(csi));
925 if (csi.tinterval >= 0) {
926 cp = ioctlp->outDatap;
927 memcpy(cp, (char *)&cm_daemonCheckInterval, sizeof(long));
928 ioctlp->outDatap += sizeof(long);
929 if (csi.tinterval > 0) {
930 if (!smb_SUser(userp))
931 return CM_ERROR_NOACCESS;
932 cm_daemonCheckInterval = csi.tinterval;
940 } else { /* For pre afs3.3 versions */
941 memcpy((char *)&temp, ioctlp->inDatap, sizeof(long));
942 ioctlp->inDatap = cp = ioctlp->inDatap + sizeof(long);
943 if (cp - ioctlp->inAllocp < ioctlp->inCopied) /* still more data available */
948 * 1: fast check, don't contact servers.
949 * 2: local cell only.
952 /* have cell name, too */
953 cellp = cm_GetCell(cp, 0);
954 if (!cellp) return CM_ERROR_NOSUCHCELL;
956 else cellp = (cm_cell_t *) 0;
957 if (!cellp && (temp & 2)) {
959 cellp = cm_FindCellByID(1);
961 if (!(temp & 1)) { /* if not fast, call server checker routine */
962 /* check down servers */
963 cm_CheckServers(CM_FLAG_CHECKDOWNSERVERS | CM_FLAG_CHECKUPSERVERS,
967 /* now return the current down server list */
968 cp = ioctlp->outDatap;
969 lock_ObtainRead(&cm_serverLock);
970 for (tsp = cm_allServersp; tsp; tsp=tsp->allNextp) {
971 if (cellp && tsp->cellp != cellp) continue; /* cell spec'd and wrong */
972 if ((tsp->flags & CM_SERVERFLAG_DOWN)
973 && tsp->type == CM_SERVER_FILE) {
974 memcpy(cp, (char *)&tsp->addr.sin_addr.s_addr, sizeof(long));
978 lock_ReleaseRead(&cm_serverLock);
980 ioctlp->outDatap = cp;
984 long cm_IoctlGag(struct smb_ioctl *ioctlp, struct cm_user *userp)
986 /* we don't print anything superfluous, so we don't support the gag call */
987 return CM_ERROR_INVAL;
990 long cm_IoctlCheckVolumes(struct smb_ioctl *ioctlp, struct cm_user *userp)
996 long cm_IoctlSetCacheSize(struct smb_ioctl *ioctlp, struct cm_user *userp)
1001 cm_SkipIoctlPath(ioctlp);
1003 memcpy(&temp, ioctlp->inDatap, sizeof(temp));
1005 temp = cm_data.buf_nOrigBuffers;
1007 /* temp is in 1K units, convert to # of buffers */
1008 temp = temp / (cm_data.buf_blockSize / 1024);
1011 /* now adjust the cache size */
1012 code = buf_SetNBuffers(temp);
1017 long cm_IoctlTraceControl(struct smb_ioctl *ioctlp, struct cm_user *userp)
1021 cm_SkipIoctlPath(ioctlp);
1023 memcpy(&inValue, ioctlp->inDatap, sizeof(long));
1027 afsd_ForceTrace(FALSE);
1028 buf_ForceTrace(FALSE);
1032 /* set tracing value to low order bit */
1033 if ((inValue & 1) == 0) {
1034 /* disable tracing */
1035 osi_LogDisable(afsd_logp);
1038 /* enable tracing */
1039 osi_LogEnable(afsd_logp);
1043 /* see if we're supposed to do a reset, too */
1045 osi_LogReset(afsd_logp);
1048 /* and copy out tracing flag */
1049 inValue = afsd_logp->enabled; /* use as a temp vbl */
1050 memcpy(ioctlp->outDatap, &inValue, sizeof(long));
1051 ioctlp->outDatap += sizeof(long);
1055 long cm_IoctlGetCacheParms(struct smb_ioctl *ioctlp, struct cm_user *userp)
1057 cm_cacheParms_t parms;
1059 memset(&parms, 0, sizeof(parms));
1061 /* first we get, in 1K units, the cache size */
1062 parms.parms[0] = cm_data.buf_nbuffers * (cm_data.buf_blockSize / 1024);
1064 /* and then the actual # of buffers in use (not in the free list, I guess,
1065 * will be what we do).
1067 parms.parms[1] = (cm_data.buf_nbuffers - buf_CountFreeList()) * (cm_data.buf_blockSize / 1024);
1069 memcpy(ioctlp->outDatap, &parms, sizeof(parms));
1070 ioctlp->outDatap += sizeof(parms);
1075 long cm_IoctlGetCell(struct smb_ioctl *ioctlp, struct cm_user *userp)
1080 cm_serverRef_t *serverRefp;
1081 cm_server_t *serverp;
1087 cm_SkipIoctlPath(ioctlp);
1089 tp = ioctlp->inDatap;
1091 memcpy((char *)&whichCell, tp, sizeof(long));
1094 /* see if more than one long passed in, ignoring the null pathname (the -1) */
1095 if (ioctlp->inCopied-1 > sizeof(long)) {
1096 memcpy((char *)&magic, tp, sizeof(long));
1099 lock_ObtainRead(&cm_cellLock);
1100 for (tcellp = cm_data.allCellsp; tcellp; tcellp = tcellp->nextp) {
1101 if (whichCell == 0) break;
1104 lock_ReleaseRead(&cm_cellLock);
1108 cp = ioctlp->outDatap;
1110 if (magic == 0x12345678) {
1111 memcpy(cp, (char *)&magic, sizeof(long));
1114 memset(cp, 0, max * sizeof(long));
1116 lock_ObtainRead(&cm_serverLock); /* for going down server list */
1117 /* jaltman - do the reference counts to serverRefp contents need to be increased? */
1118 serverRefp = tcellp->vlServersp;
1119 for (i=0; i<max; i++) {
1120 if (!serverRefp) break;
1121 serverp = serverRefp->server;
1122 memcpy(cp, &serverp->addr.sin_addr.s_addr, sizeof(long));
1124 serverRefp = serverRefp->next;
1126 lock_ReleaseRead(&cm_serverLock);
1127 cp = basep + max * sizeof(afs_int32);
1128 StringCbCopyA(cp, 999999, tcellp->name);
1129 cp += strlen(tcellp->name)+1;
1130 ioctlp->outDatap = cp;
1136 return CM_ERROR_NOMORETOKENS; /* mapped to EDOM */
1139 extern long cm_AddCellProc(void *rockp, struct sockaddr_in *addrp, char *namep);
1141 long cm_IoctlNewCell(struct smb_ioctl *ioctlp, struct cm_user *userp)
1143 /* NT cache manager will read cell information from CellServDB each time
1144 * cell is accessed. So, this call is necessary only if list of server for a cell
1145 * changes (or IP addresses of cell servers changes).
1146 * All that needs to be done is to refresh server information for all cells that
1147 * are already loaded.
1149 * cell list will be cm_CellLock and cm_ServerLock will be held for write.
1154 cm_SkipIoctlPath(ioctlp);
1155 lock_ObtainWrite(&cm_cellLock);
1157 for (cp = cm_data.allCellsp; cp; cp=cp->nextp)
1160 /* delete all previous server lists - cm_FreeServerList will ask for write on cm_ServerLock*/
1161 cm_FreeServerList(&cp->vlServersp);
1162 cp->vlServersp = NULL;
1163 code = cm_SearchCellFile(cp->name, cp->name, cm_AddCellProc, cp);
1164 #ifdef AFS_AFSDB_ENV
1166 if (cm_dnsEnabled) {
1168 code = cm_SearchCellByDNS(cp->name, cp->name, &ttl, cm_AddCellProc, cp);
1169 if ( code == 0 ) { /* got cell from DNS */
1170 cp->flags |= CM_CELLFLAG_DNS;
1171 cp->flags &= ~CM_CELLFLAG_VLSERVER_INVALID;
1172 cp->timeout = time(0) + ttl;
1177 cp->flags &= ~CM_CELLFLAG_DNS;
1179 #endif /* AFS_AFSDB_ENV */
1181 cp->flags |= CM_CELLFLAG_VLSERVER_INVALID;
1184 cp->flags &= ~CM_CELLFLAG_VLSERVER_INVALID;
1185 cm_RandomizeServer(&cp->vlServersp);
1189 lock_ReleaseWrite(&cm_cellLock);
1193 long cm_IoctlGetWsCell(smb_ioctl_t *ioctlp, cm_user_t *userp)
1197 if (cm_freelanceEnabled) {
1198 if (cm_GetRootCellName(ioctlp->outDatap))
1199 StringCbCopyA(ioctlp->outDatap, 999999, "Freelance.Local.Root");
1200 ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
1201 } else if (cm_data.rootCellp) {
1202 /* return the default cellname to the caller */
1203 StringCbCopyA(ioctlp->outDatap, 999999, cm_data.rootCellp->name);
1204 ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
1206 /* if we don't know our default cell, return failure */
1207 code = CM_ERROR_NOSUCHCELL;
1213 long cm_IoctlSysName(struct smb_ioctl *ioctlp, struct cm_user *userp)
1215 long setSysName, foundname = 0;
1216 char *cp, *cp2, inname[MAXSYSNAME], outname[MAXSYSNAME];
1217 int t, count, num = 0;
1218 char **sysnamelist[MAXSYSNAME];
1220 cm_SkipIoctlPath(ioctlp);
1222 memcpy(&setSysName, ioctlp->inDatap, sizeof(long));
1223 ioctlp->inDatap += sizeof(long);
1227 if ( setSysName < 0 || setSysName > MAXNUMSYSNAMES )
1229 cp2 = ioctlp->inDatap;
1230 for ( cp=ioctlp->inDatap, count = 0; count < setSysName; count++ ) {
1231 /* won't go past end of ioctlp->inDatap since maxsysname*num < ioctlp->inDatap length */
1233 if (t >= MAXSYSNAME || t <= 0)
1235 /* check for names that can shoot us in the foot */
1236 if (*cp == '.' && (cp[1] == 0 || (cp[1] == '.' && cp[2] == 0)))
1242 /* inname gets first entry in case we're being a translator */
1243 /* (we are never a translator) */
1244 t = strlen(ioctlp->inDatap);
1245 memcpy(inname, ioctlp->inDatap, t + 1);
1246 ioctlp->inDatap += t + 1;
1250 /* Not xlating, so local case */
1252 osi_panic("cm_IoctlSysName: !cm_sysName\n", __FILE__, __LINE__);
1254 if (!setSysName) { /* user just wants the info */
1255 StringCbCopyA(outname, sizeof(outname), cm_sysName);
1256 foundname = cm_sysNameCount;
1257 *sysnamelist = cm_sysNameList;
1259 /* Local guy; only root can change sysname */
1260 /* clear @sys entries from the dnlc, once afs_lookup can
1261 * do lookups of @sys entries and thinks it can trust them */
1262 /* privs ok, store the entry, ... */
1263 StringCbCopyA(cm_sysName, sizeof(cm_sysName), inname);
1264 StringCbCopyA(cm_sysNameList[0], MAXSYSNAME, inname);
1265 if (setSysName > 1) { /* ... or list */
1266 cp = ioctlp->inDatap;
1267 for (count = 1; count < setSysName; ++count) {
1268 if (!cm_sysNameList[count])
1269 osi_panic("cm_IoctlSysName: no cm_sysNameList entry to write\n",
1270 __FILE__, __LINE__);
1272 StringCbCopyA(cm_sysNameList[count], MAXSYSNAME, cp);
1276 cm_sysNameCount = setSysName;
1280 /* return the sysname to the caller */
1281 cp = ioctlp->outDatap;
1282 memcpy(cp, (char *)&foundname, sizeof(afs_int32));
1283 cp += sizeof(afs_int32); /* skip found flag */
1285 StringCbCopyA(cp, 999999, outname);
1286 cp += strlen(outname) + 1; /* skip name and terminating null char */
1287 for ( count=1; count < foundname ; ++count) { /* ... or list */
1288 if ( !(*sysnamelist)[count] )
1289 osi_panic("cm_IoctlSysName: no cm_sysNameList entry to read\n",
1290 __FILE__, __LINE__);
1291 t = strlen((*sysnamelist)[count]);
1292 if (t >= MAXSYSNAME)
1293 osi_panic("cm_IoctlSysName: sysname entry garbled\n",
1294 __FILE__, __LINE__);
1295 StringCbCopyA(cp, 999999, (*sysnamelist)[count]);
1299 ioctlp->outDatap = cp;
1306 long cm_IoctlGetCellStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
1311 cm_SkipIoctlPath(ioctlp);
1313 cellp = cm_GetCell(ioctlp->inDatap, 0);
1315 return CM_ERROR_NOSUCHCELL;
1318 lock_ObtainMutex(&cellp->mx);
1319 if (cellp->flags & CM_CELLFLAG_SUID)
1320 temp |= CM_SETCELLFLAG_SUID;
1321 lock_ReleaseMutex(&cellp->mx);
1323 /* now copy out parm */
1324 memcpy(ioctlp->outDatap, &temp, sizeof(long));
1325 ioctlp->outDatap += sizeof(long);
1330 long cm_IoctlSetCellStatus(struct smb_ioctl *ioctlp, struct cm_user *userp)
1335 cm_SkipIoctlPath(ioctlp);
1337 cellp = cm_GetCell(ioctlp->inDatap + 2*sizeof(long), 0);
1339 return CM_ERROR_NOSUCHCELL;
1341 memcpy((char *)&temp, ioctlp->inDatap, sizeof(long));
1343 lock_ObtainMutex(&cellp->mx);
1344 if (temp & CM_SETCELLFLAG_SUID)
1345 cellp->flags |= CM_CELLFLAG_SUID;
1347 cellp->flags &= ~CM_CELLFLAG_SUID;
1348 lock_ReleaseMutex(&cellp->mx);
1353 long cm_IoctlSetSPrefs(struct smb_ioctl *ioctlp, struct cm_user *userp)
1355 cm_SSetPref_t *spin; /* input */
1356 cm_SPref_t *srvin; /* one input component */
1358 int i, vlonly, noServers, type;
1359 struct sockaddr_in tmp;
1360 unsigned short rank;
1362 cm_SkipIoctlPath(ioctlp); /* we don't care about the path */
1364 spin = (cm_SSetPref_t *)ioctlp->inDatap;
1365 noServers = spin->num_servers;
1366 vlonly = spin->flags;
1368 type = CM_SERVER_VLDB;
1370 type = CM_SERVER_FILE;
1372 for ( i=0; i < noServers; i++)
1374 srvin = &(spin->servers[i]);
1375 rank = srvin->rank + (rand() & 0x000f);
1376 tmp.sin_addr = srvin->host;
1377 tmp.sin_family = AF_INET;
1379 tsp = cm_FindServer(&tmp, type);
1380 if ( tsp ) /* an existing server - ref count increased */
1382 tsp->ipRank = rank; /* no need to protect by mutex*/
1384 if (type == CM_SERVER_FILE)
1386 /* find volumes which might have RO copy
1387 /* on server and change the ordering of
1390 cm_ChangeRankVolume(tsp);
1394 /* set preferences for an existing vlserver */
1395 cm_ChangeRankCellVLServer(tsp);
1397 cm_PutServer(tsp); /* decrease refcount */
1399 else /* add a new server without a cell */
1401 tsp = cm_NewServer(&tmp, type, NULL); /* refcount = 1 */
1408 long cm_IoctlGetSPrefs(struct smb_ioctl *ioctlp, struct cm_user *userp)
1410 cm_SPrefRequest_t *spin; /* input */
1411 cm_SPrefInfo_t *spout; /* output */
1412 cm_SPref_t *srvout; /* one output component */
1414 int i, vlonly, noServers;
1416 cm_SkipIoctlPath(ioctlp); /* we don't care about the path */
1418 spin = (cm_SPrefRequest_t *)ioctlp->inDatap;
1419 spout = (cm_SPrefInfo_t *) ioctlp->outDatap;
1420 srvout = spout->servers;
1421 noServers = spin->num_servers;
1422 vlonly = spin->flags & CM_SPREF_VLONLY;
1423 spout->num_servers = 0;
1425 lock_ObtainRead(&cm_serverLock); /* get server lock */
1427 for (tsp=cm_allServersp, i=0; tsp && noServers; tsp=tsp->allNextp,i++){
1428 if (spin->offset > i) {
1429 continue; /* catch up to where we left off */
1432 if ( vlonly && (tsp->type == CM_SERVER_FILE) )
1433 continue; /* ignore fileserver for -vlserver option*/
1434 if ( !vlonly && (tsp->type == CM_SERVER_VLDB) )
1435 continue; /* ignore vlservers */
1437 srvout->host = tsp->addr.sin_addr;
1438 srvout->rank = tsp->ipRank;
1440 spout->num_servers++;
1443 lock_ReleaseRead(&cm_serverLock); /* release server lock */
1445 if ( tsp ) /* we ran out of space in the output buffer */
1446 spout->next_offset = i;
1448 spout->next_offset = 0;
1449 ioctlp->outDatap += sizeof(cm_SPrefInfo_t) +
1450 (spout->num_servers -1 ) * sizeof(cm_SPref_t) ;
1454 long cm_IoctlStoreBehind(struct smb_ioctl *ioctlp, struct cm_user *userp)
1456 /* we ignore default asynchrony since we only have one way
1457 * of doing this today.
1462 long cm_IoctlCreateMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
1464 char leaf[LEAF_SIZE];
1478 code = cm_ParseIoctlParent(ioctlp, userp, &req, &dscp, leaf);
1479 if (code) return code;
1481 /* Translate chars for the mount point name */
1482 TranslateExtendedChars(leaf);
1485 * The fs command allows the user to specify partial cell names on NT. These must
1486 * be expanded to the full cell name for mount points so that the mount points will
1487 * work on UNIX clients.
1490 /* Extract the possibly partial cell name */
1491 StringCbCopyA(cell, sizeof(cell), ioctlp->inDatap + 1); /* Skip the mp type character */
1493 if (cp = strchr(cell, ':')) {
1494 /* Extract the volume name */
1496 StringCbCopyA(volume, sizeof(volume), cp + 1);
1498 /* Get the full name for this cell */
1499 code = cm_SearchCellFile(cell, fullCell, 0, 0);
1500 #ifdef AFS_AFSDB_ENV
1501 if (code && cm_dnsEnabled)
1502 code = cm_SearchCellByDNS(cell, fullCell, &ttl, 0, 0);
1505 return CM_ERROR_NOSUCHCELL;
1507 StringCbPrintfA(mpInfo, sizeof(mpInfo), "%c%s:%s", *ioctlp->inDatap, fullCell, volume);
1509 /* No cell name specified */
1510 StringCbCopyA(mpInfo, sizeof(mpInfo), ioctlp->inDatap);
1513 #ifdef AFS_FREELANCE_CLIENT
1514 if (cm_freelanceEnabled && dscp == cm_data.rootSCachep) {
1515 /* we are adding the mount point to the root dir., so call
1516 * the freelance code to do the add. */
1517 osi_Log0(afsd_logp,"IoctlCreateMountPoint within Freelance root dir");
1518 code = cm_FreelanceAddMount(leaf, fullCell, volume,
1519 *ioctlp->inDatap == '%', NULL);
1523 /* create the symlink with mode 644. The lack of X bits tells
1524 * us that it is a mount point.
1526 tattr.mask = CM_ATTRMASK_UNIXMODEBITS | CM_ATTRMASK_CLIENTMODTIME;
1527 tattr.unixModeBits = 0644;
1528 tattr.clientModTime = time(NULL);
1530 code = cm_SymLink(dscp, leaf, mpInfo, 0, &tattr, userp, &req);
1531 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
1532 smb_NotifyChange(FILE_ACTION_ADDED,
1533 FILE_NOTIFY_CHANGE_DIR_NAME,
1534 dscp, leaf, NULL, TRUE);
1536 cm_ReleaseSCache(dscp);
1540 long cm_IoctlSymlink(struct smb_ioctl *ioctlp, struct cm_user *userp)
1542 char leaf[LEAF_SIZE];
1551 code = cm_ParseIoctlParent(ioctlp, userp, &req, &dscp, leaf);
1552 if (code) return code;
1554 /* Translate chars for the link name */
1555 TranslateExtendedChars(leaf);
1557 /* Translate chars for the linked to name */
1558 TranslateExtendedChars(ioctlp->inDatap);
1560 cp = ioctlp->inDatap; /* contents of link */
1562 #ifdef AFS_FREELANCE_CLIENT
1563 if (cm_freelanceEnabled && dscp == cm_data.rootSCachep) {
1564 /* we are adding the symlink to the root dir., so call
1565 * the freelance code to do the add. */
1566 if (cp[0] == cp[1] && cp[1] == '\\' &&
1567 !_strnicmp(cm_NetbiosName,cp+2,strlen(cm_NetbiosName)))
1569 /* skip \\AFS\ or \\AFS\all\ */
1571 p = cp + 2 + strlen(cm_NetbiosName) + 1;
1572 if ( !_strnicmp("all", p, 3) )
1576 osi_Log0(afsd_logp,"IoctlCreateSymlink within Freelance root dir");
1577 code = cm_FreelanceAddSymlink(leaf, cp, NULL);
1582 /* Create symlink with mode 0755. */
1583 tattr.mask = CM_ATTRMASK_UNIXMODEBITS;
1584 tattr.unixModeBits = 0755;
1586 code = cm_SymLink(dscp, leaf, cp, 0, &tattr, userp, &req);
1587 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
1588 smb_NotifyChange(FILE_ACTION_ADDED,
1589 FILE_NOTIFY_CHANGE_FILE_NAME
1590 | FILE_NOTIFY_CHANGE_DIR_NAME,
1591 dscp, leaf, NULL, TRUE);
1593 cm_ReleaseSCache(dscp);
1599 long cm_IoctlListlink(struct smb_ioctl *ioctlp, struct cm_user *userp)
1606 cm_scache_t *newRootScp;
1611 code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp);
1612 if (code) return code;
1614 cp = ioctlp->inDatap;
1616 code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &req, &scp);
1617 cm_ReleaseSCache(dscp);
1618 if (code) return code;
1620 /* Check that it's a real symlink */
1621 if (scp->fileType != CM_SCACHETYPE_SYMLINK &&
1622 scp->fileType != CM_SCACHETYPE_DFSLINK &&
1623 scp->fileType != CM_SCACHETYPE_INVALID) {
1624 cm_ReleaseSCache(scp);
1625 return CM_ERROR_INVAL;
1628 code = cm_AssembleLink(scp, "", &newRootScp, &spacep, userp, &req);
1629 cm_ReleaseSCache(scp);
1631 cp = ioctlp->outDatap;
1632 if (newRootScp != NULL) {
1633 StringCbCopyA(cp, 999999, cm_mountRoot);
1634 StringCbCatA(cp, 999999, "/");
1637 StringCbCopyA(cp, 999999, spacep->data);
1638 cp += strlen(cp) + 1;
1639 ioctlp->outDatap = cp;
1640 cm_FreeSpace(spacep);
1641 if (newRootScp != NULL)
1642 cm_ReleaseSCache(newRootScp);
1644 } else if (code == CM_ERROR_PATH_NOT_COVERED &&
1645 scp->fileType == CM_SCACHETYPE_DFSLINK ||
1646 code == CM_ERROR_NOSUCHPATH &&
1647 scp->fileType == CM_SCACHETYPE_INVALID) {
1648 cp = ioctlp->outDatap;
1649 StringCbCopyA(cp, 999999, spacep->data);
1650 cp += strlen(cp) + 1;
1651 ioctlp->outDatap = cp;
1652 cm_FreeSpace(spacep);
1653 if (newRootScp != NULL)
1654 cm_ReleaseSCache(newRootScp);
1661 long cm_IoctlIslink(struct smb_ioctl *ioctlp, struct cm_user *userp)
1662 {/*CHECK FOR VALID SYMLINK*/
1671 code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp);
1672 if (code) return code;
1674 cp = ioctlp->inDatap;
1675 osi_LogEvent("cm_IoctlListlink",NULL," name[%s]",cp);
1677 code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &req, &scp);
1678 cm_ReleaseSCache(dscp);
1679 if (code) return code;
1681 /* Check that it's a real symlink */
1682 if (scp->fileType != CM_SCACHETYPE_SYMLINK &&
1683 scp->fileType != CM_SCACHETYPE_DFSLINK &&
1684 scp->fileType != CM_SCACHETYPE_INVALID)
1685 code = CM_ERROR_INVAL;
1686 cm_ReleaseSCache(scp);
1690 long cm_IoctlDeletelink(struct smb_ioctl *ioctlp, struct cm_user *userp)
1700 code = cm_ParseIoctlPath(ioctlp, userp, &req, &dscp);
1701 if (code) return code;
1703 cp = ioctlp->inDatap;
1705 #ifdef AFS_FREELANCE_CLIENT
1706 if (cm_freelanceEnabled && dscp == cm_data.rootSCachep) {
1707 /* we are adding the mount point to the root dir., so call
1708 * the freelance code to do the add. */
1709 osi_Log0(afsd_logp,"IoctlDeletelink from Freelance root dir");
1710 code = cm_FreelanceRemoveSymlink(cp);
1715 code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &req, &scp);
1717 /* if something went wrong, bail out now */
1722 lock_ObtainMutex(&scp->mx);
1723 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1724 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1726 lock_ReleaseMutex(&scp->mx);
1727 cm_ReleaseSCache(scp);
1731 /* now check that this is a real symlink */
1732 if (scp->fileType != CM_SCACHETYPE_SYMLINK &&
1733 scp->fileType != CM_SCACHETYPE_DFSLINK &&
1734 scp->fileType != CM_SCACHETYPE_INVALID) {
1735 lock_ReleaseMutex(&scp->mx);
1736 cm_ReleaseSCache(scp);
1737 code = CM_ERROR_INVAL;
1741 /* time to make the RPC, so drop the lock */
1742 lock_ReleaseMutex(&scp->mx);
1743 cm_ReleaseSCache(scp);
1745 /* easier to do it this way */
1746 code = cm_Unlink(dscp, cp, userp, &req);
1747 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
1748 smb_NotifyChange(FILE_ACTION_REMOVED,
1749 FILE_NOTIFY_CHANGE_FILE_NAME
1750 | FILE_NOTIFY_CHANGE_DIR_NAME,
1751 dscp, cp, NULL, TRUE);
1754 cm_ReleaseSCache(dscp);
1758 long cm_IoctlSetToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
1765 struct ClearToken ct;
1774 saveDataPtr = ioctlp->inDatap;
1776 cm_SkipIoctlPath(ioctlp);
1778 tp = ioctlp->inDatap;
1781 memcpy(&ticketLen, tp, sizeof(ticketLen));
1782 tp += sizeof(ticketLen);
1783 if (ticketLen < MINKTCTICKETLEN || ticketLen > MAXKTCTICKETLEN)
1784 return CM_ERROR_INVAL;
1786 /* remember ticket and skip over it for now */
1790 /* clear token size */
1791 memcpy(&ctSize, tp, sizeof(ctSize));
1792 tp += sizeof(ctSize);
1793 if (ctSize != sizeof(struct ClearToken))
1794 return CM_ERROR_INVAL;
1797 memcpy(&ct, tp, ctSize);
1799 if (ct.AuthHandle == -1)
1800 ct.AuthHandle = 999; /* more rxvab compat stuff */
1802 /* more stuff, if any */
1803 if (ioctlp->inCopied > tp - saveDataPtr) {
1804 /* flags: logon flag */
1805 memcpy(&flags, tp, sizeof(int));
1809 cellp = cm_GetCell(tp, CM_FLAG_CREATE);
1810 if (!cellp) return CM_ERROR_NOSUCHCELL;
1811 tp += strlen(tp) + 1;
1815 tp += strlen(tp) + 1;
1817 #ifndef AFSIFS /* no SMB username, so we cannot log based on this */
1818 if (flags & PIOCTL_LOGON) {
1819 /* SMB user name with which to associate tokens */
1821 osi_Log2(smb_logp,"cm_IoctlSetToken for user [%s] smbname [%s]",
1822 osi_LogSaveString(smb_logp,uname), osi_LogSaveString(smb_logp,smbname));
1823 fprintf(stderr, "SMB name = %s\n", smbname);
1824 tp += strlen(tp) + 1;
1826 osi_Log1(smb_logp,"cm_IoctlSetToken for user [%s]",
1827 osi_LogSaveString(smb_logp,uname));
1831 #ifndef DJGPP /* for win95, session key is back in pioctl */
1833 memcpy(&uuid, tp, sizeof(uuid));
1834 if (!cm_FindTokenEvent(uuid, sessionKey))
1835 return CM_ERROR_INVAL;
1838 cellp = cm_data.rootCellp;
1839 osi_Log0(smb_logp,"cm_IoctlSetToken - no name specified");
1842 if (flags & PIOCTL_LOGON) {
1843 userp = smb_FindCMUserByName(smbname, ioctlp->fidp->vcp->rname);
1846 /* store the token */
1847 lock_ObtainMutex(&userp->mx);
1848 ucellp = cm_GetUCell(userp, cellp);
1849 osi_Log1(smb_logp,"cm_IoctlSetToken ucellp %lx", ucellp);
1850 ucellp->ticketLen = ticketLen;
1851 if (ucellp->ticketp)
1852 free(ucellp->ticketp); /* Discard old token if any */
1853 ucellp->ticketp = malloc(ticketLen);
1854 memcpy(ucellp->ticketp, ticket, ticketLen);
1857 * Get the session key from the RPC, rather than from the pioctl.
1860 memcpy(&ucellp->sessionKey, ct.HandShakeKey, sizeof(ct.HandShakeKey));
1862 memcpy(ucellp->sessionKey.data, sessionKey, sizeof(sessionKey));
1864 /* for win95, we are getting the session key from the pioctl */
1865 memcpy(&ucellp->sessionKey, ct.HandShakeKey, sizeof(ct.HandShakeKey));
1867 ucellp->kvno = ct.AuthHandle;
1868 ucellp->expirationTime = ct.EndTimestamp;
1871 StringCbCopyA(ucellp->userName, MAXKTCNAMELEN, uname);
1872 ucellp->flags |= CM_UCELLFLAG_RXKAD;
1873 lock_ReleaseMutex(&userp->mx);
1875 if (flags & PIOCTL_LOGON) {
1876 ioctlp->flags |= SMB_IOCTLFLAG_LOGON;
1879 cm_ResetACLCache(userp);
1884 long cm_IoctlGetTokenIter(struct smb_ioctl *ioctlp, struct cm_user *userp)
1890 struct ClearToken ct;
1892 cm_SkipIoctlPath(ioctlp);
1894 tp = ioctlp->inDatap;
1895 cp = ioctlp->outDatap;
1898 memcpy(&iterator, tp, sizeof(iterator));
1899 tp += sizeof(iterator);
1901 lock_ObtainMutex(&userp->mx);
1903 /* look for token */
1904 for (;;iterator++) {
1905 ucellp = cm_FindUCell(userp, iterator);
1907 lock_ReleaseMutex(&userp->mx);
1908 return CM_ERROR_NOMORETOKENS;
1910 if (ucellp->flags & CM_UCELLFLAG_RXKAD)
1915 temp = ucellp->iterator + 1;
1916 memcpy(cp, &temp, sizeof(temp));
1920 memcpy(cp, &ucellp->ticketLen, sizeof(ucellp->ticketLen));
1921 cp += sizeof(ucellp->ticketLen);
1924 memcpy(cp, ucellp->ticketp, ucellp->ticketLen);
1925 cp += ucellp->ticketLen;
1927 /* clear token size */
1929 memcpy(cp, &temp, sizeof(temp));
1933 ct.AuthHandle = ucellp->kvno;
1936 * Don't give out a real session key here
1939 memcpy(ct.HandShakeKey, &ucellp->sessionKey, sizeof(ct.HandShakeKey));
1941 memset(ct.HandShakeKey, 0, sizeof(ct.HandShakeKey));
1943 memcpy(ct.HandShakeKey, &ucellp->sessionKey, sizeof(ct.HandShakeKey));
1945 ct.ViceId = 37; /* XXX */
1946 ct.BeginTimestamp = 0; /* XXX */
1947 ct.EndTimestamp = ucellp->expirationTime;
1948 memcpy(cp, &ct, sizeof(ct));
1951 /* Primary flag (unused) */
1953 memcpy(cp, &temp, sizeof(temp));
1957 StringCbCopyA(cp, 999999, ucellp->cellp->name);
1958 cp += strlen(cp) + 1;
1961 StringCbCopyA(cp, 999999, ucellp->userName);
1962 cp += strlen(cp) + 1;
1964 ioctlp->outDatap = cp;
1966 lock_ReleaseMutex(&userp->mx);
1971 long cm_IoctlGetToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
1977 struct ClearToken ct;
1983 cm_SkipIoctlPath(ioctlp);
1985 tp = ioctlp->inDatap;
1987 cp = ioctlp->outDatap;
1989 /* cell name is right here */
1990 cellp = cm_GetCell(tp, 0);
1992 return CM_ERROR_NOSUCHCELL;
1993 tp += strlen(tp) + 1;
1997 memcpy(&uuid, tp, sizeof(uuid));
2000 lock_ObtainMutex(&userp->mx);
2002 ucellp = cm_GetUCell(userp, cellp);
2003 if (!ucellp || !(ucellp->flags & CM_UCELLFLAG_RXKAD)) {
2004 lock_ReleaseMutex(&userp->mx);
2005 return CM_ERROR_NOMORETOKENS;
2009 memcpy(cp, &ucellp->ticketLen, sizeof(ucellp->ticketLen));
2010 cp += sizeof(ucellp->ticketLen);
2013 memcpy(cp, ucellp->ticketp, ucellp->ticketLen);
2014 cp += ucellp->ticketLen;
2016 /* clear token size */
2018 memcpy(cp, &temp, sizeof(temp));
2022 ct.AuthHandle = ucellp->kvno;
2025 * Don't give out a real session key here
2028 memcpy(ct.HandShakeKey, &ucellp->sessionKey, sizeof(ct.HandShakeKey));
2030 memset(ct.HandShakeKey, 0, sizeof(ct.HandShakeKey));
2032 memcpy(ct.HandShakeKey, &ucellp->sessionKey, sizeof(ct.HandShakeKey));
2034 ct.ViceId = 37; /* XXX */
2035 ct.BeginTimestamp = 0; /* XXX */
2036 ct.EndTimestamp = ucellp->expirationTime;
2037 memcpy(cp, &ct, sizeof(ct));
2040 /* Primary flag (unused) */
2042 memcpy(cp, &temp, sizeof(temp));
2046 StringCbCopyA(cp, 999999, ucellp->cellp->name);
2047 cp += strlen(cp) + 1;
2050 StringCbCopyA(cp, 999999, ucellp->userName);
2051 cp += strlen(cp) + 1;
2053 ioctlp->outDatap = cp;
2055 lock_ReleaseMutex(&userp->mx);
2058 cm_RegisterNewTokenEvent(uuid, ucellp->sessionKey.data);
2064 long cm_IoctlDelToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
2070 cm_SkipIoctlPath(ioctlp);
2072 cp = ioctlp->outDatap;
2074 /* cell name is right here */
2075 cellp = cm_GetCell(ioctlp->inDatap, 0);
2076 if (!cellp) return CM_ERROR_NOSUCHCELL;
2078 lock_ObtainMutex(&userp->mx);
2080 ucellp = cm_GetUCell(userp, cellp);
2082 lock_ReleaseMutex(&userp->mx);
2083 return CM_ERROR_NOMORETOKENS;
2086 osi_Log1(smb_logp,"cm_IoctlDelToken ucellp %lx", ucellp);
2088 if (ucellp->ticketp) {
2089 free(ucellp->ticketp);
2090 ucellp->ticketp = NULL;
2092 ucellp->flags &= ~CM_UCELLFLAG_RXKAD;
2095 lock_ReleaseMutex(&userp->mx);
2097 cm_ResetACLCache(userp);
2102 long cm_IoctlDelAllToken(struct smb_ioctl *ioctlp, struct cm_user *userp)
2106 lock_ObtainMutex(&userp->mx);
2108 for (ucellp = userp->cellInfop; ucellp; ucellp = ucellp->nextp) {
2109 osi_Log1(smb_logp,"cm_IoctlDelAllToken ucellp %lx", ucellp);
2110 ucellp->flags &= ~CM_UCELLFLAG_RXKAD;
2114 lock_ReleaseMutex(&userp->mx);
2116 cm_ResetACLCache(userp);
2121 long cm_IoctlMakeSubmount(smb_ioctl_t *ioctlp, cm_user_t *userp)
2123 char afspath[MAX_PATH];
2125 int nextAutoSubmount;
2127 DWORD dwType, dwSize;
2132 cm_SkipIoctlPath(ioctlp);
2134 /* Serialize this one, to prevent simultaneous mods
2137 lock_ObtainMutex(&cm_Afsdsbmt_Lock);
2139 /* Parse the input parameters--first the required afs path,
2140 * then the requested submount name (which may be "").
2142 cm_NormalizeAfsPath (afspath, sizeof(afspath), ioctlp->inDatap);
2143 submountreqp = ioctlp->inDatap + (strlen(ioctlp->inDatap)+1);
2145 /* If the caller supplied a suggested submount name, see if
2146 * that submount name is in use... if so, the submount's path
2147 * has to match our path.
2150 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
2151 AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
2154 REG_OPTION_NON_VOLATILE,
2155 KEY_READ|KEY_WRITE|KEY_QUERY_VALUE,
2160 if (submountreqp && *submountreqp) {
2161 char submountPathNormalized[MAX_PATH];
2162 char submountPath[MAX_PATH];
2164 dwSize = sizeof(submountPath);
2165 status = RegQueryValueEx( hkSubmounts, submountreqp, 0,
2166 &dwType, submountPath, &dwSize);
2168 if (status != ERROR_SUCCESS) {
2170 /* The suggested submount name isn't in use now--
2171 * so we can safely map the requested submount name
2172 * to the supplied path. Remember not to write the
2173 * leading "/afs" when writing out the submount.
2175 RegSetValueEx( hkSubmounts, submountreqp, 0,
2177 (strlen(&afspath[strlen(cm_mountRoot)])) ?
2178 &afspath[strlen(cm_mountRoot)]:"/",
2179 (strlen(&afspath[strlen(cm_mountRoot)])) ?
2180 strlen(&afspath[strlen(cm_mountRoot)])+1:2);
2182 RegCloseKey( hkSubmounts );
2183 StringCbCopyA(ioctlp->outDatap, 999999, submountreqp);
2184 ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
2185 lock_ReleaseMutex(&cm_Afsdsbmt_Lock);
2189 /* The suggested submount name is already in use--if the
2190 * supplied path matches the submount's path, we can still
2191 * use the suggested submount name.
2193 cm_NormalizeAfsPath (submountPathNormalized, sizeof(submountPathNormalized), submountPath);
2194 if (!strcmp (submountPathNormalized, afspath)) {
2195 StringCbCopyA(ioctlp->outDatap, 999999, submountreqp);
2196 ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
2197 RegCloseKey( hkSubmounts );
2198 lock_ReleaseMutex(&cm_Afsdsbmt_Lock);
2203 RegQueryInfoKey( hkSubmounts,
2205 NULL, /* lpcClass */
2206 NULL, /* lpReserved */
2207 NULL, /* lpcSubKeys */
2208 NULL, /* lpcMaxSubKeyLen */
2209 NULL, /* lpcMaxClassLen */
2210 &dwSubmounts, /* lpcValues */
2211 NULL, /* lpcMaxValueNameLen */
2212 NULL, /* lpcMaxValueLen */
2213 NULL, /* lpcbSecurityDescriptor */
2214 NULL /* lpftLastWriteTime */
2218 /* Having obtained a list of all available submounts, start
2219 * searching that list for a path which matches the requested
2220 * AFS path. We'll also keep track of the highest "auto15"/"auto47"
2221 * submount, in case we need to add a new one later.
2224 nextAutoSubmount = 1;
2226 for ( dwIndex = 0; dwIndex < dwSubmounts; dwIndex ++ ) {
2227 char submountPathNormalized[MAX_PATH];
2228 char submountPath[MAX_PATH] = "";
2229 DWORD submountPathLen = sizeof(submountPath);
2230 char submountName[MAX_PATH];
2231 DWORD submountNameLen = sizeof(submountName);
2234 RegEnumValue( hkSubmounts, dwIndex, submountName, &submountNameLen, NULL,
2235 &dwType, submountPath, &submountPathLen);
2236 if (dwType == REG_EXPAND_SZ) {
2238 StringCbCopyA(buf, MAX_PATH, submountPath);
2239 submountPathLen = ExpandEnvironmentStrings(buf, submountPath, MAX_PATH);
2240 if (submountPathLen > MAX_PATH)
2244 /* If this is an Auto### submount, remember its ### value */
2245 if ((!strnicmp (submountName, "auto", 4)) &&
2246 (isdigit (submountName[strlen("auto")]))) {
2247 int thisAutoSubmount;
2248 thisAutoSubmount = atoi (&submountName[strlen("auto")]);
2249 nextAutoSubmount = max (nextAutoSubmount,
2250 thisAutoSubmount+1);
2253 if ((submountPathLen == 0) ||
2254 (submountPathLen == sizeof(submountPath) - 1)) {
2258 /* See if the path for this submount matches the path
2259 * that our caller specified. If so, we can return
2262 cm_NormalizeAfsPath (submountPathNormalized, sizeof(submountPathNormalized), submountPath);
2263 if (!strcmp (submountPathNormalized, afspath)) {
2264 StringCbCopyA(ioctlp->outDatap, 999999, submountName);
2265 ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
2266 RegCloseKey(hkSubmounts);
2267 lock_ReleaseMutex(&cm_Afsdsbmt_Lock);
2273 /* We've been through the entire list of existing submounts, and
2274 * didn't find any which matched the specified path. So, we'll
2275 * just have to add one. Remember not to write the leading "/afs"
2276 * when writing out the submount.
2279 StringCbPrintfA(ioctlp->outDatap, 999999, "auto%ld", nextAutoSubmount);
2281 RegSetValueEx( hkSubmounts,
2285 (strlen(&afspath[strlen(cm_mountRoot)])) ?
2286 &afspath[strlen(cm_mountRoot)]:"/",
2287 (strlen(&afspath[strlen(cm_mountRoot)])) ?
2288 strlen(&afspath[strlen(cm_mountRoot)])+1:2);
2290 ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
2291 RegCloseKey(hkSubmounts);
2292 lock_ReleaseMutex(&cm_Afsdsbmt_Lock);
2296 long cm_IoctlGetRxkcrypt(smb_ioctl_t *ioctlp, cm_user_t *userp)
2298 memcpy(ioctlp->outDatap, &cryptall, sizeof(cryptall));
2299 ioctlp->outDatap += sizeof(cryptall);
2304 long cm_IoctlSetRxkcrypt(smb_ioctl_t *ioctlp, cm_user_t *userp)
2306 cm_SkipIoctlPath(ioctlp);
2308 memcpy(&cryptall, ioctlp->inDatap, sizeof(cryptall));
2314 extern int afsd_shutdown(int);
2315 extern int afs_shutdown;
2317 long cm_IoctlShutdown(smb_ioctl_t *ioctlp, cm_user_t *userp) {
2318 afs_shutdown = 1; /* flag to shut down */
2323 long cm_IoctlGetSMBName(smb_ioctl_t *ioctlp, cm_user_t *userp)
2325 smb_user_t *uidp = ioctlp->uidp;
2327 if (uidp && uidp->unp) {
2328 memcpy(ioctlp->outDatap, uidp->unp->name, strlen(uidp->unp->name));
2329 ioctlp->outDatap += strlen(uidp->unp->name);
2336 * functions to dump contents of various structures.
2337 * In debug build (linked with crt debug library) will dump allocated but not freed memory
2339 extern int cm_DumpSCache(FILE *outputFile, char *cookie, int lock);
2340 extern int cm_DumpBufHashTable(FILE *outputFile, char *cookie, int lock);
2341 extern int smb_DumpVCP(FILE *outputFile, char *cookie, int lock);
2343 long cm_IoctlMemoryDump(struct smb_ioctl *ioctlp, struct cm_user *userp)
2347 char logfileName[MAX_PATH+1];
2352 static _CrtMemState memstate;
2355 cm_SkipIoctlPath(ioctlp);
2356 memcpy(&inValue, ioctlp->inDatap, sizeof(long));
2358 dwSize = GetEnvironmentVariable("TEMP", logfileName, sizeof(logfileName));
2359 if ( dwSize == 0 || dwSize > sizeof(logfileName) )
2361 GetWindowsDirectory(logfileName, sizeof(logfileName));
2363 strncat(logfileName, "\\afsd_alloc.log", sizeof(logfileName));
2365 hLogFile = CreateFile(logfileName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2371 memcpy(ioctlp->outDatap, &inValue, sizeof(long));
2372 ioctlp->outDatap += sizeof(long);
2377 SetFilePointer(hLogFile, 0, NULL, FILE_END);
2379 cookie = inValue ? "b" : "e";
2385 _CrtMemCheckpoint(&memstate);
2389 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2390 _CrtSetReportFile(_CRT_WARN, hLogFile);
2391 _CrtMemDumpAllObjectsSince(&memstate);
2395 /* dump all interesting data */
2396 cm_DumpSCache(hLogFile, cookie, 1);
2397 cm_DumpBufHashTable(hLogFile, cookie, 1);
2398 smb_DumpVCP(hLogFile, cookie, 1);
2400 CloseHandle(hLogFile);
2402 memcpy(ioctlp->outDatap, &inValue, sizeof(long));
2403 ioctlp->outDatap += sizeof(long);