1134a1f4eSCasper H.S. Dik /* 2134a1f4eSCasper H.S. Dik * CDDL HEADER START 3134a1f4eSCasper H.S. Dik * 4134a1f4eSCasper H.S. Dik * The contents of this file are subject to the terms of the 5134a1f4eSCasper H.S. Dik * Common Development and Distribution License (the "License"). 6134a1f4eSCasper H.S. Dik * You may not use this file except in compliance with the License. 7134a1f4eSCasper H.S. Dik * 8134a1f4eSCasper H.S. Dik * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9134a1f4eSCasper H.S. Dik * or http://www.opensolaris.org/os/licensing. 10134a1f4eSCasper H.S. Dik * See the License for the specific language governing permissions 11134a1f4eSCasper H.S. Dik * and limitations under the License. 12134a1f4eSCasper H.S. Dik * 13134a1f4eSCasper H.S. Dik * When distributing Covered Code, include this CDDL HEADER in each 14134a1f4eSCasper H.S. Dik * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15134a1f4eSCasper H.S. Dik * If applicable, add the following below this CDDL HEADER, with the 16134a1f4eSCasper H.S. Dik * fields enclosed by brackets "[]" replaced with your own identifying 17134a1f4eSCasper H.S. Dik * information: Portions Copyright [yyyy] [name of copyright owner] 18134a1f4eSCasper H.S. Dik * 19134a1f4eSCasper H.S. Dik * CDDL HEADER END 20134a1f4eSCasper H.S. Dik * 21134a1f4eSCasper H.S. Dik * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 22*b01b59e3SRobert Mustacchi * Copyright 2015, Joyent, Inc. 23134a1f4eSCasper H.S. Dik */ 24134a1f4eSCasper H.S. Dik 25134a1f4eSCasper H.S. Dik #define _POSIX_PTHREAD_SEMANTICS 1 26134a1f4eSCasper H.S. Dik 27134a1f4eSCasper H.S. Dik #include <sys/param.h> 28134a1f4eSCasper H.S. Dik #include <sys/klpd.h> 29134a1f4eSCasper H.S. Dik #include <sys/syscall.h> 30134a1f4eSCasper H.S. Dik #include <sys/systeminfo.h> 31134a1f4eSCasper H.S. Dik 32134a1f4eSCasper H.S. Dik #include <alloca.h> 33134a1f4eSCasper H.S. Dik #include <ctype.h> 34134a1f4eSCasper H.S. Dik #include <deflt.h> 35134a1f4eSCasper H.S. Dik #include <door.h> 36134a1f4eSCasper H.S. Dik #include <errno.h> 37134a1f4eSCasper H.S. Dik #include <grp.h> 38134a1f4eSCasper H.S. Dik #include <priv.h> 39134a1f4eSCasper H.S. Dik #include <pwd.h> 40134a1f4eSCasper H.S. Dik #include <regex.h> 41134a1f4eSCasper H.S. Dik #include <secdb.h> 42134a1f4eSCasper H.S. Dik #include <signal.h> 43134a1f4eSCasper H.S. Dik #include <stdio.h> 44134a1f4eSCasper H.S. Dik #include <stdlib.h> 45134a1f4eSCasper H.S. Dik #include <string.h> 46134a1f4eSCasper H.S. Dik #include <syslog.h> 47134a1f4eSCasper H.S. Dik #include <unistd.h> 48134a1f4eSCasper H.S. Dik 49134a1f4eSCasper H.S. Dik #include <auth_attr.h> 50134a1f4eSCasper H.S. Dik #include <exec_attr.h> 51134a1f4eSCasper H.S. Dik #include <prof_attr.h> 52134a1f4eSCasper H.S. Dik #include <user_attr.h> 53134a1f4eSCasper H.S. Dik 54134a1f4eSCasper H.S. Dik static int doorfd = -1; 55134a1f4eSCasper H.S. Dik 56134a1f4eSCasper H.S. Dik static size_t repsz, setsz; 57134a1f4eSCasper H.S. Dik 58134a1f4eSCasper H.S. Dik static uid_t get_uid(const char *, boolean_t *, char *); 59134a1f4eSCasper H.S. Dik static gid_t get_gid(const char *, boolean_t *, char *); 60134a1f4eSCasper H.S. Dik static priv_set_t *get_privset(const char *, boolean_t *, char *); 61134a1f4eSCasper H.S. Dik static priv_set_t *get_granted_privs(uid_t); 62134a1f4eSCasper H.S. Dik 63134a1f4eSCasper H.S. Dik /* 64134a1f4eSCasper H.S. Dik * Remove the isaexec path of an executable if we can't find the 65134a1f4eSCasper H.S. Dik * executable at the first attempt. 66134a1f4eSCasper H.S. Dik */ 67134a1f4eSCasper H.S. Dik 68134a1f4eSCasper H.S. Dik static regex_t regc; 69134a1f4eSCasper H.S. Dik static boolean_t cansplice = B_TRUE; 70134a1f4eSCasper H.S. Dik 71134a1f4eSCasper H.S. Dik static void 72134a1f4eSCasper H.S. Dik init_isa_regex(void) 73134a1f4eSCasper H.S. Dik { 74134a1f4eSCasper H.S. Dik char *isalist; 75134a1f4eSCasper H.S. Dik size_t isalen = 255; /* wild guess */ 76134a1f4eSCasper H.S. Dik size_t len; 77134a1f4eSCasper H.S. Dik long ret; 78134a1f4eSCasper H.S. Dik char *regexpr; 79134a1f4eSCasper H.S. Dik char *p; 80134a1f4eSCasper H.S. Dik 81134a1f4eSCasper H.S. Dik /* 82134a1f4eSCasper H.S. Dik * Extract the isalist(5) for userland from the kernel. 83134a1f4eSCasper H.S. Dik */ 84134a1f4eSCasper H.S. Dik isalist = malloc(isalen); 85134a1f4eSCasper H.S. Dik do { 86134a1f4eSCasper H.S. Dik ret = sysinfo(SI_ISALIST, isalist, isalen); 87134a1f4eSCasper H.S. Dik if (ret == -1l) { 88134a1f4eSCasper H.S. Dik free(isalist); 89134a1f4eSCasper H.S. Dik return; 90134a1f4eSCasper H.S. Dik } 91134a1f4eSCasper H.S. Dik if (ret > isalen) { 92134a1f4eSCasper H.S. Dik isalen = ret; 93134a1f4eSCasper H.S. Dik isalist = realloc(isalist, isalen); 94134a1f4eSCasper H.S. Dik } else 95134a1f4eSCasper H.S. Dik break; 96134a1f4eSCasper H.S. Dik } while (isalist != NULL); 97134a1f4eSCasper H.S. Dik 98134a1f4eSCasper H.S. Dik 99134a1f4eSCasper H.S. Dik if (isalist == NULL) 100134a1f4eSCasper H.S. Dik return; 101134a1f4eSCasper H.S. Dik 102134a1f4eSCasper H.S. Dik /* allocate room for the regex + (/())/[^/]*$ + needed \\. */ 103134a1f4eSCasper H.S. Dik #define LEFT "(/(" 104134a1f4eSCasper H.S. Dik #define RIGHT "))/[^/]*$" 105134a1f4eSCasper H.S. Dik 106134a1f4eSCasper H.S. Dik regexpr = alloca(ret * 2 + sizeof (LEFT RIGHT)); 107134a1f4eSCasper H.S. Dik (void) strcpy(regexpr, LEFT); 108134a1f4eSCasper H.S. Dik len = strlen(regexpr); 109134a1f4eSCasper H.S. Dik 110134a1f4eSCasper H.S. Dik for (p = isalist; *p; p++) { 111134a1f4eSCasper H.S. Dik switch (*p) { 112134a1f4eSCasper H.S. Dik case '+': 113134a1f4eSCasper H.S. Dik case '|': 114134a1f4eSCasper H.S. Dik case '*': 115134a1f4eSCasper H.S. Dik case '[': 116134a1f4eSCasper H.S. Dik case ']': 117134a1f4eSCasper H.S. Dik case '{': 118134a1f4eSCasper H.S. Dik case '}': 119134a1f4eSCasper H.S. Dik case '\\': 120134a1f4eSCasper H.S. Dik regexpr[len++] = '\\'; 121134a1f4eSCasper H.S. Dik default: 122134a1f4eSCasper H.S. Dik regexpr[len++] = *p; 123134a1f4eSCasper H.S. Dik break; 124134a1f4eSCasper H.S. Dik case ' ': 125134a1f4eSCasper H.S. Dik case '\t': 126134a1f4eSCasper H.S. Dik regexpr[len++] = '|'; 127134a1f4eSCasper H.S. Dik break; 128134a1f4eSCasper H.S. Dik } 129134a1f4eSCasper H.S. Dik } 130134a1f4eSCasper H.S. Dik 131134a1f4eSCasper H.S. Dik free(isalist); 132134a1f4eSCasper H.S. Dik regexpr[len] = '\0'; 133134a1f4eSCasper H.S. Dik (void) strcat(regexpr, RIGHT); 134134a1f4eSCasper H.S. Dik 135134a1f4eSCasper H.S. Dik if (regcomp(®c, regexpr, REG_EXTENDED) != 0) 136134a1f4eSCasper H.S. Dik return; 137134a1f4eSCasper H.S. Dik 138134a1f4eSCasper H.S. Dik cansplice = B_TRUE; 139134a1f4eSCasper H.S. Dik } 140134a1f4eSCasper H.S. Dik 141134a1f4eSCasper H.S. Dik #define NMATCH 2 142134a1f4eSCasper H.S. Dik 143134a1f4eSCasper H.S. Dik static boolean_t 144134a1f4eSCasper H.S. Dik removeisapath(char *path) 145134a1f4eSCasper H.S. Dik { 146134a1f4eSCasper H.S. Dik regmatch_t match[NMATCH]; 147134a1f4eSCasper H.S. Dik 148134a1f4eSCasper H.S. Dik if (!cansplice || regexec(®c, path, NMATCH, match, 0) != 0) 149134a1f4eSCasper H.S. Dik return (B_FALSE); 150134a1f4eSCasper H.S. Dik 151134a1f4eSCasper H.S. Dik /* 152134a1f4eSCasper H.S. Dik * The first match includes the whole matched expression including the 153134a1f4eSCasper H.S. Dik * end of the string. The second match includes the "/" + "isa" and 154134a1f4eSCasper H.S. Dik * that is the part we need to remove. 155134a1f4eSCasper H.S. Dik */ 156134a1f4eSCasper H.S. Dik 157134a1f4eSCasper H.S. Dik if (match[1].rm_so == -1) 158134a1f4eSCasper H.S. Dik return (B_FALSE); 159134a1f4eSCasper H.S. Dik 160134a1f4eSCasper H.S. Dik /* match[0].rm_eo == strlen(path) */ 161134a1f4eSCasper H.S. Dik (void) memmove(path + match[1].rm_so, path + match[1].rm_eo, 162134a1f4eSCasper H.S. Dik match[0].rm_eo - match[1].rm_eo + 1); 163134a1f4eSCasper H.S. Dik 164134a1f4eSCasper H.S. Dik return (B_TRUE); 165134a1f4eSCasper H.S. Dik } 166134a1f4eSCasper H.S. Dik 167134a1f4eSCasper H.S. Dik static int 168134a1f4eSCasper H.S. Dik register_pfexec(int fd) 169134a1f4eSCasper H.S. Dik { 170134a1f4eSCasper H.S. Dik int ret = syscall(SYS_privsys, PRIVSYS_PFEXEC_REG, fd); 171134a1f4eSCasper H.S. Dik 172134a1f4eSCasper H.S. Dik return (ret); 173134a1f4eSCasper H.S. Dik } 174134a1f4eSCasper H.S. Dik 175134a1f4eSCasper H.S. Dik /* ARGSUSED */ 176134a1f4eSCasper H.S. Dik static void 177134a1f4eSCasper H.S. Dik unregister_pfexec(int sig) 178134a1f4eSCasper H.S. Dik { 179134a1f4eSCasper H.S. Dik if (doorfd != -1) 180134a1f4eSCasper H.S. Dik (void) syscall(SYS_privsys, PRIVSYS_PFEXEC_UNREG, doorfd); 181134a1f4eSCasper H.S. Dik _exit(0); 182134a1f4eSCasper H.S. Dik } 183134a1f4eSCasper H.S. Dik 184134a1f4eSCasper H.S. Dik static int 185134a1f4eSCasper H.S. Dik alldigits(const char *s) 186134a1f4eSCasper H.S. Dik { 187134a1f4eSCasper H.S. Dik int c; 188134a1f4eSCasper H.S. Dik 189134a1f4eSCasper H.S. Dik if (*s == '\0') 190134a1f4eSCasper H.S. Dik return (0); 191134a1f4eSCasper H.S. Dik 192134a1f4eSCasper H.S. Dik while ((c = *s++) != '\0') { 193134a1f4eSCasper H.S. Dik if (!isdigit(c)) { 194134a1f4eSCasper H.S. Dik return (0); 195134a1f4eSCasper H.S. Dik } 196134a1f4eSCasper H.S. Dik } 197134a1f4eSCasper H.S. Dik 198134a1f4eSCasper H.S. Dik return (1); 199134a1f4eSCasper H.S. Dik } 200134a1f4eSCasper H.S. Dik 201134a1f4eSCasper H.S. Dik static uid_t 202134a1f4eSCasper H.S. Dik get_uid(const char *v, boolean_t *ok, char *path) 203134a1f4eSCasper H.S. Dik { 204134a1f4eSCasper H.S. Dik struct passwd *pwd, pwdm; 205134a1f4eSCasper H.S. Dik char buf[1024]; 206134a1f4eSCasper H.S. Dik 207134a1f4eSCasper H.S. Dik if (getpwnam_r(v, &pwdm, buf, sizeof (buf), &pwd) == 0 && pwd != NULL) 208134a1f4eSCasper H.S. Dik return (pwd->pw_uid); 209134a1f4eSCasper H.S. Dik 210134a1f4eSCasper H.S. Dik if (alldigits(v)) 211134a1f4eSCasper H.S. Dik return (atoi(v)); 212134a1f4eSCasper H.S. Dik 213134a1f4eSCasper H.S. Dik *ok = B_FALSE; 214134a1f4eSCasper H.S. Dik syslog(LOG_ERR, "%s: %s: unknown username\n", path, v); 215134a1f4eSCasper H.S. Dik return ((uid_t)-1); 216134a1f4eSCasper H.S. Dik } 217134a1f4eSCasper H.S. Dik 218134a1f4eSCasper H.S. Dik static uid_t 219134a1f4eSCasper H.S. Dik get_gid(const char *v, boolean_t *ok, char *path) 220134a1f4eSCasper H.S. Dik { 221134a1f4eSCasper H.S. Dik struct group *grp, grpm; 222134a1f4eSCasper H.S. Dik char buf[1024]; 223134a1f4eSCasper H.S. Dik 224134a1f4eSCasper H.S. Dik if (getgrnam_r(v, &grpm, buf, sizeof (buf), &grp) == 0 && grp != NULL) 225134a1f4eSCasper H.S. Dik return (grp->gr_gid); 226134a1f4eSCasper H.S. Dik 227134a1f4eSCasper H.S. Dik if (alldigits(v)) 228134a1f4eSCasper H.S. Dik return (atoi(v)); 229134a1f4eSCasper H.S. Dik 230134a1f4eSCasper H.S. Dik *ok = B_FALSE; 231134a1f4eSCasper H.S. Dik syslog(LOG_ERR, "%s: %s: unknown groupname\n", path, v); 232134a1f4eSCasper H.S. Dik return ((gid_t)-1); 233134a1f4eSCasper H.S. Dik } 234134a1f4eSCasper H.S. Dik 235134a1f4eSCasper H.S. Dik static priv_set_t * 236134a1f4eSCasper H.S. Dik get_privset(const char *s, boolean_t *ok, char *path) 237134a1f4eSCasper H.S. Dik { 238134a1f4eSCasper H.S. Dik priv_set_t *res; 239134a1f4eSCasper H.S. Dik 240134a1f4eSCasper H.S. Dik if ((res = priv_str_to_set(s, ",", NULL)) == NULL) { 241134a1f4eSCasper H.S. Dik syslog(LOG_ERR, "%s: %s: bad privilege set\n", path, s); 242134a1f4eSCasper H.S. Dik if (ok != NULL) 243134a1f4eSCasper H.S. Dik *ok = B_FALSE; 244134a1f4eSCasper H.S. Dik } 245134a1f4eSCasper H.S. Dik return (res); 246134a1f4eSCasper H.S. Dik } 247134a1f4eSCasper H.S. Dik 248134a1f4eSCasper H.S. Dik /*ARGSUSED*/ 249134a1f4eSCasper H.S. Dik static int 250134a1f4eSCasper H.S. Dik ggp_callback(const char *prof, kva_t *attr, void *ctxt, void *vres) 251134a1f4eSCasper H.S. Dik { 252134a1f4eSCasper H.S. Dik priv_set_t *res = vres; 253134a1f4eSCasper H.S. Dik char *privs; 254134a1f4eSCasper H.S. Dik 255134a1f4eSCasper H.S. Dik if (attr == NULL) 256134a1f4eSCasper H.S. Dik return (0); 257134a1f4eSCasper H.S. Dik 258134a1f4eSCasper H.S. Dik /* get privs from this profile */ 259134a1f4eSCasper H.S. Dik privs = kva_match(attr, PROFATTR_PRIVS_KW); 260134a1f4eSCasper H.S. Dik if (privs != NULL) { 261134a1f4eSCasper H.S. Dik priv_set_t *tmp = priv_str_to_set(privs, ",", NULL); 262134a1f4eSCasper H.S. Dik if (tmp != NULL) { 263134a1f4eSCasper H.S. Dik priv_union(tmp, res); 264134a1f4eSCasper H.S. Dik priv_freeset(tmp); 265134a1f4eSCasper H.S. Dik } 266134a1f4eSCasper H.S. Dik } 267134a1f4eSCasper H.S. Dik 268134a1f4eSCasper H.S. Dik return (0); 269134a1f4eSCasper H.S. Dik } 270134a1f4eSCasper H.S. Dik 271134a1f4eSCasper H.S. Dik /* 272134a1f4eSCasper H.S. Dik * This routine exists on failure and returns NULL if no granted privileges 273134a1f4eSCasper H.S. Dik * are set. 274134a1f4eSCasper H.S. Dik */ 275134a1f4eSCasper H.S. Dik static priv_set_t * 276134a1f4eSCasper H.S. Dik get_granted_privs(uid_t uid) 277134a1f4eSCasper H.S. Dik { 278134a1f4eSCasper H.S. Dik priv_set_t *res; 279134a1f4eSCasper H.S. Dik struct passwd *pwd, pwdm; 280134a1f4eSCasper H.S. Dik char buf[1024]; 281134a1f4eSCasper H.S. Dik 282134a1f4eSCasper H.S. Dik if (getpwuid_r(uid, &pwdm, buf, sizeof (buf), &pwd) != 0 || pwd == NULL) 283134a1f4eSCasper H.S. Dik return (NULL); 284134a1f4eSCasper H.S. Dik 285134a1f4eSCasper H.S. Dik res = priv_allocset(); 286134a1f4eSCasper H.S. Dik if (res == NULL) 287134a1f4eSCasper H.S. Dik return (NULL); 288134a1f4eSCasper H.S. Dik 289134a1f4eSCasper H.S. Dik priv_emptyset(res); 290134a1f4eSCasper H.S. Dik 291134a1f4eSCasper H.S. Dik (void) _enum_profs(pwd->pw_name, ggp_callback, NULL, res); 292134a1f4eSCasper H.S. Dik 293134a1f4eSCasper H.S. Dik return (res); 294134a1f4eSCasper H.S. Dik } 295134a1f4eSCasper H.S. Dik 296134a1f4eSCasper H.S. Dik static void 297134a1f4eSCasper H.S. Dik callback_forced_privs(pfexec_arg_t *pap) 298134a1f4eSCasper H.S. Dik { 299134a1f4eSCasper H.S. Dik execattr_t *exec; 300134a1f4eSCasper H.S. Dik char *value; 301134a1f4eSCasper H.S. Dik priv_set_t *fset; 302134a1f4eSCasper H.S. Dik void *res = alloca(setsz); 303134a1f4eSCasper H.S. Dik 304134a1f4eSCasper H.S. Dik /* Empty set signifies no forced privileges. */ 305134a1f4eSCasper H.S. Dik priv_emptyset(res); 306134a1f4eSCasper H.S. Dik 307134a1f4eSCasper H.S. Dik exec = getexecprof("Forced Privilege", KV_COMMAND, pap->pfa_path, 308134a1f4eSCasper H.S. Dik GET_ONE); 309134a1f4eSCasper H.S. Dik 310134a1f4eSCasper H.S. Dik if (exec == NULL && removeisapath(pap->pfa_path)) { 311134a1f4eSCasper H.S. Dik exec = getexecprof("Forced Privilege", KV_COMMAND, 312134a1f4eSCasper H.S. Dik pap->pfa_path, GET_ONE); 313134a1f4eSCasper H.S. Dik } 314134a1f4eSCasper H.S. Dik 315134a1f4eSCasper H.S. Dik if (exec == NULL) { 316134a1f4eSCasper H.S. Dik (void) door_return(res, setsz, NULL, 0); 317134a1f4eSCasper H.S. Dik return; 318134a1f4eSCasper H.S. Dik } 319134a1f4eSCasper H.S. Dik 320134a1f4eSCasper H.S. Dik if ((value = kva_match(exec->attr, EXECATTR_IPRIV_KW)) == NULL || 321134a1f4eSCasper H.S. Dik (fset = get_privset(value, NULL, pap->pfa_path)) == NULL) { 322134a1f4eSCasper H.S. Dik free_execattr(exec); 323134a1f4eSCasper H.S. Dik (void) door_return(res, setsz, NULL, 0); 324134a1f4eSCasper H.S. Dik return; 325134a1f4eSCasper H.S. Dik } 326134a1f4eSCasper H.S. Dik 327134a1f4eSCasper H.S. Dik priv_copyset(fset, res); 328134a1f4eSCasper H.S. Dik priv_freeset(fset); 329134a1f4eSCasper H.S. Dik 330134a1f4eSCasper H.S. Dik free_execattr(exec); 331134a1f4eSCasper H.S. Dik (void) door_return(res, setsz, NULL, 0); 332134a1f4eSCasper H.S. Dik } 333134a1f4eSCasper H.S. Dik 334134a1f4eSCasper H.S. Dik static void 335134a1f4eSCasper H.S. Dik callback_user_privs(pfexec_arg_t *pap) 336134a1f4eSCasper H.S. Dik { 337134a1f4eSCasper H.S. Dik priv_set_t *gset, *wset; 338134a1f4eSCasper H.S. Dik uint32_t res; 339134a1f4eSCasper H.S. Dik 340134a1f4eSCasper H.S. Dik wset = (priv_set_t *)&pap->pfa_buf; 341134a1f4eSCasper H.S. Dik gset = get_granted_privs(pap->pfa_uid); 342134a1f4eSCasper H.S. Dik 343134a1f4eSCasper H.S. Dik res = priv_issubset(wset, gset); 344134a1f4eSCasper H.S. Dik priv_freeset(gset); 345134a1f4eSCasper H.S. Dik 346134a1f4eSCasper H.S. Dik (void) door_return((char *)&res, sizeof (res), NULL, 0); 347134a1f4eSCasper H.S. Dik } 348134a1f4eSCasper H.S. Dik 349134a1f4eSCasper H.S. Dik static void 350134a1f4eSCasper H.S. Dik callback_pfexec(pfexec_arg_t *pap) 351134a1f4eSCasper H.S. Dik { 352134a1f4eSCasper H.S. Dik pfexec_reply_t *res = alloca(repsz); 353134a1f4eSCasper H.S. Dik uid_t uid, euid, uuid; 354134a1f4eSCasper H.S. Dik gid_t gid, egid; 355134a1f4eSCasper H.S. Dik struct passwd pw, *pwd; 356134a1f4eSCasper H.S. Dik char buf[1024]; 357bf859931SCasper H.S. Dik execattr_t *exec = NULL; 358134a1f4eSCasper H.S. Dik char *value; 359134a1f4eSCasper H.S. Dik priv_set_t *lset, *iset; 360134a1f4eSCasper H.S. Dik size_t mysz = repsz - 2 * setsz; 361134a1f4eSCasper H.S. Dik char *path = pap->pfa_path; 362134a1f4eSCasper H.S. Dik 363*b01b59e3SRobert Mustacchi /* 364*b01b59e3SRobert Mustacchi * Initialize the pfexec_reply_t to a sane state. 365*b01b59e3SRobert Mustacchi */ 366*b01b59e3SRobert Mustacchi res->pfr_vers = pap->pfa_vers; 367*b01b59e3SRobert Mustacchi res->pfr_len = 0; 368*b01b59e3SRobert Mustacchi res->pfr_ruid = PFEXEC_NOTSET; 369*b01b59e3SRobert Mustacchi res->pfr_euid = PFEXEC_NOTSET; 370*b01b59e3SRobert Mustacchi res->pfr_rgid = PFEXEC_NOTSET; 371*b01b59e3SRobert Mustacchi res->pfr_egid = PFEXEC_NOTSET; 372*b01b59e3SRobert Mustacchi res->pfr_setcred = B_FALSE; 373*b01b59e3SRobert Mustacchi res->pfr_scrubenv = B_TRUE; 374*b01b59e3SRobert Mustacchi res->pfr_allowed = B_FALSE; 375*b01b59e3SRobert Mustacchi res->pfr_ioff = 0; 376*b01b59e3SRobert Mustacchi res->pfr_loff = 0; 377*b01b59e3SRobert Mustacchi 378134a1f4eSCasper H.S. Dik uuid = pap->pfa_uid; 379134a1f4eSCasper H.S. Dik 380134a1f4eSCasper H.S. Dik if (getpwuid_r(uuid, &pw, buf, sizeof (buf), &pwd) != 0 || pwd == NULL) 381134a1f4eSCasper H.S. Dik goto stdexec; 382134a1f4eSCasper H.S. Dik 383134a1f4eSCasper H.S. Dik exec = getexecuser(pwd->pw_name, KV_COMMAND, path, GET_ONE); 384134a1f4eSCasper H.S. Dik 385bf859931SCasper H.S. Dik if ((exec == NULL || exec->attr == NULL) && removeisapath(path)) { 386bf859931SCasper H.S. Dik free_execattr(exec); 387134a1f4eSCasper H.S. Dik exec = getexecuser(pwd->pw_name, KV_COMMAND, path, GET_ONE); 388bf859931SCasper H.S. Dik } 389134a1f4eSCasper H.S. Dik 390134a1f4eSCasper H.S. Dik if (exec == NULL) { 391134a1f4eSCasper H.S. Dik res->pfr_allowed = B_FALSE; 392134a1f4eSCasper H.S. Dik goto ret; 393134a1f4eSCasper H.S. Dik } 394134a1f4eSCasper H.S. Dik 395134a1f4eSCasper H.S. Dik if (exec->attr == NULL) 396134a1f4eSCasper H.S. Dik goto stdexec; 397134a1f4eSCasper H.S. Dik 398134a1f4eSCasper H.S. Dik /* Found in execattr, so clearly we can use it */ 399134a1f4eSCasper H.S. Dik res->pfr_allowed = B_TRUE; 400134a1f4eSCasper H.S. Dik 401134a1f4eSCasper H.S. Dik uid = euid = (uid_t)-1; 402134a1f4eSCasper H.S. Dik gid = egid = (gid_t)-1; 403134a1f4eSCasper H.S. Dik lset = iset = NULL; 404134a1f4eSCasper H.S. Dik 405134a1f4eSCasper H.S. Dik /* 406134a1f4eSCasper H.S. Dik * If there's an error in parsing uid, gid, privs, then return 407134a1f4eSCasper H.S. Dik * failure. 408134a1f4eSCasper H.S. Dik */ 409134a1f4eSCasper H.S. Dik if ((value = kva_match(exec->attr, EXECATTR_UID_KW)) != NULL) 410134a1f4eSCasper H.S. Dik euid = uid = get_uid(value, &res->pfr_allowed, path); 411134a1f4eSCasper H.S. Dik 412134a1f4eSCasper H.S. Dik if ((value = kva_match(exec->attr, EXECATTR_GID_KW)) != NULL) 413134a1f4eSCasper H.S. Dik egid = gid = get_gid(value, &res->pfr_allowed, path); 414134a1f4eSCasper H.S. Dik 415134a1f4eSCasper H.S. Dik if ((value = kva_match(exec->attr, EXECATTR_EUID_KW)) != NULL) 416134a1f4eSCasper H.S. Dik euid = get_uid(value, &res->pfr_allowed, path); 417134a1f4eSCasper H.S. Dik 418134a1f4eSCasper H.S. Dik if ((value = kva_match(exec->attr, EXECATTR_EGID_KW)) != NULL) 419134a1f4eSCasper H.S. Dik egid = get_gid(value, &res->pfr_allowed, path); 420134a1f4eSCasper H.S. Dik 421134a1f4eSCasper H.S. Dik if ((value = kva_match(exec->attr, EXECATTR_LPRIV_KW)) != NULL) 422134a1f4eSCasper H.S. Dik lset = get_privset(value, &res->pfr_allowed, path); 423134a1f4eSCasper H.S. Dik 424134a1f4eSCasper H.S. Dik if ((value = kva_match(exec->attr, EXECATTR_IPRIV_KW)) != NULL) 425134a1f4eSCasper H.S. Dik iset = get_privset(value, &res->pfr_allowed, path); 426134a1f4eSCasper H.S. Dik 427134a1f4eSCasper H.S. Dik /* 428134a1f4eSCasper H.S. Dik * Remove LD_* variables in the kernel when the runtime linker might 429134a1f4eSCasper H.S. Dik * use them later on because the uids are equal. 430134a1f4eSCasper H.S. Dik */ 431134a1f4eSCasper H.S. Dik res->pfr_scrubenv = (uid != (uid_t)-1 && euid == uid) || 432134a1f4eSCasper H.S. Dik (gid != (gid_t)-1 && egid == gid) || iset != NULL; 433134a1f4eSCasper H.S. Dik 434134a1f4eSCasper H.S. Dik res->pfr_euid = euid; 435134a1f4eSCasper H.S. Dik res->pfr_ruid = uid; 436134a1f4eSCasper H.S. Dik res->pfr_egid = egid; 437134a1f4eSCasper H.S. Dik res->pfr_rgid = gid; 438134a1f4eSCasper H.S. Dik 439134a1f4eSCasper H.S. Dik /* Now add the privilege sets */ 440134a1f4eSCasper H.S. Dik res->pfr_ioff = res->pfr_loff = 0; 441134a1f4eSCasper H.S. Dik if (iset != NULL) { 442134a1f4eSCasper H.S. Dik res->pfr_ioff = mysz; 443134a1f4eSCasper H.S. Dik priv_copyset(iset, PFEXEC_REPLY_IPRIV(res)); 444134a1f4eSCasper H.S. Dik mysz += setsz; 445134a1f4eSCasper H.S. Dik priv_freeset(iset); 446134a1f4eSCasper H.S. Dik } 447134a1f4eSCasper H.S. Dik if (lset != NULL) { 448134a1f4eSCasper H.S. Dik res->pfr_loff = mysz; 449134a1f4eSCasper H.S. Dik priv_copyset(lset, PFEXEC_REPLY_LPRIV(res)); 450134a1f4eSCasper H.S. Dik mysz += setsz; 451134a1f4eSCasper H.S. Dik priv_freeset(lset); 452134a1f4eSCasper H.S. Dik } 453134a1f4eSCasper H.S. Dik 454134a1f4eSCasper H.S. Dik res->pfr_setcred = uid != (uid_t)-1 || euid != (uid_t)-1 || 455134a1f4eSCasper H.S. Dik egid != (gid_t)-1 || gid != (gid_t)-1 || iset != NULL || 456134a1f4eSCasper H.S. Dik lset != NULL; 457134a1f4eSCasper H.S. Dik 458134a1f4eSCasper H.S. Dik /* If the real uid changes, we stop running under a profile shell */ 459134a1f4eSCasper H.S. Dik res->pfr_clearflag = uid != (uid_t)-1 && uid != uuid; 460134a1f4eSCasper H.S. Dik free_execattr(exec); 461134a1f4eSCasper H.S. Dik ret: 462134a1f4eSCasper H.S. Dik (void) door_return((char *)res, mysz, NULL, 0); 463134a1f4eSCasper H.S. Dik return; 464134a1f4eSCasper H.S. Dik 465134a1f4eSCasper H.S. Dik stdexec: 466bf859931SCasper H.S. Dik free_execattr(exec); 467bf859931SCasper H.S. Dik 468134a1f4eSCasper H.S. Dik res->pfr_scrubenv = B_FALSE; 469134a1f4eSCasper H.S. Dik res->pfr_setcred = B_FALSE; 470134a1f4eSCasper H.S. Dik res->pfr_allowed = B_TRUE; 471134a1f4eSCasper H.S. Dik 472134a1f4eSCasper H.S. Dik (void) door_return((char *)res, mysz, NULL, 0); 473134a1f4eSCasper H.S. Dik } 474134a1f4eSCasper H.S. Dik 475134a1f4eSCasper H.S. Dik /* ARGSUSED */ 476134a1f4eSCasper H.S. Dik static void 477134a1f4eSCasper H.S. Dik callback(void *cookie, char *argp, size_t asz, door_desc_t *dp, uint_t ndesc) 478134a1f4eSCasper H.S. Dik { 479134a1f4eSCasper H.S. Dik /* LINTED ALIGNMENT */ 480134a1f4eSCasper H.S. Dik pfexec_arg_t *pap = (pfexec_arg_t *)argp; 481134a1f4eSCasper H.S. Dik 482134a1f4eSCasper H.S. Dik if (asz < sizeof (pfexec_arg_t) || pap->pfa_vers != PFEXEC_ARG_VERS) { 483134a1f4eSCasper H.S. Dik (void) door_return(NULL, 0, NULL, 0); 484134a1f4eSCasper H.S. Dik return; 485134a1f4eSCasper H.S. Dik } 486134a1f4eSCasper H.S. Dik 487134a1f4eSCasper H.S. Dik switch (pap->pfa_call) { 488134a1f4eSCasper H.S. Dik case PFEXEC_EXEC_ATTRS: 489134a1f4eSCasper H.S. Dik callback_pfexec(pap); 490134a1f4eSCasper H.S. Dik break; 491134a1f4eSCasper H.S. Dik case PFEXEC_FORCED_PRIVS: 492134a1f4eSCasper H.S. Dik callback_forced_privs(pap); 493134a1f4eSCasper H.S. Dik break; 494134a1f4eSCasper H.S. Dik case PFEXEC_USER_PRIVS: 495134a1f4eSCasper H.S. Dik callback_user_privs(pap); 496134a1f4eSCasper H.S. Dik break; 497134a1f4eSCasper H.S. Dik default: 498134a1f4eSCasper H.S. Dik syslog(LOG_ERR, "Bad Call: %d\n", pap->pfa_call); 499134a1f4eSCasper H.S. Dik break; 500134a1f4eSCasper H.S. Dik } 501134a1f4eSCasper H.S. Dik 502134a1f4eSCasper H.S. Dik /* 503134a1f4eSCasper H.S. Dik * If the door_return(ptr, size, NULL, 0) fails, make sure we 504134a1f4eSCasper H.S. Dik * don't lose server threads. 505134a1f4eSCasper H.S. Dik */ 506134a1f4eSCasper H.S. Dik (void) door_return(NULL, 0, NULL, 0); 507134a1f4eSCasper H.S. Dik } 508134a1f4eSCasper H.S. Dik 509134a1f4eSCasper H.S. Dik int 510134a1f4eSCasper H.S. Dik main(void) 511134a1f4eSCasper H.S. Dik { 512134a1f4eSCasper H.S. Dik const priv_impl_info_t *info; 513134a1f4eSCasper H.S. Dik 514134a1f4eSCasper H.S. Dik (void) signal(SIGINT, unregister_pfexec); 515134a1f4eSCasper H.S. Dik (void) signal(SIGQUIT, unregister_pfexec); 516134a1f4eSCasper H.S. Dik (void) signal(SIGTERM, unregister_pfexec); 517134a1f4eSCasper H.S. Dik (void) signal(SIGHUP, unregister_pfexec); 518134a1f4eSCasper H.S. Dik 519134a1f4eSCasper H.S. Dik info = getprivimplinfo(); 520134a1f4eSCasper H.S. Dik if (info == NULL) 521134a1f4eSCasper H.S. Dik exit(1); 522134a1f4eSCasper H.S. Dik 523134a1f4eSCasper H.S. Dik if (fork() > 0) 524134a1f4eSCasper H.S. Dik _exit(0); 525134a1f4eSCasper H.S. Dik 526134a1f4eSCasper H.S. Dik openlog("pfexecd", LOG_PID, LOG_DAEMON); 527134a1f4eSCasper H.S. Dik setsz = info->priv_setsize * sizeof (priv_chunk_t); 528134a1f4eSCasper H.S. Dik repsz = 2 * setsz + sizeof (pfexec_reply_t); 529134a1f4eSCasper H.S. Dik 530134a1f4eSCasper H.S. Dik init_isa_regex(); 531134a1f4eSCasper H.S. Dik 532134a1f4eSCasper H.S. Dik doorfd = door_create(callback, NULL, DOOR_REFUSE_DESC); 533134a1f4eSCasper H.S. Dik 534134a1f4eSCasper H.S. Dik if (doorfd == -1 || register_pfexec(doorfd) != 0) { 535134a1f4eSCasper H.S. Dik perror("doorfd"); 536134a1f4eSCasper H.S. Dik exit(1); 537134a1f4eSCasper H.S. Dik } 538134a1f4eSCasper H.S. Dik 539134a1f4eSCasper H.S. Dik /* LINTED CONSTCOND */ 540134a1f4eSCasper H.S. Dik while (1) 541134a1f4eSCasper H.S. Dik (void) sigpause(SIGINT); 542134a1f4eSCasper H.S. Dik 543134a1f4eSCasper H.S. Dik return (0); 544134a1f4eSCasper H.S. Dik } 545