adding in the jetty-setuid setup from codehaus, java source needs updated to new connector setup and need to finish wiring up the per platform builds once that is done

This commit is contained in:
Jesse McConnell 2012-09-13 17:32:51 -05:00
parent 427a01855c
commit cb33d2db18
16 changed files with 1847 additions and 0 deletions

12
jetty-setuid/README.TXT Normal file
View File

@ -0,0 +1,12 @@
Configuration
-------------
Change etc/jetty-setuid.xml to use the userid you want.
Running
-------
In the top level jetty directory do:
sudo java -jar start.jar etc/jetty-setuid.xml etc/jetty.xml

View File

@ -0,0 +1,44 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<groupId>org.eclipse.jetty.setuid</groupId>
<artifactId>jetty-setuid-parent</artifactId>
<version>9.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jetty-setuid-java</artifactId>
<name>Jetty :: SetUID Java</name>
<packaging>jar</packaging>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptorRefs>
<descriptorRef>config</descriptorRef>
</descriptorRefs>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-util</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<assembly>
<id>config</id>
<includeBaseDirectory>false</includeBaseDirectory>
<formats>
<format>jar</format>
</formats>
<fileSets>
<fileSet>
<directory>src/main/config/etc</directory>
<outputDirectory></outputDirectory>
<includes>
<include>**</include>
</includes>
</fileSet>
</fileSets>
</assembly>

View File

@ -0,0 +1,27 @@
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
<!-- ================================================================ -->
<!-- Configure the Jetty SetUIDServer -->
<!-- This configuration file *must* be specified first in the list of -->
<!-- configuration files and should be used in combination with other -->
<!-- configuration files eg jetty.xml -->
<!-- ================================================================ -->
<Configure id="Server" class="org.mortbay.setuid.SetUIDServer">
<Set name="startServerAsPrivileged">false</Set>
<Set name="umask">2</Set>
<Set name="username">jetty</Set>
<Set name="groupname">jetty</Set>
<!-- uncomment to change the limits on number of open file descriptors for root -->
<!--
<Call name="setRLimitNoFiles">
<Arg>
<New class="org.mortbay.setuid.RLimit">
<Set name="soft">20000</Set>
<Set name="hard">40000</Set>
</New>
</Arg>
</Call>
-->
</Configure>

View File

@ -0,0 +1,81 @@
//
// ========================================================================
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.setuid;
/**
* Class is the equivalent java class used for holding values from native c code structure group. for more information please see man pages for getgrnam and getgrgid
* struct group {
* char *gr_name; // group name
* char *gr_passwd; // group password
* gid_t gr_gid; // group ID
* char **gr_mem; // group members
* };
*
*/
public class Group
{
private String _grName; /* group name */
private String _grPasswd; /* group password */
private int _grGid; /* group id */
private String[] _grMem; /* group members */
public String getGrName()
{
return _grName;
}
public void setGrName(String grName)
{
_grName = grName;
}
public String getGrPasswd()
{
return _grPasswd;
}
public void setGrPasswd(String grPasswd)
{
_grPasswd = grPasswd;
}
public int getGrGid()
{
return _grGid;
}
public void setGrGid(int grGid)
{
_grGid = grGid;
}
public String[] getGrMem()
{
return _grMem;
}
public void setGrMem(String[] grMem)
{
_grMem = grMem;
}
}

View File

@ -0,0 +1,116 @@
//
// ========================================================================
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.setuid;
/**
* Class is the equivalent java class used for holding values from native c code structure passwd. for more information please see man pages for getpwuid and getpwnam
* struct passwd {
* char *pw_name; // user name
* char *pw_passwd; // user password
* uid_t pw_uid; // user id
* gid_t pw_gid; // group id
* char *pw_gecos; // real name
* char *pw_dir; // home directory
* char *pw_shell; // shell program
* };
*
*/
public class Passwd
{
private String _pwName; /* user name */
private String _pwPasswd; /* user password */
private int _pwUid; /* user id */
private int _pwGid; /* group id */
private String _pwGecos; /* real name */
private String _pwDir; /* home directory */
private String _pwShell; /* shell program */
public String getPwName()
{
return _pwName;
}
public void setPwName(String pwName)
{
_pwName = pwName;
}
public String getPwPasswd()
{
return _pwPasswd;
}
public void setPwPasswd(String pwPasswd)
{
_pwPasswd = pwPasswd;
}
public int getPwUid()
{
return _pwUid;
}
public void setPwUid(int pwUid)
{
_pwUid = pwUid;
}
public int getPwGid()
{
return _pwGid;
}
public void setPwGid(int pwGid)
{
_pwGid = pwGid;
}
public String getPwGecos()
{
return _pwGecos;
}
public void setPwGid(String pwGecos)
{
_pwGecos = pwGecos;
}
public String getPwDir()
{
return _pwDir;
}
public void setPwDir(String pwDir)
{
_pwDir = pwDir;
}
public String getPwShell()
{
return _pwShell;
}
public void setPwShell(String pwShell)
{
_pwShell = pwShell;
}
}

View File

