Example usage for java.security PrivilegedAction PrivilegedAction

List of usage examples for java.security PrivilegedAction PrivilegedAction

Introduction

In this page you can find the example usage for java.security PrivilegedAction PrivilegedAction.

Prototype

PrivilegedAction

Source Link

Usage

From source file:org.apache.hama.bsp.JobImpl.java

/**
 *
 * @param rpc//  w w  w.  j a va 2 s .co m
 * @param nmToken
 * @param nodeId
 * @param user
 * @return
 */
protected ContainerManagementProtocol getContainerManagementProtocolProxy(final YarnRPC rpc, Token nmToken,
        NodeId nodeId, String user) {
    ContainerManagementProtocol proxy;
    UserGroupInformation ugi = UserGroupInformation.createRemoteUser(user);
    final InetSocketAddress addr = NetUtils.createSocketAddr(nodeId.getHost(), nodeId.getPort());
    if (nmToken != null) {
        ugi.addToken(ConverterUtils.convertFromYarn(nmToken, addr));
    }

    proxy = ugi.doAs(new PrivilegedAction<ContainerManagementProtocol>() {
        @Override
        public ContainerManagementProtocol run() {
            return (ContainerManagementProtocol) rpc.getProxy(ContainerManagementProtocol.class, addr, conf);
        }
    });
    return proxy;
}

From source file:org.apache.axis2.jaxws.server.endpoint.injection.impl.WebServiceContextInjectorImpl.java

/**
 * Gets all of the fields in this class and the super classes
 *
 * @param beanClass//from w  ww. j  av  a 2s  .  com
 * @return
 */
static private List<Method> getMethods(final Class beanClass) {
    // This class must remain private due to Java 2 Security concerns
    List<Method> methods;
    methods = (List<Method>) AccessController.doPrivileged(new PrivilegedAction() {
        public Object run() {
            List<Method> methods = new ArrayList<Method>();
            Class cls = beanClass;
            while (cls != null) {
                Method[] methodArray = cls.getDeclaredMethods();
                for (Method method : methodArray) {
                    methods.add(method);
                }
                cls = cls.getSuperclass();
            }
            return methods;
        }
    });

    return methods;
}

From source file:org.kitesdk.spring.hbase.example.service.WebPageSnapshotService.java

/**
 * Get the epoch timestamps for every snapshot time of an URL in HBase.
 *
 * @param url The URL of the page to get snapshot timestamps for
 * @return The list of timestamps//www  . ja  v  a2 s .c  o m
 */
public List<Long> getSnapshotTimestamps(String url, final String user) throws IOException {
    List<Long> snapshotTimestamps = null;
    final String normalizedUrl = normalizeUrl(url, user);
    LOG.error("Getting snapshot timestamps: url = {}, user = {}, normalized url = {}",
            new Object[] { url, user, normalizedUrl });
    UserGroupInformation ugi = UserGroupInformation.createProxyUser(user, UserGroupInformation.getLoginUser());

    snapshotTimestamps = ugi.doAs(new PrivilegedAction<List<Long>>() {

        @Override
        public List<Long> run() {
            List<Long> snapshotTimestamps = new ArrayList<Long>();
            DatasetReader<WebPageSnapshotModel> reader = null;
            try {
                reader = webPageSnapshotModels(user).from("url", normalizedUrl).from("fetchedAtRevTs", 0L)
                        .to("url", normalizedUrl).to("fetchedAtRevTs", Long.MAX_VALUE).newReader();
                while (reader.hasNext()) {
                    snapshotTimestamps.add(reader.next().getFetchedAt());
                }
            } finally {
                if (reader != null) {
                    reader.close();
                }
            }
            return snapshotTimestamps;
        }
    });

    return snapshotTimestamps;
}

From source file:org.apache.hadoop.yarn.server.TestContainerTokenSecretManager.java

