# HG changeset patch # User asaha # Date 1245269562 25200 # Node ID bc0aa59e8e4014656a1ef9e7e048beb50c2c66f0 # Parent c8f6e154868b65c6da01773fc010c50062778a2b# Parent dd50d75d88e6278de2a80095951da30a96a28095 Merge diff -r c8f6e154868b -r bc0aa59e8e40 jdk/src/share/classes/java/lang/System.java --- a/jdk/src/share/classes/java/lang/System.java Fri Jun 12 12:26:20 2009 -0700 +++ b/jdk/src/share/classes/java/lang/System.java Wed Jun 17 13:12:42 2009 -0700 @@ -1174,6 +1174,12 @@ public void registerShutdownHook(int slot, boolean registerShutdownInProgress, Runnable hook) { Shutdown.add(slot, registerShutdownInProgress, hook); } + public int getStackTraceDepth(Throwable t) { + return t.getStackTraceDepth(); + } + public StackTraceElement getStackTraceElement(Throwable t, int i) { + return t.getStackTraceElement(i); + } }); } diff -r c8f6e154868b -r bc0aa59e8e40 jdk/src/share/classes/java/lang/Throwable.java --- a/jdk/src/share/classes/java/lang/Throwable.java Fri Jun 12 12:26:20 2009 -0700 +++ b/jdk/src/share/classes/java/lang/Throwable.java Wed Jun 17 13:12:42 2009 -0700 @@ -645,17 +645,21 @@ /** * Returns the number of elements in the stack trace (or 0 if the stack * trace is unavailable). + * + * package-protection for use by SharedSecrets. */ - private native int getStackTraceDepth(); + native int getStackTraceDepth(); /** * Returns the specified element of the stack trace. * + * package-protection for use by SharedSecrets. + * * @param index index of the element to return. * @throws IndexOutOfBoundsException if <tt>index < 0 || * index >= getStackTraceDepth() </tt> */ - private native StackTraceElement getStackTraceElement(int index); + native StackTraceElement getStackTraceElement(int index); private synchronized void writeObject(java.io.ObjectOutputStream s) throws IOException diff -r c8f6e154868b -r bc0aa59e8e40 jdk/src/share/classes/java/util/logging/LogRecord.java --- a/jdk/src/share/classes/java/util/logging/LogRecord.java Fri Jun 12 12:26:20 2009 -0700 +++ b/jdk/src/share/classes/java/util/logging/LogRecord.java Wed Jun 17 13:12:42 2009 -0700 @@ -29,6 +29,9 @@ import java.util.concurrent.atomic.AtomicLong; import java.io.*; +import sun.misc.JavaLangAccess; +import sun.misc.SharedSecrets; + /** * LogRecord objects are used to pass logging requests between * the logging framework and individual log Handlers. @@ -522,29 +525,31 @@ // Private method to infer the caller's class and method names private void inferCaller() { needToInferCaller = false; - // Get the stack trace. - StackTraceElement stack[] = (new Throwable()).getStackTrace(); - // First, search back to a method in the Logger class. - int ix = 0; - while (ix < stack.length) { - StackTraceElement frame = stack[ix]; + JavaLangAccess access = SharedSecrets.getJavaLangAccess(); + Throwable throwable = new Throwable(); + int depth = access.getStackTraceDepth(throwable); + + String logClassName = "java.util.logging.Logger"; + boolean lookingForLogger = true; + for (int ix = 0; ix < depth; ix++) { + // Calling getStackTraceElement directly prevents the VM + // from paying the cost of building the entire stack frame. + StackTraceElement frame = + access.getStackTraceElement(throwable, ix); String cname = frame.getClassName(); - if (cname.equals("java.util.logging.Logger")) { - break; + if (lookingForLogger) { + // Skip all frames until we have found the first logger frame. + if (cname.equals(logClassName)) { + lookingForLogger = false; + } + } else { + if (!cname.equals(logClassName)) { + // We've found the relevant frame. + setSourceClassName(cname); + setSourceMethodName(frame.getMethodName()); + return; + } } - ix++; - } - // Now search for the first frame before the "Logger" class. - while (ix < stack.length) { - StackTraceElement frame = stack[ix]; - String cname = frame.getClassName(); - if (!cname.equals("java.util.logging.Logger")) { - // We've found the relevant frame. - setSourceClassName(cname); - setSourceMethodName(frame.getMethodName()); - return; - } - ix++; } // We haven't found a suitable frame, so just punt. This is // OK as we are only committed to making a "best effort" here. diff -r c8f6e154868b -r bc0aa59e8e40 jdk/src/share/classes/sun/misc/JavaLangAccess.java --- a/jdk/src/share/classes/sun/misc/JavaLangAccess.java Fri Jun 12 12:26:20 2009 -0700 +++ b/jdk/src/share/classes/sun/misc/JavaLangAccess.java Wed Jun 17 13:12:42 2009 -0700 @@ -73,4 +73,14 @@ * the slot is not valid to register. */ void registerShutdownHook(int slot, boolean registerShutdownInProgress, Runnable hook); + + /** + * Returns the number of stack frames represented by the given throwable. + */ + int getStackTraceDepth(Throwable t); + + /** + * Returns the ith StackTraceElement for the given throwable. + */ + StackTraceElement getStackTraceElement(Throwable t, int i); } diff -r c8f6e154868b -r bc0aa59e8e40 jdk/src/share/classes/sun/security/x509/CertificateVersion.java --- a/jdk/src/share/classes/sun/security/x509/CertificateVersion.java Fri Jun 12 12:26:20 2009 -0700 +++ b/jdk/src/share/classes/sun/security/x509/CertificateVersion.java Wed Jun 17 13:12:42 2009 -0700 @@ -28,7 +28,6 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.util.Date; import java.util.Enumeration; import sun.security.util.*; diff -r c8f6e154868b -r bc0aa59e8e40 jdk/src/share/classes/sun/security/x509/InvalidityDateExtension.java --- a/jdk/src/share/classes/sun/security/x509/InvalidityDateExtension.java Fri Jun 12 12:26:20 2009 -0700 +++ b/jdk/src/share/classes/sun/security/x509/InvalidityDateExtension.java Wed Jun 17 13:12:42 2009 -0700 @@ -140,7 +140,11 @@ */ public Object get(String name) throws IOException { if (name.equalsIgnoreCase(DATE)) { - return date; + if (date == null) { + return null; + } else { + return (new Date(date.getTime())); // clone + } } else { throw new IOException ("Name not supported by InvalidityDateExtension"); diff -r c8f6e154868b -r bc0aa59e8e40 jdk/src/solaris/native/java/lang/UNIXProcess_md.c --- a/jdk/src/solaris/native/java/lang/UNIXProcess_md.c Fri Jun 12 12:26:20 2009 -0700 +++ b/jdk/src/solaris/native/java/lang/UNIXProcess_md.c Wed Jun 17 13:12:42 2009 -0700 @@ -49,6 +49,18 @@ #include <fcntl.h> #include <limits.h> +#ifndef USE_CLONE +#ifdef __linux__ +#define USE_CLONE 1 +#else +#define USE_CLONE 0 +#endif +#endif + +#if USE_CLONE +#include <sched.h> +#endif + #ifndef STDIN_FILENO #define STDIN_FILENO 0 #endif @@ -376,70 +388,61 @@ } #endif /* DEBUG_PROCESS */ -/* Version of execvpe when child's PATH differs from parent's */ -static int -execvp_usingParentPath(const char *file, const char *const argv[]) +/** + * Exec FILE as a traditional Bourne shell script (i.e. one without #!). + * If we could do it over again, we would probably not support such an ancient + * misfeature, but compatibility wins over sanity. The original support for + * this was imported accidentally from execvp(). + */ +static void +execve_as_traditional_shell_script(const char *file, + const char *argv[], + const char *const envp[]) { - char expanded_file[PATH_MAX]; - int filelen = strlen(file); - int sticky_errno = 0; - const char * const * dirs; - /* Search parent's PATH */ - for (dirs = parentPathv; *dirs; dirs++) { - const char * dir = *dirs; - int dirlen = strlen(dir); - if (filelen + dirlen + 1 >= PATH_MAX) { - /* Resist the urge to remove this limit; - * calling malloc after fork is unsafe. */ - errno = ENAMETOOLONG; - continue; - } - strcpy(expanded_file, dir); - strcpy(expanded_file + dirlen, file); - execvp(expanded_file, (char **) argv); - /* There are 3 responses to various classes of errno: - * return immediately, continue (especially for ENOENT), - * or continue with "sticky" errno. - * - * From exec(3): - * - * If permission is denied for a file (the attempted - * execve returned EACCES), these functions will continue - * searching the rest of the search path. If no other - * file is found, however, they will return with the - * global variable errno set to EACCES. - */ - switch (errno) { - case EACCES: - sticky_errno = errno; - /* FALLTHRU */ - case ENOENT: - case ENOTDIR: -#ifdef ELOOP - case ELOOP: -#endif -#ifdef ESTALE - case ESTALE: -#endif -#ifdef ENODEV - case ENODEV: -#endif -#ifdef ETIMEDOUT - case ETIMEDOUT: -#endif - break; /* Try other directories in PATH */ - default: - return -1; - } - } - if (sticky_errno != 0) - errno = sticky_errno; - return -1; + /* Use the extra word of space provided for us in argv by caller. */ + const char *argv0 = argv[0]; + const char *const *end = argv; + while (*end != NULL) + ++end; + memmove(argv+2, argv+1, (end-argv) * sizeof (*end)); + argv[0] = "/bin/sh"; + argv[1] = file; + execve(argv[0], (char **) argv, (char **) envp); + /* Can't even exec /bin/sh? Big trouble, but let's soldier on... */ + memmove(argv+1, argv+2, (end-argv) * sizeof (*end)); + argv[0] = argv0; } -/* execvpe should have been included in the Unix standards. */ -static int -execvpe(const char *file, const char *const argv[], const char *const envp[]) +/** + * Like execve(2), except that in case of ENOEXEC, FILE is assumed to + * be a shell script and the system default shell is invoked to run it. + */ +static void +execve_with_shell_fallback(const char *file, + const char *argv[], + const char *const envp[]) +{ +#if USE_CLONE + execve(file, (char **) argv, (char **) envp); + if (errno == ENOEXEC) + execve_as_traditional_shell_script(file, argv, envp); +#else + /* Our address space is unshared, so can mutate environ. */ + extern char **environ; + environ = (char **) envp; + execvp(file, (char **) argv); +#endif +} + +/** + * execvpe should have been included in the Unix standards. + * execvpe is identical to execvp, except that the child environment is + * specified via the 3rd argument instead of being inherited from environ. + */ +static void +execvpe(const char *file, + const char *argv[], + const char *const envp[]) { /* This is one of the rare times it's more portable to declare an * external symbol explicitly, rather than via a system header. @@ -454,28 +457,73 @@ */ extern char **environ; - if (envp != NULL) - environ = (char **) envp; + if (envp == NULL || (char **) envp == environ) { + execvp(file, (char **) argv); + return; + } - if (/* Parent and child environment the same? Use child PATH. */ - (envp == NULL) + if (*file == '\0') { + errno = ENOENT; + return; + } - /* http://www.opengroup.org/onlinepubs/009695399/functions/exec.html - * "If the file argument contains a slash character, it is used as - * the pathname for this file. Otherwise, the path prefix for this - * file is obtained by a search of the directories passed in the - * PATH environment variable" */ - || (strchr(file, '/') != NULL) - - /* Parent and child PATH the same? Use child PATH. */ - || (strcmp(parentPath, effectivePath()) == 0) - - /* We want ENOENT, not EACCES, for zero-length program names. */ - || (*file == '\0')) - - return execvp(file, (char **) argv); - else - return execvp_usingParentPath(file, argv); + if (strchr(file, '/') != NULL) { + execve_with_shell_fallback(file, argv, envp); + } else { + /* We must search PATH (parent's, not child's) */ + char expanded_file[PATH_MAX]; + int filelen = strlen(file); + int sticky_errno = 0; + const char * const * dirs; + for (dirs = parentPathv; *dirs; dirs++) { + const char * dir = *dirs; + int dirlen = strlen(dir); + if (filelen + dirlen + 1 >= PATH_MAX) { + errno = ENAMETOOLONG; + continue; + } + memcpy(expanded_file, dir, dirlen); + memcpy(expanded_file + dirlen, file, filelen); + expanded_file[dirlen + filelen] = '\0'; + execve_with_shell_fallback(expanded_file, argv, envp); + /* There are 3 responses to various classes of errno: + * return immediately, continue (especially for ENOENT), + * or continue with "sticky" errno. + * + * From exec(3): + * + * If permission is denied for a file (the attempted + * execve returned EACCES), these functions will continue + * searching the rest of the search path. If no other + * file is found, however, they will return with the + * global variable errno set to EACCES. + */ + switch (errno) { + case EACCES: + sticky_errno = errno; + /* FALLTHRU */ + case ENOENT: + case ENOTDIR: +#ifdef ELOOP + case ELOOP: +#endif +#ifdef ESTALE + case ESTALE: +#endif +#ifdef ENODEV + case ENODEV: +#endif +#ifdef ETIMEDOUT + case ETIMEDOUT: +#endif + break; /* Try other directories in PATH */ + default: + return; + } + } + if (sticky_errno != 0) + errno = sticky_errno; + } } static void @@ -516,10 +564,95 @@ } } -#ifndef __solaris__ -#undef fork1 -#define fork1() fork() -#endif +typedef struct _ChildStuff +{ + int in[2]; + int out[2]; + int err[2]; + int fail[2]; + int fds[3]; + const char **argv; + const char **envv; + const char *pdir; + jboolean redirectErrorStream; +} ChildStuff; + +static void +copyPipe(int from[2], int to[2]) +{ + to[0] = from[0]; + to[1] = from[1]; +} + +/** + * Child process after a successful fork() or clone(). + * This function must not return, and must be prepared for either all + * of its address space to be shared with its parent, or to be a copy. + * It must not modify global variables such as "environ". + */ +static int +childProcess(void *arg) +{ + const ChildStuff* p = (const ChildStuff*) arg; + + /* Close the parent sides of the pipes. + Closing pipe fds here is redundant, since closeDescriptors() + would do it anyways, but a little paranoia is a good thing. */ + closeSafely(p->in[1]); + closeSafely(p->out[0]); + closeSafely(p->err[0]); + closeSafely(p->fail[0]); + + /* Give the child sides of the pipes the right fileno's. */ + /* Note: it is possible for in[0] == 0 */ + moveDescriptor(p->in[0] != -1 ? p->in[0] : p->fds[0], STDIN_FILENO); + moveDescriptor(p->out[1]!= -1 ? p->out[1] : p->fds[1], STDOUT_FILENO); + + if (p->redirectErrorStream) { + closeSafely(p->err[1]); + dup2(STDOUT_FILENO, STDERR_FILENO); + } else { + moveDescriptor(p->err[1] != -1 ? p->err[1] : p->fds[2], STDERR_FILENO); + } + + moveDescriptor(p->fail[1], FAIL_FILENO); + + /* close everything */ + if (closeDescriptors() == 0) { /* failed, close the old way */ + int max_fd = (int)sysconf(_SC_OPEN_MAX); + int i; + for (i = FAIL_FILENO + 1; i < max_fd; i++) + close(i); + } + + /* change to the new working directory */ + if (p->pdir != NULL && chdir(p->pdir) < 0) + goto WhyCantJohnnyExec; + + if (fcntl(FAIL_FILENO, F_SETFD, FD_CLOEXEC) == -1) + goto WhyCantJohnnyExec; + + execvpe(p->argv[0], p->argv, p->envv); + + WhyCantJohnnyExec: + /* We used to go to an awful lot of trouble to predict whether the + * child would fail, but there is no reliable way to predict the + * success of an operation without *trying* it, and there's no way + * to try a chdir or exec in the parent. Instead, all we need is a + * way to communicate any failure back to the parent. Easy; we just + * send the errno back to the parent over a pipe in case of failure. + * The tricky thing is, how do we communicate the *success* of exec? + * We use FD_CLOEXEC together with the fact that a read() on a pipe + * yields EOF when the write ends (we have two of them!) are closed. + */ + { + int errnum = errno; + write(FAIL_FILENO, &errnum, sizeof(errnum)); + } + close(FAIL_FILENO); + _exit(-1); + return 0; /* Suppress warning "no return value from function" */ +} JNIEXPORT jint JNICALL Java_java_lang_UNIXProcess_forkAndExec(JNIEnv *env, @@ -533,34 +666,43 @@ { int errnum; int resultPid = -1; +#if USE_CLONE + void *clone_stack = NULL; +#endif int in[2], out[2], err[2], fail[2]; - const char **argv = NULL; - const char **envv = NULL; - const char *pprog = getBytes(env, prog); - const char *pargBlock = getBytes(env, argBlock); - const char *penvBlock = getBytes(env, envBlock); - const char *pdir = getBytes(env, dir); jint *fds = NULL; + const char *pprog = NULL; + const char *pargBlock = NULL; + const char *penvBlock = NULL; + ChildStuff *c; in[0] = in[1] = out[0] = out[1] = err[0] = err[1] = fail[0] = fail[1] = -1; - assert(prog != NULL && argBlock != NULL); - if (pprog == NULL) goto Catch; - if (pargBlock == NULL) goto Catch; - if (envBlock != NULL && penvBlock == NULL) goto Catch; - if (dir != NULL && pdir == NULL) goto Catch; + if ((c = NEW(ChildStuff, 1)) == NULL) return -1; + c->argv = NULL; + c->envv = NULL; + c->pdir = NULL; - /* Convert pprog + pargBlock into a char ** argv */ - if ((argv = NEW(const char *, argc + 2)) == NULL) - goto Catch; - argv[0] = pprog; - initVectorFromBlock(argv+1, pargBlock, argc); + /* Convert prog + argBlock into a char ** argv. + * Add one word room for expansion of argv for use by + * execve_as_traditional_shell_script. + */ + assert(prog != NULL && argBlock != NULL); + if ((pprog = getBytes(env, prog)) == NULL) goto Catch; + if ((pargBlock = getBytes(env, argBlock)) == NULL) goto Catch; + if ((c->argv = NEW(const char *, argc + 3)) == NULL) goto Catch; + c->argv[0] = pprog; + initVectorFromBlock(c->argv+1, pargBlock, argc); if (envBlock != NULL) { - /* Convert penvBlock into a char ** envv */ - if ((envv = NEW(const char *, envc + 1)) == NULL) - goto Catch; - initVectorFromBlock(envv, penvBlock, envc); + /* Convert envBlock into a char ** envv */ + if ((penvBlock = getBytes(env, envBlock)) == NULL) goto Catch; + if ((c->envv = NEW(const char *, envc + 1)) == NULL) goto Catch; + initVectorFromBlock(c->envv, penvBlock, envc); + } + + if (dir != NULL) { + if ((c->pdir = getBytes(env, dir)) == NULL) goto Catch; } assert(std_fds != NULL); @@ -574,72 +716,45 @@ throwIOException(env, errno, "Bad file descriptor"); goto Catch; } + c->fds[0] = fds[0]; + c->fds[1] = fds[1]; + c->fds[2] = fds[2]; - resultPid = fork1(); + copyPipe(in, c->in); + copyPipe(out, c->out); + copyPipe(err, c->err); + copyPipe(fail, c->fail); + + c->redirectErrorStream = redirectErrorStream; + + { +#if USE_CLONE + /* See clone(2). + * Instead of worrying about which direction the stack grows, just + * allocate twice as much and start the stack in the middle. */ + const int stack_size = 64 * 1024; + if ((clone_stack = NEW(char, 2 * stack_size)) == NULL) goto Catch; + resultPid = clone(childProcess, clone_stack + stack_size, + /* CLONE_VFORK | // works, but unnecessary */ + CLONE_VM | SIGCHLD, c); +#else + /* From fork(2): In Solaris 10, a call to fork() is identical + * to a call to fork1(); only the calling thread is replicated + * in the child process. This is the POSIX-specified behavior + * for fork(). */ + resultPid = fork(); + if (resultPid == 0) { + childProcess(c); + assert(0); /* childProcess must not return */ + } +#endif + } + if (resultPid < 0) { throwIOException(env, errno, "Fork failed"); goto Catch; } - if (resultPid == 0) { - /* Child process */ - - /* Close the parent sides of the pipes. - Closing pipe fds here is redundant, since closeDescriptors() - would do it anyways, but a little paranoia is a good thing. */ - closeSafely(in[1]); - closeSafely(out[0]); - closeSafely(err[0]); - closeSafely(fail[0]); - - /* Give the child sides of the pipes the right fileno's. */ - /* Note: it is possible for in[0] == 0 */ - moveDescriptor(in[0] != -1 ? in[0] : fds[0], STDIN_FILENO); - moveDescriptor(out[1]!= -1 ? out[1] : fds[1], STDOUT_FILENO); - - if (redirectErrorStream) { - closeSafely(err[1]); - dup2(STDOUT_FILENO, STDERR_FILENO); - } else { - moveDescriptor(err[1] != -1 ? err[1] : fds[2], STDERR_FILENO); - } - - moveDescriptor(fail[1], FAIL_FILENO); - - /* close everything */ - if (closeDescriptors() == 0) { /* failed, close the old way */ - int max_fd = (int)sysconf(_SC_OPEN_MAX); - int i; - for (i = FAIL_FILENO + 1; i < max_fd; i++) - close(i); - } - - /* change to the new working directory */ - if (pdir != NULL && chdir(pdir) < 0) - goto WhyCantJohnnyExec; - - if (fcntl(FAIL_FILENO, F_SETFD, FD_CLOEXEC) == -1) - goto WhyCantJohnnyExec; - - execvpe(argv[0], argv, envv); - - WhyCantJohnnyExec: - /* We used to go to an awful lot of trouble to predict whether the - * child would fail, but there is no reliable way to predict the - * success of an operation without *trying* it, and there's no way - * to try a chdir or exec in the parent. Instead, all we need is a - * way to communicate any failure back to the parent. Easy; we just - * send the errno back to the parent over a pipe in case of failure. - * The tricky thing is, how do we communicate the *success* of exec? - * We use FD_CLOEXEC together with the fact that a read() on a pipe - * yields EOF when the write ends (we have two of them!) are closed. - */ - errnum = errno; - write(FAIL_FILENO, &errnum, sizeof(errnum)); - close(FAIL_FILENO); - _exit(-1); - } - /* parent process */ close(fail[1]); fail[1] = -1; /* See: WhyCantJohnnyExec */ @@ -660,6 +775,10 @@ fds[2] = (err[0] != -1) ? err[0] : -1; Finally: +#if USE_CLONE + free(clone_stack); +#endif + /* Always clean up the child's side of the pipes */ closeSafely(in [0]); closeSafely(out[1]); @@ -669,13 +788,14 @@ closeSafely(fail[0]); closeSafely(fail[1]); - free(argv); - free(envv); - releaseBytes(env, prog, pprog); releaseBytes(env, argBlock, pargBlock); releaseBytes(env, envBlock, penvBlock); - releaseBytes(env, dir, pdir); + releaseBytes(env, dir, c->pdir); + + free(c->argv); + free(c->envv); + free(c); if (fds != NULL) (*env)->ReleaseIntArrayElements(env, std_fds, fds, 0); diff -r c8f6e154868b -r bc0aa59e8e40 jdk/test/java/lang/ProcessBuilder/Basic.java --- a/jdk/test/java/lang/ProcessBuilder/Basic.java Fri Jun 12 12:26:20 2009 -0700 +++ b/jdk/test/java/lang/ProcessBuilder/Basic.java Wed Jun 17 13:12:42 2009 -0700 @@ -257,6 +257,18 @@ s.write(bytes); // Might hang! } + static void checkPermissionDenied(ProcessBuilder pb) { + try { + pb.start(); + fail("Expected IOException not thrown"); + } catch (IOException e) { + String m = e.getMessage(); + if (EnglishUnix.is() && + ! matches(m, "Permission denied")) + unexpected(e); + } catch (Throwable t) { unexpected(t); } + } + public static class JavaChild { public static void main(String args[]) throws Throwable { String action = args[0]; @@ -317,12 +329,10 @@ for (final ProcessBuilder pb : new ProcessBuilder[] {pb1, pb2}) { pb.command("true"); - r = run(pb.start()); - equal(r.exitValue(), True.exitValue()); + equal(run(pb).exitValue(), True.exitValue()); pb.command("false"); - r = run(pb.start()); - equal(r.exitValue(), False.exitValue()); + equal(run(pb).exitValue(), False.exitValue()); } if (failed != 0) throw new Error("null PATH"); @@ -367,31 +377,82 @@ // Can't execute a directory -- permission denied // Report EACCES errno new File("dir1/prog").mkdirs(); - try { - pb.start(); - fail("Expected IOException not thrown"); - } catch (IOException e) { - String m = e.getMessage(); - if (EnglishUnix.is() && - ! matches(m, "Permission denied")) - unexpected(e); - } catch (Throwable t) { unexpected(t); } + checkPermissionDenied(pb); // continue searching if EACCES copy("/bin/true", "dir2/prog"); - equal(run(pb.start()).exitValue(), True.exitValue()); + equal(run(pb).exitValue(), True.exitValue()); new File("dir1/prog").delete(); new File("dir2/prog").delete(); new File("dir2/prog").mkdirs(); copy("/bin/true", "dir1/prog"); - equal(run(pb.start()).exitValue(), True.exitValue()); + equal(run(pb).exitValue(), True.exitValue()); - // Check empty PATH component means current directory + // Check empty PATH component means current directory. + // + // While we're here, let's test different kinds of + // Unix executables, and PATH vs explicit searching. new File("dir1/prog").delete(); new File("dir2/prog").delete(); - copy("/bin/true", "./prog"); - equal(run(pb.start()).exitValue(), True.exitValue()); + for (String[] command : + new String[][] { + new String[] {"./prog"}, + cmd}) { + pb.command(command); + File prog = new File("./prog"); + // "Normal" binaries + copy("/bin/true", "./prog"); + equal(run(pb).exitValue(), + True.exitValue()); + copy("/bin/false", "./prog"); + equal(run(pb).exitValue(), + False.exitValue()); + prog.delete(); + // Interpreter scripts with #! + setFileContents(prog, "#!/bin/true\n"); + prog.setExecutable(true); + equal(run(pb).exitValue(), + True.exitValue()); + prog.delete(); + setFileContents(prog, "#!/bin/false\n"); + prog.setExecutable(true); + equal(run(pb).exitValue(), + False.exitValue()); + // Traditional shell scripts without #! + setFileContents(prog, "exec /bin/true\n"); + prog.setExecutable(true); + equal(run(pb).exitValue(), + True.exitValue()); + prog.delete(); + setFileContents(prog, "exec /bin/false\n"); + prog.setExecutable(true); + equal(run(pb).exitValue(), + False.exitValue()); + prog.delete(); + } + + // Test Unix interpreter scripts + File dir1Prog = new File("dir1/prog"); + dir1Prog.delete(); + pb.command(new String[] {"prog", "world"}); + setFileContents(dir1Prog, "#!/bin/echo hello\n"); + checkPermissionDenied(pb); + dir1Prog.setExecutable(true); + equal(run(pb).out(), "hello dir1/prog world\n"); + equal(run(pb).exitValue(), True.exitValue()); + dir1Prog.delete(); + pb.command(cmd); + + // Test traditional shell scripts without #! + setFileContents(dir1Prog, "/bin/echo \"$@\"\n"); + pb.command(new String[] {"prog", "hello", "world"}); + checkPermissionDenied(pb); + dir1Prog.setExecutable(true); + equal(run(pb).out(), "hello world\n"); + equal(run(pb).exitValue(), True.exitValue()); + dir1Prog.delete(); + pb.command(cmd); // If prog found on both parent and child's PATH, // parent's is used. @@ -402,10 +463,10 @@ copy("/bin/true", "dir1/prog"); copy("/bin/false", "dir3/prog"); pb.environment().put("PATH","dir3"); - equal(run(pb.start()).exitValue(), True.exitValue()); + equal(run(pb).exitValue(), True.exitValue()); copy("/bin/true", "dir3/prog"); copy("/bin/false", "dir1/prog"); - equal(run(pb.start()).exitValue(), False.exitValue()); + equal(run(pb).exitValue(), False.exitValue()); } finally { // cleanup @@ -1503,21 +1564,19 @@ childArgs.add("OutErr"); ProcessBuilder pb = new ProcessBuilder(childArgs); { - ProcessResults r = run(pb.start()); + ProcessResults r = run(pb); equal(r.out(), "outout"); equal(r.err(), "errerr"); } { pb.redirectErrorStream(true); - ProcessResults r = run(pb.start()); + ProcessResults r = run(pb); equal(r.out(), "outerrouterr"); equal(r.err(), ""); } } catch (Throwable t) { unexpected(t); } - if (! Windows.is() && - new File("/bin/true").exists() && - new File("/bin/false").exists()) { + if (Unix.is()) { //---------------------------------------------------------------- // We can find true and false when PATH is null //---------------------------------------------------------------- @@ -1526,7 +1585,7 @@ childArgs.add("null PATH"); ProcessBuilder pb = new ProcessBuilder(childArgs); pb.environment().remove("PATH"); - ProcessResults r = run(pb.start()); + ProcessResults r = run(pb); equal(r.out(), ""); equal(r.err(), ""); equal(r.exitValue(), 0); @@ -1540,7 +1599,7 @@ childArgs.add("PATH search algorithm"); ProcessBuilder pb = new ProcessBuilder(childArgs); pb.environment().put("PATH", "dir1:dir2:"); - ProcessResults r = run(pb.start()); + ProcessResults r = run(pb); equal(r.out(), ""); equal(r.err(), ""); equal(r.exitValue(), True.exitValue()); diff -r c8f6e154868b -r bc0aa59e8e40 jdk/test/java/lang/ProcessBuilder/BigFork.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/ProcessBuilder/BigFork.java Wed Jun 17 13:12:42 2009 -0700 @@ -0,0 +1,103 @@ +/* + * Copyright 2009 Google Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +import java.util.*; +import java.io.*; + +/** + * A manual test that demonstrates the ability to start a subprocess + * on Linux without getting ENOMEM. Run this test like: + * + * java -Xmx7000m BigFork + * + * providing a -Xmx flag suitable for your operating environment. + * Here's the bad old behavior: + * + * ==> java -Xmx7000m -esa -ea BigFork + * ------- + * CommitLimit: 6214700 kB + * Committed_AS: 2484452 kB + * ------- + * size=4.6GB + * ------- + * CommitLimit: 6214700 kB + * Committed_AS: 7219680 kB + * ------- + * Exception in thread "main" java.io.IOException: Cannot run program "/bin/true": java.io.IOException: error=12, Cannot allocate memory + * at java.lang.ProcessBuilder.start(ProcessBuilder.java:1018) + * at BigFork.main(BigFork.java:79) + * Caused by: java.io.IOException: java.io.IOException: error=12, Cannot allocate memory + * at java.lang.UNIXProcess.<init>(UNIXProcess.java:190) + * at java.lang.ProcessImpl.start(ProcessImpl.java:128) + * at java.lang.ProcessBuilder.start(ProcessBuilder.java:1010) + * ... 1 more + */ +public class BigFork { + static final Random rnd = new Random(); + static void touchPages(byte[] chunk) { + final int pageSize = 4096; + for (int i = 0; i < chunk.length; i+= pageSize) { + chunk[i] = (byte) rnd.nextInt(); + } + } + + static void showCommittedMemory() throws IOException { + BufferedReader r = + new BufferedReader( + new InputStreamReader( + new FileInputStream("/proc/meminfo"))); + System.out.println("-------"); + String line; + while ((line = r.readLine()) != null) { + if (line.startsWith("Commit")) { + System.out.printf("%s%n", line); + } + } + System.out.println("-------"); + } + + public static void main(String[] args) throws Throwable { + showCommittedMemory(); + + final int chunkSize = 1024 * 1024 * 100; + List<byte[]> chunks = new ArrayList<byte[]>(100); + try { + for (;;) { + byte[] chunk = new byte[chunkSize]; + touchPages(chunk); + chunks.add(chunk); + } + } catch (OutOfMemoryError e) { + chunks.set(0, null); // Free up one chunk + System.gc(); + int size = chunks.size(); + System.out.printf("size=%.2gGB%n", (double)size/10); + + showCommittedMemory(); + + // Can we fork/exec in our current bloated state? + Process p = new ProcessBuilder("/bin/true").start(); + p.waitFor(); + } + } +} diff -r c8f6e154868b -r bc0aa59e8e40 jdk/test/sun/security/krb5/auto/CrossRealm.java --- a/jdk/test/sun/security/krb5/auto/CrossRealm.java Fri Jun 12 12:26:20 2009 -0700 +++ b/jdk/test/sun/security/krb5/auto/CrossRealm.java Wed Jun 17 13:12:42 2009 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ * @bug 6706974 * @summary Add krb5 test infrastructure */ +import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.security.Security; @@ -50,17 +51,20 @@ KDC kdc1 = KDC.create("RABBIT.HOLE"); kdc1.addPrincipal("dummy", "bogus".toCharArray()); kdc1.addPrincipalRandKey("krbtgt/RABBIT.HOLE"); - kdc1.addPrincipal("krbtgt/SNAKE.HOLE", "sharedsec".toCharArray()); + kdc1.addPrincipal("krbtgt/SNAKE.HOLE@RABBIT.HOLE", + "rabbit->snake".toCharArray()); KDC kdc2 = KDC.create("SNAKE.HOLE"); kdc2.addPrincipalRandKey("krbtgt/SNAKE.HOLE"); - kdc2.addPrincipal("krbtgt/RABBIT.HOLE", "sharedsec".toCharArray()); + kdc2.addPrincipal("krbtgt/SNAKE.HOLE@RABBIT.HOLE", + "rabbit->snake".toCharArray()); kdc2.addPrincipalRandKey("host/www.snake.hole"); KDC.saveConfig("krb5-localkdc.conf", kdc1, kdc2, "forwardable=true", "[domain_realm]", ".snake.hole=SNAKE.HOLE"); + new File("krb5-localkdc.conf").deleteOnExit(); System.setProperty("java.security.krb5.conf", "krb5-localkdc.conf"); } @@ -68,6 +72,7 @@ Security.setProperty("auth.login.defaultCallbackHandler", "CrossRealm"); System.setProperty("java.security.auth.login.config", "jaas-localkdc.conf"); System.setProperty("javax.security.auth.useSubjectCredsOnly", "false"); + new File("jaas-localkdc.conf").deleteOnExit(); FileOutputStream fos = new FileOutputStream("jaas-localkdc.conf"); fos.write(("com.sun.security.jgss.krb5.initiate {\n" + " com.sun.security.auth.module.Krb5LoginModule\n" + diff -r c8f6e154868b -r bc0aa59e8e40 jdk/test/sun/security/krb5/auto/HttpNegotiateServer.java --- a/jdk/test/sun/security/krb5/auto/HttpNegotiateServer.java Fri Jun 12 12:26:20 2009 -0700 +++ b/jdk/test/sun/security/krb5/auto/HttpNegotiateServer.java Wed Jun 17 13:12:42 2009 -0700 @@ -25,7 +25,6 @@ * @test * @bug 6578647 * @summary Undefined requesting URL in java.net.Authenticator.getPasswordAuthentication() - * @run main/othervm -Dsun.net.spi.nameservice.provider.1=ns,mock HttpNegotiateServer */ import com.sun.net.httpserver.Headers; @@ -40,12 +39,10 @@ import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.InetSocketAddress; -import java.net.InetAddress; import java.net.PasswordAuthentication; import java.net.Proxy; import java.net.URL; import java.security.PrivilegedExceptionAction; -import java.net.UnknownHostException; import java.util.HashMap; import java.util.Map; import javax.security.auth.Subject; @@ -53,8 +50,6 @@ import org.ietf.jgss.GSSCredential; import org.ietf.jgss.GSSManager; import sun.security.jgss.GSSUtil; -import sun.net.spi.nameservice.NameService; -import sun.net.spi.nameservice.NameServiceDescriptor; import sun.security.krb5.Config; /** @@ -62,7 +57,7 @@ * party uses JAAS login to get subjects and executes JGSS calls using * Subject.doAs. */ -public class HttpNegotiateServer implements NameServiceDescriptor { +public class HttpNegotiateServer { // Two realm, web server in one, proxy server in another final static String REALM_WEB = "WEB.DOMAIN"; @@ -142,12 +137,12 @@ public static void main(String[] args) throws Exception { - KDC kdcw = new KDC(REALM_WEB, 0, true); + KDC kdcw = KDC.create(REALM_WEB); kdcw.addPrincipal(WEB_USER, WEB_PASS); kdcw.addPrincipalRandKey("krbtgt/" + REALM_WEB); kdcw.addPrincipalRandKey("HTTP/" + WEB_HOST); - KDC kdcp = new KDC(REALM_PROXY, 0, true); + KDC kdcp = KDC.create(REALM_PROXY); kdcp.addPrincipal(PROXY_USER, PROXY_PASS); kdcp.addPrincipalRandKey("krbtgt/" + REALM_PROXY); kdcp.addPrincipalRandKey("HTTP/" + PROXY_HOST); @@ -306,36 +301,5 @@ } } } - - @Override - public NameService createNameService() throws Exception { - NameService ns = new NameService() { - @Override - public InetAddress[] lookupAllHostAddr(String host) - throws UnknownHostException { - // Everything is localhost - return new InetAddress[]{ - InetAddress.getByAddress(host, new byte[]{127,0,0,1}) - }; - } - @Override - public String getHostByAddr(byte[] addr) - throws UnknownHostException { - // No reverse lookup - throw new UnknownHostException(); - } - }; - return ns; - } - - @Override - public String getProviderName() { - return "mock"; - } - - @Override - public String getType() { - return "ns"; - } } diff -r c8f6e154868b -r bc0aa59e8e40 jdk/test/sun/security/krb5/auto/KDC.java --- a/jdk/test/sun/security/krb5/auto/KDC.java Fri Jun 12 12:26:20 2009 -0700 +++ b/jdk/test/sun/security/krb5/auto/KDC.java Wed Jun 17 13:12:42 2009 -0700 @@ -30,6 +30,8 @@ import java.security.SecureRandom; import java.util.*; import java.util.concurrent.*; +import sun.net.spi.nameservice.NameService; +import sun.net.spi.nameservice.NameServiceDescriptor; import sun.security.krb5.*; import sun.security.krb5.internal.*; import sun.security.krb5.internal.ccache.CredentialsCache; @@ -118,14 +120,16 @@ // The random generator to generate random keys (including session keys) private static SecureRandom secureRandom = new SecureRandom(); - // Principal db + // Principal db. principal -> pass private Map<String,char[]> passwords = new HashMap<String,char[]>(); // Realm name private String realm; + // KDC + private String kdc; + // Service port number + private int port; // The request/response job queue private BlockingQueue<Job> q = new ArrayBlockingQueue<Job>(100); - // Service port number - private int port; // Options private Map<Option,Object> options = new HashMap<Option,Object>(); @@ -139,33 +143,21 @@ PREAUTH_REQUIRED, }; + static { + System.setProperty("sun.net.spi.nameservice.provider.1", "ns,mock"); + } + /** * A standalone KDC server. - * @param args - * @throws java.lang.Exception */ public static void main(String[] args) throws Exception { - if (args.length > 0) { - if (args[0].equals("-help") || args[0].equals("--help")) { - System.out.println("Usage:"); - System.out.println(" java " + KDC.class + " " + - "Start KDC on port 8888"); - return; - } - } - String localhost = "localhost"; - try { - localhost = InetAddress.getByName(localhost) - .getCanonicalHostName(); - } catch (UnknownHostException uhe) { - ; // Ignore, localhost is still "localhost" - } - KDC kdc = create("RABBIT.HOLE", 8888, false); + KDC kdc = create("RABBIT.HOLE", "kdc.rabbit,hole", 0, false); kdc.addPrincipal("dummy", "bogus".toCharArray()); kdc.addPrincipal("foo", "bar".toCharArray()); - kdc.addPrincipalRandKey("krbtgt/" + kdc.realm); - kdc.addPrincipalRandKey("server/" + localhost); - kdc.addPrincipalRandKey("backend/" + localhost); + kdc.addPrincipalRandKey("krbtgt/RABBIT.HOLE"); + kdc.addPrincipalRandKey("server/host.rabbit.hole"); + kdc.addPrincipalRandKey("backend/host.rabbit.hole"); + KDC.saveConfig("krb5.conf", kdc, "forwardable = true"); } /** @@ -175,7 +167,7 @@ * @throws java.io.IOException for any socket creation error */ public static KDC create(String realm) throws IOException { - return create(realm, 0, true); + return create(realm, "kdc." + realm.toLowerCase(), 0, true); } /** @@ -187,8 +179,8 @@ * @return the running KDC instance * @throws java.io.IOException for any socket creation error */ - public static KDC create(String realm, int port, boolean asDaemon) throws IOException { - return new KDC(realm, port, asDaemon); + public static KDC create(String realm, String kdc, int port, boolean asDaemon) throws IOException { + return new KDC(realm, kdc, port, asDaemon); } /** @@ -228,10 +220,7 @@ KeyTab ktab = KeyTab.create(tab); for (KDC kdc: kdcs) { for (String name : kdc.passwords.keySet()) { - if (name.equals("krbtgt/" + kdc.realm)) { - continue; - } - ktab.addEntry(new PrincipalName(name + "@" + kdc.realm, + ktab.addEntry(new PrincipalName(name, name.indexOf('/') < 0 ? PrincipalName.KRB_NT_UNKNOWN : PrincipalName.KRB_NT_SRV_HST), @@ -255,6 +244,9 @@ * @param pass the password for the principal */ public void addPrincipal(String user, char[] pass) { + if (user.indexOf('@') < 0) { + user = user + "@" + realm; + } passwords.put(user, pass); } @@ -264,7 +256,7 @@ * form of host/f.q.d.n */ public void addPrincipalRandKey(String user) { - passwords.put(user, randomPassword()); + addPrincipal(user, randomPassword()); } /** @@ -276,6 +268,14 @@ } /** + * Returns the name of kdc + * @return the name of kdc + */ + public String getKDC() { + return kdc; + } + + /** * Writes a krb5.conf for one or more KDC that includes KDC locations for * each realm and the default realm name. You can also add extra strings * into the file. The method should be called like: @@ -299,7 +299,7 @@ * * [realms] * REALM.NAME = { - * kdc = localhost:port_number + * kdc = host:port_number * } * </pre> * @@ -320,10 +320,10 @@ * * [realms] * KDC1.NAME = { - * kdc = localhost:port1 + * kdc = host:port1 * } * KDC2.NAME = { - * kdc = localhost:port2 + * kdc = host:port2 * } * </pre> * @param file the name of the file to write into @@ -372,16 +372,17 @@ * Private constructor, cannot be called outside. * @param realm */ - private KDC(String realm) { + private KDC(String realm, String kdc) { this.realm = realm; + this.kdc = kdc; } /** * A constructor that starts the KDC service also. */ - protected KDC(String realm, int port, boolean asDaemon) + protected KDC(String realm, String kdc, int port, boolean asDaemon) throws IOException { - this(realm); + this(realm, kdc); startServer(port, asDaemon); } /** @@ -426,7 +427,11 @@ * the database. */ private char[] getPassword(PrincipalName p) throws KrbException { - char[] pass = passwords.get(p.getNameString()); + String pn = p.toString(); + if (p.getRealmString() == null) { + pn = pn + "@" + getRealm(); + } + char[] pass = passwords.get(pn); if (pass == null) { throw new KrbException(Krb5.KDC_ERR_C_PRINCIPAL_UNKNOWN); } @@ -434,29 +439,18 @@ } /** - * Returns the salt string for the principal. For normal users, the - * concatenation for the realm name and the sections of the principal; - * for krgtgt/A@B and krbtgt/B@A, always return AB (so that inter-realm - * principals have the same key). + * Returns the salt string for the principal. * @param p principal * @return the salt */ private String getSalt(PrincipalName p) { String[] ns = p.getNameStrings(); - if (ns[0].equals("krbtgt") && ns.length > 1) { - // Shared cross-realm keys must be the same - if (ns[1].compareTo(realm) < 0) { - return ns[1] + realm; - } else { - return realm + ns[1]; - } - } else { - String s = getRealm(); - for (String n: p.getNameStrings()) { - s += n; - } - return s; + String s = p.getRealmString(); + if (s == null) s = getRealm(); + for (String n: p.getNameStrings()) { + s += n; } + return s; } /** @@ -525,14 +519,8 @@ EncryptedData ed = apReq.authenticator; tkt = apReq.ticket; etype = tkt.encPart.getEType(); - EncryptionKey kkey = null; - if (!tkt.realm.toString().equals(realm)) { - if (tkt.sname.getNameString().equals("krbtgt/" + realm)) { - kkey = keyForUser(new PrincipalName("krbtgt/" + tkt.realm.toString(), realm), etype); - } - } else { - kkey = keyForUser(tkt.sname, etype); - } + tkt.sname.setRealm(tkt.realm); + EncryptionKey kkey = keyForUser(tkt.sname, etype); byte[] bb = tkt.encPart.decrypt(kkey, KeyUsage.KU_TICKET); DerInputStream derIn = new DerInputStream(bb); DerValue der = derIn.getDerValue(); @@ -857,10 +845,13 @@ /** * Generates a line for a KDC to put inside [realms] of krb5.conf * @param kdc the KDC - * @return REALM.NAME = { kdc = localhost:port } + * @return REALM.NAME = { kdc = host:port } */ private static String realmLineForKDC(KDC kdc) { - return String.format(" %s = {\n kdc = localhost:%d\n }\n", kdc.realm, kdc.port); + return String.format(" %s = {\n kdc = %s:%d\n }\n", + kdc.realm, + kdc.kdc, + kdc.port); } /** @@ -1000,4 +991,37 @@ } } } + + public static class KDCNameService implements NameServiceDescriptor { + @Override + public NameService createNameService() throws Exception { + NameService ns = new NameService() { + @Override + public InetAddress[] lookupAllHostAddr(String host) + throws UnknownHostException { + // Everything is localhost + return new InetAddress[]{ + InetAddress.getByAddress(host, new byte[]{127,0,0,1}) + }; + } + @Override + public String getHostByAddr(byte[] addr) + throws UnknownHostException { + // No reverse lookup, PrincipalName use original string + throw new UnknownHostException(); + } + }; + return ns; + } + + @Override + public String getProviderName() { + return "mock"; + } + + @Override + public String getType() { + return "ns"; + } + } } diff -r c8f6e154868b -r bc0aa59e8e40 jdk/test/sun/security/krb5/auto/META-INF/services/sun.net.spi.nameservice.NameServiceDescriptor --- a/jdk/test/sun/security/krb5/auto/META-INF/services/sun.net.spi.nameservice.NameServiceDescriptor Fri Jun 12 12:26:20 2009 -0700 +++ b/jdk/test/sun/security/krb5/auto/META-INF/services/sun.net.spi.nameservice.NameServiceDescriptor Wed Jun 17 13:12:42 2009 -0700 @@ -1,1 +1,1 @@ -HttpNegotiateServer +KDC$KDCNameService diff -r c8f6e154868b -r bc0aa59e8e40 jdk/test/sun/security/krb5/auto/OneKDC.java --- a/jdk/test/sun/security/krb5/auto/OneKDC.java Fri Jun 12 12:26:20 2009 -0700 +++ b/jdk/test/sun/security/krb5/auto/OneKDC.java Wed Jun 17 13:12:42 2009 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,35 +46,22 @@ */ public class OneKDC extends KDC { - // The krb5 codes would try to canonicalize hostnames before creating - // a service principal name, so let's find out the canonicalized form - // of localhost first. The following codes mimic the process inside - // PrincipalName.java. - static String localhost = "localhost"; - static { - try { - localhost = InetAddress.getByName(localhost) - .getCanonicalHostName(); - } catch (UnknownHostException uhe) { - ; // Ignore, localhost is still "localhost" - } - } public static final String USER = "dummy"; public static final char[] PASS = "bogus".toCharArray(); - public static String SERVER = "server/" + localhost; - public static String BACKEND = "backend/" + localhost; public static final String KRB5_CONF = "localkdc-krb5.conf"; public static final String KTAB = "localkdc.ktab"; public static final String JAAS_CONF = "localkdc-jaas.conf"; public static final String REALM = "RABBIT.HOLE"; - + public static String SERVER = "server/host." + REALM.toLowerCase(); + public static String BACKEND = "backend/host." + REALM.toLowerCase(); + public static String KDCHOST = "kdc." + REALM.toLowerCase(); /** * Creates the KDC and starts it. * @param etype Encryption type, null if not specified * @throws java.lang.Exception if there's anything wrong */ public OneKDC(String etype) throws Exception { - super(REALM, 0, true); + super(REALM, KDCHOST, 0, true); addPrincipal(USER, PASS); addPrincipalRandKey("krbtgt/" + REALM); addPrincipalRandKey(SERVER); diff -r c8f6e154868b -r bc0aa59e8e40 jdk/test/sun/security/krb5/auto/basic.sh --- a/jdk/test/sun/security/krb5/auto/basic.sh Fri Jun 12 12:26:20 2009 -0700 +++ b/jdk/test/sun/security/krb5/auto/basic.sh Wed Jun 17 13:12:42 2009 -0700 @@ -1,5 +1,5 @@ # -# Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -41,25 +41,31 @@ case "$OS" in Windows_* ) FS="\\" + SEP=";" ;; * ) FS="/" + SEP=":" ;; esac -${TESTJAVA}${FS}bin${FS}javac -d . \ +${TESTJAVA}${FS}bin${FS}javac -XDignore.symbol.file -d . \ ${TESTSRC}${FS}BasicKrb5Test.java \ ${TESTSRC}${FS}KDC.java \ ${TESTSRC}${FS}OneKDC.java \ ${TESTSRC}${FS}Action.java \ ${TESTSRC}${FS}Context.java \ || exit 10 -${TESTJAVA}${FS}bin${FS}java -Dtest.src=$TESTSRC BasicKrb5Test || exit 100 -${TESTJAVA}${FS}bin${FS}java -Dtest.src=$TESTSRC BasicKrb5Test des-cbc-crc || exit 1 -${TESTJAVA}${FS}bin${FS}java -Dtest.src=$TESTSRC BasicKrb5Test des-cbc-md5 || exit 3 -${TESTJAVA}${FS}bin${FS}java -Dtest.src=$TESTSRC BasicKrb5Test des3-cbc-sha1 || exit 16 -${TESTJAVA}${FS}bin${FS}java -Dtest.src=$TESTSRC BasicKrb5Test aes128-cts || exit 17 -${TESTJAVA}${FS}bin${FS}java -Dtest.src=$TESTSRC BasicKrb5Test aes256-cts || exit 18 -${TESTJAVA}${FS}bin${FS}java -Dtest.src=$TESTSRC BasicKrb5Test rc4-hmac || exit 23 + +# Add $TESTSRC to classpath so that customized nameservice can be used +J="${TESTJAVA}${FS}bin${FS}java -cp $TESTSRC${SEP}. BasicKrb5Test" + +$J || exit 100 +$J des-cbc-crc || exit 1 +$J des-cbc-md5 || exit 3 +$J des3-cbc-sha1 || exit 16 +$J aes128-cts || exit 17 +$J aes256-cts || exit 18 +$J rc4-hmac || exit 23 exit 0