@ -0,0 +1,52 @@
//
// ========================================================================
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.setuid;
public class RLimit
{
int _soft;
int _hard;
public int getSoft ()
{
return _soft;
}
public void setSoft (int soft)
{
_soft = soft;
}
public int getHard ()
{
return _hard;
}
public void setHard (int hard)
{
_hard = hard;
}
public String toString()
{
return "rlimit_nofiles (soft="+_soft+", hard="+_hard+")";
}
}

View File

@ -0,0 +1,184 @@
//
// ========================================================================
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.setuid;
import java.io.File;
import java.io.FilenameFilter;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
/**
* Class is for changing user and groupId, it can also be use to retrieve user information by using getpwuid(uid) or getpwnam(username) of both linux and unix systems
*/
public class SetUID
{
private static final Logger LOG = Log.getLogger(SetUID.class);
public static final String __FILENAME = "libsetuid";
public static final int OK = 0;
public static final int ERROR = -1;
public static native int setumask(int mask);
public static native int setuid(int uid);
public static native int setgid(int gid);
public static native Passwd getpwnam(String name) throws SecurityException;
public static native Passwd getpwuid(int uid) throws SecurityException;
public static native Group getgrnam(String name) throws SecurityException;
public static native Group getgrgid(int gid) throws SecurityException;
public static native RLimit getrlimitnofiles();
public static native int setrlimitnofiles(RLimit rlimit);
private static class LibFilenameFilter implements FilenameFilter
{
public boolean accept(File dir, String name)
{
if (name.toLowerCase().contains(__FILENAME))
return true;
return false;
}
}
private static void loadLibrary()
{
// try loading file from ${jetty.libsetuid.path}
try
{
if(System.getProperty("jetty.libsetuid.path") != null)
{
File lib = new File(System.getProperty("jetty.libsetuid.path"));
if(lib.exists())
{
System.load(lib.getCanonicalPath());
}
return;
}
}
catch (Throwable e)
{
//Ignorable if there is another way to find the lib
if (LOG.isDebugEnabled())
LOG.debug(e);
}
//try loading using the platform native library name mapping
try
{
System.loadLibrary("setuid");
return;
}
catch (Throwable e)
{
//Ignorable if ther eis another way to find the lib
if (LOG.isDebugEnabled())
LOG.debug(e);
}
// try loading using well-known path
try
{
if(System.getProperty("jetty.home") != null)
{
File lib = getLib(new File (System.getProperty("jetty.home"), "lib/setuid/"));
if(lib != null && lib.exists())
{
System.load(lib.getCanonicalPath());
}
return;
}
}
catch (Throwable e)
{
if (LOG.isDebugEnabled())
LOG.debug(e);
}
// try to load from jetty.lib where rpm puts this file
try
{
if(System.getProperty("jetty.lib") != null)
{
File lib = getLib(new File(System.getProperty("jetty.lib")));
if(lib != null && lib.exists())
{
System.load(lib.getCanonicalPath());
}
return;
}
}
catch (Throwable e)
{
if (LOG.isDebugEnabled())
LOG.debug(e);
}
LOG.warn("Error: libsetuid.so could not be found");
}
private static File getLib (File dir)
{
File[] files = dir.listFiles(new LibFilenameFilter());
if (files == null || files.length == 0)
return null;
File file = null;
for (File f:files)
{
if (f.getName().endsWith(Server.getVersion()+".so"))
{
file = f;
break;
}
}
if (file == null)
file = files[0]; //couldn't get a match on version number, just pick first
if (LOG.isDebugEnabled())
LOG.debug("setuid library "+file.getName());
return file;
}
private static File getLib (String dir)
{
return getLib(new File (dir));
}
static
{
loadLibrary();
}
}

View File