@Test
public void test() throws IOException, InterruptedException {

    final ApplicationId appID = recordFactory.newRecordInstance(ApplicationId.class);
    appID.setClusterTimestamp(1234);// ww  w  .jav  a2  s .  c  om
    appID.setId(5);

    final Configuration conf = new Configuration();
    conf.set(CommonConfigurationKeysPublic.HADOOP_SECURITY_AUTHENTICATION, "kerberos");
    // Set AM expiry interval to be very long.
    conf.setLong(YarnConfiguration.AM_EXPIRY_INTERVAL, 100000L);
    UserGroupInformation.setConfiguration(conf);
    MiniYARNCluster yarnCluster = new MiniYARNCluster(TestContainerTokenSecretManager.class.getName());
    yarnCluster.init(conf);
    yarnCluster.start();

    ResourceManager resourceManager = yarnCluster.getResourceManager();

    final YarnRPC yarnRPC = YarnRPC.create(conf);

    // Submit an application
    ApplicationSubmissionContext appSubmissionContext = recordFactory
            .newRecordInstance(ApplicationSubmissionContext.class);
    appSubmissionContext.setApplicationId(appID);
    appSubmissionContext.setMasterCapability(recordFactory.newRecordInstance(Resource.class));
    appSubmissionContext.getMasterCapability().setMemory(1024);
    //    appSubmissionContext.resources = new HashMap<String, URL>();
    appSubmissionContext.setUser("testUser");
    //    appSubmissionContext.environment = new HashMap<String, String>();
    //    appSubmissionContext.command = new ArrayList<String>();
    appSubmissionContext.addCommand("sleep");
    appSubmissionContext.addCommand("100");

    // TODO: Use a resource to work around bugs. Today NM doesn't create local
    // app-dirs if there are no file to download!!
    File file = new File(localDir.getAbsolutePath(), "testFile");
    FileWriter tmpFile = new FileWriter(file);
    tmpFile.write("testing");
    tmpFile.close();
    URL testFileURL = ConverterUtils.getYarnUrlFromPath(
            FileContext.getFileContext().makeQualified(new Path(localDir.getAbsolutePath(), "testFile")));
    LocalResource rsrc = recordFactory.newRecordInstance(LocalResource.class);
    rsrc.setResource(testFileURL);
    rsrc.setSize(file.length());
    rsrc.setTimestamp(file.lastModified());
    rsrc.setType(LocalResourceType.FILE);
    rsrc.setVisibility(LocalResourceVisibility.PRIVATE);
    appSubmissionContext.setResourceTodo("testFile", rsrc);
    SubmitApplicationRequest submitRequest = recordFactory.newRecordInstance(SubmitApplicationRequest.class);
    submitRequest.setApplicationSubmissionContext(appSubmissionContext);
    resourceManager.getClientRMService().submitApplication(submitRequest);

    // Wait till container gets allocated for AM
    int waitCounter = 0;
    RMApp app = resourceManager.getRMContext().getRMApps().get(appID);
    RMAppAttempt appAttempt = app == null ? null : app.getCurrentAppAttempt();
    RMAppAttemptState state = appAttempt == null ? null : appAttempt.getAppAttemptState();
    while ((app == null || appAttempt == null || state == null || !state.equals(RMAppAttemptState.LAUNCHED))
            && waitCounter++ != 20) {
        LOG.info("Waiting for applicationAttempt to be created.. ");
        Thread.sleep(1000);
        app = resourceManager.getRMContext().getRMApps().get(appID);
        appAttempt = app == null ? null : app.getCurrentAppAttempt();
        state = appAttempt == null ? null : appAttempt.getAppAttemptState();
    }
    Assert.assertNotNull(app);
    Assert.assertNotNull(appAttempt);
    Assert.assertNotNull(state);
    Assert.assertEquals(RMAppAttemptState.LAUNCHED, state);

    UserGroupInformation currentUser = UserGroupInformation.getCurrentUser();

    // Ask for a container from the RM
    String schedulerAddressString = conf.get(YarnConfiguration.SCHEDULER_ADDRESS,
            YarnConfiguration.DEFAULT_SCHEDULER_BIND_ADDRESS);
    final InetSocketAddress schedulerAddr = NetUtils.createSocketAddr(schedulerAddressString);
    ApplicationTokenIdentifier appTokenIdentifier = new ApplicationTokenIdentifier(appID);
    ApplicationTokenSecretManager appTokenSecretManager = new ApplicationTokenSecretManager();
    appTokenSecretManager.setMasterKey(ApplicationTokenSecretManager.createSecretKey("Dummy".getBytes())); // TODO: FIX. Be in Sync with
                                                                                                           // ResourceManager.java
    Token<ApplicationTokenIdentifier> appToken = new Token<ApplicationTokenIdentifier>(appTokenIdentifier,
            appTokenSecretManager);
    appToken.setService(new Text(schedulerAddressString));
    currentUser.addToken(appToken);

    conf.setClass(YarnConfiguration.YARN_SECURITY_INFO, SchedulerSecurityInfo.class, SecurityInfo.class);
    AMRMProtocol scheduler = currentUser.doAs(new PrivilegedAction<AMRMProtocol>() {
        @Override
        public AMRMProtocol run() {
            return (AMRMProtocol) yarnRPC.getProxy(AMRMProtocol.class, schedulerAddr, conf);
        }
    });

    // Register the appMaster 
    RegisterApplicationMasterRequest request = recordFactory
            .newRecordInstance(RegisterApplicationMasterRequest.class);
    ApplicationMaster applicationMaster = recordFactory.newRecordInstance(ApplicationMaster.class);
    request.setApplicationAttemptId(
            resourceManager.getRMContext().getRMApps().get(appID).getCurrentAppAttempt().getAppAttemptId());
    scheduler.registerApplicationMaster(request);

    // Now request a container allocation.
    List<ResourceRequest> ask = new ArrayList<ResourceRequest>();
    ResourceRequest rr = recordFactory.newRecordInstance(ResourceRequest.class);
    rr.setCapability(recordFactory.newRecordInstance(Resource.class));
    rr.getCapability().setMemory(1024);
    rr.setHostName("*");
    rr.setNumContainers(1);
    rr.setPriority(recordFactory.newRecordInstance(Priority.class));
    rr.getPriority().setPriority(0);
    ask.add(rr);
    ArrayList<ContainerId> release = new ArrayList<ContainerId>();

    AllocateRequest allocateRequest = recordFactory.newRecordInstance(AllocateRequest.class);
    allocateRequest.setApplicationAttemptId(appAttempt.getAppAttemptId());
    allocateRequest.setResponseId(0);
    allocateRequest.addAllAsks(ask);
    allocateRequest.addAllReleases(release);
    List<Container> allocatedContainers = scheduler.allocate(allocateRequest).getAMResponse()
            .getNewContainerList();

    waitCounter = 0;
    while ((allocatedContainers == null || allocatedContainers.size() == 0) && waitCounter++ != 20) {
        LOG.info("Waiting for container to be allocated..");
        Thread.sleep(1000);
        allocateRequest.setResponseId(allocateRequest.getResponseId() + 1);
        allocatedContainers = scheduler.allocate(allocateRequest).getAMResponse().getNewContainerList();
    }

    Assert.assertNotNull("Container is not allocted!", allocatedContainers);
    Assert.assertEquals("Didn't get one container!", 1, allocatedContainers.size());

    // Now talk to the NM for launching the container.
    final Container allocatedContainer = allocatedContainers.get(0);
    ContainerToken containerToken = allocatedContainer.getContainerToken();
    Token<ContainerTokenIdentifier> token = new Token<ContainerTokenIdentifier>(
            containerToken.getIdentifier().array(), containerToken.getPassword().array(),
            new Text(containerToken.getKind()), new Text(containerToken.getService()));
    currentUser.addToken(token);
    conf.setClass(YarnConfiguration.YARN_SECURITY_INFO, ContainerManagerSecurityInfo.class, SecurityInfo.class);
    currentUser.doAs(new PrivilegedAction<Void>() {
        @Override
        public Void run() {
            ContainerManager client = (ContainerManager) yarnRPC.getProxy(ContainerManager.class,
                    NetUtils.createSocketAddr(allocatedContainer.getNodeId().toString()), conf);
            try {
                LOG.info("Going to make a getContainerStatus() legal request");
                GetContainerStatusRequest request = recordFactory
                        .newRecordInstance(GetContainerStatusRequest.class);
                ContainerId containerID = recordFactory.newRecordInstance(ContainerId.class);
                ApplicationAttemptId appAttemptId = recordFactory.newRecordInstance(ApplicationAttemptId.class);
                appAttemptId.setApplicationId(appID);
                appAttemptId.setAttemptId(1);
                containerID.setAppId(appID);
                containerID.setId(1);
                containerID.setAppAttemptId(appAttemptId);
                request.setContainerId(containerID);
                client.getContainerStatus(request);
            } catch (YarnRemoteException e) {
                LOG.info("Error", e);
            } catch (AvroRuntimeException e) {
                LOG.info("Got the expected exception");
            }
            return null;
        }
    });

    UserGroupInformation maliceUser = UserGroupInformation.createRemoteUser(currentUser.getShortUserName());
    byte[] identifierBytes = containerToken.getIdentifier().array();
    DataInputBuffer di = new DataInputBuffer();
    di.reset(identifierBytes, identifierBytes.length);
    ContainerTokenIdentifier dummyIdentifier = new ContainerTokenIdentifier();
    dummyIdentifier.readFields(di);
    Resource modifiedResource = recordFactory.newRecordInstance(Resource.class);
    modifiedResource.setMemory(2048);
    ContainerTokenIdentifier modifiedIdentifier = new ContainerTokenIdentifier(dummyIdentifier.getContainerID(),
            dummyIdentifier.getNmHostName(), modifiedResource);
    // Malice user modifies the resource amount
    Token<ContainerTokenIdentifier> modifiedToken = new Token<ContainerTokenIdentifier>(
            modifiedIdentifier.getBytes(), containerToken.getPassword().array(),
            new Text(containerToken.getKind()), new Text(containerToken.getService()));
    maliceUser.addToken(modifiedToken);
    maliceUser.doAs(new PrivilegedAction<Void>() {
        @Override
        public Void run() {
            ContainerManager client = (ContainerManager) yarnRPC.getProxy(ContainerManager.class,
                    NetUtils.createSocketAddr(allocatedContainer.getNodeId().toString()), conf);
            ContainerId containerID;

            LOG.info("Going to contact NM:  ilLegal request");
            GetContainerStatusRequest request = recordFactory
                    .newRecordInstance(GetContainerStatusRequest.class);
            containerID = recordFactory.newRecordInstance(ContainerId.class);
            ApplicationAttemptId appAttemptId = recordFactory.newRecordInstance(ApplicationAttemptId.class);
            appAttemptId.setApplicationId(appID);
            appAttemptId.setAttemptId(1);
            containerID.setAppId(appID);
            containerID.setId(1);
            containerID.setAppAttemptId(appAttemptId);
            request.setContainerId(containerID);
            try {
                client.getContainerStatus(request);
                fail("Connection initiation with illegally modified " + "tokens is expected to fail.");
            } catch (YarnRemoteException e) {
                LOG.error("Got exception", e);
                fail("Cannot get a YARN remote exception as " + "it will indicate RPC success");
            } catch (Exception e) {
                Assert.assertEquals(java.lang.reflect.UndeclaredThrowableException.class.getCanonicalName(),
                        e.getClass().getCanonicalName());
                Assert.assertEquals("DIGEST-MD5: digest response format violation. Mismatched response.",
                        e.getCause().getCause().getMessage());
            }
            return null;
        }
    });
}

