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. 22b01b59e3SRobert 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++] = '\\'; 121*2dedcc4fSToomas Soome /* FALLTHROUGH */ 122134a1f4eSCasper H.S. Dik default: 123134a1f4eSCasper H.S. Dik regexpr[len++] = *p; 124134a1f4eSCasper H.S. Dik break; 125134a1f4eSCasper H.S. Dik case ' ': 126134a1f4eSCasper H.S. Dik case '\t': 127134a1f4eSCasper H.S. Dik regexpr[len++] = '|'; 128134a1f4eSCasper H.S. Dik break; 129134a1f4eSCasper H.S. Dik } 130134a1f4eSCasper H.S. Dik } 131134a1f4eSCasper H.S. Dik 132134a1f4eSCasper H.S. Dik free(isalist); 133134a1f4eSCasper H.S. Dik regexpr[len] = '\0'; 134134a1f4eSCasper H.S. Dik (void) strcat(regexpr, RIGHT); 135134a1f4eSCasper H.S. Dik 136134a1f4eSCasper H.S. Dik if (regcomp(®c, regexpr, REG_EXTENDED) != 0) 137134a1f4eSCasper H.S. Dik return; 138134a1f4eSCasper H.S. Dik 139134a1f4eSCasper H.S. Dik cansplice = B_TRUE; 140134a1f4eSCasper H.S. Dik } 141134a1f4eSCasper H.S. Dik 142134a1f4eSCasper H.S. Dik #define NMATCH 2 143134a1f4eSCasper H.S. Dik 144134a1f4eSCasper H.S. Dik static boolean_t 145134a1f4eSCasper H.S. Dik removeisapath(char *path) 146134a1f4eSCasper H.S. Dik { 147134a1f4eSCasper H.S. Dik regmatch_t match[NMATCH]; 148134a1f4eSCasper H.S. Dik 149134a1f4eSCasper H.S. Dik if (!cansplice || regexec(®c, path, NMATCH, match, 0) != 0) 150134a1f4eSCasper H.S. Dik return (B_FALSE); 151134a1f4eSCasper H.S. Dik 152134a1f4eSCasper H.S. Dik /* 153134a1f4eSCasper H.S. Dik * The first match includes the whole matched expression including the 154134a1f4eSCasper H.S. Dik * end of the string. The second match includes the "/" + "isa" and 155134a1f4eSCasper H.S. Dik * that is the part we need to remove. 156134a1f4eSCasper H.S. Dik */ 157134a1f4eSCasper H.S. Dik 158134a1f4eSCasper H.S. Dik if (match[1].rm_so == -1) 159134a1f4eSCasper H.S. Dik return (B_FALSE); 160134a1f4eSCasper H.S. Dik 161134a1f4eSCasper H.S. Dik /* match[0].rm_eo == strlen(path) */ 162134a1f4eSCasper H.S. Dik (void) memmove(path + match[1].rm_so, path + match[1].rm_eo, 163134a1f4eSCasper H.S. Dik match[0].rm_eo - match[1].rm_eo + 1); 164134a1f4eSCasper H.S. Dik 165134a1f4eSCasper H.S. Dik return (B_TRUE); 166134a1f4eSCasper H.S. Dik } 167134a1f4eSCasper H.S. Dik 168134a1f4eSCasper H.S. Dik static int 169134a1f4eSCasper H.S. Dik register_pfexec(int fd) 170134a1f4eSCasper H.S. Dik { 171134a1f4eSCasper H.S. Dik int ret = syscall(SYS_privsys, PRIVSYS_PFEXEC_REG, fd); 172134a1f4eSCasper H.S. Dik 173134a1f4eSCasper H.S. Dik return (ret); 174134a1f4eSCasper H.S. Dik } 175134a1f4eSCasper H.S. Dik 176134a1f4eSCasper H.S. Dik /* ARGSUSED */ 177134a1f4eSCasper H.S. Dik static void 178134a1f4eSCasper H.S. Dik unregister_pfexec(int sig) 179134a1f4eSCasper H.S. Dik { 180134a1f4eSCasper H.S. Dik if (doorfd != -1) 181134a1f4eSCasper H.S. Dik (void) syscall(SYS_privsys, PRIVSYS_PFEXEC_UNREG, doorfd); 182134a1f4eSCasper H.S. Dik _exit(0); 183134a1f4eSCasper H.S. Dik } 184134a1f4eSCasper H.S. Dik 185134a1f4eSCasper H.S. Dik static int 186134a1f4eSCasper H.S. Dik alldigits(const char *s) 187134a1f4eSCasper H.S. Dik { 188134a1f4eSCasper H.S. Dik int c; 189134a1f4eSCasper H.S. Dik 190134a1f4eSCasper H.S. Dik if (*s == '\0') 191134a1f4eSCasper H.S. Dik return (0); 192134a1f4eSCasper H.S. Dik 193134a1f4eSCasper H.S. Dik while ((c = *s++) != '\0') { 194134a1f4eSCasper H.S. Dik if (!isdigit(c)) { 195134a1f4eSCasper H.S. Dik return (0); 196134a1f4eSCasper H.S. Dik } 197134a1f4eSCasper H.S. Dik } 198134a1f4eSCasper H.S. Dik 199134a1f4eSCasper H.S. Dik return (1); 200134a1f4eSCasper H.S. Dik } 201134a1f4eSCasper H.S. Dik 202134a1f4eSCasper H.S. Dik static uid_t 203134a1f4eSCasper H.S. Dik get_uid(const char *v, boolean_t *ok, char *path) 204134a1f4eSCasper H.S. Dik { 205134a1f4eSCasper H.S. Dik struct passwd *pwd, pwdm; 206134a1f4eSCasper H.S. Dik char buf[1024]; 207134a1f4eSCasper H.S. Dik 208134a1f4eSCasper H.S. Dik if (getpwnam_r(v, &pwdm, buf, sizeof (buf), &pwd) == 0 && pwd != NULL) 209134a1f4eSCasper H.S. Dik return (pwd->pw_uid); 210134a1f4eSCasper H.S. Dik 211134a1f4eSCasper H.S. Dik if (alldigits(v)) 212134a1f4eSCasper H.S. Dik return (atoi(v)); 213134a1f4eSCasper H.S. Dik 214134a1f4eSCasper H.S. Dik *ok = B_FALSE; 215134a1f4eSCasper H.S. Dik syslog(LOG_ERR, "%s: %s: unknown username\n", path, v); 216134a1f4eSCasper H.S. Dik return ((uid_t)-1); 217134a1f4eSCasper H.S. Dik } 218134a1f4eSCasper H.S. Dik 219134a1f4eSCasper H.S. Dik static uid_t 220134a1f4eSCasper H.S. Dik get_gid(const char *v, boolean_t *ok, char *path) 221134a1f4eSCasper H.S. Dik { 222134a1f4eSCasper H.S. Dik struct group *grp, grpm; 223134a1f4eSCasper H.S. Dik char buf[1024]; 224134a1f4eSCasper H.S. Dik 225134a1f4eSCasper H.S. Dik if (getgrnam_r(v, &grpm, buf, sizeof (buf), &grp) == 0 && grp != NULL) 226134a1f4eSCasper H.S. Dik return (grp->gr_gid); 227134a1f4eSCasper H.S. Dik 228134a1f4eSCasper H.S. Dik if (alldigits(v)) 229134a1f4eSCasper H.S. Dik return (atoi(v)); 230134a1f4eSCasper H.S. Dik 231134a1f4eSCasper H.S. Dik *ok = B_FALSE; 232134a1f4eSCasper H.S. Dik syslog(LOG_ERR, "%s: %s: unknown groupname\n", path, v); 233134a1f4eSCasper H.S. Dik return ((gid_t)-1); 234134a1f4eSCasper H.S. Dik } 235134a1f4eSCasper H.S. Dik 236134a1f4eSCasper H.S. Dik static priv_set_t * 237134a1f4eSCasper H.S. Dik get_privset(const char *s, boolean_t *ok, char *path) 238134a1f4eSCasper H.S. Dik { 239134a1f4eSCasper H.S. Dik priv_set_t *res; 240134a1f4eSCasper H.S. Dik 241134a1f4eSCasper H.S. Dik if ((res = priv_str_to_set(s, ",", NULL)) == NULL) { 242134a1f4eSCasper H.S. Dik syslog(LOG_ERR, "%s: %s: bad privilege set\n", path, s); 243134a1f4eSCasper H.S. Dik if (ok != NULL) 244134a1f4eSCasper H.S. Dik *ok = B_FALSE; 245134a1f4eSCasper H.S. Dik } 246134a1f4eSCasper H.S. Dik return (res); 247134a1f4eSCasper H.S. Dik } 248134a1f4eSCasper H.S. Dik 249134a1f4eSCasper H.S. Dik /*ARGSUSED*/ 250134a1f4eSCasper H.S. Dik static int 251134a1f4eSCasper H.S. Dik ggp_callback(const char *prof, kva_t *attr, void *ctxt, void *vres) 252134a1f4eSCasper H.S. Dik { 253134a1f4eSCasper H.S. Dik priv_set_t *res = vres; 254134a1f4eSCasper H.S. Dik char *privs; 255134a1f4eSCasper H.S. Dik 256134a1f4eSCasper H.S. Dik if (attr == NULL) 257134a1f4eSCasper H.S. Dik return (0); 258134a1f4eSCasper H.S. Dik 259134a1f4eSCasper H.S. Dik /* get privs from this profile */ 260134a1f4eSCasper H.S. Dik privs = kva_match(attr, PROFATTR_PRIVS_KW); 261134a1f4eSCasper H.S. Dik if (privs != NULL) { 262134a1f4eSCasper H.S. Dik priv_set_t *tmp = priv_str_to_set(privs, ",", NULL); 263134a1f4eSCasper H.S. Dik if (tmp != NULL) { 264134a1f4eSCasper H.S. Dik priv_union(tmp, res); 265134a1f4eSCasper H.S. Dik priv_freeset(tmp); 266134a1f4eSCasper H.S. Dik } 267134a1f4eSCasper H.S. Dik } 268134a1f4eSCasper H.S. Dik 269134a1f4eSCasper H.S. Dik return (0); 270134a1f4eSCasper H.S. Dik } 271134a1f4eSCasper H.S. Dik 272134a1f4eSCasper H.S. Dik /* 273134a1f4eSCasper H.S. Dik * This routine exists on failure and returns NULL if no granted privileges 274134a1f4eSCasper H.S. Dik * are set. 275134a1f4eSCasper H.S. Dik */ 276134a1f4eSCasper H.S. Dik static priv_set_t * 277134a1f4eSCasper H.S. Dik get_granted_privs(uid_t uid) 278134a1f4eSCasper H.S. Dik { 279134a1f4eSCasper H.S. Dik priv_set_t *res; 280134a1f4eSCasper H.S. Dik struct passwd *pwd, pwdm; 281134a1f4eSCasper H.S. Dik char buf[1024]; 282134a1f4eSCasper H.S. Dik 283134a1f4eSCasper H.S. Dik if (getpwuid_r(uid, &pwdm, buf, sizeof (buf), &pwd) != 0 || pwd == NULL) 284134a1f4eSCasper H.S. Dik return (NULL); 285134a1f4eSCasper H.S. Dik 286134a1f4eSCasper H.S. Dik res = priv_allocset(); 287134a1f4eSCasper H.S. Dik if (res == NULL) 288134a1f4eSCasper H.S. Dik return (NULL); 289134a1f4eSCasper H.S. Dik 290134a1f4eSCasper H.S. Dik priv_emptyset(res); 291134a1f4eSCasper H.S. Dik 292134a1f4eSCasper H.S. Dik (void) _enum_profs(pwd->pw_name, ggp_callback, NULL, res); 293134a1f4eSCasper H.S. Dik 294134a1f4eSCasper H.S. Dik return (res); 295134a1f4eSCasper H.S. Dik } 296134a1f4eSCasper H.S. Dik 297134a1f4eSCasper H.S. Dik static void 298134a1f4eSCasper H.S. Dik callback_forced_privs(pfexec_arg_t *pap) 299134a1f4eSCasper H.S. Dik { 300134a1f4eSCasper H.S. Dik execattr_t *exec; 301134a1f4eSCasper H.S. Dik char *value; 302134a1f4eSCasper H.S. Dik priv_set_t *fset; 303134a1f4eSCasper H.S. Dik void *res = alloca(setsz); 304134a1f4eSCasper H.S. Dik 305134a1f4eSCasper H.S. Dik /* Empty set signifies no forced privileges. */ 306134a1f4eSCasper H.S. Dik priv_emptyset(res); 307134a1f4eSCasper H.S. Dik 308134a1f4eSCasper H.S. Dik exec = getexecprof("Forced Privilege", KV_COMMAND, pap->pfa_path, 309134a1f4eSCasper H.S. Dik GET_ONE); 310134a1f4eSCasper H.S. Dik 311134a1f4eSCasper H.S. Dik if (exec == NULL && removeisapath(pap->pfa_path)) { 312134a1f4eSCasper H.S. Dik exec = getexecprof("Forced Privilege", KV_COMMAND, 313134a1f4eSCasper H.S. Dik pap->pfa_path, GET_ONE); 314134a1f4eSCasper H.S. Dik } 315134a1f4eSCasper H.S. Dik 316134a1f4eSCasper H.S. Dik if (exec == NULL) { 317134a1f4eSCasper H.S. Dik (void) door_return(res, setsz, NULL, 0); 318134a1f4eSCasper H.S. Dik return; 319134a1f4eSCasper H.S. Dik } 320134a1f4eSCasper H.S. Dik 321134a1f4eSCasper H.S. Dik if ((value = kva_match(exec->attr, EXECATTR_IPRIV_KW)) == NULL || 322134a1f4eSCasper H.S. Dik (fset = get_privset(value, NULL, pap->pfa_path)) == NULL) { 323134a1f4eSCasper H.S. Dik free_execattr(exec); 324134a1f4eSCasper H.S. Dik (void) door_return(res, setsz, NULL, 0); 325134a1f4eSCasper H.S. Dik return; 326134a1f4eSCasper H.S. Dik } 327134a1f4eSCasper H.S. Dik 328134a1f4eSCasper H.S. Dik priv_copyset(fset, res); 329134a1f4eSCasper H.S. Dik priv_freeset(fset); 330134a1f4eSCasper H.S. Dik 331134a1f4eSCasper H.S. Dik free_execattr(exec); 332134a1f4eSCasper H.S. Dik (void) door_return(res, setsz, NULL, 0); 333134a1f4eSCasper H.S. Dik } 334134a1f4eSCasper H.S. Dik 335134a1f4eSCasper H.S. Dik static void 336134a1f4eSCasper H.S. Dik callback_user_privs(pfexec_arg_t *pap) 337134a1f4eSCasper H.S. Dik { 338134a1f4eSCasper H.S. Dik priv_set_t *gset, *wset; 339134a1f4eSCasper H.S. Dik uint32_t res; 340134a1f4eSCasper H.S. Dik 341134a1f4eSCasper H.S. Dik wset = (priv_set_t *)&pap->pfa_buf; 342134a1f4eSCasper H.S. Dik gset = get_granted_privs(pap->pfa_uid); 343134a1f4eSCasper H.S. Dik 344134a1f4eSCasper H.S. Dik res = priv_issubset(wset, gset); 345134a1f4eSCasper H.S. Dik priv_freeset(gset); 346134a1f4eSCasper H.S. Dik 347134a1f4eSCasper H.S. Dik (void) door_return((char *)&res, sizeof (res), NULL, 0); 348134a1f4eSCasper H.S. Dik } 349134a1f4eSCasper H.S. Dik 350134a1f4eSCasper H.S. Dik static void 351134a1f4eSCasper H.S. Dik callback_pfexec(pfexec_arg_t *pap) 352134a1f4eSCasper H.S. Dik { 353134a1f4eSCasper H.S. Dik pfexec_reply_t *res = alloca(repsz); 354134a1f4eSCasper H.S. Dik uid_t uid, euid, uuid; 355134a1f4eSCasper H.S. Dik gid_t gid, egid; 356134a1f4eSCasper H.S. Dik struct passwd pw, *pwd; 357134a1f4eSCasper H.S. Dik char buf[1024]; 358bf859931SCasper H.S. Dik execattr_t *exec = NULL; 359134a1f4eSCasper H.S. Dik char *value; 360134a1f4eSCasper H.S. Dik priv_set_t *lset, *iset; 361134a1f4eSCasper H.S. Dik size_t mysz = repsz - 2 * setsz; 362134a1f4eSCasper H.S. Dik char *path = pap->pfa_path; 363134a1f4eSCasper H.S. Dik 364b01b59e3SRobert Mustacchi /* 365b01b59e3SRobert Mustacchi * Initialize the pfexec_reply_t to a sane state. 366b01b59e3SRobert Mustacchi */ 367b01b59e3SRobert Mustacchi res->pfr_vers = pap->pfa_vers; 368b01b59e3SRobert Mustacchi res->pfr_len = 0; 369b01b59e3SRobert Mustacchi res->pfr_ruid = PFEXEC_NOTSET; 370b01b59e3SRobert Mustacchi res->pfr_euid = PFEXEC_NOTSET; 371b01b59e3SRobert Mustacchi res->pfr_rgid = PFEXEC_NOTSET; 372b01b59e3SRobert Mustacchi res->pfr_egid = PFEXEC_NOTSET; 373b01b59e3SRobert Mustacchi res->pfr_setcred = B_FALSE; 374b01b59e3SRobert Mustacchi res->pfr_scrubenv = B_TRUE; 375b01b59e3SRobert Mustacchi res->pfr_allowed = B_FALSE; 376b01b59e3SRobert Mustacchi res->pfr_ioff = 0; 377b01b59e3SRobert Mustacchi res->pfr_loff = 0; 378b01b59e3SRobert Mustacchi 379134a1f4eSCasper H.S. Dik uuid = pap->pfa_uid; 380134a1f4eSCasper H.S. Dik 381134a1f4eSCasper H.S. Dik if (getpwuid_r(uuid, &pw, buf, sizeof (buf), &pwd) != 0 || pwd == NULL) 382134a1f4eSCasper H.S. Dik goto stdexec; 383134a1f4eSCasper H.S. Dik 384134a1f4eSCasper H.S. Dik exec = getexecuser(pwd->pw_name, KV_COMMAND, path, GET_ONE); 385134a1f4eSCasper H.S. Dik 386bf859931SCasper H.S. Dik if ((exec == NULL || exec->attr == NULL) && removeisapath(path)) { 387bf859931SCasper H.S. Dik free_execattr(exec); 388134a1f4eSCasper H.S. Dik exec = getexecuser(pwd->pw_name, KV_COMMAND, path, GET_ONE); 389bf859931SCasper H.S. Dik } 390134a1f4eSCasper H.S. Dik 391134a1f4eSCasper H.S. Dik if (exec == NULL) { 392134a1f4eSCasper H.S. Dik res->pfr_allowed = B_FALSE; 393134a1f4eSCasper H.S. Dik goto ret; 394134a1f4eSCasper H.S. Dik } 395134a1f4eSCasper H.S. Dik 396134a1f4eSCasper H.S. Dik if (exec->attr == NULL) 397134a1f4eSCasper H.S. Dik goto stdexec; 398134a1f4eSCasper H.S. Dik 399134a1f4eSCasper H.S. Dik /* Found in execattr, so clearly we can use it */ 400134a1f4eSCasper H.S. Dik res->pfr_allowed = B_TRUE; 401134a1f4eSCasper H.S. Dik 402134a1f4eSCasper H.S. Dik uid = euid = (uid_t)-1; 403134a1f4eSCasper H.S. Dik gid = egid = (gid_t)-1; 404134a1f4eSCasper H.S. Dik lset = iset = NULL; 405134a1f4eSCasper H.S. Dik 406134a1f4eSCasper H.S. Dik /* 407134a1f4eSCasper H.S. Dik * If there's an error in parsing uid, gid, privs, then return 408134a1f4eSCasper H.S. Dik * failure. 409134a1f4eSCasper H.S. Dik */ 410134a1f4eSCasper H.S. Dik if ((value = kva_match(exec->attr, EXECATTR_UID_KW)) != NULL) 411134a1f4eSCasper H.S. Dik euid = uid = get_uid(value, &res->pfr_allowed, path); 412134a1f4eSCasper H.S. Dik 413134a1f4eSCasper H.S. Dik if ((value = kva_match(exec->attr, EXECATTR_GID_KW)) != NULL) 414134a1f4eSCasper H.S. Dik egid = gid = get_gid(value, &res->pfr_allowed, path); 415134a1f4eSCasper H.S. Dik 416134a1f4eSCasper H.S. Dik if ((value = kva_match(exec->attr, EXECATTR_EUID_KW)) != NULL) 417134a1f4eSCasper H.S. Dik euid = get_uid(value, &res->pfr_allowed, path); 418134a1f4eSCasper H.S. Dik 419134a1f4eSCasper H.S. Dik if ((value = kva_match(exec->attr, EXECATTR_EGID_KW)) != NULL) 420134a1f4eSCasper H.S. Dik egid = get_gid(value, &res->pfr_allowed, path); 421134a1f4eSCasper H.S. Dik 422134a1f4eSCasper H.S. Dik if ((value = kva_match(exec->attr, EXECATTR_LPRIV_KW)) != NULL) 423134a1f4eSCasper H.S. Dik lset = get_privset(value, &res->pfr_allowed, path); 424134a1f4eSCasper H.S. Dik 425134a1f4eSCasper H.S. Dik if ((value = kva_match(exec->attr, EXECATTR_IPRIV_KW)) != NULL) 426134a1f4eSCasper H.S. Dik iset = get_privset(value, &res->pfr_allowed, path); 427134a1f4eSCasper H.S. Dik 428134a1f4eSCasper H.S. Dik /* 429134a1f4eSCasper H.S. Dik * Remove LD_* variables in the kernel when the runtime linker might 430134a1f4eSCasper H.S. Dik * use them later on because the uids are equal. 431134a1f4eSCasper H.S. Dik */ 432134a1f4eSCasper H.S. Dik res->pfr_scrubenv = (uid != (uid_t)-1 && euid == uid) || 433134a1f4eSCasper H.S. Dik (gid != (gid_t)-1 && egid == gid) || iset != NULL; 434134a1f4eSCasper H.S. Dik 435134a1f4eSCasper H.S. Dik res->pfr_euid = euid; 436134a1f4eSCasper H.S. Dik res->pfr_ruid = uid; 437134a1f4eSCasper H.S. Dik res->pfr_egid = egid; 438134a1f4eSCasper H.S. Dik res->pfr_rgid = gid; 439134a1f4eSCasper H.S. Dik 440134a1f4eSCasper H.S. Dik /* Now add the privilege sets */ 441134a1f4eSCasper H.S. Dik res->pfr_ioff = res->pfr_loff = 0; 442134a1f4eSCasper H.S. Dik if (iset != NULL) { 443134a1f4eSCasper H.S. Dik res->pfr_ioff = mysz; 444134a1f4eSCasper H.S. Dik priv_copyset(iset, PFEXEC_REPLY_IPRIV(res)); 445134a1f4eSCasper H.S. Dik mysz += setsz; 446134a1f4eSCasper H.S. Dik priv_freeset(iset); 447134a1f4eSCasper H.S. Dik } 448134a1f4eSCasper H.S. Dik if (lset != NULL) { 449134a1f4eSCasper H.S. Dik res->pfr_loff = mysz; 450134a1f4eSCasper H.S. Dik priv_copyset(lset, PFEXEC_REPLY_LPRIV(res)); 451134a1f4eSCasper H.S. Dik mysz += setsz; 452134a1f4eSCasper H.S. Dik priv_freeset(lset); 453134a1f4eSCasper H.S. Dik } 454134a1f4eSCasper H.S. Dik 455134a1f4eSCasper H.S. Dik res->pfr_setcred = uid != (uid_t)-1 || euid != (uid_t)-1 || 456134a1f4eSCasper H.S. Dik egid != (gid_t)-1 || gid != (gid_t)-1 || iset != NULL || 457134a1f4eSCasper H.S. Dik lset != NULL; 458134a1f4eSCasper H.S. Dik 459134a1f4eSCasper H.S. Dik /* If the real uid changes, we stop running under a profile shell */ 460134a1f4eSCasper H.S. Dik res->pfr_clearflag = uid != (uid_t)-1 && uid != uuid; 461134a1f4eSCasper H.S. Dik free_execattr(exec); 462134a1f4eSCasper H.S. Dik ret: 463134a1f4eSCasper H.S. Dik (void) door_return((char *)res, mysz, NULL, 0); 464134a1f4eSCasper H.S. Dik return; 465134a1f4eSCasper H.S. Dik 466134a1f4eSCasper H.S. Dik stdexec: 467bf859931SCasper H.S. Dik free_execattr(exec); 468bf859931SCasper H.S. Dik 469134a1f4eSCasper H.S. Dik res->pfr_scrubenv = B_FALSE; 470134a1f4eSCasper H.S. Dik res->pfr_setcred = B_FALSE; 471134a1f4eSCasper H.S. Dik res->pfr_allowed = B_TRUE; 472134a1f4eSCasper H.S. Dik 473134a1f4eSCasper H.S. Dik (void) door_return((char *)res, mysz, NULL, 0); 474134a1f4eSCasper H.S. Dik } 475134a1f4eSCasper H.S. Dik 476134a1f4eSCasper H.S. Dik /* ARGSUSED */ 477134a1f4eSCasper H.S. Dik static void 478134a1f4eSCasper H.S. Dik callback(void *cookie, char *argp, size_t asz, door_desc_t *dp, uint_t ndesc) 479134a1f4eSCasper H.S. Dik { 480134a1f4eSCasper H.S. Dik /* LINTED ALIGNMENT */ 481134a1f4eSCasper H.S. Dik pfexec_arg_t *pap = (pfexec_arg_t *)argp; 482134a1f4eSCasper H.S. Dik 483134a1f4eSCasper H.S. Dik if (asz < sizeof (pfexec_arg_t) || pap->pfa_vers != PFEXEC_ARG_VERS) { 484134a1f4eSCasper H.S. Dik (void) door_return(NULL, 0, NULL, 0); 485134a1f4eSCasper H.S. Dik return; 486134a1f4eSCasper H.S. Dik } 487134a1f4eSCasper H.S. Dik 488134a1f4eSCasper H.S. Dik switch (pap->pfa_call) { 489134a1f4eSCasper H.S. Dik case PFEXEC_EXEC_ATTRS: 490134a1f4eSCasper H.S. Dik callback_pfexec(pap); 491134a1f4eSCasper H.S. Dik break; 492134a1f4eSCasper H.S. Dik case PFEXEC_FORCED_PRIVS: 493134a1f4eSCasper H.S. Dik callback_forced_privs(pap); 494134a1f4eSCasper H.S. Dik break; 495134a1f4eSCasper H.S. Dik case PFEXEC_USER_PRIVS: 496134a1f4eSCasper H.S. Dik callback_user_privs(pap); 497134a1f4eSCasper H.S. Dik break; 498134a1f4eSCasper H.S. Dik default: 499134a1f4eSCasper H.S. Dik syslog(LOG_ERR, "Bad Call: %d\n", pap->pfa_call); 500134a1f4eSCasper H.S. Dik break; 501134a1f4eSCasper H.S. Dik } 502134a1f4eSCasper H.S. Dik 503134a1f4eSCasper H.S. Dik /* 504134a1f4eSCasper H.S. Dik * If the door_return(ptr, size, NULL, 0) fails, make sure we 505134a1f4eSCasper H.S. Dik * don't lose server threads. 506134a1f4eSCasper H.S. Dik */ 507134a1f4eSCasper H.S. Dik (void) door_return(NULL, 0, NULL, 0); 508134a1f4eSCasper H.S. Dik } 509134a1f4eSCasper H.S. Dik 510134a1f4eSCasper H.S. Dik int 511134a1f4eSCasper H.S. Dik main(void) 512134a1f4eSCasper H.S. Dik { 513134a1f4eSCasper H.S. Dik const priv_impl_info_t *info; 514134a1f4eSCasper H.S. Dik 515134a1f4eSCasper H.S. Dik (void) signal(SIGINT, unregister_pfexec); 516134a1f4eSCasper H.S. Dik (void) signal(SIGQUIT, unregister_pfexec); 517134a1f4eSCasper H.S. Dik (void) signal(SIGTERM, unregister_pfexec); 518134a1f4eSCasper H.S. Dik (void) signal(SIGHUP, unregister_pfexec); 519134a1f4eSCasper H.S. Dik 520134a1f4eSCasper H.S. Dik info = getprivimplinfo(); 521134a1f4eSCasper H.S. Dik if (info == NULL) 522134a1f4eSCasper H.S. Dik exit(1); 523134a1f4eSCasper H.S. Dik 524134a1f4eSCasper H.S. Dik if (fork() > 0) 525134a1f4eSCasper H.S. Dik _exit(0); 526134a1f4eSCasper H.S. Dik 527134a1f4eSCasper H.S. Dik openlog("pfexecd", LOG_PID, LOG_DAEMON); 528134a1f4eSCasper H.S. Dik setsz = info->priv_setsize * sizeof (priv_chunk_t); 529134a1f4eSCasper H.S. Dik repsz = 2 * setsz + sizeof (pfexec_reply_t); 530134a1f4eSCasper H.S. Dik 531134a1f4eSCasper H.S. Dik init_isa_regex(); 532134a1f4eSCasper H.S. Dik 533134a1f4eSCasper H.S. Dik doorfd = door_create(callback, NULL, DOOR_REFUSE_DESC); 534134a1f4eSCasper H.S. Dik 535134a1f4eSCasper H.S. Dik if (doorfd == -1 || register_pfexec(doorfd) != 0) { 536134a1f4eSCasper H.S. Dik perror("doorfd"); 537134a1f4eSCasper H.S. Dik exit(1); 538134a1f4eSCasper H.S. Dik } 539134a1f4eSCasper H.S. Dik 540134a1f4eSCasper H.S. Dik /* LINTED CONSTCOND */ 541134a1f4eSCasper H.S. Dik while (1) 542134a1f4eSCasper H.S. Dik (void) sigpause(SIGINT); 543134a1f4eSCasper H.S. Dik 544134a1f4eSCasper H.S. Dik return (0); 545134a1f4eSCasper H.S. Dik } 546