@ -0,0 +1,205 @@
//
// ========================================================================
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.setuid;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
/**
* This extension of {@link Server} will make a JNI call to set the unix UID.
*
* This can be used to start the server as root so that privileged ports may
* be accessed and then switch to a non-root user for security.
* Depending on the value of {@link #setStartServerAsPrivileged(boolean)}, either the
* server will be started and then the UID set; or the {@link Server#getConnectors()} will be
* opened with a call to {@link Connector#open()}, the UID set and then the server is started.
* The later is the default and avoids any webapplication code being run as a privileged user,
* but will not work if the application code also needs to open privileged ports.
*
*<p>
* The configured umask is set before the server is started and the configured
* uid is set after the server is started.
* </p>
*
*/
public class SetUIDServer extends Server
{
private static final Logger LOG = Log.getLogger(SetUIDServer.class);
private int _uid=0;
private int _gid=0;
private int _umask=-1;
private boolean _startServerAsPrivileged;
private RLimit _rlimitNoFiles = null;
public void setUsername(String username)
{
Passwd passwd = SetUID.getpwnam(username);
_uid = passwd.getPwUid();
}
public String getUsername()
{
Passwd passwd = SetUID.getpwuid(_uid);
return passwd.getPwName();
}
public void setGroupname(String groupname)
{
Group group = SetUID.getgrnam(groupname);
_gid = group.getGrGid();
}
public String getGroupname()
{
Group group = SetUID.getgrgid(_gid);
return group.getGrName();
}
public int getUmask ()
{
return _umask;
}
public String getUmaskOctal()
{
return Integer.toOctalString(_umask);
}
public void setUmask(int umask)
{
_umask=umask;
}
public void setUmaskOctal(String umask )
{
_umask=Integer.parseInt(umask,8);
}
public int getUid()
{
return _uid;
}
public void setUid(int uid)
{
_uid=uid;
}
public void setGid(int gid)
{
_gid=gid;
}
public int getGid()
{
return _gid;
}
public void setRLimitNoFiles(RLimit rlimit)
{
_rlimitNoFiles = rlimit;
}
public RLimit getRLimitNoFiles ()
{
return _rlimitNoFiles;
}
@Override
protected void doStart() throws Exception
{
if (_umask>-1)
{
LOG.info("Setting umask=0"+Integer.toString(_umask,8));
SetUID.setumask(_umask);
}
if (_rlimitNoFiles != null)
{
LOG.info("Current "+SetUID.getrlimitnofiles());
int success = SetUID.setrlimitnofiles(_rlimitNoFiles);
if (success < 0)
LOG.warn("Failed to set rlimit_nofiles, returned status "+success);
LOG.info("Set "+SetUID.getrlimitnofiles());
}
if (_startServerAsPrivileged)
{
super.doStart();
if (_gid!=0)
{
LOG.info("Setting GID="+_gid);
SetUID.setgid(_gid);
}
if (_uid!=0)
{
LOG.info("Setting UID="+_uid);
SetUID.setuid(_uid);
Passwd pw = SetUID.getpwuid(_uid);
System.setProperty("user.name", pw.getPwName());
System.setProperty("user.home", pw.getPwDir());
}
}
else
{
Connector[] connectors = getConnectors();
for (int i=0;connectors!=null && i<connectors.length;i++)
{
connectors[i].open();
}
if (_gid!=0)
{
LOG.info("Setting GID="+_gid);
SetUID.setgid(_gid);
}
if (_uid!=0)
{
LOG.info("Setting UID="+_uid);
SetUID.setuid(_uid);
Passwd pw = SetUID.getpwuid(_uid);
System.setProperty("user.name", pw.getPwName());
System.setProperty("user.home", pw.getPwDir());
}
super.doStart();
}
}
/* ------------------------------------------------------------ */
/**
* @return the startServerAsPrivileged
*/
public boolean isStartServerAsPrivileged()
{
return _startServerAsPrivileged;
}
/* ------------------------------------------------------------ */
/**
* @param startContextsAsPrivileged if true, the server is started and then the process UID is switched. If false, the connectors are opened, the UID is switched and then the server is started.
*/
public void setStartServerAsPrivileged(boolean startContextsAsPrivileged)
{
_startServerAsPrivileged=startContextsAsPrivileged;
}
}

View File

@ -0,0 +1,133 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<groupId>org.eclipse.jetty.setuid</groupId>
<artifactId>jetty-setuid-parent</artifactId>
<version>9.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jetty-setuid-linux</artifactId>
<name>Jetty :: SetUID Linux Native</name>
<packaging>so</packaging>
<properties>
<native-source-dir>target/native</native-source-dir>
<jetty-setuid-linkerStartOption>-shared -lc -ldl-shared -lc -ldl</jetty-setuid-linkerStartOption>
<jetty-setuid-linkerEndOption>target/libsetuid.so</jetty-setuid-linkerEndOption>
</properties>
<build>
<finalName>libsetuid</finalName>
<plugins>
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>unpack</id>
<phase>generate-resources</phase>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>org.eclipse.jetty.setuid</groupId>
<artifactId>jetty-setuid-native</artifactId>
<version>${project.version}</version>
<overWrite>true</overWrite>
<outputDirectory>${native-source-dir}/</outputDirectory>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>copy-jni-implementation</id>
<phase>generate-sources</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<copy failonerror="false" file="${native-source-dir}/org_eclipse_jetty_setuid_SetUID.c" todir="target/generated" />
</tasks>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>native-maven-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<javahOS>mac</javahOS>
<jdkIncludePath>${java.home}/include</jdkIncludePath>
<compilerStartOptions>
<compilerStartOption>-fPIC -O</compilerStartOption>
</compilerStartOptions>
<sources>
<source>
<directory>target/generated</directory>
<fileNames>
<fileName>org_mortbay_setuid_SetUID.c</fileName>
</fileNames>
</source>
</sources>
<linkerStartOptions>
<linkerStartOption>${jetty-setuid-linkerStartOption}</linkerStartOption>
</linkerStartOptions>
<linkerEndOptions>
<linkerEndOptions>-o
${project.build.directory}/libsetuid.so</linkerEndOptions>
</linkerEndOptions>
</configuration>
<executions>
<execution>
<id>javah</id>
<phase>generate-sources</phase>
<configuration>
<classNames>
<className>org.eclipse.jetty.setuid.SetUID</className>
</classNames>
<outputDirectory>target/generated</outputDirectory>
</configuration>
<goals>
<goal>javah</goal>
</goals>
</execution>
<execution>
<id>compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.eclipse.jetty.setuid</groupId>
<artifactId>jetty-setuid-java</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,11 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<groupId>org.eclipse.jetty.setuid</groupId>
<artifactId>jetty-setuid-parent</artifactId>
<version>9.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jetty-setuid-native</artifactId>
<name>Jetty :: SetUID Native</name>
<packaging>jar</packaging>
</project>

