1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate /* 30*0Sstevel@tonic-gate * Launch Java executables via exec(2). 31*0Sstevel@tonic-gate * 32*0Sstevel@tonic-gate * Java executables are platform-independent executable files 33*0Sstevel@tonic-gate * based on the JAR file format. Executable JAR files contain a 34*0Sstevel@tonic-gate * special 'extra field' header in the first file of the archive 35*0Sstevel@tonic-gate * that marks the file as a true executable. The data in that field 36*0Sstevel@tonic-gate * is used to pass additional run-time information to the Java VM. 37*0Sstevel@tonic-gate * 38*0Sstevel@tonic-gate * This handler looks for the appropriate magic number on the 39*0Sstevel@tonic-gate * front of the file, checks that the JAR file is executable, then 40*0Sstevel@tonic-gate * invokes the Java runtime environment to do the rest of the work. 41*0Sstevel@tonic-gate */ 42*0Sstevel@tonic-gate 43*0Sstevel@tonic-gate #include <sys/types.h> 44*0Sstevel@tonic-gate #include <sys/proc.h> 45*0Sstevel@tonic-gate #include <sys/vnode.h> 46*0Sstevel@tonic-gate #include <sys/exec.h> 47*0Sstevel@tonic-gate #include <sys/modctl.h> 48*0Sstevel@tonic-gate #include <sys/cmn_err.h> 49*0Sstevel@tonic-gate #include <sys/pathname.h> 50*0Sstevel@tonic-gate 51*0Sstevel@tonic-gate /* 52*0Sstevel@tonic-gate * These variables can be tweaked via /etc/system to allow prototyping 53*0Sstevel@tonic-gate * and debugging. See PSARC/1997/123. 54*0Sstevel@tonic-gate * 55*0Sstevel@tonic-gate * Modified by PSARC/1999/012 to be Contract Private between Solaris and 56*0Sstevel@tonic-gate * the Java Technology Group. It is expected that any future change to 57*0Sstevel@tonic-gate * these variables be coordinated between the consolidations. 58*0Sstevel@tonic-gate */ 59*0Sstevel@tonic-gate #if defined(__sparc) 60*0Sstevel@tonic-gate char *jexec = "/usr/java/jre/lib/sparc/jexec"; 61*0Sstevel@tonic-gate #elif defined(__i386) || defined(__i386_COMPAT) 62*0Sstevel@tonic-gate char *jexec = "/usr/java/jre/lib/i386/jexec"; 63*0Sstevel@tonic-gate #else 64*0Sstevel@tonic-gate #error "Unknown ISA" 65*0Sstevel@tonic-gate #endif 66*0Sstevel@tonic-gate char *jexec_arg = "-jar"; 67*0Sstevel@tonic-gate 68*0Sstevel@tonic-gate /* 69*0Sstevel@tonic-gate * ZIP/JAR file header information 70*0Sstevel@tonic-gate */ 71*0Sstevel@tonic-gate #define SIGSIZ 4 72*0Sstevel@tonic-gate #define LOCSIG "PK\003\004" 73*0Sstevel@tonic-gate #define LOCHDRSIZ 30 74*0Sstevel@tonic-gate 75*0Sstevel@tonic-gate #define CH(b, n) (((unsigned char *)(b))[n]) 76*0Sstevel@tonic-gate #define SH(b, n) (CH(b, n) | (CH(b, n+1) << 8)) 77*0Sstevel@tonic-gate #define LG(b, n) (SH(b, n) | (SH(b, n+2) << 16)) 78*0Sstevel@tonic-gate 79*0Sstevel@tonic-gate #define LOCNAM(b) (SH(b, 26)) /* filename size */ 80*0Sstevel@tonic-gate #define LOCEXT(b) (SH(b, 28)) /* extra field size */ 81*0Sstevel@tonic-gate 82*0Sstevel@tonic-gate #define XFHSIZ 4 /* header id, data size */ 83*0Sstevel@tonic-gate #define XFHID(b) (SH(b, 0)) /* extract field header id */ 84*0Sstevel@tonic-gate #define XFDATASIZ(b) (SH(b, 2)) /* extract field data size */ 85*0Sstevel@tonic-gate #define XFJAVASIG 0xcafe /* java executables */ 86*0Sstevel@tonic-gate 87*0Sstevel@tonic-gate /*ARGSUSED3*/ 88*0Sstevel@tonic-gate static int 89*0Sstevel@tonic-gate javaexec(vnode_t *vp, struct execa *uap, struct uarg *args, 90*0Sstevel@tonic-gate struct intpdata *idatap, int level, long *execsz, int setid, 91*0Sstevel@tonic-gate caddr_t execfile, cred_t *cred) 92*0Sstevel@tonic-gate { 93*0Sstevel@tonic-gate struct intpdata idata; 94*0Sstevel@tonic-gate int error; 95*0Sstevel@tonic-gate ssize_t resid; 96*0Sstevel@tonic-gate vnode_t *nvp; 97*0Sstevel@tonic-gate off_t xoff, xoff_end; 98*0Sstevel@tonic-gate char lochdr[LOCHDRSIZ]; 99*0Sstevel@tonic-gate struct pathname lookpn; 100*0Sstevel@tonic-gate struct pathname resolvepn; 101*0Sstevel@tonic-gate char *opath; 102*0Sstevel@tonic-gate 103*0Sstevel@tonic-gate if (level) 104*0Sstevel@tonic-gate return (ENOEXEC); /* no recursion */ 105*0Sstevel@tonic-gate 106*0Sstevel@tonic-gate /* 107*0Sstevel@tonic-gate * Read in the full local file header, and validate 108*0Sstevel@tonic-gate * the initial signature. 109*0Sstevel@tonic-gate */ 110*0Sstevel@tonic-gate if ((error = vn_rdwr(UIO_READ, vp, lochdr, sizeof (lochdr), 111*0Sstevel@tonic-gate 0, UIO_SYSSPACE, 0, (rlim64_t)0, cred, &resid)) != 0) 112*0Sstevel@tonic-gate return (error); 113*0Sstevel@tonic-gate if (resid != 0 || strncmp(lochdr, LOCSIG, SIGSIZ) != 0) 114*0Sstevel@tonic-gate return (ENOEXEC); 115*0Sstevel@tonic-gate 116*0Sstevel@tonic-gate /* 117*0Sstevel@tonic-gate * Ok, so this -is- a ZIP file, and might even be a JAR file. 118*0Sstevel@tonic-gate * Is it a Java executable? 119*0Sstevel@tonic-gate */ 120*0Sstevel@tonic-gate xoff = sizeof (lochdr) + LOCNAM(lochdr); 121*0Sstevel@tonic-gate xoff_end = xoff + LOCEXT(lochdr); 122*0Sstevel@tonic-gate 123*0Sstevel@tonic-gate while (xoff < xoff_end) { 124*0Sstevel@tonic-gate char xfhdr[XFHSIZ]; 125*0Sstevel@tonic-gate 126*0Sstevel@tonic-gate if ((error = vn_rdwr(UIO_READ, vp, xfhdr, sizeof (xfhdr), 127*0Sstevel@tonic-gate xoff, UIO_SYSSPACE, 0, (rlim64_t)0, cred, &resid)) != 0) 128*0Sstevel@tonic-gate return (error); 129*0Sstevel@tonic-gate if (resid != 0) 130*0Sstevel@tonic-gate return (ENOEXEC); 131*0Sstevel@tonic-gate if (XFHID(xfhdr) == XFJAVASIG) 132*0Sstevel@tonic-gate break; 133*0Sstevel@tonic-gate xoff += sizeof (xfhdr) + XFDATASIZ(xfhdr); 134*0Sstevel@tonic-gate } 135*0Sstevel@tonic-gate 136*0Sstevel@tonic-gate if (xoff >= xoff_end) 137*0Sstevel@tonic-gate return (ENOEXEC); 138*0Sstevel@tonic-gate 139*0Sstevel@tonic-gate /* 140*0Sstevel@tonic-gate * Note: If we ever make setid execution work, we need to ensure 141*0Sstevel@tonic-gate * that we use /dev/fd to avoid the classic setuid shell script 142*0Sstevel@tonic-gate * security hole. 143*0Sstevel@tonic-gate */ 144*0Sstevel@tonic-gate if (setid) 145*0Sstevel@tonic-gate return (EACCES); 146*0Sstevel@tonic-gate 147*0Sstevel@tonic-gate /* 148*0Sstevel@tonic-gate * Find and invoke the Java runtime environment on the file 149*0Sstevel@tonic-gate */ 150*0Sstevel@tonic-gate idata.intp = NULL; 151*0Sstevel@tonic-gate idata.intp_name = jexec; 152*0Sstevel@tonic-gate idata.intp_arg = jexec_arg; 153*0Sstevel@tonic-gate if (error = pn_get(idata.intp_name, UIO_SYSSPACE, &lookpn)) 154*0Sstevel@tonic-gate return (error); 155*0Sstevel@tonic-gate pn_alloc(&resolvepn); 156*0Sstevel@tonic-gate if (error = lookuppn(&lookpn, &resolvepn, FOLLOW, NULLVPP, &nvp)) { 157*0Sstevel@tonic-gate pn_free(&resolvepn); 158*0Sstevel@tonic-gate pn_free(&lookpn); 159*0Sstevel@tonic-gate return (ENOEXEC); 160*0Sstevel@tonic-gate } 161*0Sstevel@tonic-gate opath = args->pathname; 162*0Sstevel@tonic-gate args->pathname = resolvepn.pn_path; 163*0Sstevel@tonic-gate /* don't free resolvepn until we are done with args */ 164*0Sstevel@tonic-gate pn_free(&lookpn); 165*0Sstevel@tonic-gate error = gexec(&nvp, 166*0Sstevel@tonic-gate uap, args, &idata, level + 1, execsz, execfile, cred); 167*0Sstevel@tonic-gate VN_RELE(nvp); 168*0Sstevel@tonic-gate args->pathname = opath; 169*0Sstevel@tonic-gate pn_free(&resolvepn); 170*0Sstevel@tonic-gate return (error); 171*0Sstevel@tonic-gate } 172*0Sstevel@tonic-gate 173*0Sstevel@tonic-gate static struct execsw jexecsw = { 174*0Sstevel@tonic-gate javamagicstr, 175*0Sstevel@tonic-gate 0, 176*0Sstevel@tonic-gate 4, 177*0Sstevel@tonic-gate javaexec, 178*0Sstevel@tonic-gate NULL 179*0Sstevel@tonic-gate }; 180*0Sstevel@tonic-gate 181*0Sstevel@tonic-gate static struct modlexec jmodlexec = { 182*0Sstevel@tonic-gate &mod_execops, "exec for Java", &jexecsw 183*0Sstevel@tonic-gate }; 184*0Sstevel@tonic-gate 185*0Sstevel@tonic-gate static struct modlinkage jmodlinkage = { 186*0Sstevel@tonic-gate MODREV_1, &jmodlexec, NULL 187*0Sstevel@tonic-gate }; 188*0Sstevel@tonic-gate 189*0Sstevel@tonic-gate int 190*0Sstevel@tonic-gate _init(void) 191*0Sstevel@tonic-gate { 192*0Sstevel@tonic-gate return (mod_install(&jmodlinkage)); 193*0Sstevel@tonic-gate } 194*0Sstevel@tonic-gate 195*0Sstevel@tonic-gate int 196*0Sstevel@tonic-gate _fini(void) 197*0Sstevel@tonic-gate { 198*0Sstevel@tonic-gate return (mod_remove(&jmodlinkage)); 199*0Sstevel@tonic-gate } 200*0Sstevel@tonic-gate 201*0Sstevel@tonic-gate int 202*0Sstevel@tonic-gate _info(struct modinfo *modinfop) 203*0Sstevel@tonic-gate { 204*0Sstevel@tonic-gate return (mod_info(&jmodlinkage, modinfop)); 205*0Sstevel@tonic-gate } 206