From source file:org.apache.ranger.admin.client.RangerAdminRESTClient.java

@Override
public void revokeAccess(final GrantRevokeRequest request) throws Exception {
    if (LOG.isDebugEnabled()) {
        LOG.debug("==> RangerAdminRESTClient.revokeAccess(" + request + ")");
    }/*from w  w  w.j  a  v  a  2 s  . c o m*/

    ClientResponse response = null;
    UserGroupInformation user = MiscUtil.getUGILoginUser();
    boolean isSecureMode = user != null && UserGroupInformation.isSecurityEnabled();

    if (isSecureMode) {
        PrivilegedAction<ClientResponse> action = new PrivilegedAction<ClientResponse>() {
            public ClientResponse run() {
                WebResource secureWebResource = createWebResource(
                        RangerRESTUtils.REST_URL_SECURE_SERVICE_REVOKE_ACCESS + serviceName)
                                .queryParam(RangerRESTUtils.REST_PARAM_PLUGIN_ID, pluginId);
                return secureWebResource.accept(RangerRESTUtils.REST_EXPECTED_MIME_TYPE)
                        .type(RangerRESTUtils.REST_EXPECTED_MIME_TYPE)
                        .post(ClientResponse.class, restClient.toJson(request));
            };
        };
        if (LOG.isDebugEnabled()) {
            LOG.debug("revokeAccess as user " + user);
        }
        response = user.doAs(action);
    } else {
        WebResource webResource = createWebResource(
                RangerRESTUtils.REST_URL_SERVICE_REVOKE_ACCESS + serviceName)
                        .queryParam(RangerRESTUtils.REST_PARAM_PLUGIN_ID, pluginId);
        response = webResource.accept(RangerRESTUtils.REST_EXPECTED_MIME_TYPE)
                .type(RangerRESTUtils.REST_EXPECTED_MIME_TYPE)
                .post(ClientResponse.class, restClient.toJson(request));
    }

    if (response != null && response.getStatus() != 200) {
        RESTResponse resp = RESTResponse.fromClientResponse(response);
        LOG.error("revokeAccess() failed: HTTP status=" + response.getStatus() + ", message="
                + resp.getMessage() + ", isSecure=" + isSecureMode + (isSecureMode ? (", user=" + user) : ""));

        if (response.getStatus() == 401) {
            throw new AccessControlException();
        }

        throw new Exception("HTTP " + response.getStatus() + " Error: " + resp.getMessage());
    } else if (response == null) {
        throw new Exception("unknown error. revokeAccess(). serviceName=" + serviceName);
    }

    if (LOG.isDebugEnabled()) {
        LOG.debug("<== RangerAdminRESTClient.revokeAccess(" + request + ")");
    }
}

