1*134a1f4eSCasper H.S. Dik /* 2*134a1f4eSCasper H.S. Dik * CDDL HEADER START 3*134a1f4eSCasper H.S. Dik * 4*134a1f4eSCasper H.S. Dik * The contents of this file are subject to the terms of the 5*134a1f4eSCasper H.S. Dik * Common Development and Distribution License (the "License"). 6*134a1f4eSCasper H.S. Dik * You may not use this file except in compliance with the License. 7*134a1f4eSCasper H.S. Dik * 8*134a1f4eSCasper H.S. Dik * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*134a1f4eSCasper H.S. Dik * or http://www.opensolaris.org/os/licensing. 10*134a1f4eSCasper H.S. Dik * See the License for the specific language governing permissions 11*134a1f4eSCasper H.S. Dik * and limitations under the License. 12*134a1f4eSCasper H.S. Dik * 13*134a1f4eSCasper H.S. Dik * When distributing Covered Code, include this CDDL HEADER in each 14*134a1f4eSCasper H.S. Dik * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*134a1f4eSCasper H.S. Dik * If applicable, add the following below this CDDL HEADER, with the 16*134a1f4eSCasper H.S. Dik * fields enclosed by brackets "[]" replaced with your own identifying 17*134a1f4eSCasper H.S. Dik * information: Portions Copyright [yyyy] [name of copyright owner] 18*134a1f4eSCasper H.S. Dik * 19*134a1f4eSCasper H.S. Dik * CDDL HEADER END 20*134a1f4eSCasper H.S. Dik * 21*134a1f4eSCasper H.S. Dik * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 22*134a1f4eSCasper H.S. Dik * 23*134a1f4eSCasper H.S. Dik */ 24*134a1f4eSCasper H.S. Dik 25*134a1f4eSCasper H.S. Dik #define _POSIX_PTHREAD_SEMANTICS 1 26*134a1f4eSCasper H.S. Dik 27*134a1f4eSCasper H.S. Dik #include <sys/param.h> 28*134a1f4eSCasper H.S. Dik #include <sys/klpd.h> 29*134a1f4eSCasper H.S. Dik #include <sys/syscall.h> 30*134a1f4eSCasper H.S. Dik #include <sys/systeminfo.h> 31*134a1f4eSCasper H.S. Dik 32*134a1f4eSCasper H.S. Dik #include <alloca.h> 33*134a1f4eSCasper H.S. Dik #include <ctype.h> 34*134a1f4eSCasper H.S. Dik #include <deflt.h> 35*134a1f4eSCasper H.S. Dik #include <door.h> 36*134a1f4eSCasper H.S. Dik #include <errno.h> 37*134a1f4eSCasper H.S. Dik #include <grp.h> 38*134a1f4eSCasper H.S. Dik #include <priv.h> 39*134a1f4eSCasper H.S. Dik #include <pwd.h> 40*134a1f4eSCasper H.S. Dik #include <regex.h> 41*134a1f4eSCasper H.S. Dik #include <secdb.h> 42*134a1f4eSCasper H.S. Dik #include <signal.h> 43*134a1f4eSCasper H.S. Dik #include <stdio.h> 44*134a1f4eSCasper H.S. Dik #include <stdlib.h> 45*134a1f4eSCasper H.S. Dik #include <string.h> 46*134a1f4eSCasper H.S. Dik #include <syslog.h> 47*134a1f4eSCasper H.S. Dik #include <unistd.h> 48*134a1f4eSCasper H.S. Dik 49*134a1f4eSCasper H.S. Dik #include <auth_attr.h> 50*134a1f4eSCasper H.S. Dik #include <exec_attr.h> 51*134a1f4eSCasper H.S. Dik #include <prof_attr.h> 52*134a1f4eSCasper H.S. Dik #include <user_attr.h> 53*134a1f4eSCasper H.S. Dik 54*134a1f4eSCasper H.S. Dik static int doorfd = -1; 55*134a1f4eSCasper H.S. Dik 56*134a1f4eSCasper H.S. Dik static size_t repsz, setsz; 57*134a1f4eSCasper H.S. Dik 58*134a1f4eSCasper H.S. Dik static uid_t get_uid(const char *, boolean_t *, char *); 59*134a1f4eSCasper H.S. Dik static gid_t get_gid(const char *, boolean_t *, char *); 60*134a1f4eSCasper H.S. Dik static priv_set_t *get_privset(const char *, boolean_t *, char *); 61*134a1f4eSCasper H.S. Dik static priv_set_t *get_granted_privs(uid_t); 62*134a1f4eSCasper H.S. Dik 63*134a1f4eSCasper H.S. Dik /* 64*134a1f4eSCasper H.S. Dik * Remove the isaexec path of an executable if we can't find the 65*134a1f4eSCasper H.S. Dik * executable at the first attempt. 66*134a1f4eSCasper H.S. Dik */ 67*134a1f4eSCasper H.S. Dik 68*134a1f4eSCasper H.S. Dik static regex_t regc; 69*134a1f4eSCasper H.S. Dik static boolean_t cansplice = B_TRUE; 70*134a1f4eSCasper H.S. Dik 71*134a1f4eSCasper H.S. Dik static void 72*134a1f4eSCasper H.S. Dik init_isa_regex(void) 73*134a1f4eSCasper H.S. Dik { 74*134a1f4eSCasper H.S. Dik char *isalist; 75*134a1f4eSCasper H.S. Dik size_t isalen = 255; /* wild guess */ 76*134a1f4eSCasper H.S. Dik size_t len; 77*134a1f4eSCasper H.S. Dik long ret; 78*134a1f4eSCasper H.S. Dik char *regexpr; 79*134a1f4eSCasper H.S. Dik char *p; 80*134a1f4eSCasper H.S. Dik 81*134a1f4eSCasper H.S. Dik /* 82*134a1f4eSCasper H.S. Dik * Extract the isalist(5) for userland from the kernel. 83*134a1f4eSCasper H.S. Dik */ 84*134a1f4eSCasper H.S. Dik isalist = malloc(isalen); 85*134a1f4eSCasper H.S. Dik do { 86*134a1f4eSCasper H.S. Dik ret = sysinfo(SI_ISALIST, isalist, isalen); 87*134a1f4eSCasper H.S. Dik if (ret == -1l) { 88*134a1f4eSCasper H.S. Dik free(isalist); 89*134a1f4eSCasper H.S. Dik return; 90*134a1f4eSCasper H.S. Dik } 91*134a1f4eSCasper H.S. Dik if (ret > isalen) { 92*134a1f4eSCasper H.S. Dik isalen = ret; 93*134a1f4eSCasper H.S. Dik isalist = realloc(isalist, isalen); 94*134a1f4eSCasper H.S. Dik } else 95*134a1f4eSCasper H.S. Dik break; 96*134a1f4eSCasper H.S. Dik } while (isalist != NULL); 97*134a1f4eSCasper H.S. Dik 98*134a1f4eSCasper H.S. Dik 99*134a1f4eSCasper H.S. Dik if (isalist == NULL) 100*134a1f4eSCasper H.S. Dik return; 101*134a1f4eSCasper H.S. Dik 102*134a1f4eSCasper H.S. Dik /* allocate room for the regex + (/())/[^/]*$ + needed \\. */ 103*134a1f4eSCasper H.S. Dik #define LEFT "(/(" 104*134a1f4eSCasper H.S. Dik #define RIGHT "))/[^/]*$" 105*134a1f4eSCasper H.S. Dik 106*134a1f4eSCasper H.S. Dik regexpr = alloca(ret * 2 + sizeof (LEFT RIGHT)); 107*134a1f4eSCasper H.S. Dik (void) strcpy(regexpr, LEFT); 108*134a1f4eSCasper H.S. Dik len = strlen(regexpr); 109*134a1f4eSCasper H.S. Dik 110*134a1f4eSCasper H.S. Dik for (p = isalist; *p; p++) { 111*134a1f4eSCasper H.S. Dik switch (*p) { 112*134a1f4eSCasper H.S. Dik case '+': 113*134a1f4eSCasper H.S. Dik case '|': 114*134a1f4eSCasper H.S. Dik case '*': 115*134a1f4eSCasper H.S. Dik case '[': 116*134a1f4eSCasper H.S. Dik case ']': 117*134a1f4eSCasper H.S. Dik case '{': 118*134a1f4eSCasper H.S. Dik case '}': 119*134a1f4eSCasper H.S. Dik case '\\': 120*134a1f4eSCasper H.S. Dik regexpr[len++] = '\\'; 121*134a1f4eSCasper H.S. Dik default: 122*134a1f4eSCasper H.S. Dik regexpr[len++] = *p; 123*134a1f4eSCasper H.S. Dik break; 124*134a1f4eSCasper H.S. Dik case ' ': 125*134a1f4eSCasper H.S. Dik case '\t': 126*134a1f4eSCasper H.S. Dik regexpr[len++] = '|'; 127*134a1f4eSCasper H.S. Dik break; 128*134a1f4eSCasper H.S. Dik } 129*134a1f4eSCasper H.S. Dik } 130*134a1f4eSCasper H.S. Dik 131*134a1f4eSCasper H.S. Dik free(isalist); 132*134a1f4eSCasper H.S. Dik regexpr[len] = '\0'; 133*134a1f4eSCasper H.S. Dik (void) strcat(regexpr, RIGHT); 134*134a1f4eSCasper H.S. Dik 135*134a1f4eSCasper H.S. Dik if (regcomp(®c, regexpr, REG_EXTENDED) != 0) 136*134a1f4eSCasper H.S. Dik return; 137*134a1f4eSCasper H.S. Dik 138*134a1f4eSCasper H.S. Dik cansplice = B_TRUE; 139*134a1f4eSCasper H.S. Dik } 140*134a1f4eSCasper H.S. Dik 141*134a1f4eSCasper H.S. Dik #define NMATCH 2 142*134a1f4eSCasper H.S. Dik 143*134a1f4eSCasper H.S. Dik static boolean_t 144*134a1f4eSCasper H.S. Dik removeisapath(char *path) 145*134a1f4eSCasper H.S. Dik { 146*134a1f4eSCasper H.S. Dik regmatch_t match[NMATCH]; 147*134a1f4eSCasper H.S. Dik 148*134a1f4eSCasper H.S. Dik if (!cansplice || regexec(®c, path, NMATCH, match, 0) != 0) 149*134a1f4eSCasper H.S. Dik return (B_FALSE); 150*134a1f4eSCasper H.S. Dik 151*134a1f4eSCasper H.S. Dik /* 152*134a1f4eSCasper H.S. Dik * The first match includes the whole matched expression including the 153*134a1f4eSCasper H.S. Dik * end of the string. The second match includes the "/" + "isa" and 154*134a1f4eSCasper H.S. Dik * that is the part we need to remove. 155*134a1f4eSCasper H.S. Dik */ 156*134a1f4eSCasper H.S. Dik 157*134a1f4eSCasper H.S. Dik if (match[1].rm_so == -1) 158*134a1f4eSCasper H.S. Dik return (B_FALSE); 159*134a1f4eSCasper H.S. Dik 160*134a1f4eSCasper H.S. Dik /* match[0].rm_eo == strlen(path) */ 161*134a1f4eSCasper H.S. Dik (void) memmove(path + match[1].rm_so, path + match[1].rm_eo, 162*134a1f4eSCasper H.S. Dik match[0].rm_eo - match[1].rm_eo + 1); 163*134a1f4eSCasper H.S. Dik 164*134a1f4eSCasper H.S. Dik return (B_TRUE); 165*134a1f4eSCasper H.S. Dik } 166*134a1f4eSCasper H.S. Dik 167*134a1f4eSCasper H.S. Dik static int 168*134a1f4eSCasper H.S. Dik register_pfexec(int fd) 169*134a1f4eSCasper H.S. Dik { 170*134a1f4eSCasper H.S. Dik int ret = syscall(SYS_privsys, PRIVSYS_PFEXEC_REG, fd); 171*134a1f4eSCasper H.S. Dik 172*134a1f4eSCasper H.S. Dik return (ret); 173*134a1f4eSCasper H.S. Dik } 174*134a1f4eSCasper H.S. Dik 175*134a1f4eSCasper H.S. Dik /* ARGSUSED */ 176*134a1f4eSCasper H.S. Dik static void 177*134a1f4eSCasper H.S. Dik unregister_pfexec(int sig) 178*134a1f4eSCasper H.S. Dik { 179*134a1f4eSCasper H.S. Dik if (doorfd != -1) 180*134a1f4eSCasper H.S. Dik (void) syscall(SYS_privsys, PRIVSYS_PFEXEC_UNREG, doorfd); 181*134a1f4eSCasper H.S. Dik _exit(0); 182*134a1f4eSCasper H.S. Dik } 183*134a1f4eSCasper H.S. Dik 184*134a1f4eSCasper H.S. Dik static int 185*134a1f4eSCasper H.S. Dik alldigits(const char *s) 186*134a1f4eSCasper H.S. Dik { 187*134a1f4eSCasper H.S. Dik int c; 188*134a1f4eSCasper H.S. Dik 189*134a1f4eSCasper H.S. Dik if (*s == '\0') 190*134a1f4eSCasper H.S. Dik return (0); 191*134a1f4eSCasper H.S. Dik 192*134a1f4eSCasper H.S. Dik while ((c = *s++) != '\0') { 193*134a1f4eSCasper H.S. Dik if (!isdigit(c)) { 194*134a1f4eSCasper H.S. Dik return (0); 195*134a1f4eSCasper H.S. Dik } 196*134a1f4eSCasper H.S. Dik } 197*134a1f4eSCasper H.S. Dik 198*134a1f4eSCasper H.S. Dik return (1); 199*134a1f4eSCasper H.S. Dik } 200*134a1f4eSCasper H.S. Dik 201*134a1f4eSCasper H.S. Dik static uid_t 202*134a1f4eSCasper H.S. Dik get_uid(const char *v, boolean_t *ok, char *path) 203*134a1f4eSCasper H.S. Dik { 204*134a1f4eSCasper H.S. Dik struct passwd *pwd, pwdm; 205*134a1f4eSCasper H.S. Dik char buf[1024]; 206*134a1f4eSCasper H.S. Dik 207*134a1f4eSCasper H.S. Dik if (getpwnam_r(v, &pwdm, buf, sizeof (buf), &pwd) == 0 && pwd != NULL) 208*134a1f4eSCasper H.S. Dik return (pwd->pw_uid); 209*134a1f4eSCasper H.S. Dik 210*134a1f4eSCasper H.S. Dik if (alldigits(v)) 211*134a1f4eSCasper H.S. Dik return (atoi(v)); 212*134a1f4eSCasper H.S. Dik 213*134a1f4eSCasper H.S. Dik *ok = B_FALSE; 214*134a1f4eSCasper H.S. Dik syslog(LOG_ERR, "%s: %s: unknown username\n", path, v); 215*134a1f4eSCasper H.S. Dik return ((uid_t)-1); 216*134a1f4eSCasper H.S. Dik } 217*134a1f4eSCasper H.S. Dik 218*134a1f4eSCasper H.S. Dik static uid_t 219*134a1f4eSCasper H.S. Dik get_gid(const char *v, boolean_t *ok, char *path) 220*134a1f4eSCasper H.S. Dik { 221*134a1f4eSCasper H.S. Dik struct group *grp, grpm; 222*134a1f4eSCasper H.S. Dik char buf[1024]; 223*134a1f4eSCasper H.S. Dik 224*134a1f4eSCasper H.S. Dik if (getgrnam_r(v, &grpm, buf, sizeof (buf), &grp) == 0 && grp != NULL) 225*134a1f4eSCasper H.S. Dik return (grp->gr_gid); 226*134a1f4eSCasper H.S. Dik 227*134a1f4eSCasper H.S. Dik if (alldigits(v)) 228*134a1f4eSCasper H.S. Dik return (atoi(v)); 229*134a1f4eSCasper H.S. Dik 230*134a1f4eSCasper H.S. Dik *ok = B_FALSE; 231*134a1f4eSCasper H.S. Dik syslog(LOG_ERR, "%s: %s: unknown groupname\n", path, v); 232*134a1f4eSCasper H.S. Dik return ((gid_t)-1); 233*134a1f4eSCasper H.S. Dik } 234*134a1f4eSCasper H.S. Dik 235*134a1f4eSCasper H.S. Dik static priv_set_t * 236*134a1f4eSCasper H.S. Dik get_privset(const char *s, boolean_t *ok, char *path) 237*134a1f4eSCasper H.S. Dik { 238*134a1f4eSCasper H.S. Dik priv_set_t *res; 239*134a1f4eSCasper H.S. Dik 240*134a1f4eSCasper H.S. Dik if ((res = priv_str_to_set(s, ",", NULL)) == NULL) { 241*134a1f4eSCasper H.S. Dik syslog(LOG_ERR, "%s: %s: bad privilege set\n", path, s); 242*134a1f4eSCasper H.S. Dik if (ok != NULL) 243*134a1f4eSCasper H.S. Dik *ok = B_FALSE; 244*134a1f4eSCasper H.S. Dik } 245*134a1f4eSCasper H.S. Dik return (res); 246*134a1f4eSCasper H.S. Dik } 247*134a1f4eSCasper H.S. Dik 248*134a1f4eSCasper H.S. Dik /*ARGSUSED*/ 249*134a1f4eSCasper H.S. Dik static int 250*134a1f4eSCasper H.S. Dik ggp_callback(const char *prof, kva_t *attr, void *ctxt, void *vres) 251*134a1f4eSCasper H.S. Dik { 252*134a1f4eSCasper H.S. Dik priv_set_t *res = vres; 253*134a1f4eSCasper H.S. Dik char *privs; 254*134a1f4eSCasper H.S. Dik 255*134a1f4eSCasper H.S. Dik if (attr == NULL) 256*134a1f4eSCasper H.S. Dik return (0); 257*134a1f4eSCasper H.S. Dik 258*134a1f4eSCasper H.S. Dik /* get privs from this profile */ 259*134a1f4eSCasper H.S. Dik privs = kva_match(attr, PROFATTR_PRIVS_KW); 260*134a1f4eSCasper H.S. Dik if (privs != NULL) { 261*134a1f4eSCasper H.S. Dik priv_set_t *tmp = priv_str_to_set(privs, ",", NULL); 262*134a1f4eSCasper H.S. Dik if (tmp != NULL) { 263*134a1f4eSCasper H.S. Dik priv_union(tmp, res); 264*134a1f4eSCasper H.S. Dik priv_freeset(tmp); 265*134a1f4eSCasper H.S. Dik } 266*134a1f4eSCasper H.S. Dik } 267*134a1f4eSCasper H.S. Dik 268*134a1f4eSCasper H.S. Dik return (0); 269*134a1f4eSCasper H.S. Dik } 270*134a1f4eSCasper H.S. Dik 271*134a1f4eSCasper H.S. Dik /* 272*134a1f4eSCasper H.S. Dik * This routine exists on failure and returns NULL if no granted privileges 273*134a1f4eSCasper H.S. Dik * are set. 274*134a1f4eSCasper H.S. Dik */ 275*134a1f4eSCasper H.S. Dik static priv_set_t * 276*134a1f4eSCasper H.S. Dik get_granted_privs(uid_t uid) 277*134a1f4eSCasper H.S. Dik { 278*134a1f4eSCasper H.S. Dik priv_set_t *res; 279*134a1f4eSCasper H.S. Dik struct passwd *pwd, pwdm; 280*134a1f4eSCasper H.S. Dik char buf[1024]; 281*134a1f4eSCasper H.S. Dik 282*134a1f4eSCasper H.S. Dik if (getpwuid_r(uid, &pwdm, buf, sizeof (buf), &pwd) != 0 || pwd == NULL) 283*134a1f4eSCasper H.S. Dik return (NULL); 284*134a1f4eSCasper H.S. Dik 285*134a1f4eSCasper H.S. Dik res = priv_allocset(); 286*134a1f4eSCasper H.S. Dik if (res == NULL) 287*134a1f4eSCasper H.S. Dik return (NULL); 288*134a1f4eSCasper H.S. Dik 289*134a1f4eSCasper H.S. Dik priv_emptyset(res); 290*134a1f4eSCasper H.S. Dik 291*134a1f4eSCasper H.S. Dik (void) _enum_profs(pwd->pw_name, ggp_callback, NULL, res); 292*134a1f4eSCasper H.S. Dik 293*134a1f4eSCasper H.S. Dik return (res); 294*134a1f4eSCasper H.S. Dik } 295*134a1f4eSCasper H.S. Dik 296*134a1f4eSCasper H.S. Dik static void 297*134a1f4eSCasper H.S. Dik callback_forced_privs(pfexec_arg_t *pap) 298*134a1f4eSCasper H.S. Dik { 299*134a1f4eSCasper H.S. Dik execattr_t *exec; 300*134a1f4eSCasper H.S. Dik char *value; 301*134a1f4eSCasper H.S. Dik priv_set_t *fset; 302*134a1f4eSCasper H.S. Dik void *res = alloca(setsz); 303*134a1f4eSCasper H.S. Dik 304*134a1f4eSCasper H.S. Dik /* Empty set signifies no forced privileges. */ 305*134a1f4eSCasper H.S. Dik priv_emptyset(res); 306*134a1f4eSCasper H.S. Dik 307*134a1f4eSCasper H.S. Dik exec = getexecprof("Forced Privilege", KV_COMMAND, pap->pfa_path, 308*134a1f4eSCasper H.S. Dik GET_ONE); 309*134a1f4eSCasper H.S. Dik 310*134a1f4eSCasper H.S. Dik if (exec == NULL && removeisapath(pap->pfa_path)) { 311*134a1f4eSCasper H.S. Dik exec = getexecprof("Forced Privilege", KV_COMMAND, 312*134a1f4eSCasper H.S. Dik pap->pfa_path, GET_ONE); 313*134a1f4eSCasper H.S. Dik } 314*134a1f4eSCasper H.S. Dik 315*134a1f4eSCasper H.S. Dik if (exec == NULL) { 316*134a1f4eSCasper H.S. Dik (void) door_return(res, setsz, NULL, 0); 317*134a1f4eSCasper H.S. Dik return; 318*134a1f4eSCasper H.S. Dik } 319*134a1f4eSCasper H.S. Dik 320*134a1f4eSCasper H.S. Dik if ((value = kva_match(exec->attr, EXECATTR_IPRIV_KW)) == NULL || 321*134a1f4eSCasper H.S. Dik (fset = get_privset(value, NULL, pap->pfa_path)) == NULL) { 322*134a1f4eSCasper H.S. Dik free_execattr(exec); 323*134a1f4eSCasper H.S. Dik (void) door_return(res, setsz, NULL, 0); 324*134a1f4eSCasper H.S. Dik return; 325*134a1f4eSCasper H.S. Dik } 326*134a1f4eSCasper H.S. Dik 327*134a1f4eSCasper H.S. Dik priv_copyset(fset, res); 328*134a1f4eSCasper H.S. Dik priv_freeset(fset); 329*134a1f4eSCasper H.S. Dik 330*134a1f4eSCasper H.S. Dik free_execattr(exec); 331*134a1f4eSCasper H.S. Dik (void) door_return(res, setsz, NULL, 0); 332*134a1f4eSCasper H.S. Dik } 333*134a1f4eSCasper H.S. Dik 334*134a1f4eSCasper H.S. Dik static void 335*134a1f4eSCasper H.S. Dik callback_user_privs(pfexec_arg_t *pap) 336*134a1f4eSCasper H.S. Dik { 337*134a1f4eSCasper H.S. Dik priv_set_t *gset, *wset; 338*134a1f4eSCasper H.S. Dik uint32_t res; 339*134a1f4eSCasper H.S. Dik 340*134a1f4eSCasper H.S. Dik wset = (priv_set_t *)&pap->pfa_buf; 341*134a1f4eSCasper H.S. Dik gset = get_granted_privs(pap->pfa_uid); 342*134a1f4eSCasper H.S. Dik 343*134a1f4eSCasper H.S. Dik res = priv_issubset(wset, gset); 344*134a1f4eSCasper H.S. Dik priv_freeset(gset); 345*134a1f4eSCasper H.S. Dik 346*134a1f4eSCasper H.S. Dik (void) door_return((char *)&res, sizeof (res), NULL, 0); 347*134a1f4eSCasper H.S. Dik } 348*134a1f4eSCasper H.S. Dik 349*134a1f4eSCasper H.S. Dik static void 350*134a1f4eSCasper H.S. Dik callback_pfexec(pfexec_arg_t *pap) 351*134a1f4eSCasper H.S. Dik { 352*134a1f4eSCasper H.S. Dik pfexec_reply_t *res = alloca(repsz); 353*134a1f4eSCasper H.S. Dik uid_t uid, euid, uuid; 354*134a1f4eSCasper H.S. Dik gid_t gid, egid; 355*134a1f4eSCasper H.S. Dik struct passwd pw, *pwd; 356*134a1f4eSCasper H.S. Dik char buf[1024]; 357*134a1f4eSCasper H.S. Dik execattr_t *exec; 358*134a1f4eSCasper H.S. Dik char *value; 359*134a1f4eSCasper H.S. Dik priv_set_t *lset, *iset; 360*134a1f4eSCasper H.S. Dik size_t mysz = repsz - 2 * setsz; 361*134a1f4eSCasper H.S. Dik char *path = pap->pfa_path; 362*134a1f4eSCasper H.S. Dik 363*134a1f4eSCasper H.S. Dik uuid = pap->pfa_uid; 364*134a1f4eSCasper H.S. Dik 365*134a1f4eSCasper H.S. Dik if (getpwuid_r(uuid, &pw, buf, sizeof (buf), &pwd) != 0 || pwd == NULL) 366*134a1f4eSCasper H.S. Dik goto stdexec; 367*134a1f4eSCasper H.S. Dik 368*134a1f4eSCasper H.S. Dik exec = getexecuser(pwd->pw_name, KV_COMMAND, path, GET_ONE); 369*134a1f4eSCasper H.S. Dik 370*134a1f4eSCasper H.S. Dik if (exec == NULL && removeisapath(path)) 371*134a1f4eSCasper H.S. Dik exec = getexecuser(pwd->pw_name, KV_COMMAND, path, GET_ONE); 372*134a1f4eSCasper H.S. Dik 373*134a1f4eSCasper H.S. Dik if (exec == NULL) { 374*134a1f4eSCasper H.S. Dik res->pfr_allowed = B_FALSE; 375*134a1f4eSCasper H.S. Dik goto ret; 376*134a1f4eSCasper H.S. Dik } 377*134a1f4eSCasper H.S. Dik 378*134a1f4eSCasper H.S. Dik if (exec->attr == NULL) 379*134a1f4eSCasper H.S. Dik goto stdexec; 380*134a1f4eSCasper H.S. Dik 381*134a1f4eSCasper H.S. Dik /* Found in execattr, so clearly we can use it */ 382*134a1f4eSCasper H.S. Dik res->pfr_allowed = B_TRUE; 383*134a1f4eSCasper H.S. Dik 384*134a1f4eSCasper H.S. Dik uid = euid = (uid_t)-1; 385*134a1f4eSCasper H.S. Dik gid = egid = (gid_t)-1; 386*134a1f4eSCasper H.S. Dik lset = iset = NULL; 387*134a1f4eSCasper H.S. Dik 388*134a1f4eSCasper H.S. Dik /* 389*134a1f4eSCasper H.S. Dik * If there's an error in parsing uid, gid, privs, then return 390*134a1f4eSCasper H.S. Dik * failure. 391*134a1f4eSCasper H.S. Dik */ 392*134a1f4eSCasper H.S. Dik if ((value = kva_match(exec->attr, EXECATTR_UID_KW)) != NULL) 393*134a1f4eSCasper H.S. Dik euid = uid = get_uid(value, &res->pfr_allowed, path); 394*134a1f4eSCasper H.S. Dik 395*134a1f4eSCasper H.S. Dik if ((value = kva_match(exec->attr, EXECATTR_GID_KW)) != NULL) 396*134a1f4eSCasper H.S. Dik egid = gid = get_gid(value, &res->pfr_allowed, path); 397*134a1f4eSCasper H.S. Dik 398*134a1f4eSCasper H.S. Dik if ((value = kva_match(exec->attr, EXECATTR_EUID_KW)) != NULL) 399*134a1f4eSCasper H.S. Dik euid = get_uid(value, &res->pfr_allowed, path); 400*134a1f4eSCasper H.S. Dik 401*134a1f4eSCasper H.S. Dik if ((value = kva_match(exec->attr, EXECATTR_EGID_KW)) != NULL) 402*134a1f4eSCasper H.S. Dik egid = get_gid(value, &res->pfr_allowed, path); 403*134a1f4eSCasper H.S. Dik 404*134a1f4eSCasper H.S. Dik if ((value = kva_match(exec->attr, EXECATTR_LPRIV_KW)) != NULL) 405*134a1f4eSCasper H.S. Dik lset = get_privset(value, &res->pfr_allowed, path); 406*134a1f4eSCasper H.S. Dik 407*134a1f4eSCasper H.S. Dik if ((value = kva_match(exec->attr, EXECATTR_IPRIV_KW)) != NULL) 408*134a1f4eSCasper H.S. Dik iset = get_privset(value, &res->pfr_allowed, path); 409*134a1f4eSCasper H.S. Dik 410*134a1f4eSCasper H.S. Dik /* 411*134a1f4eSCasper H.S. Dik * Remove LD_* variables in the kernel when the runtime linker might 412*134a1f4eSCasper H.S. Dik * use them later on because the uids are equal. 413*134a1f4eSCasper H.S. Dik */ 414*134a1f4eSCasper H.S. Dik res->pfr_scrubenv = (uid != (uid_t)-1 && euid == uid) || 415*134a1f4eSCasper H.S. Dik (gid != (gid_t)-1 && egid == gid) || iset != NULL; 416*134a1f4eSCasper H.S. Dik 417*134a1f4eSCasper H.S. Dik res->pfr_euid = euid; 418*134a1f4eSCasper H.S. Dik res->pfr_ruid = uid; 419*134a1f4eSCasper H.S. Dik res->pfr_egid = egid; 420*134a1f4eSCasper H.S. Dik res->pfr_rgid = gid; 421*134a1f4eSCasper H.S. Dik 422*134a1f4eSCasper H.S. Dik /* Now add the privilege sets */ 423*134a1f4eSCasper H.S. Dik res->pfr_ioff = res->pfr_loff = 0; 424*134a1f4eSCasper H.S. Dik if (iset != NULL) { 425*134a1f4eSCasper H.S. Dik res->pfr_ioff = mysz; 426*134a1f4eSCasper H.S. Dik priv_copyset(iset, PFEXEC_REPLY_IPRIV(res)); 427*134a1f4eSCasper H.S. Dik mysz += setsz; 428*134a1f4eSCasper H.S. Dik priv_freeset(iset); 429*134a1f4eSCasper H.S. Dik } 430*134a1f4eSCasper H.S. Dik if (lset != NULL) { 431*134a1f4eSCasper H.S. Dik res->pfr_loff = mysz; 432*134a1f4eSCasper H.S. Dik priv_copyset(lset, PFEXEC_REPLY_LPRIV(res)); 433*134a1f4eSCasper H.S. Dik mysz += setsz; 434*134a1f4eSCasper H.S. Dik priv_freeset(lset); 435*134a1f4eSCasper H.S. Dik } 436*134a1f4eSCasper H.S. Dik 437*134a1f4eSCasper H.S. Dik res->pfr_setcred = uid != (uid_t)-1 || euid != (uid_t)-1 || 438*134a1f4eSCasper H.S. Dik egid != (gid_t)-1 || gid != (gid_t)-1 || iset != NULL || 439*134a1f4eSCasper H.S. Dik lset != NULL; 440*134a1f4eSCasper H.S. Dik 441*134a1f4eSCasper H.S. Dik /* If the real uid changes, we stop running under a profile shell */ 442*134a1f4eSCasper H.S. Dik res->pfr_clearflag = uid != (uid_t)-1 && uid != uuid; 443*134a1f4eSCasper H.S. Dik free_execattr(exec); 444*134a1f4eSCasper H.S. Dik ret: 445*134a1f4eSCasper H.S. Dik (void) door_return((char *)res, mysz, NULL, 0); 446*134a1f4eSCasper H.S. Dik return; 447*134a1f4eSCasper H.S. Dik 448*134a1f4eSCasper H.S. Dik stdexec: 449*134a1f4eSCasper H.S. Dik res->pfr_scrubenv = B_FALSE; 450*134a1f4eSCasper H.S. Dik res->pfr_setcred = B_FALSE; 451*134a1f4eSCasper H.S. Dik res->pfr_allowed = B_TRUE; 452*134a1f4eSCasper H.S. Dik 453*134a1f4eSCasper H.S. Dik (void) door_return((char *)res, mysz, NULL, 0); 454*134a1f4eSCasper H.S. Dik } 455*134a1f4eSCasper H.S. Dik 456*134a1f4eSCasper H.S. Dik /* ARGSUSED */ 457*134a1f4eSCasper H.S. Dik static void 458*134a1f4eSCasper H.S. Dik callback(void *cookie, char *argp, size_t asz, door_desc_t *dp, uint_t ndesc) 459*134a1f4eSCasper H.S. Dik { 460*134a1f4eSCasper H.S. Dik /* LINTED ALIGNMENT */ 461*134a1f4eSCasper H.S. Dik pfexec_arg_t *pap = (pfexec_arg_t *)argp; 462*134a1f4eSCasper H.S. Dik 463*134a1f4eSCasper H.S. Dik if (asz < sizeof (pfexec_arg_t) || pap->pfa_vers != PFEXEC_ARG_VERS) { 464*134a1f4eSCasper H.S. Dik (void) door_return(NULL, 0, NULL, 0); 465*134a1f4eSCasper H.S. Dik return; 466*134a1f4eSCasper H.S. Dik } 467*134a1f4eSCasper H.S. Dik 468*134a1f4eSCasper H.S. Dik switch (pap->pfa_call) { 469*134a1f4eSCasper H.S. Dik case PFEXEC_EXEC_ATTRS: 470*134a1f4eSCasper H.S. Dik callback_pfexec(pap); 471*134a1f4eSCasper H.S. Dik break; 472*134a1f4eSCasper H.S. Dik case PFEXEC_FORCED_PRIVS: 473*134a1f4eSCasper H.S. Dik callback_forced_privs(pap); 474*134a1f4eSCasper H.S. Dik break; 475*134a1f4eSCasper H.S. Dik case PFEXEC_USER_PRIVS: 476*134a1f4eSCasper H.S. Dik callback_user_privs(pap); 477*134a1f4eSCasper H.S. Dik break; 478*134a1f4eSCasper H.S. Dik default: 479*134a1f4eSCasper H.S. Dik syslog(LOG_ERR, "Bad Call: %d\n", pap->pfa_call); 480*134a1f4eSCasper H.S. Dik break; 481*134a1f4eSCasper H.S. Dik } 482*134a1f4eSCasper H.S. Dik 483*134a1f4eSCasper H.S. Dik /* 484*134a1f4eSCasper H.S. Dik * If the door_return(ptr, size, NULL, 0) fails, make sure we 485*134a1f4eSCasper H.S. Dik * don't lose server threads. 486*134a1f4eSCasper H.S. Dik */ 487*134a1f4eSCasper H.S. Dik (void) door_return(NULL, 0, NULL, 0); 488*134a1f4eSCasper H.S. Dik } 489*134a1f4eSCasper H.S. Dik 490*134a1f4eSCasper H.S. Dik int 491*134a1f4eSCasper H.S. Dik main(void) 492*134a1f4eSCasper H.S. Dik { 493*134a1f4eSCasper H.S. Dik const priv_impl_info_t *info; 494*134a1f4eSCasper H.S. Dik 495*134a1f4eSCasper H.S. Dik (void) signal(SIGINT, unregister_pfexec); 496*134a1f4eSCasper H.S. Dik (void) signal(SIGQUIT, unregister_pfexec); 497*134a1f4eSCasper H.S. Dik (void) signal(SIGTERM, unregister_pfexec); 498*134a1f4eSCasper H.S. Dik (void) signal(SIGHUP, unregister_pfexec); 499*134a1f4eSCasper H.S. Dik 500*134a1f4eSCasper H.S. Dik info = getprivimplinfo(); 501*134a1f4eSCasper H.S. Dik if (info == NULL) 502*134a1f4eSCasper H.S. Dik exit(1); 503*134a1f4eSCasper H.S. Dik 504*134a1f4eSCasper H.S. Dik if (fork() > 0) 505*134a1f4eSCasper H.S. Dik _exit(0); 506*134a1f4eSCasper H.S. Dik 507*134a1f4eSCasper H.S. Dik openlog("pfexecd", LOG_PID, LOG_DAEMON); 508*134a1f4eSCasper H.S. Dik setsz = info->priv_setsize * sizeof (priv_chunk_t); 509*134a1f4eSCasper H.S. Dik repsz = 2 * setsz + sizeof (pfexec_reply_t); 510*134a1f4eSCasper H.S. Dik 511*134a1f4eSCasper H.S. Dik init_isa_regex(); 512*134a1f4eSCasper H.S. Dik 513*134a1f4eSCasper H.S. Dik doorfd = door_create(callback, NULL, DOOR_REFUSE_DESC); 514*134a1f4eSCasper H.S. Dik 515*134a1f4eSCasper H.S. Dik if (doorfd == -1 || register_pfexec(doorfd) != 0) { 516*134a1f4eSCasper H.S. Dik perror("doorfd"); 517*134a1f4eSCasper H.S. Dik exit(1); 518*134a1f4eSCasper H.S. Dik } 519*134a1f4eSCasper H.S. Dik 520*134a1f4eSCasper H.S. Dik /* LINTED CONSTCOND */ 521*134a1f4eSCasper H.S. Dik while (1) 522*134a1f4eSCasper H.S. Dik (void) sigpause(SIGINT); 523*134a1f4eSCasper H.S. Dik 524*134a1f4eSCasper H.S. Dik return (0); 525*134a1f4eSCasper H.S. Dik } 526