1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #include <errno.h> 30*7c478bd9Sstevel@tonic-gate #include <deflt.h> 31*7c478bd9Sstevel@tonic-gate #include <locale.h> 32*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 33*7c478bd9Sstevel@tonic-gate #include <sys/param.h> 34*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 35*7c478bd9Sstevel@tonic-gate #include <unistd.h> 36*7c478bd9Sstevel@tonic-gate #include <ctype.h> 37*7c478bd9Sstevel@tonic-gate #include <pwd.h> 38*7c478bd9Sstevel@tonic-gate #include <grp.h> 39*7c478bd9Sstevel@tonic-gate #include <string.h> 40*7c478bd9Sstevel@tonic-gate #include <exec_attr.h> 41*7c478bd9Sstevel@tonic-gate #include <user_attr.h> 42*7c478bd9Sstevel@tonic-gate #include <auth_attr.h> 43*7c478bd9Sstevel@tonic-gate #include <prof_attr.h> 44*7c478bd9Sstevel@tonic-gate #include <errno.h> 45*7c478bd9Sstevel@tonic-gate #include <priv.h> 46*7c478bd9Sstevel@tonic-gate 47*7c478bd9Sstevel@tonic-gate #include <bsm/adt.h> 48*7c478bd9Sstevel@tonic-gate #include <bsm/adt_event.h> 49*7c478bd9Sstevel@tonic-gate 50*7c478bd9Sstevel@tonic-gate #ifndef TEXT_DOMAIN /* Should be defined by cc -D */ 51*7c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" 52*7c478bd9Sstevel@tonic-gate #endif 53*7c478bd9Sstevel@tonic-gate 54*7c478bd9Sstevel@tonic-gate extern int cannot_audit(int); 55*7c478bd9Sstevel@tonic-gate 56*7c478bd9Sstevel@tonic-gate static char *pathsearch(char *); 57*7c478bd9Sstevel@tonic-gate static int getrealpath(const char *, char *); 58*7c478bd9Sstevel@tonic-gate static int checkattrs(char *, int, char *[]); 59*7c478bd9Sstevel@tonic-gate static void sanitize_environ(); 60*7c478bd9Sstevel@tonic-gate static uid_t get_uid(char *); 61*7c478bd9Sstevel@tonic-gate static gid_t get_gid(char *); 62*7c478bd9Sstevel@tonic-gate static priv_set_t *get_privset(const char *); 63*7c478bd9Sstevel@tonic-gate static priv_set_t *get_granted_privs(uid_t); 64*7c478bd9Sstevel@tonic-gate static void get_default_privs(priv_set_t *); 65*7c478bd9Sstevel@tonic-gate static void get_profile_privs(char *, char **, int *, priv_set_t *); 66*7c478bd9Sstevel@tonic-gate 67*7c478bd9Sstevel@tonic-gate static int isnumber(char *); 68*7c478bd9Sstevel@tonic-gate static void usage(void); 69*7c478bd9Sstevel@tonic-gate 70*7c478bd9Sstevel@tonic-gate extern char **environ; 71*7c478bd9Sstevel@tonic-gate 72*7c478bd9Sstevel@tonic-gate #define PROFLIST_SEP "," 73*7c478bd9Sstevel@tonic-gate 74*7c478bd9Sstevel@tonic-gate int 75*7c478bd9Sstevel@tonic-gate main(int argc, char *argv[]) 76*7c478bd9Sstevel@tonic-gate { 77*7c478bd9Sstevel@tonic-gate char *cmd; 78*7c478bd9Sstevel@tonic-gate char **cmdargs; 79*7c478bd9Sstevel@tonic-gate char cmd_realpath[MAXPATHLEN]; 80*7c478bd9Sstevel@tonic-gate int c; 81*7c478bd9Sstevel@tonic-gate char *pset = NULL; 82*7c478bd9Sstevel@tonic-gate 83*7c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 84*7c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 85*7c478bd9Sstevel@tonic-gate 86*7c478bd9Sstevel@tonic-gate while ((c = getopt(argc, argv, "P:")) != EOF) { 87*7c478bd9Sstevel@tonic-gate switch (c) { 88*7c478bd9Sstevel@tonic-gate case 'P': 89*7c478bd9Sstevel@tonic-gate if (pset == NULL) { 90*7c478bd9Sstevel@tonic-gate pset = optarg; 91*7c478bd9Sstevel@tonic-gate break; 92*7c478bd9Sstevel@tonic-gate } 93*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 94*7c478bd9Sstevel@tonic-gate default: 95*7c478bd9Sstevel@tonic-gate usage(); 96*7c478bd9Sstevel@tonic-gate } 97*7c478bd9Sstevel@tonic-gate } 98*7c478bd9Sstevel@tonic-gate argc -= optind; 99*7c478bd9Sstevel@tonic-gate argv += optind; 100*7c478bd9Sstevel@tonic-gate 101*7c478bd9Sstevel@tonic-gate if (argc < 1) 102*7c478bd9Sstevel@tonic-gate usage(); 103*7c478bd9Sstevel@tonic-gate 104*7c478bd9Sstevel@tonic-gate cmd = argv[0]; 105*7c478bd9Sstevel@tonic-gate cmdargs = &argv[0]; 106*7c478bd9Sstevel@tonic-gate 107*7c478bd9Sstevel@tonic-gate if (pset != NULL) { 108*7c478bd9Sstevel@tonic-gate uid_t uid = getuid(); 109*7c478bd9Sstevel@tonic-gate priv_set_t *wanted = get_privset(pset); 110*7c478bd9Sstevel@tonic-gate priv_set_t *granted; 111*7c478bd9Sstevel@tonic-gate 112*7c478bd9Sstevel@tonic-gate adt_session_data_t *ah; /* audit session handle */ 113*7c478bd9Sstevel@tonic-gate adt_event_data_t *event; /* event to be generated */ 114*7c478bd9Sstevel@tonic-gate char cwd[MAXPATHLEN]; 115*7c478bd9Sstevel@tonic-gate 116*7c478bd9Sstevel@tonic-gate granted = get_granted_privs(uid); 117*7c478bd9Sstevel@tonic-gate 118*7c478bd9Sstevel@tonic-gate /* Audit use */ 119*7c478bd9Sstevel@tonic-gate if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) { 120*7c478bd9Sstevel@tonic-gate perror("pfexec: adt_start_session"); 121*7c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE); 122*7c478bd9Sstevel@tonic-gate } 123*7c478bd9Sstevel@tonic-gate if ((event = adt_alloc_event(ah, ADT_prof_cmd)) == NULL) { 124*7c478bd9Sstevel@tonic-gate perror("pfexec: adt_alloc_event"); 125*7c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE); 126*7c478bd9Sstevel@tonic-gate } 127*7c478bd9Sstevel@tonic-gate if ((event->adt_prof_cmd.cwdpath = 128*7c478bd9Sstevel@tonic-gate getcwd(cwd, sizeof (cwd))) == NULL) { 129*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 130*7c478bd9Sstevel@tonic-gate gettext("pfexec: can't add cwd path\n")); 131*7c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE); 132*7c478bd9Sstevel@tonic-gate } 133*7c478bd9Sstevel@tonic-gate 134*7c478bd9Sstevel@tonic-gate event->adt_prof_cmd.cmdpath = cmd; 135*7c478bd9Sstevel@tonic-gate event->adt_prof_cmd.argc = argc - 1; 136*7c478bd9Sstevel@tonic-gate event->adt_prof_cmd.argv = &argv[1]; 137*7c478bd9Sstevel@tonic-gate event->adt_prof_cmd.envp = environ; 138*7c478bd9Sstevel@tonic-gate 139*7c478bd9Sstevel@tonic-gate if (granted != NULL) { 140*7c478bd9Sstevel@tonic-gate priv_intersect(granted, wanted); 141*7c478bd9Sstevel@tonic-gate event->adt_prof_cmd.inherit_set = wanted; 142*7c478bd9Sstevel@tonic-gate if (adt_put_event(event, ADT_SUCCESS, 143*7c478bd9Sstevel@tonic-gate ADT_SUCCESS) != 0) { 144*7c478bd9Sstevel@tonic-gate perror("pfexec: adt_put_event"); 145*7c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE); 146*7c478bd9Sstevel@tonic-gate } 147*7c478bd9Sstevel@tonic-gate if (setppriv(PRIV_ON, PRIV_INHERITABLE, wanted) != 0) { 148*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 149*7c478bd9Sstevel@tonic-gate gettext("setppriv(): %s\n"), 150*7c478bd9Sstevel@tonic-gate strerror(errno)); 151*7c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE); 152*7c478bd9Sstevel@tonic-gate } 153*7c478bd9Sstevel@tonic-gate /* Trick exec into thinking we're not suid */ 154*7c478bd9Sstevel@tonic-gate (void) setppriv(PRIV_ON, PRIV_PERMITTED, wanted); 155*7c478bd9Sstevel@tonic-gate priv_freeset(event->adt_prof_cmd.inherit_set); 156*7c478bd9Sstevel@tonic-gate } else { 157*7c478bd9Sstevel@tonic-gate if (adt_put_event(event, ADT_SUCCESS, 158*7c478bd9Sstevel@tonic-gate ADT_SUCCESS) != 0) { 159*7c478bd9Sstevel@tonic-gate perror("pfexec: adt_put_event"); 160*7c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE); 161*7c478bd9Sstevel@tonic-gate } 162*7c478bd9Sstevel@tonic-gate } 163*7c478bd9Sstevel@tonic-gate adt_free_event(event); 164*7c478bd9Sstevel@tonic-gate (void) adt_end_session(ah); 165*7c478bd9Sstevel@tonic-gate (void) setreuid(uid, uid); 166*7c478bd9Sstevel@tonic-gate (void) execvp(cmd, cmdargs); 167*7c478bd9Sstevel@tonic-gate perror(cmd); 168*7c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE); 169*7c478bd9Sstevel@tonic-gate } 170*7c478bd9Sstevel@tonic-gate 171*7c478bd9Sstevel@tonic-gate if ((cmd = pathsearch(cmd)) == NULL) 172*7c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE); 173*7c478bd9Sstevel@tonic-gate 174*7c478bd9Sstevel@tonic-gate if (getrealpath(cmd, cmd_realpath) == 0) 175*7c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE); 176*7c478bd9Sstevel@tonic-gate 177*7c478bd9Sstevel@tonic-gate if (checkattrs(cmd_realpath, argc, argv) == 0) 178*7c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE); 179*7c478bd9Sstevel@tonic-gate 180*7c478bd9Sstevel@tonic-gate (void) execv(cmd, cmdargs); 181*7c478bd9Sstevel@tonic-gate /* 182*7c478bd9Sstevel@tonic-gate * We'd be here only if execv fails. 183*7c478bd9Sstevel@tonic-gate */ 184*7c478bd9Sstevel@tonic-gate perror("pfexec"); 185*7c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE); 186*7c478bd9Sstevel@tonic-gate /* LINTED */ 187*7c478bd9Sstevel@tonic-gate } 188*7c478bd9Sstevel@tonic-gate 189*7c478bd9Sstevel@tonic-gate 190*7c478bd9Sstevel@tonic-gate /* 191*7c478bd9Sstevel@tonic-gate * gets realpath for cmd. 192*7c478bd9Sstevel@tonic-gate * return 1 on success, 0 on failure. 193*7c478bd9Sstevel@tonic-gate */ 194*7c478bd9Sstevel@tonic-gate static int 195*7c478bd9Sstevel@tonic-gate getrealpath(const char *cmd, char *cmd_realpath) 196*7c478bd9Sstevel@tonic-gate { 197*7c478bd9Sstevel@tonic-gate if (realpath(cmd, cmd_realpath) == NULL) { 198*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 199*7c478bd9Sstevel@tonic-gate gettext("pfexec: can't get real path of ``%s''\n"), cmd); 200*7c478bd9Sstevel@tonic-gate return (0); 201*7c478bd9Sstevel@tonic-gate } 202*7c478bd9Sstevel@tonic-gate return (1); 203*7c478bd9Sstevel@tonic-gate } 204*7c478bd9Sstevel@tonic-gate 205*7c478bd9Sstevel@tonic-gate /* 206*7c478bd9Sstevel@tonic-gate * gets execution attributed for cmd, sets uids/gids, checks environ. 207*7c478bd9Sstevel@tonic-gate * returns 1 on success, 0 on failure. 208*7c478bd9Sstevel@tonic-gate */ 209*7c478bd9Sstevel@tonic-gate static int 210*7c478bd9Sstevel@tonic-gate checkattrs(char *cmd_realpath, int argc, char *argv[]) 211*7c478bd9Sstevel@tonic-gate { 212*7c478bd9Sstevel@tonic-gate char *value; 213*7c478bd9Sstevel@tonic-gate uid_t uid, euid; 214*7c478bd9Sstevel@tonic-gate gid_t gid = -1; 215*7c478bd9Sstevel@tonic-gate gid_t egid = -1; 216*7c478bd9Sstevel@tonic-gate struct passwd *pwent; 217*7c478bd9Sstevel@tonic-gate execattr_t *exec; 218*7c478bd9Sstevel@tonic-gate priv_set_t *lset = NULL; 219*7c478bd9Sstevel@tonic-gate priv_set_t *iset = NULL; 220*7c478bd9Sstevel@tonic-gate 221*7c478bd9Sstevel@tonic-gate adt_session_data_t *ah; /* audit session handle */ 222*7c478bd9Sstevel@tonic-gate adt_event_data_t *event; /* event to be generated */ 223*7c478bd9Sstevel@tonic-gate char cwd[MAXPATHLEN]; 224*7c478bd9Sstevel@tonic-gate 225*7c478bd9Sstevel@tonic-gate uid = euid = getuid(); 226*7c478bd9Sstevel@tonic-gate if ((pwent = getpwuid(uid)) == NULL) { 227*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%d: ", (int)uid); 228*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("can't get passwd entry\n")); 229*7c478bd9Sstevel@tonic-gate return (0); 230*7c478bd9Sstevel@tonic-gate } 231*7c478bd9Sstevel@tonic-gate /* Set up to audit use */ 232*7c478bd9Sstevel@tonic-gate if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) { 233*7c478bd9Sstevel@tonic-gate perror("pfexec: adt_start_session"); 234*7c478bd9Sstevel@tonic-gate return (0); 235*7c478bd9Sstevel@tonic-gate } 236*7c478bd9Sstevel@tonic-gate if ((event = adt_alloc_event(ah, ADT_prof_cmd)) == NULL) { 237*7c478bd9Sstevel@tonic-gate perror("pfexec: adt_alloc_event"); 238*7c478bd9Sstevel@tonic-gate return (0); 239*7c478bd9Sstevel@tonic-gate } 240*7c478bd9Sstevel@tonic-gate if ((event->adt_prof_cmd.cwdpath = getcwd(cwd, sizeof (cwd))) == NULL) { 241*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("pfexec: can't add cwd path\n")); 242*7c478bd9Sstevel@tonic-gate return (0); 243*7c478bd9Sstevel@tonic-gate } 244*7c478bd9Sstevel@tonic-gate /* 245*7c478bd9Sstevel@tonic-gate * Get the exec attrs: uid, gid, euid and egid 246*7c478bd9Sstevel@tonic-gate */ 247*7c478bd9Sstevel@tonic-gate if ((exec = getexecuser(pwent->pw_name, 248*7c478bd9Sstevel@tonic-gate KV_COMMAND, (char *)cmd_realpath, GET_ONE)) == NULL) { 249*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: ", cmd_realpath); 250*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 251*7c478bd9Sstevel@tonic-gate gettext("can't get execution attributes\n")); 252*7c478bd9Sstevel@tonic-gate return (0); 253*7c478bd9Sstevel@tonic-gate } 254*7c478bd9Sstevel@tonic-gate if ((value = kva_match(exec->attr, EXECATTR_UID_KW)) != NULL) { 255*7c478bd9Sstevel@tonic-gate euid = uid = get_uid(value); 256*7c478bd9Sstevel@tonic-gate event->adt_prof_cmd.proc_euid = uid; 257*7c478bd9Sstevel@tonic-gate event->adt_prof_cmd.proc_ruid = uid; 258*7c478bd9Sstevel@tonic-gate } 259*7c478bd9Sstevel@tonic-gate if ((value = kva_match(exec->attr, EXECATTR_GID_KW)) != NULL) { 260*7c478bd9Sstevel@tonic-gate egid = gid = get_gid(value); 261*7c478bd9Sstevel@tonic-gate event->adt_prof_cmd.proc_egid = gid; 262*7c478bd9Sstevel@tonic-gate event->adt_prof_cmd.proc_rgid = gid; 263*7c478bd9Sstevel@tonic-gate } 264*7c478bd9Sstevel@tonic-gate if ((value = kva_match(exec->attr, EXECATTR_EUID_KW)) != NULL) { 265*7c478bd9Sstevel@tonic-gate event->adt_prof_cmd.proc_euid = euid = get_uid(value); 266*7c478bd9Sstevel@tonic-gate } 267*7c478bd9Sstevel@tonic-gate if ((value = kva_match(exec->attr, EXECATTR_EGID_KW)) != NULL) { 268*7c478bd9Sstevel@tonic-gate event->adt_prof_cmd.proc_egid = egid = get_gid(value); 269*7c478bd9Sstevel@tonic-gate } 270*7c478bd9Sstevel@tonic-gate if ((value = kva_match(exec->attr, EXECATTR_LPRIV_KW)) != NULL) { 271*7c478bd9Sstevel@tonic-gate lset = get_privset(value); 272*7c478bd9Sstevel@tonic-gate event->adt_prof_cmd.limit_set = lset; 273*7c478bd9Sstevel@tonic-gate } 274*7c478bd9Sstevel@tonic-gate if ((value = kva_match(exec->attr, EXECATTR_IPRIV_KW)) != NULL) { 275*7c478bd9Sstevel@tonic-gate iset = get_privset(value); 276*7c478bd9Sstevel@tonic-gate event->adt_prof_cmd.inherit_set = iset; 277*7c478bd9Sstevel@tonic-gate } 278*7c478bd9Sstevel@tonic-gate if (euid == uid || iset != NULL) { 279*7c478bd9Sstevel@tonic-gate sanitize_environ(); 280*7c478bd9Sstevel@tonic-gate } 281*7c478bd9Sstevel@tonic-gate 282*7c478bd9Sstevel@tonic-gate /* Finish audit info */ 283*7c478bd9Sstevel@tonic-gate event->adt_prof_cmd.cmdpath = cmd_realpath; 284*7c478bd9Sstevel@tonic-gate event->adt_prof_cmd.argc = argc - 1; 285*7c478bd9Sstevel@tonic-gate event->adt_prof_cmd.argv = &argv[1]; 286*7c478bd9Sstevel@tonic-gate event->adt_prof_cmd.envp = environ; 287*7c478bd9Sstevel@tonic-gate if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) { 288*7c478bd9Sstevel@tonic-gate perror("pfexec: adt_put_event"); 289*7c478bd9Sstevel@tonic-gate return (0); 290*7c478bd9Sstevel@tonic-gate } 291*7c478bd9Sstevel@tonic-gate adt_free_event(event); 292*7c478bd9Sstevel@tonic-gate (void) adt_end_session(ah); 293*7c478bd9Sstevel@tonic-gate 294*7c478bd9Sstevel@tonic-gate set_attrs: 295*7c478bd9Sstevel@tonic-gate /* 296*7c478bd9Sstevel@tonic-gate * Set gids/uids and privileges. 297*7c478bd9Sstevel@tonic-gate * 298*7c478bd9Sstevel@tonic-gate */ 299*7c478bd9Sstevel@tonic-gate if ((gid != -1) || (egid != -1)) { 300*7c478bd9Sstevel@tonic-gate if ((setregid(gid, egid) == -1)) { 301*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: ", cmd_realpath); 302*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("can't set gid\n")); 303*7c478bd9Sstevel@tonic-gate return (0); 304*7c478bd9Sstevel@tonic-gate } 305*7c478bd9Sstevel@tonic-gate } 306*7c478bd9Sstevel@tonic-gate if (lset != NULL && setppriv(PRIV_SET, PRIV_LIMIT, lset) != 0 || 307*7c478bd9Sstevel@tonic-gate iset != NULL && setppriv(PRIV_ON, PRIV_INHERITABLE, iset) != 0) { 308*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: can't set privileges\n"), 309*7c478bd9Sstevel@tonic-gate cmd_realpath); 310*7c478bd9Sstevel@tonic-gate return (0); 311*7c478bd9Sstevel@tonic-gate } 312*7c478bd9Sstevel@tonic-gate if (setreuid(uid, euid) == -1) { 313*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: ", cmd_realpath); 314*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("can't set uid\n")); 315*7c478bd9Sstevel@tonic-gate return (0); 316*7c478bd9Sstevel@tonic-gate } 317*7c478bd9Sstevel@tonic-gate if (iset != NULL && getppriv(PRIV_INHERITABLE, iset) == 0) 318*7c478bd9Sstevel@tonic-gate (void) setppriv(PRIV_SET, PRIV_PERMITTED, iset); 319*7c478bd9Sstevel@tonic-gate 320*7c478bd9Sstevel@tonic-gate free_execattr(exec); 321*7c478bd9Sstevel@tonic-gate 322*7c478bd9Sstevel@tonic-gate return (1); 323*7c478bd9Sstevel@tonic-gate } 324*7c478bd9Sstevel@tonic-gate 325*7c478bd9Sstevel@tonic-gate 326*7c478bd9Sstevel@tonic-gate /* 327*7c478bd9Sstevel@tonic-gate * cleans up environ. code from su.c 328*7c478bd9Sstevel@tonic-gate */ 329*7c478bd9Sstevel@tonic-gate static void 330*7c478bd9Sstevel@tonic-gate sanitize_environ() 331*7c478bd9Sstevel@tonic-gate { 332*7c478bd9Sstevel@tonic-gate char **pp = environ; 333*7c478bd9Sstevel@tonic-gate char **qq, *p; 334*7c478bd9Sstevel@tonic-gate 335*7c478bd9Sstevel@tonic-gate while ((p = *pp) != NULL) { 336*7c478bd9Sstevel@tonic-gate if (*p == 'L' && p[1] == 'D' && p[2] == '_') { 337*7c478bd9Sstevel@tonic-gate for (qq = pp; (*qq = qq[1]) != NULL; qq++) { 338*7c478bd9Sstevel@tonic-gate ; 339*7c478bd9Sstevel@tonic-gate } 340*7c478bd9Sstevel@tonic-gate } else { 341*7c478bd9Sstevel@tonic-gate pp++; 342*7c478bd9Sstevel@tonic-gate } 343*7c478bd9Sstevel@tonic-gate } 344*7c478bd9Sstevel@tonic-gate } 345*7c478bd9Sstevel@tonic-gate 346*7c478bd9Sstevel@tonic-gate 347*7c478bd9Sstevel@tonic-gate static uid_t 348*7c478bd9Sstevel@tonic-gate get_uid(char *value) 349*7c478bd9Sstevel@tonic-gate { 350*7c478bd9Sstevel@tonic-gate struct passwd *passwd_ent; 351*7c478bd9Sstevel@tonic-gate 352*7c478bd9Sstevel@tonic-gate if ((passwd_ent = getpwnam(value)) != NULL) 353*7c478bd9Sstevel@tonic-gate return (passwd_ent->pw_uid); 354*7c478bd9Sstevel@tonic-gate 355*7c478bd9Sstevel@tonic-gate if (isnumber(value)) 356*7c478bd9Sstevel@tonic-gate return (atoi(value)); 357*7c478bd9Sstevel@tonic-gate 358*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "pfexec: %s: ", value); 359*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("can't get user entry\n")); 360*7c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE); 361*7c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 362*7c478bd9Sstevel@tonic-gate } 363*7c478bd9Sstevel@tonic-gate 364*7c478bd9Sstevel@tonic-gate 365*7c478bd9Sstevel@tonic-gate static uid_t 366*7c478bd9Sstevel@tonic-gate get_gid(char *value) 367*7c478bd9Sstevel@tonic-gate { 368*7c478bd9Sstevel@tonic-gate struct group *group_ent; 369*7c478bd9Sstevel@tonic-gate 370*7c478bd9Sstevel@tonic-gate if ((group_ent = getgrnam(value)) != NULL) 371*7c478bd9Sstevel@tonic-gate return (group_ent->gr_gid); 372*7c478bd9Sstevel@tonic-gate 373*7c478bd9Sstevel@tonic-gate if (isnumber(value)) 374*7c478bd9Sstevel@tonic-gate return (atoi(value)); 375*7c478bd9Sstevel@tonic-gate 376*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "pfexec: %s: ", value); 377*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("can't get group entry\n")); 378*7c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE); 379*7c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 380*7c478bd9Sstevel@tonic-gate } 381*7c478bd9Sstevel@tonic-gate 382*7c478bd9Sstevel@tonic-gate 383*7c478bd9Sstevel@tonic-gate static int 384*7c478bd9Sstevel@tonic-gate isnumber(char *s) 385*7c478bd9Sstevel@tonic-gate { 386*7c478bd9Sstevel@tonic-gate int c; 387*7c478bd9Sstevel@tonic-gate 388*7c478bd9Sstevel@tonic-gate if (*s == '\0') 389*7c478bd9Sstevel@tonic-gate return (0); 390*7c478bd9Sstevel@tonic-gate 391*7c478bd9Sstevel@tonic-gate while ((c = *s++) != '\0') { 392*7c478bd9Sstevel@tonic-gate if (!isdigit(c)) { 393*7c478bd9Sstevel@tonic-gate return (0); 394*7c478bd9Sstevel@tonic-gate } 395*7c478bd9Sstevel@tonic-gate } 396*7c478bd9Sstevel@tonic-gate 397*7c478bd9Sstevel@tonic-gate return (1); 398*7c478bd9Sstevel@tonic-gate } 399*7c478bd9Sstevel@tonic-gate 400*7c478bd9Sstevel@tonic-gate static priv_set_t * 401*7c478bd9Sstevel@tonic-gate get_privset(const char *s) 402*7c478bd9Sstevel@tonic-gate { 403*7c478bd9Sstevel@tonic-gate priv_set_t *res; 404*7c478bd9Sstevel@tonic-gate 405*7c478bd9Sstevel@tonic-gate if ((res = priv_str_to_set(s, ",", NULL)) == NULL) { 406*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: bad privilege set\n", s); 407*7c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE); 408*7c478bd9Sstevel@tonic-gate } 409*7c478bd9Sstevel@tonic-gate return (res); 410*7c478bd9Sstevel@tonic-gate } 411*7c478bd9Sstevel@tonic-gate 412*7c478bd9Sstevel@tonic-gate static void 413*7c478bd9Sstevel@tonic-gate usage(void) 414*7c478bd9Sstevel@tonic-gate { 415*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("pfexec [-P privset] cmd [arg ..]\n")); 416*7c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE); 417*7c478bd9Sstevel@tonic-gate } 418*7c478bd9Sstevel@tonic-gate 419*7c478bd9Sstevel@tonic-gate 420*7c478bd9Sstevel@tonic-gate /* 421*7c478bd9Sstevel@tonic-gate * This routine exists on failure and returns NULL if no granted privileges 422*7c478bd9Sstevel@tonic-gate * are set. 423*7c478bd9Sstevel@tonic-gate */ 424*7c478bd9Sstevel@tonic-gate static priv_set_t * 425*7c478bd9Sstevel@tonic-gate get_granted_privs(uid_t uid) 426*7c478bd9Sstevel@tonic-gate { 427*7c478bd9Sstevel@tonic-gate struct passwd *pwent; 428*7c478bd9Sstevel@tonic-gate userattr_t *ua; 429*7c478bd9Sstevel@tonic-gate char *profs; 430*7c478bd9Sstevel@tonic-gate priv_set_t *res; 431*7c478bd9Sstevel@tonic-gate char *profArray[MAXPROFS]; 432*7c478bd9Sstevel@tonic-gate int profcnt = 0; 433*7c478bd9Sstevel@tonic-gate 434*7c478bd9Sstevel@tonic-gate res = priv_allocset(); 435*7c478bd9Sstevel@tonic-gate if (res == NULL) { 436*7c478bd9Sstevel@tonic-gate perror("priv_allocset"); 437*7c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE); 438*7c478bd9Sstevel@tonic-gate } 439*7c478bd9Sstevel@tonic-gate 440*7c478bd9Sstevel@tonic-gate priv_emptyset(res); 441*7c478bd9Sstevel@tonic-gate 442*7c478bd9Sstevel@tonic-gate if ((pwent = getpwuid(uid)) == NULL) { 443*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%d: ", (int)uid); 444*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("can't get passwd entry\n")); 445*7c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE); 446*7c478bd9Sstevel@tonic-gate } 447*7c478bd9Sstevel@tonic-gate 448*7c478bd9Sstevel@tonic-gate ua = getusernam(pwent->pw_name); 449*7c478bd9Sstevel@tonic-gate 450*7c478bd9Sstevel@tonic-gate if (ua != NULL && ua->attr != NULL && 451*7c478bd9Sstevel@tonic-gate (profs = kva_match(ua->attr, USERATTR_PROFILES_KW)) != NULL) { 452*7c478bd9Sstevel@tonic-gate get_profile_privs(profs, profArray, &profcnt, res); 453*7c478bd9Sstevel@tonic-gate free_proflist(profArray, profcnt); 454*7c478bd9Sstevel@tonic-gate } 455*7c478bd9Sstevel@tonic-gate 456*7c478bd9Sstevel@tonic-gate get_default_privs(res); 457*7c478bd9Sstevel@tonic-gate 458*7c478bd9Sstevel@tonic-gate if (ua != NULL) 459*7c478bd9Sstevel@tonic-gate free_userattr(ua); 460*7c478bd9Sstevel@tonic-gate 461*7c478bd9Sstevel@tonic-gate return (res); 462*7c478bd9Sstevel@tonic-gate } 463*7c478bd9Sstevel@tonic-gate 464*7c478bd9Sstevel@tonic-gate static void 465*7c478bd9Sstevel@tonic-gate get_default_privs(priv_set_t *pset) 466*7c478bd9Sstevel@tonic-gate { 467*7c478bd9Sstevel@tonic-gate char *profs = NULL; 468*7c478bd9Sstevel@tonic-gate char *profArray[MAXPROFS]; 469*7c478bd9Sstevel@tonic-gate int profcnt = 0; 470*7c478bd9Sstevel@tonic-gate 471*7c478bd9Sstevel@tonic-gate if (defopen(AUTH_POLICY) == 0) { 472*7c478bd9Sstevel@tonic-gate /* get privileges from default profiles */ 473*7c478bd9Sstevel@tonic-gate profs = defread(DEF_PROF); 474*7c478bd9Sstevel@tonic-gate if (profs != NULL) { 475*7c478bd9Sstevel@tonic-gate get_profile_privs(profs, profArray, &profcnt, pset); 476*7c478bd9Sstevel@tonic-gate free_proflist(profArray, profcnt); 477*7c478bd9Sstevel@tonic-gate } 478*7c478bd9Sstevel@tonic-gate } 479*7c478bd9Sstevel@tonic-gate (void) defopen(NULL); 480*7c478bd9Sstevel@tonic-gate } 481*7c478bd9Sstevel@tonic-gate 482*7c478bd9Sstevel@tonic-gate static void 483*7c478bd9Sstevel@tonic-gate get_profile_privs(char *profiles, char **profArray, int *profcnt, 484*7c478bd9Sstevel@tonic-gate priv_set_t *pset) 485*7c478bd9Sstevel@tonic-gate { 486*7c478bd9Sstevel@tonic-gate 487*7c478bd9Sstevel@tonic-gate char *prof; 488*7c478bd9Sstevel@tonic-gate char *lasts; 489*7c478bd9Sstevel@tonic-gate profattr_t *pa; 490*7c478bd9Sstevel@tonic-gate char *privs; 491*7c478bd9Sstevel@tonic-gate int i; 492*7c478bd9Sstevel@tonic-gate 493*7c478bd9Sstevel@tonic-gate for (prof = strtok_r(profiles, PROFLIST_SEP, &lasts); 494*7c478bd9Sstevel@tonic-gate prof != NULL; 495*7c478bd9Sstevel@tonic-gate prof = strtok_r(NULL, PROFLIST_SEP, &lasts)) 496*7c478bd9Sstevel@tonic-gate getproflist(prof, profArray, profcnt); 497*7c478bd9Sstevel@tonic-gate 498*7c478bd9Sstevel@tonic-gate /* get the privileges from list of profiles */ 499*7c478bd9Sstevel@tonic-gate for (i = 0; i < *profcnt; i++) { 500*7c478bd9Sstevel@tonic-gate 501*7c478bd9Sstevel@tonic-gate if ((pa = getprofnam(profArray[i])) == NULL) { 502*7c478bd9Sstevel@tonic-gate /* 503*7c478bd9Sstevel@tonic-gate * this should never happen. 504*7c478bd9Sstevel@tonic-gate * unless the database has an undefined profile 505*7c478bd9Sstevel@tonic-gate */ 506*7c478bd9Sstevel@tonic-gate continue; 507*7c478bd9Sstevel@tonic-gate } 508*7c478bd9Sstevel@tonic-gate 509*7c478bd9Sstevel@tonic-gate /* get privs from this profile */ 510*7c478bd9Sstevel@tonic-gate privs = kva_match(pa->attr, PROFATTR_PRIVS_KW); 511*7c478bd9Sstevel@tonic-gate if (privs != NULL) { 512*7c478bd9Sstevel@tonic-gate priv_set_t *tmp = priv_str_to_set(privs, ",", NULL); 513*7c478bd9Sstevel@tonic-gate if (tmp != NULL) { 514*7c478bd9Sstevel@tonic-gate priv_union(tmp, pset); 515*7c478bd9Sstevel@tonic-gate priv_freeset(tmp); 516*7c478bd9Sstevel@tonic-gate } 517*7c478bd9Sstevel@tonic-gate } 518*7c478bd9Sstevel@tonic-gate 519*7c478bd9Sstevel@tonic-gate free_profattr(pa); 520*7c478bd9Sstevel@tonic-gate } 521*7c478bd9Sstevel@tonic-gate } 522*7c478bd9Sstevel@tonic-gate 523*7c478bd9Sstevel@tonic-gate /* 524*7c478bd9Sstevel@tonic-gate * This function can return either the first argument or dynamically 525*7c478bd9Sstevel@tonic-gate * allocated memory. Reuse with care. 526*7c478bd9Sstevel@tonic-gate */ 527*7c478bd9Sstevel@tonic-gate static char * 528*7c478bd9Sstevel@tonic-gate pathsearch(char *cmd) 529*7c478bd9Sstevel@tonic-gate { 530*7c478bd9Sstevel@tonic-gate char *path, *dir; 531*7c478bd9Sstevel@tonic-gate char buf[MAXPATHLEN]; 532*7c478bd9Sstevel@tonic-gate 533*7c478bd9Sstevel@tonic-gate /* 534*7c478bd9Sstevel@tonic-gate * Implement shell like PATH searching; if the pathname contains 535*7c478bd9Sstevel@tonic-gate * one or more slashes, don't search the path, even if the '/' 536*7c478bd9Sstevel@tonic-gate * isn't the first character. (E.g., ./command or dir/command) 537*7c478bd9Sstevel@tonic-gate * No path equals to a search in ".", just like the shell. 538*7c478bd9Sstevel@tonic-gate */ 539*7c478bd9Sstevel@tonic-gate if (strchr(cmd, '/') != NULL) 540*7c478bd9Sstevel@tonic-gate return (cmd); 541*7c478bd9Sstevel@tonic-gate 542*7c478bd9Sstevel@tonic-gate path = getenv("PATH"); 543*7c478bd9Sstevel@tonic-gate if (path == NULL) 544*7c478bd9Sstevel@tonic-gate return (cmd); 545*7c478bd9Sstevel@tonic-gate 546*7c478bd9Sstevel@tonic-gate /* 547*7c478bd9Sstevel@tonic-gate * We need to copy $PATH because our sub processes may need it. 548*7c478bd9Sstevel@tonic-gate */ 549*7c478bd9Sstevel@tonic-gate path = strdup(path); 550*7c478bd9Sstevel@tonic-gate if (path == NULL) { 551*7c478bd9Sstevel@tonic-gate perror("pfexec: strdup $PATH"); 552*7c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE); 553*7c478bd9Sstevel@tonic-gate } 554*7c478bd9Sstevel@tonic-gate 555*7c478bd9Sstevel@tonic-gate for (dir = strtok(path, ":"); dir; dir = strtok(NULL, ":")) { 556*7c478bd9Sstevel@tonic-gate if (snprintf(buf, sizeof (buf), "%s/%s", dir, cmd) >= 557*7c478bd9Sstevel@tonic-gate sizeof (buf)) { 558*7c478bd9Sstevel@tonic-gate continue; 559*7c478bd9Sstevel@tonic-gate } 560*7c478bd9Sstevel@tonic-gate if (access(buf, X_OK) == 0) { 561*7c478bd9Sstevel@tonic-gate free(path); 562*7c478bd9Sstevel@tonic-gate return (strdup(buf)); 563*7c478bd9Sstevel@tonic-gate } 564*7c478bd9Sstevel@tonic-gate } 565*7c478bd9Sstevel@tonic-gate free(path); 566*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: Command not found\n"), cmd); 567*7c478bd9Sstevel@tonic-gate return (NULL); 568*7c478bd9Sstevel@tonic-gate } 569