View File

@ -0,0 +1,529 @@
// ========================================================================
// Copyright 2002-2005 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ========================================================================
#include <jni.h>
#include "org_mortbay_setuid_SetUID.h"
#include <sys/types.h>
#include <unistd.h>
#include <sys/resource.h>
#include <stdio.h>
#include <pwd.h>
#include <grp.h>
#include <stdio.h>
#include <errno.h>
/**
* Native code for SetUID, class is for changing user and groupId, it can also be use to retrieve user information by using getpwuid(uid) or getpwnam(username) of both linux and unix systems
*/
/* Start of Helper functions Declaration */
jmethodID getJavaMethodId(JNIEnv *env, jclass clazz, const char *name, const char *sig);
void setJavaFieldInt(JNIEnv *env, jobject obj, const char *name, int value);
void setJavaFieldLong(JNIEnv *env, jobject obj, const char *name, long value);
void setJavaFieldString(JNIEnv *env, jobject obj, const char *name, const char *value);
void throwNewJavaException(JNIEnv *env, const char *name, const char *msg);
void throwNewJavaSecurityException(JNIEnv *env, const char *msg);
int getJavaFieldInt(JNIEnv *env, jobject obj, const char *name);
/* End of Helper functions Declaration */
JNIEXPORT jint JNICALL
Java_org_mortbay_setuid_SetUID_setuid (JNIEnv * env, jclass j, jint uid)
{
return((jint)setuid((uid_t)uid));
}
JNIEXPORT jint JNICALL
Java_org_mortbay_setuid_SetUID_setumask (JNIEnv * env, jclass j, jint mask)
{
return((jint)umask((mode_t)mask));
}
JNIEXPORT jint JNICALL
Java_org_mortbay_setuid_SetUID_setgid (JNIEnv * env, jclass j, jint gid)
{
return((jint)setgid((gid_t)gid));
}
/* User informaton implementatons */
JNIEXPORT jobject JNICALL
Java_org_mortbay_setuid_SetUID_getpwnam(JNIEnv * env, jclass j, jstring name)
{
struct passwd* pw;
jboolean iscopy;
char *pname;
pname = (char*) (*env)->GetStringUTFChars(env, name, &iscopy);
pw=getpwnam((char *) pname);
if (!pw)
{
char strErr[255];
sprintf(strErr, "User %s is not found!!!", pname);
throwNewJavaSecurityException(env, strErr);
return NULL;
}
// free as in amnesty
(*env)->ReleaseStringUTFChars( env, name, pname );
// get The java class org.mortbay.setuid.Passwd
jclass cls;
cls = (*env)->FindClass(env,"org/mortbay/setuid/Passwd");
if(!cls)
{
throwNewJavaSecurityException(env, "Class: org.mortbay.setuid.Passwd is not found!!!");
return NULL;
}
// get the default constructor of org.mortbay.setuid.Passwd
jmethodID constructorMethod = getJavaMethodId(env, cls, "<init>", "()V");
// construct org.mortbay.setuid.Passwd java object
jobject retVal = (*env)->NewObject(env, cls,constructorMethod);
if(!retVal)
{
throwNewJavaSecurityException(env, "Object Construction error of Class: org.mortbay.setuid.Passwd!!!");
return NULL;
}
// copy the struct passwd values to java object org.mortbay.setuid.Passwd
//char *pw_name;
setJavaFieldString(env, retVal, "_pwName", pw->pw_name);
//char *pw_passwd;
setJavaFieldString(env, retVal, "_pwPasswd", pw->pw_passwd);
//uid_t pw_uid;
setJavaFieldInt(env, retVal, "_pwUid", pw->pw_uid);
//gid_t pw_gid;
setJavaFieldInt(env, retVal, "_pwGid", pw->pw_gid);
//char *pw_gecos;
setJavaFieldString(env, retVal, "_pwGecos", pw->pw_gecos);
//char *pw_dir;
setJavaFieldString(env, retVal, "_pwDir", pw->pw_dir);
//char *pw_shell;
setJavaFieldString(env, retVal, "_pwShell", pw->pw_shell);
(*env)->DeleteLocalRef(env, cls);
return retVal;
}
JNIEXPORT jobject JNICALL
Java_org_mortbay_setuid_SetUID_getpwuid(JNIEnv * env, jclass j, jint uid)
{
struct passwd* pw;
pw=getpwuid((uid_t) uid);
if (!pw)
{
char strErr[255];
sprintf(strErr, "User with uid %d is not found!!!", uid);
throwNewJavaSecurityException(env, strErr);
return NULL;
}
// get The java class org.mortbay.setuid.Passwd
jclass cls;
cls = (*env)->FindClass(env,"org/mortbay/setuid/Passwd");
if(!cls)
{
throwNewJavaSecurityException(env, "Class: org.mortbay.setuid.Passwd is not found!!!");
return NULL;
}
// get the default constructor of org.mortbay.setuid.Passwd
jmethodID constructorMethod = getJavaMethodId(env, cls, "<init>", "()V");
// construct org.mortbay.setuid.Passwd java object
jobject retVal = (*env)->NewObject(env, cls,constructorMethod);
if(!retVal)
{
throwNewJavaSecurityException(env, "Object Construction error of Class: org.mortbay.setuid.Passwd!!!");
return NULL;
}
// copy the struct passwd values to java object org.mortbay.setuid.Passwd
//char *pw_name;
setJavaFieldString(env, retVal, "_pwName", pw->pw_name);
//char *pw_passwd;
setJavaFieldString(env, retVal, "_pwPasswd", pw->pw_passwd);
//uid_t pw_uid;
setJavaFieldInt(env, retVal, "_pwUid", pw->pw_uid);
//gid_t pw_gid;
setJavaFieldInt(env, retVal, "_pwGid", pw->pw_gid);
//char *pw_gecos;
setJavaFieldString(env, retVal, "_pwGecos", pw->pw_gecos);
//char *pw_dir;
setJavaFieldString(env, retVal, "_pwDir", pw->pw_dir);
//char *pw_shell;
setJavaFieldString(env, retVal, "_pwShell", pw->pw_shell);
(*env)->DeleteLocalRef(env, cls);
return retVal;
}
/* Group information implimentations */
JNIEXPORT jobject JNICALL
Java_org_mortbay_setuid_SetUID_getgrnam(JNIEnv * env, jclass j, jstring name)
{
struct group* gr;
jboolean iscopy;
char *pname;
pname = (char*) (*env)->GetStringUTFChars(env, name, &iscopy);
gr=getgrnam((char *) pname);
if (!gr)
{
char strErr[255];
sprintf(strErr, "Group %s is not found!!!", pname);
throwNewJavaSecurityException(env, strErr);
return NULL;
}
// free as in amnesty
(*env)->ReleaseStringUTFChars( env, name, pname );
// get The java class org.mortbay.setuid.Passwd
jclass cls;
cls = (*env)->FindClass(env,"org/mortbay/setuid/Group");
if(!cls)
{
throwNewJavaSecurityException(env, "Class: org.mortbay.setuid.Group is not found!!!");
return NULL;
}
// get the default constructor of org.mortbay.setuid.Group
jmethodID constructorMethod = getJavaMethodId(env, cls, "<init>", "()V");
// construct org.mortbay.setuid.Group java object
jobject retVal = (*env)->NewObject(env, cls,constructorMethod);
if(!retVal)
{
throwNewJavaSecurityException(env, "Object Construction error of Class: org.mortbay.setuid.Group!!!");
return NULL;
}
// copy the struct grpup values to java object org.mortbay.setuid.Group
//char *gr_name;
setJavaFieldString(env, retVal, "_grName", gr->gr_name);
//char *gr_passwd;
setJavaFieldString(env, retVal, "_grPasswd", gr->gr_passwd);
//gid_t gr_gid;
setJavaFieldInt(env, retVal, "_grGid", gr->gr_gid);
if (gr->gr_mem != NULL)
{
int array_size, i;
jobjectArray gr_mems;
for(array_size =0; gr->gr_mem[array_size] != NULL; array_size++);
if(array_size)
{
jobjectArray strArr = (*env)->NewObjectArray(env, array_size,
(*env)->FindClass(env, "java/lang/String"),
(*env)->NewStringUTF(env, ""));
for(i=0;i<array_size;i++)
{
(*env)->SetObjectArrayElement(env,strArr,i,
(*env)->NewStringUTF(env, gr->gr_mem[i]));
}
// set string array field;
// find field
jfieldID fieldId = (*env)->GetFieldID(env, cls, "_grMem", "[Ljava/lang/String;");
if(!fieldId)
{
throwNewJavaSecurityException(env, "Class: Java Object Field is not found: String[] _grMem!!!");
}
(*env)->SetObjectField(env, retVal, fieldId, strArr);
}
}
(*env)->DeleteLocalRef(env, cls);
return retVal;
}
JNIEXPORT jobject JNICALL
Java_org_mortbay_setuid_SetUID_getgrgid(JNIEnv * env, jclass j, jint gid)
{
struct group* gr;
gr=getgrgid(gid);
if (!gr)
{
char strErr[255];
sprintf(strErr, "Group with gid %d is not found!!!", gid);
throwNewJavaSecurityException(env, strErr);
return NULL;
}
// get The java class org.mortbay.setuid.Passwd
jclass cls;
cls = (*env)->FindClass(env,"org/mortbay/setuid/Group");
if(!cls)
{
throwNewJavaSecurityException(env, "Class: org.mortbay.setuid.Group is not found!!!");
return NULL;
}
// get the default constructor of org.mortbay.setuid.Group
jmethodID constructorMethod = getJavaMethodId(env, cls, "<init>", "()V");
// construct org.mortbay.setuid.Group java object
jobject retVal = (*env)->NewObject(env, cls,constructorMethod);
if(!retVal)
{
throwNewJavaSecurityException(env, "Object Construction Error of Class: org.mortbay.setuid.Group!!!");
return NULL;
}
// copy the struct grpup values to java object org.mortbay.setuid.Group
//char *gr_name;
setJavaFieldString(env, retVal, "_grName", gr->gr_name);
//char *gr_passwd;
setJavaFieldString(env, retVal, "_grPasswd", gr->gr_passwd);
//gid_t gr_gid;
setJavaFieldInt(env, retVal, "_grGid", gr->gr_gid);
if (gr->gr_mem != NULL)
{
int array_size, i;
jobjectArray gr_mems;
for(array_size =0; gr->gr_mem[array_size] != NULL; array_size++);
if(array_size)
{
jobjectArray strArr = (*env)->NewObjectArray(env, array_size,
(*env)->FindClass(env, "java/lang/String"),
(*env)->NewStringUTF(env, ""));
for(i=0;i<array_size;i++)
{
(*env)->SetObjectArrayElement(env,strArr,i,
(*env)->NewStringUTF(env, gr->gr_mem[i]));
}
// set string array field;
// find field
jfieldID fieldId = (*env)->GetFieldID(env, cls, "_grMem", "[Ljava/lang/String;");
if(!fieldId)
{
throwNewJavaSecurityException(env, "Java Object Field is not found: String _grMem!!!");
}
(*env)->SetObjectField(env, retVal, fieldId, strArr);
}
}
(*env)->DeleteLocalRef(env, cls);
return retVal;
}
/*
* Class: org_mortbay_setuid_SetUID
* Method: getrlimitnofiles
* Signature: ()Lorg/mortbay/setuid/RLimit;
*/
JNIEXPORT jobject JNICALL Java_org_mortbay_setuid_SetUID_getrlimitnofiles
(JNIEnv *env, jclass j)
{
struct rlimit rlim;
int success = getrlimit(RLIMIT_NOFILE, &rlim);
if (success < 0)
{
throwNewJavaSecurityException(env, "getrlimit failed");
return NULL;
}
// get The java class org.mortbay.setuid.RLimit
jclass cls = (*env)->FindClass(env, "org/mortbay/setuid/RLimit");
if(!cls)
{
throwNewJavaSecurityException(env, "Class: org.mortbay.setuid.RLimit is not found!!!");
return NULL;
}
// get the default constructor of org.mortbay.setuid.RLimit
jmethodID constructorMethod = getJavaMethodId(env, cls, "<init>", "()V");
// construct org.mortbay.setuid.RLimit java object
jobject retVal = (*env)->NewObject(env, cls,constructorMethod);
if(!retVal)
{
throwNewJavaSecurityException(env, "Object Construction Error of Class: org.mortbay.setuid.RLimit!!!");
return NULL;
}
setJavaFieldInt(env, retVal, "_soft", rlim.rlim_cur);
setJavaFieldInt(env, retVal, "_hard", rlim.rlim_max);
(*env)->DeleteLocalRef(env, cls);
return retVal;
}
/*
* Class: org_mortbay_setuid_SetUID
* Method: setrlimitnofiles
* Signature: (Lorg/mortbay/setuid/RLimit;)I
*/
JNIEXPORT jint JNICALL Java_org_mortbay_setuid_SetUID_setrlimitnofiles
(JNIEnv *env, jclass j, jobject jo)
{
struct rlimit rlim;
jclass cls = (*env)->FindClass(env, "org/mortbay/setuid/RLimit");
rlim.rlim_cur=getJavaFieldInt(env,jo, "_soft");
rlim.rlim_max=getJavaFieldInt(env,jo, "_hard");
int success = setrlimit(RLIMIT_NOFILE, &rlim);
(*env)->DeleteLocalRef(env, cls);
return (jint)success;
}
/* Start of Helper Functions Implimentations */
jmethodID getJavaMethodId(JNIEnv *env, jclass clazz, const char *name, const char *sig)
{
jmethodID methodId = (*env)->GetMethodID(env, clazz,name,sig);
if(!methodId)
{
char strErr[255];
sprintf(strErr, "Java Method is not found: %s !!!", name);
throwNewJavaSecurityException(env, strErr);
return NULL;
}
return methodId;
}
int getJavaFieldInt(JNIEnv *env, jobject obj, const char *name)
{
jclass clazz = (*env)->GetObjectClass(env, obj);
jfieldID fieldId = (*env)->GetFieldID(env, clazz, name, "I");
if(!fieldId)
{
char strErr[255];
sprintf(strErr, "Java Object Field is not found: int %s !!!", name);
throwNewJavaSecurityException(env, strErr);
}
int val = (*env)->GetIntField(env, obj, fieldId);
(*env)->DeleteLocalRef(env, clazz);
return val;
}
void setJavaFieldInt(JNIEnv *env, jobject obj, const char *name, int value)
{
jclass clazz = (*env)->GetObjectClass(env, obj);
jfieldID fieldId = (*env)->GetFieldID(env, clazz, name, "I");
if(!fieldId)
{
char strErr[255];
sprintf(strErr, "Java Object Field is not found: int %s !!!", name);
throwNewJavaSecurityException(env, strErr);
}
(*env)->SetIntField(env, obj, fieldId, value);
(*env)->DeleteLocalRef(env, clazz);
}
void setJavaFieldLong(JNIEnv *env, jobject obj, const char *name, long value)
{
jclass clazz = (*env)->GetObjectClass(env, obj);
jfieldID fieldId = (*env)->GetFieldID(env, clazz, name, "L");
if(!fieldId)
{
char strErr[255];
sprintf(strErr, "Java Object Field is not found: long %s !!!", name);
throwNewJavaSecurityException(env, strErr);
}
(*env)->SetLongField(env, obj, fieldId, value);
(*env)->DeleteLocalRef(env, clazz);
}
void setJavaFieldString(JNIEnv *env, jobject obj, const char *name, const char *value)
{
jclass clazz = (*env)->GetObjectClass(env, obj);
jfieldID fieldId = (*env)->GetFieldID(env, clazz, name, "Ljava/lang/String;");
if(!fieldId)
{
char strErr[255];
sprintf(strErr, "Java Object Field is not found: String %s !!!", name);
throwNewJavaSecurityException(env, strErr);
}
jstring jstr = (*env)->NewStringUTF(env, value);
(*env)->SetObjectField(env, obj, fieldId, jstr);
(*env)->DeleteLocalRef(env, clazz);
}
void throwNewJavaException(JNIEnv *env, const char *name, const char *msg)
{
jclass clazz = (*env)->FindClass(env, name);
if (clazz)
{
(*env)->ThrowNew(env, clazz, msg);
}
(*env)->DeleteLocalRef(env, clazz);
}
void throwNewJavaSecurityException(JNIEnv *env, const char *msg)
{
throwNewJavaException(env, "java/lang/SecurityException", msg);
}
/* End of Helper Functions Implimentations */