From source file:org.nebulaframework.grid.cluster.manager.services.jobs.ClusterJobServiceImpl.java

protected ClassLoader createArchiveClassLoader(final GridArchive archive, final UUID owner) {

    return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {

        @Override/*from  www  .j a va 2  s  .  c om*/
        public ClassLoader run() {
            return new GridArchiveClassLoader(archive, createNodeClassLoader(owner));
        }

    });
}

From source file:org.javascool.polyfilewriter.Gateway.java

/**
 * Open an AWT FileDialog./*from w w  w  .java2s . co  m*/
 * Allow to ask to the user to ask any file to the user.
 *
 * @param forSave If it's true, the AWT Dialog will be opened in save mode. Otherwise, it will be opened in open
 *                mode
 * @param ext     Allowed extensions separated by spaces. Leave null or empty string to allow all extensions
 * @return The path of the selected file.
 */
public String askFile(final boolean forSave, String ext, final String path) throws Exception {
    assertSafeUsage();
    try {
        if (ext == null)
            ext = "";
        try {
            final JFileChooser fc = AccessController.doPrivileged(new PrivilegedAction<JFileChooser>() {
                public JFileChooser run() {
                    return new JFileChooser(getFile(path));
                }
            });
            return AccessController.doPrivileged(new PrivilegedAction<String>() {
                @Override
                public String run() {
                    int r = JFileChooser.ABORT;
                    if (forSave)
                        r = fc.showSaveDialog(null);
                    else
                        r = fc.showOpenDialog(null);
                    if (r == JFileChooser.APPROVE_OPTION) {
                        final File file = fc.getSelectedFile();
                        return file.getAbsolutePath();
                    } else
                        return null;
                }
            });
        } catch (Exception e) {
            return null;
        }
    } catch (Exception e) {
        popException(e);
        throw e;
    }
}