View File

@ -0,0 +1,133 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<groupId>org.eclipse.jetty.setuid</groupId>
<artifactId>jetty-setuid-parent</artifactId>
<version>9.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jetty-setuid-osx</artifactId>
<name>Jetty :: SetUID OSX Native</name>
<packaging>so</packaging>
<properties>
<native-source-dir>target/native</native-source-dir>
<jetty-setuid-linkerStartOption>-lc -ldl -dynamiclib -undefined dynamic_lookup -single_module</jetty-setuid-linkerStartOption>
<jetty-setuid-linkerEndOption>target/libsetuid.so</jetty-setuid-linkerEndOption>
</properties>
<build>
<finalName>libsetuid</finalName>
<plugins>
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>unpack</id>
<phase>generate-resources</phase>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>org.eclipse.jetty.setuid</groupId>
<artifactId>jetty-setuid-native</artifactId>
<version>${project.version}</version>
<overWrite>true</overWrite>
<outputDirectory>${native-source-dir}/</outputDirectory>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>copy-jni-implementation</id>
<phase>generate-sources</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<copy failonerror="false" file="${native-source-dir}/org_eclipse_jetty_setuid_SetUID.c" todir="target/generated" />
</tasks>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>native-maven-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<javahOS>mac</javahOS>
<jdkIncludePath>${java.home}/include</jdkIncludePath>
<compilerStartOptions>
<compilerStartOption>-fPIC -O</compilerStartOption>
</compilerStartOptions>
<sources>
<source>
<directory>target/generated</directory>
<fileNames>
<fileName>org_mortbay_setuid_SetUID.c</fileName>
</fileNames>
</source>
</sources>
<linkerStartOptions>
<linkerStartOption>${jetty-setuid-linkerStartOption}</linkerStartOption>
</linkerStartOptions>
<linkerEndOptions>
<linkerEndOptions>-o
${project.build.directory}/libsetuid.so</linkerEndOptions>
</linkerEndOptions>
</configuration>
<executions>
<execution>
<id>javah</id>
<phase>generate-sources</phase>
<configuration>
<classNames>
<className>org.eclipse.jetty.setuid.SetUID</className>
</classNames>
<outputDirectory>target/generated</outputDirectory>
</configuration>
<goals>
<goal>javah</goal>
</goals>
</execution>
<execution>
<id>compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.eclipse.jetty.setuid</groupId>
<artifactId>jetty-setuid-java</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,41 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<groupId>org.eclipse.jetty.setuid</groupId>
<artifactId>jetty-setuid-parent</artifactId>
<version>9.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jetty-setuid-test</artifactId>
<name>Jetty :: SetUID Test</name>
<packaging>jar</packaging>
<build>
<defaultGoal>test</defaultGoal>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.eclipse.jetty.setuid</groupId>
<artifactId>jetty-setuid-java</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-setuid-native</artifactId>
<version>${project.version}</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,136 @@
//
// ========================================================================
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.setuid;
import junit.framework.TestCase;
import org.eclipse.jetty.setuid.SetUID;
import java.io.File;
import org.eclipse.jetty.setuid.Passwd;
import org.eclipse.jetty.setuid.Group;
public class TestSetuid extends TestCase
{
public void testSetuid() throws Exception
{
try
{
// TODO use the dependency plugin to grab the proper lib and put it into place, no relative goop
File lib = new File("../../modules/native/target/libsetuid.so");
String libPath = lib.getCanonicalPath();
System.setProperty("jetty.libsetuid.path", libPath);
try
{
SetUID.getpwnam("TheQuickBrownFoxJumpsOverToTheLazyDog");
assertTrue(false);
}
catch(SecurityException se)
{
assertTrue(true);
}
try
{
SetUID.getpwuid(-9999);
assertTrue(false);
}
catch(SecurityException se)
{
assertTrue(true);
}
// get the passwd info of root
Passwd passwd1 = SetUID.getpwnam("root");
// get the roots passwd info using the aquired uid
Passwd passwd2 = SetUID.getpwuid(passwd1.getPwUid());
assertEquals(passwd1.getPwName(), passwd2.getPwName());
assertEquals(passwd1.getPwPasswd(), passwd2.getPwPasswd());
assertEquals(passwd1.getPwUid(), passwd2.getPwUid());
assertEquals(passwd1.getPwGid(), passwd2.getPwGid());
assertEquals(passwd1.getPwGecos(), passwd2.getPwGecos());
assertEquals(passwd1.getPwDir(), passwd2.getPwDir());
assertEquals(passwd1.getPwShell(), passwd2.getPwShell());
try
{
SetUID.getgrnam("TheQuickBrownFoxJumpsOverToTheLazyDog");
assertTrue(false);
}
catch(SecurityException se)
{
assertTrue(true);
}
try
{
SetUID.getgrgid(-9999);
assertTrue(false);
}
catch(SecurityException se)
{
assertTrue(true);
}
// get the group using the roots groupid
Group gr1 = SetUID.getgrgid(passwd1.getPwGid());
// get the group name using the aquired name
Group gr2 = SetUID.getgrnam(gr1.getGrName());
assertEquals(gr1.getGrName(), gr2.getGrName());
assertEquals(gr1.getGrPasswd(), gr2.getGrPasswd());
assertEquals(gr1.getGrGid(), gr2.getGrGid());
// search and check through membership lists
if(gr1.getGrMem() != null)
{
assertEquals(gr1.getGrMem().length, gr2.getGrMem().length);
for(int i=0; i<gr1.getGrMem().length; i++)
{
assertEquals(gr1.getGrMem()[i], gr2.getGrMem()[i]);
}
}
}
catch(Throwable e)
{
e.printStackTrace();
assertTrue(false);
}
}
}