From source file:org.apache.hadoop.hbase.regionserver.SecureBulkLoadManager.java

public boolean secureBulkLoadHFiles(final Region region, final BulkLoadHFileRequest request)
        throws IOException {
    final List<Pair<byte[], String>> familyPaths = new ArrayList<Pair<byte[], String>>(
            request.getFamilyPathCount());
    for (ClientProtos.BulkLoadHFileRequest.FamilyPath el : request.getFamilyPathList()) {
        familyPaths.add(new Pair<byte[], String>(el.getFamily().toByteArray(), el.getPath()));
    }/*from w  w w .  j ava2s  . com*/

    Token userToken = null;
    if (userProvider.isHadoopSecurityEnabled()) {
        userToken = new Token(request.getFsToken().getIdentifier().toByteArray(),
                request.getFsToken().getPassword().toByteArray(), new Text(request.getFsToken().getKind()),
                new Text(request.getFsToken().getService()));
    }
    final String bulkToken = request.getBulkToken();
    User user = getActiveUser();
    final UserGroupInformation ugi = user.getUGI();
    if (userToken != null) {
        ugi.addToken(userToken);
    } else if (userProvider.isHadoopSecurityEnabled()) {
        //we allow this to pass through in "simple" security mode
        //for mini cluster testing
        throw new DoNotRetryIOException("User token cannot be null");
    }

    boolean bypass = false;
    if (region.getCoprocessorHost() != null) {
        bypass = region.getCoprocessorHost().preBulkLoadHFile(familyPaths);
    }
    boolean loaded = false;
    if (!bypass) {
        // Get the target fs (HBase region server fs) delegation token
        // Since we have checked the permission via 'preBulkLoadHFile', now let's give
        // the 'request user' necessary token to operate on the target fs.
        // After this point the 'doAs' user will hold two tokens, one for the source fs
        // ('request user'), another for the target fs (HBase region server principal).
        if (userProvider.isHadoopSecurityEnabled()) {
            FsDelegationToken targetfsDelegationToken = new FsDelegationToken(userProvider, "renewer");
            targetfsDelegationToken.acquireDelegationToken(fs);

            Token<?> targetFsToken = targetfsDelegationToken.getUserToken();
            if (targetFsToken != null
                    && (userToken == null || !targetFsToken.getService().equals(userToken.getService()))) {
                ugi.addToken(targetFsToken);
            }
        }

        loaded = ugi.doAs(new PrivilegedAction<Boolean>() {
            @Override
            public Boolean run() {
                FileSystem fs = null;
                try {
                    fs = FileSystem.get(conf);
                    for (Pair<byte[], String> el : familyPaths) {
                        Path stageFamily = new Path(bulkToken, Bytes.toString(el.getFirst()));
                        if (!fs.exists(stageFamily)) {
                            fs.mkdirs(stageFamily);
                            fs.setPermission(stageFamily, PERM_ALL_ACCESS);
                        }
                    }
                    //We call bulkLoadHFiles as requesting user
                    //To enable access prior to staging
                    return region.bulkLoadHFiles(familyPaths, true,
                            new SecureBulkLoadListener(fs, bulkToken, conf));
                } catch (Exception e) {
                    LOG.error("Failed to complete bulk load", e);
                }
                return false;
            }
        });
    }
    if (region.getCoprocessorHost() != null) {
        loaded = region.getCoprocessorHost().postBulkLoadHFile(familyPaths, loaded);
    }
    return loaded;
}