125
jetty-setuid/pom.xml Normal file
View File

@ -0,0 +1,125 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId>
<version>9.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.eclipse.jetty.setuid</groupId>
<artifactId>jetty-setuid-parent</artifactId>
<name>Jetty :: SetUID Parent</name>
<packaging>pom</packaging>
<modules>
<module>jetty-setuid-java</module>
<module>jetty-setuid-native</module>
<module>jetty-setuid-test</module>
</modules>
<build>
</build>
<profiles>
<profile>
<id>env-linux</id>
<activation>
<os>
<name>Linux</name>
</os>
</activation>
<modules>
<module>modules/java</module>
<module>modules/native</module>
<module>modules/test</module>
</modules>
<properties>
<jetty-setuid-linkerStartOption>-shared -lc -ldl</jetty-setuid-linkerStartOption>
<jetty-setuid-linkerEndOption>target/libsetuid.so</jetty-setuid-linkerEndOption>
</properties>
</profile>
<profile>
<id>env-SunOs</id>
<activation>
<os>
<name>SunOS</name>
</os>
</activation>
<modules>
<module>modules/java</module>
<module>modules/native</module>
</modules>
<properties>
<jetty-setuid-linkerStartOption>-lc -ldl</jetty-setuid-linkerStartOption>
<jetty-setuid-linkerEndOption>target/libsetuid.so</jetty-setuid-linkerEndOption>
</properties>
</profile>
<!--
<profile>
<id>env-unix</id>
<activation>
<os>
<family>unix</family>
<name>!Linux</name>
</os>
</activation>
<modules>
<module>modules/java</module>
<module>modules/native</module>
</modules>
<properties>
<jetty-setuid-linkerStartOption>-lc -ldl</jetty-setuid-linkerStartOption>
<jetty-setuid-linkerEndOption>target/libsetuid.so</jetty-setuid-linkerEndOption>
</properties>
</profile>
-->
<profile>
<id>env-mac</id>
<activation>
<os>
<family>mac</family>
</os>
</activation>
<modules>
<module>jetty-setuid-osx</module>
</modules>
</profile>
<profile>
<id>env-dos</id>
<activation>
<os>
<family>dos</family>
</os>
</activation>
<modules>
<module>modules/java</module>
</modules>
</profile>
<profile>
<id>env-windows</id>
<activation>
<os>
<family>windows</family>
</os>
</activation>
<modules>
<module>modules/java</module>
</modules>
</profile>
<profile>
<id>env-windows-9x</id>
<activation>
<os>
<family>win9x</family>
</os>
</activation>
<modules>
<module>modules/java</module>
</modules>
</profile>
</profiles>
</project>