From source file:org.apache.jasper.runtime.PageContextImpl.java

public Object getAttribute(final String name, final int scope) {

    if (name == null) {
        throw new NullPointerException(Localizer.getMessage("jsp.error.attribute.null_name"));
    }//from w ww  .  j a  v  a  2 s  . c  o  m

    if (System.getSecurityManager() != null) {
        return AccessController.doPrivileged(new PrivilegedAction() {
            public Object run() {
                return doGetAttribute(name, scope);
            }
        });
    } else {
        return doGetAttribute(name, scope);
    }

}

From source file:org.apache.ranger.tagsync.source.atlasrest.AtlasRESTUtil.java

private Map<String, Object> atlasAPI(final String endpoint) {

    if (LOG.isDebugEnabled()) {
        LOG.debug("==> atlasAPI(" + endpoint + ")");
    }//  w w  w .j  a v a 2s  .c o m
    Map<String, Object> ret = new HashMap<String, Object>();

    try {
        if (kerberized) {
            LOG.debug("Using kerberos authentication");
            Subject sub = SecureClientLogin.loginUserFromKeytab(principal, keytab, nameRules);
            if (LOG.isDebugEnabled()) {
                LOG.debug("Using Principal = " + principal + ", keytab = " + keytab);
            }
            ret = Subject.doAs(sub, new PrivilegedAction<Map<String, Object>>() {
                @Override
                public Map<String, Object> run() {
                    try {
                        return executeAtlasAPI(endpoint);
                    } catch (Exception e) {
                        LOG.error("Atlas API failed with message : ", e);
                    }
                    return null;
                }
            });
        } else {
            LOG.debug("Using basic authentication");
            ret = executeAtlasAPI(endpoint);
        }
    } catch (Exception exception) {
        LOG.error("Exception when fetching Atlas objects.", exception);
        ret = null;
    }

    if (LOG.isDebugEnabled()) {
        LOG.debug("<== atlasAPI(" + endpoint + ")");
    }
    return ret;
}