112273SCasper.Dik@Sun.COM /*
212273SCasper.Dik@Sun.COM * CDDL HEADER START
312273SCasper.Dik@Sun.COM *
412273SCasper.Dik@Sun.COM * The contents of this file are subject to the terms of the
512273SCasper.Dik@Sun.COM * Common Development and Distribution License (the "License").
612273SCasper.Dik@Sun.COM * You may not use this file except in compliance with the License.
712273SCasper.Dik@Sun.COM *
812273SCasper.Dik@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
912273SCasper.Dik@Sun.COM * or http://www.opensolaris.org/os/licensing.
1012273SCasper.Dik@Sun.COM * See the License for the specific language governing permissions
1112273SCasper.Dik@Sun.COM * and limitations under the License.
1212273SCasper.Dik@Sun.COM *
1312273SCasper.Dik@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
1412273SCasper.Dik@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1512273SCasper.Dik@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
1612273SCasper.Dik@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
1712273SCasper.Dik@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
1812273SCasper.Dik@Sun.COM *
1912273SCasper.Dik@Sun.COM * CDDL HEADER END
2012273SCasper.Dik@Sun.COM *
2112273SCasper.Dik@Sun.COM * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
2212273SCasper.Dik@Sun.COM *
2312273SCasper.Dik@Sun.COM */
2412273SCasper.Dik@Sun.COM
2512273SCasper.Dik@Sun.COM #define _POSIX_PTHREAD_SEMANTICS 1
2612273SCasper.Dik@Sun.COM
2712273SCasper.Dik@Sun.COM #include <sys/param.h>
2812273SCasper.Dik@Sun.COM #include <sys/klpd.h>
2912273SCasper.Dik@Sun.COM #include <sys/syscall.h>
3012273SCasper.Dik@Sun.COM #include <sys/systeminfo.h>
3112273SCasper.Dik@Sun.COM
3212273SCasper.Dik@Sun.COM #include <alloca.h>
3312273SCasper.Dik@Sun.COM #include <ctype.h>
3412273SCasper.Dik@Sun.COM #include <deflt.h>
3512273SCasper.Dik@Sun.COM #include <door.h>
3612273SCasper.Dik@Sun.COM #include <errno.h>
3712273SCasper.Dik@Sun.COM #include <grp.h>
3812273SCasper.Dik@Sun.COM #include <priv.h>
3912273SCasper.Dik@Sun.COM #include <pwd.h>
4012273SCasper.Dik@Sun.COM #include <regex.h>
4112273SCasper.Dik@Sun.COM #include <secdb.h>
4212273SCasper.Dik@Sun.COM #include <signal.h>
4312273SCasper.Dik@Sun.COM #include <stdio.h>
4412273SCasper.Dik@Sun.COM #include <stdlib.h>
4512273SCasper.Dik@Sun.COM #include <string.h>
4612273SCasper.Dik@Sun.COM #include <syslog.h>
4712273SCasper.Dik@Sun.COM #include <unistd.h>
4812273SCasper.Dik@Sun.COM
4912273SCasper.Dik@Sun.COM #include <auth_attr.h>
5012273SCasper.Dik@Sun.COM #include <exec_attr.h>
5112273SCasper.Dik@Sun.COM #include <prof_attr.h>
5212273SCasper.Dik@Sun.COM #include <user_attr.h>
5312273SCasper.Dik@Sun.COM
5412273SCasper.Dik@Sun.COM static int doorfd = -1;
5512273SCasper.Dik@Sun.COM
5612273SCasper.Dik@Sun.COM static size_t repsz, setsz;
5712273SCasper.Dik@Sun.COM
5812273SCasper.Dik@Sun.COM static uid_t get_uid(const char *, boolean_t *, char *);
5912273SCasper.Dik@Sun.COM static gid_t get_gid(const char *, boolean_t *, char *);
6012273SCasper.Dik@Sun.COM static priv_set_t *get_privset(const char *, boolean_t *, char *);
6112273SCasper.Dik@Sun.COM static priv_set_t *get_granted_privs(uid_t);
6212273SCasper.Dik@Sun.COM
6312273SCasper.Dik@Sun.COM /*
6412273SCasper.Dik@Sun.COM * Remove the isaexec path of an executable if we can't find the
6512273SCasper.Dik@Sun.COM * executable at the first attempt.
6612273SCasper.Dik@Sun.COM */
6712273SCasper.Dik@Sun.COM
6812273SCasper.Dik@Sun.COM static regex_t regc;
6912273SCasper.Dik@Sun.COM static boolean_t cansplice = B_TRUE;
7012273SCasper.Dik@Sun.COM
7112273SCasper.Dik@Sun.COM static void
init_isa_regex(void)7212273SCasper.Dik@Sun.COM init_isa_regex(void)
7312273SCasper.Dik@Sun.COM {
7412273SCasper.Dik@Sun.COM char *isalist;
7512273SCasper.Dik@Sun.COM size_t isalen = 255; /* wild guess */
7612273SCasper.Dik@Sun.COM size_t len;
7712273SCasper.Dik@Sun.COM long ret;
7812273SCasper.Dik@Sun.COM char *regexpr;
7912273SCasper.Dik@Sun.COM char *p;
8012273SCasper.Dik@Sun.COM
8112273SCasper.Dik@Sun.COM /*
8212273SCasper.Dik@Sun.COM * Extract the isalist(5) for userland from the kernel.
8312273SCasper.Dik@Sun.COM */
8412273SCasper.Dik@Sun.COM isalist = malloc(isalen);
8512273SCasper.Dik@Sun.COM do {
8612273SCasper.Dik@Sun.COM ret = sysinfo(SI_ISALIST, isalist, isalen);
8712273SCasper.Dik@Sun.COM if (ret == -1l) {
8812273SCasper.Dik@Sun.COM free(isalist);
8912273SCasper.Dik@Sun.COM return;
9012273SCasper.Dik@Sun.COM }
9112273SCasper.Dik@Sun.COM if (ret > isalen) {
9212273SCasper.Dik@Sun.COM isalen = ret;
9312273SCasper.Dik@Sun.COM isalist = realloc(isalist, isalen);
9412273SCasper.Dik@Sun.COM } else
9512273SCasper.Dik@Sun.COM break;
9612273SCasper.Dik@Sun.COM } while (isalist != NULL);
9712273SCasper.Dik@Sun.COM
9812273SCasper.Dik@Sun.COM
9912273SCasper.Dik@Sun.COM if (isalist == NULL)
10012273SCasper.Dik@Sun.COM return;
10112273SCasper.Dik@Sun.COM
10212273SCasper.Dik@Sun.COM /* allocate room for the regex + (/())/[^/]*$ + needed \\. */
10312273SCasper.Dik@Sun.COM #define LEFT "(/("
10412273SCasper.Dik@Sun.COM #define RIGHT "))/[^/]*$"
10512273SCasper.Dik@Sun.COM
10612273SCasper.Dik@Sun.COM regexpr = alloca(ret * 2 + sizeof (LEFT RIGHT));
10712273SCasper.Dik@Sun.COM (void) strcpy(regexpr, LEFT);
10812273SCasper.Dik@Sun.COM len = strlen(regexpr);
10912273SCasper.Dik@Sun.COM
11012273SCasper.Dik@Sun.COM for (p = isalist; *p; p++) {
11112273SCasper.Dik@Sun.COM switch (*p) {
11212273SCasper.Dik@Sun.COM case '+':
11312273SCasper.Dik@Sun.COM case '|':
11412273SCasper.Dik@Sun.COM case '*':
11512273SCasper.Dik@Sun.COM case '[':
11612273SCasper.Dik@Sun.COM case ']':
11712273SCasper.Dik@Sun.COM case '{':
11812273SCasper.Dik@Sun.COM case '}':
11912273SCasper.Dik@Sun.COM case '\\':
12012273SCasper.Dik@Sun.COM regexpr[len++] = '\\';
12112273SCasper.Dik@Sun.COM default:
12212273SCasper.Dik@Sun.COM regexpr[len++] = *p;
12312273SCasper.Dik@Sun.COM break;
12412273SCasper.Dik@Sun.COM case ' ':
12512273SCasper.Dik@Sun.COM case '\t':
12612273SCasper.Dik@Sun.COM regexpr[len++] = '|';
12712273SCasper.Dik@Sun.COM break;
12812273SCasper.Dik@Sun.COM }
12912273SCasper.Dik@Sun.COM }
13012273SCasper.Dik@Sun.COM
13112273SCasper.Dik@Sun.COM free(isalist);
13212273SCasper.Dik@Sun.COM regexpr[len] = '\0';
13312273SCasper.Dik@Sun.COM (void) strcat(regexpr, RIGHT);
13412273SCasper.Dik@Sun.COM
13512273SCasper.Dik@Sun.COM if (regcomp(®c, regexpr, REG_EXTENDED) != 0)
13612273SCasper.Dik@Sun.COM return;
13712273SCasper.Dik@Sun.COM
13812273SCasper.Dik@Sun.COM cansplice = B_TRUE;
13912273SCasper.Dik@Sun.COM }
14012273SCasper.Dik@Sun.COM
14112273SCasper.Dik@Sun.COM #define NMATCH 2
14212273SCasper.Dik@Sun.COM
14312273SCasper.Dik@Sun.COM static boolean_t
removeisapath(char * path)14412273SCasper.Dik@Sun.COM removeisapath(char *path)
14512273SCasper.Dik@Sun.COM {
14612273SCasper.Dik@Sun.COM regmatch_t match[NMATCH];
14712273SCasper.Dik@Sun.COM
14812273SCasper.Dik@Sun.COM if (!cansplice || regexec(®c, path, NMATCH, match, 0) != 0)
14912273SCasper.Dik@Sun.COM return (B_FALSE);
15012273SCasper.Dik@Sun.COM
15112273SCasper.Dik@Sun.COM /*
15212273SCasper.Dik@Sun.COM * The first match includes the whole matched expression including the
15312273SCasper.Dik@Sun.COM * end of the string. The second match includes the "/" + "isa" and
15412273SCasper.Dik@Sun.COM * that is the part we need to remove.
15512273SCasper.Dik@Sun.COM */
15612273SCasper.Dik@Sun.COM
15712273SCasper.Dik@Sun.COM if (match[1].rm_so == -1)
15812273SCasper.Dik@Sun.COM return (B_FALSE);
15912273SCasper.Dik@Sun.COM
16012273SCasper.Dik@Sun.COM /* match[0].rm_eo == strlen(path) */
16112273SCasper.Dik@Sun.COM (void) memmove(path + match[1].rm_so, path + match[1].rm_eo,
16212273SCasper.Dik@Sun.COM match[0].rm_eo - match[1].rm_eo + 1);
16312273SCasper.Dik@Sun.COM
16412273SCasper.Dik@Sun.COM return (B_TRUE);
16512273SCasper.Dik@Sun.COM }
16612273SCasper.Dik@Sun.COM
16712273SCasper.Dik@Sun.COM static int
register_pfexec(int fd)16812273SCasper.Dik@Sun.COM register_pfexec(int fd)
16912273SCasper.Dik@Sun.COM {
17012273SCasper.Dik@Sun.COM int ret = syscall(SYS_privsys, PRIVSYS_PFEXEC_REG, fd);
17112273SCasper.Dik@Sun.COM
17212273SCasper.Dik@Sun.COM return (ret);
17312273SCasper.Dik@Sun.COM }
17412273SCasper.Dik@Sun.COM
17512273SCasper.Dik@Sun.COM /* ARGSUSED */
17612273SCasper.Dik@Sun.COM static void
unregister_pfexec(int sig)17712273SCasper.Dik@Sun.COM unregister_pfexec(int sig)
17812273SCasper.Dik@Sun.COM {
17912273SCasper.Dik@Sun.COM if (doorfd != -1)
18012273SCasper.Dik@Sun.COM (void) syscall(SYS_privsys, PRIVSYS_PFEXEC_UNREG, doorfd);
18112273SCasper.Dik@Sun.COM _exit(0);
18212273SCasper.Dik@Sun.COM }
18312273SCasper.Dik@Sun.COM
18412273SCasper.Dik@Sun.COM static int
alldigits(const char * s)18512273SCasper.Dik@Sun.COM alldigits(const char *s)
18612273SCasper.Dik@Sun.COM {
18712273SCasper.Dik@Sun.COM int c;
18812273SCasper.Dik@Sun.COM
18912273SCasper.Dik@Sun.COM if (*s == '\0')
19012273SCasper.Dik@Sun.COM return (0);
19112273SCasper.Dik@Sun.COM
19212273SCasper.Dik@Sun.COM while ((c = *s++) != '\0') {
19312273SCasper.Dik@Sun.COM if (!isdigit(c)) {
19412273SCasper.Dik@Sun.COM return (0);
19512273SCasper.Dik@Sun.COM }
19612273SCasper.Dik@Sun.COM }
19712273SCasper.Dik@Sun.COM
19812273SCasper.Dik@Sun.COM return (1);
19912273SCasper.Dik@Sun.COM }
20012273SCasper.Dik@Sun.COM
20112273SCasper.Dik@Sun.COM static uid_t
get_uid(const char * v,boolean_t * ok,char * path)20212273SCasper.Dik@Sun.COM get_uid(const char *v, boolean_t *ok, char *path)
20312273SCasper.Dik@Sun.COM {
20412273SCasper.Dik@Sun.COM struct passwd *pwd, pwdm;
20512273SCasper.Dik@Sun.COM char buf[1024];
20612273SCasper.Dik@Sun.COM
20712273SCasper.Dik@Sun.COM if (getpwnam_r(v, &pwdm, buf, sizeof (buf), &pwd) == 0 && pwd != NULL)
20812273SCasper.Dik@Sun.COM return (pwd->pw_uid);
20912273SCasper.Dik@Sun.COM
21012273SCasper.Dik@Sun.COM if (alldigits(v))
21112273SCasper.Dik@Sun.COM return (atoi(v));
21212273SCasper.Dik@Sun.COM
21312273SCasper.Dik@Sun.COM *ok = B_FALSE;
21412273SCasper.Dik@Sun.COM syslog(LOG_ERR, "%s: %s: unknown username\n", path, v);
21512273SCasper.Dik@Sun.COM return ((uid_t)-1);
21612273SCasper.Dik@Sun.COM }
21712273SCasper.Dik@Sun.COM
21812273SCasper.Dik@Sun.COM static uid_t
get_gid(const char * v,boolean_t * ok,char * path)21912273SCasper.Dik@Sun.COM get_gid(const char *v, boolean_t *ok, char *path)
22012273SCasper.Dik@Sun.COM {
22112273SCasper.Dik@Sun.COM struct group *grp, grpm;
22212273SCasper.Dik@Sun.COM char buf[1024];
22312273SCasper.Dik@Sun.COM
22412273SCasper.Dik@Sun.COM if (getgrnam_r(v, &grpm, buf, sizeof (buf), &grp) == 0 && grp != NULL)
22512273SCasper.Dik@Sun.COM return (grp->gr_gid);
22612273SCasper.Dik@Sun.COM
22712273SCasper.Dik@Sun.COM if (alldigits(v))
22812273SCasper.Dik@Sun.COM return (atoi(v));
22912273SCasper.Dik@Sun.COM
23012273SCasper.Dik@Sun.COM *ok = B_FALSE;
23112273SCasper.Dik@Sun.COM syslog(LOG_ERR, "%s: %s: unknown groupname\n", path, v);
23212273SCasper.Dik@Sun.COM return ((gid_t)-1);
23312273SCasper.Dik@Sun.COM }
23412273SCasper.Dik@Sun.COM
23512273SCasper.Dik@Sun.COM static priv_set_t *
get_privset(const char * s,boolean_t * ok,char * path)23612273SCasper.Dik@Sun.COM get_privset(const char *s, boolean_t *ok, char *path)
23712273SCasper.Dik@Sun.COM {
23812273SCasper.Dik@Sun.COM priv_set_t *res;
23912273SCasper.Dik@Sun.COM
24012273SCasper.Dik@Sun.COM if ((res = priv_str_to_set(s, ",", NULL)) == NULL) {
24112273SCasper.Dik@Sun.COM syslog(LOG_ERR, "%s: %s: bad privilege set\n", path, s);
24212273SCasper.Dik@Sun.COM if (ok != NULL)
24312273SCasper.Dik@Sun.COM *ok = B_FALSE;
24412273SCasper.Dik@Sun.COM }
24512273SCasper.Dik@Sun.COM return (res);
24612273SCasper.Dik@Sun.COM }
24712273SCasper.Dik@Sun.COM
24812273SCasper.Dik@Sun.COM /*ARGSUSED*/
24912273SCasper.Dik@Sun.COM static int
ggp_callback(const char * prof,kva_t * attr,void * ctxt,void * vres)25012273SCasper.Dik@Sun.COM ggp_callback(const char *prof, kva_t *attr, void *ctxt, void *vres)
25112273SCasper.Dik@Sun.COM {
25212273SCasper.Dik@Sun.COM priv_set_t *res = vres;
25312273SCasper.Dik@Sun.COM char *privs;
25412273SCasper.Dik@Sun.COM
25512273SCasper.Dik@Sun.COM if (attr == NULL)
25612273SCasper.Dik@Sun.COM return (0);
25712273SCasper.Dik@Sun.COM
25812273SCasper.Dik@Sun.COM /* get privs from this profile */
25912273SCasper.Dik@Sun.COM privs = kva_match(attr, PROFATTR_PRIVS_KW);
26012273SCasper.Dik@Sun.COM if (privs != NULL) {
26112273SCasper.Dik@Sun.COM priv_set_t *tmp = priv_str_to_set(privs, ",", NULL);
26212273SCasper.Dik@Sun.COM if (tmp != NULL) {
26312273SCasper.Dik@Sun.COM priv_union(tmp, res);
26412273SCasper.Dik@Sun.COM priv_freeset(tmp);
26512273SCasper.Dik@Sun.COM }
26612273SCasper.Dik@Sun.COM }
26712273SCasper.Dik@Sun.COM
26812273SCasper.Dik@Sun.COM return (0);
26912273SCasper.Dik@Sun.COM }
27012273SCasper.Dik@Sun.COM
27112273SCasper.Dik@Sun.COM /*
27212273SCasper.Dik@Sun.COM * This routine exists on failure and returns NULL if no granted privileges
27312273SCasper.Dik@Sun.COM * are set.
27412273SCasper.Dik@Sun.COM */
27512273SCasper.Dik@Sun.COM static priv_set_t *
get_granted_privs(uid_t uid)27612273SCasper.Dik@Sun.COM get_granted_privs(uid_t uid)
27712273SCasper.Dik@Sun.COM {
27812273SCasper.Dik@Sun.COM priv_set_t *res;
27912273SCasper.Dik@Sun.COM struct passwd *pwd, pwdm;
28012273SCasper.Dik@Sun.COM char buf[1024];
28112273SCasper.Dik@Sun.COM
28212273SCasper.Dik@Sun.COM if (getpwuid_r(uid, &pwdm, buf, sizeof (buf), &pwd) != 0 || pwd == NULL)
28312273SCasper.Dik@Sun.COM return (NULL);
28412273SCasper.Dik@Sun.COM
28512273SCasper.Dik@Sun.COM res = priv_allocset();
28612273SCasper.Dik@Sun.COM if (res == NULL)
28712273SCasper.Dik@Sun.COM return (NULL);
28812273SCasper.Dik@Sun.COM
28912273SCasper.Dik@Sun.COM priv_emptyset(res);
29012273SCasper.Dik@Sun.COM
29112273SCasper.Dik@Sun.COM (void) _enum_profs(pwd->pw_name, ggp_callback, NULL, res);
29212273SCasper.Dik@Sun.COM
29312273SCasper.Dik@Sun.COM return (res);
29412273SCasper.Dik@Sun.COM }
29512273SCasper.Dik@Sun.COM
29612273SCasper.Dik@Sun.COM static void
callback_forced_privs(pfexec_arg_t * pap)29712273SCasper.Dik@Sun.COM callback_forced_privs(pfexec_arg_t *pap)
29812273SCasper.Dik@Sun.COM {
29912273SCasper.Dik@Sun.COM execattr_t *exec;
30012273SCasper.Dik@Sun.COM char *value;
30112273SCasper.Dik@Sun.COM priv_set_t *fset;
30212273SCasper.Dik@Sun.COM void *res = alloca(setsz);
30312273SCasper.Dik@Sun.COM
30412273SCasper.Dik@Sun.COM /* Empty set signifies no forced privileges. */
30512273SCasper.Dik@Sun.COM priv_emptyset(res);
30612273SCasper.Dik@Sun.COM
30712273SCasper.Dik@Sun.COM exec = getexecprof("Forced Privilege", KV_COMMAND, pap->pfa_path,
30812273SCasper.Dik@Sun.COM GET_ONE);
30912273SCasper.Dik@Sun.COM
31012273SCasper.Dik@Sun.COM if (exec == NULL && removeisapath(pap->pfa_path)) {
31112273SCasper.Dik@Sun.COM exec = getexecprof("Forced Privilege", KV_COMMAND,
31212273SCasper.Dik@Sun.COM pap->pfa_path, GET_ONE);
31312273SCasper.Dik@Sun.COM }
31412273SCasper.Dik@Sun.COM
31512273SCasper.Dik@Sun.COM if (exec == NULL) {
31612273SCasper.Dik@Sun.COM (void) door_return(res, setsz, NULL, 0);
31712273SCasper.Dik@Sun.COM return;
31812273SCasper.Dik@Sun.COM }
31912273SCasper.Dik@Sun.COM
32012273SCasper.Dik@Sun.COM if ((value = kva_match(exec->attr, EXECATTR_IPRIV_KW)) == NULL ||
32112273SCasper.Dik@Sun.COM (fset = get_privset(value, NULL, pap->pfa_path)) == NULL) {
32212273SCasper.Dik@Sun.COM free_execattr(exec);
32312273SCasper.Dik@Sun.COM (void) door_return(res, setsz, NULL, 0);
32412273SCasper.Dik@Sun.COM return;
32512273SCasper.Dik@Sun.COM }
32612273SCasper.Dik@Sun.COM
32712273SCasper.Dik@Sun.COM priv_copyset(fset, res);
32812273SCasper.Dik@Sun.COM priv_freeset(fset);
32912273SCasper.Dik@Sun.COM
33012273SCasper.Dik@Sun.COM free_execattr(exec);
33112273SCasper.Dik@Sun.COM (void) door_return(res, setsz, NULL, 0);
33212273SCasper.Dik@Sun.COM }
33312273SCasper.Dik@Sun.COM
33412273SCasper.Dik@Sun.COM static void
callback_user_privs(pfexec_arg_t * pap)33512273SCasper.Dik@Sun.COM callback_user_privs(pfexec_arg_t *pap)
33612273SCasper.Dik@Sun.COM {
33712273SCasper.Dik@Sun.COM priv_set_t *gset, *wset;
33812273SCasper.Dik@Sun.COM uint32_t res;
33912273SCasper.Dik@Sun.COM
34012273SCasper.Dik@Sun.COM wset = (priv_set_t *)&pap->pfa_buf;
34112273SCasper.Dik@Sun.COM gset = get_granted_privs(pap->pfa_uid);
34212273SCasper.Dik@Sun.COM
34312273SCasper.Dik@Sun.COM res = priv_issubset(wset, gset);
34412273SCasper.Dik@Sun.COM priv_freeset(gset);
34512273SCasper.Dik@Sun.COM
34612273SCasper.Dik@Sun.COM (void) door_return((char *)&res, sizeof (res), NULL, 0);
34712273SCasper.Dik@Sun.COM }
34812273SCasper.Dik@Sun.COM
34912273SCasper.Dik@Sun.COM static void
callback_pfexec(pfexec_arg_t * pap)35012273SCasper.Dik@Sun.COM callback_pfexec(pfexec_arg_t *pap)
35112273SCasper.Dik@Sun.COM {
35212273SCasper.Dik@Sun.COM pfexec_reply_t *res = alloca(repsz);
35312273SCasper.Dik@Sun.COM uid_t uid, euid, uuid;
35412273SCasper.Dik@Sun.COM gid_t gid, egid;
35512273SCasper.Dik@Sun.COM struct passwd pw, *pwd;
35612273SCasper.Dik@Sun.COM char buf[1024];
357*12471SCasper.Dik@Sun.COM execattr_t *exec = NULL;
35812273SCasper.Dik@Sun.COM char *value;
35912273SCasper.Dik@Sun.COM priv_set_t *lset, *iset;
36012273SCasper.Dik@Sun.COM size_t mysz = repsz - 2 * setsz;
36112273SCasper.Dik@Sun.COM char *path = pap->pfa_path;
36212273SCasper.Dik@Sun.COM
36312273SCasper.Dik@Sun.COM uuid = pap->pfa_uid;
36412273SCasper.Dik@Sun.COM
36512273SCasper.Dik@Sun.COM if (getpwuid_r(uuid, &pw, buf, sizeof (buf), &pwd) != 0 || pwd == NULL)
36612273SCasper.Dik@Sun.COM goto stdexec;
36712273SCasper.Dik@Sun.COM
36812273SCasper.Dik@Sun.COM exec = getexecuser(pwd->pw_name, KV_COMMAND, path, GET_ONE);
36912273SCasper.Dik@Sun.COM
370*12471SCasper.Dik@Sun.COM if ((exec == NULL || exec->attr == NULL) && removeisapath(path)) {
371*12471SCasper.Dik@Sun.COM free_execattr(exec);
37212273SCasper.Dik@Sun.COM exec = getexecuser(pwd->pw_name, KV_COMMAND, path, GET_ONE);
373*12471SCasper.Dik@Sun.COM }
37412273SCasper.Dik@Sun.COM
37512273SCasper.Dik@Sun.COM if (exec == NULL) {
37612273SCasper.Dik@Sun.COM res->pfr_allowed = B_FALSE;
37712273SCasper.Dik@Sun.COM goto ret;
37812273SCasper.Dik@Sun.COM }
37912273SCasper.Dik@Sun.COM
38012273SCasper.Dik@Sun.COM if (exec->attr == NULL)
38112273SCasper.Dik@Sun.COM goto stdexec;
38212273SCasper.Dik@Sun.COM
38312273SCasper.Dik@Sun.COM /* Found in execattr, so clearly we can use it */
38412273SCasper.Dik@Sun.COM res->pfr_allowed = B_TRUE;
38512273SCasper.Dik@Sun.COM
38612273SCasper.Dik@Sun.COM uid = euid = (uid_t)-1;
38712273SCasper.Dik@Sun.COM gid = egid = (gid_t)-1;
38812273SCasper.Dik@Sun.COM lset = iset = NULL;
38912273SCasper.Dik@Sun.COM
39012273SCasper.Dik@Sun.COM /*
39112273SCasper.Dik@Sun.COM * If there's an error in parsing uid, gid, privs, then return
39212273SCasper.Dik@Sun.COM * failure.
39312273SCasper.Dik@Sun.COM */
39412273SCasper.Dik@Sun.COM if ((value = kva_match(exec->attr, EXECATTR_UID_KW)) != NULL)
39512273SCasper.Dik@Sun.COM euid = uid = get_uid(value, &res->pfr_allowed, path);
39612273SCasper.Dik@Sun.COM
39712273SCasper.Dik@Sun.COM if ((value = kva_match(exec->attr, EXECATTR_GID_KW)) != NULL)
39812273SCasper.Dik@Sun.COM egid = gid = get_gid(value, &res->pfr_allowed, path);
39912273SCasper.Dik@Sun.COM
40012273SCasper.Dik@Sun.COM if ((value = kva_match(exec->attr, EXECATTR_EUID_KW)) != NULL)
40112273SCasper.Dik@Sun.COM euid = get_uid(value, &res->pfr_allowed, path);
40212273SCasper.Dik@Sun.COM
40312273SCasper.Dik@Sun.COM if ((value = kva_match(exec->attr, EXECATTR_EGID_KW)) != NULL)
40412273SCasper.Dik@Sun.COM egid = get_gid(value, &res->pfr_allowed, path);
40512273SCasper.Dik@Sun.COM
40612273SCasper.Dik@Sun.COM if ((value = kva_match(exec->attr, EXECATTR_LPRIV_KW)) != NULL)
40712273SCasper.Dik@Sun.COM lset = get_privset(value, &res->pfr_allowed, path);
40812273SCasper.Dik@Sun.COM
40912273SCasper.Dik@Sun.COM if ((value = kva_match(exec->attr, EXECATTR_IPRIV_KW)) != NULL)
41012273SCasper.Dik@Sun.COM iset = get_privset(value, &res->pfr_allowed, path);
41112273SCasper.Dik@Sun.COM
41212273SCasper.Dik@Sun.COM /*
41312273SCasper.Dik@Sun.COM * Remove LD_* variables in the kernel when the runtime linker might
41412273SCasper.Dik@Sun.COM * use them later on because the uids are equal.
41512273SCasper.Dik@Sun.COM */
41612273SCasper.Dik@Sun.COM res->pfr_scrubenv = (uid != (uid_t)-1 && euid == uid) ||
41712273SCasper.Dik@Sun.COM (gid != (gid_t)-1 && egid == gid) || iset != NULL;
41812273SCasper.Dik@Sun.COM
41912273SCasper.Dik@Sun.COM res->pfr_euid = euid;
42012273SCasper.Dik@Sun.COM res->pfr_ruid = uid;
42112273SCasper.Dik@Sun.COM res->pfr_egid = egid;
42212273SCasper.Dik@Sun.COM res->pfr_rgid = gid;
42312273SCasper.Dik@Sun.COM
42412273SCasper.Dik@Sun.COM /* Now add the privilege sets */
42512273SCasper.Dik@Sun.COM res->pfr_ioff = res->pfr_loff = 0;
42612273SCasper.Dik@Sun.COM if (iset != NULL) {
42712273SCasper.Dik@Sun.COM res->pfr_ioff = mysz;
42812273SCasper.Dik@Sun.COM priv_copyset(iset, PFEXEC_REPLY_IPRIV(res));
42912273SCasper.Dik@Sun.COM mysz += setsz;
43012273SCasper.Dik@Sun.COM priv_freeset(iset);
43112273SCasper.Dik@Sun.COM }
43212273SCasper.Dik@Sun.COM if (lset != NULL) {
43312273SCasper.Dik@Sun.COM res->pfr_loff = mysz;
43412273SCasper.Dik@Sun.COM priv_copyset(lset, PFEXEC_REPLY_LPRIV(res));
43512273SCasper.Dik@Sun.COM mysz += setsz;
43612273SCasper.Dik@Sun.COM priv_freeset(lset);
43712273SCasper.Dik@Sun.COM }
43812273SCasper.Dik@Sun.COM
43912273SCasper.Dik@Sun.COM res->pfr_setcred = uid != (uid_t)-1 || euid != (uid_t)-1 ||
44012273SCasper.Dik@Sun.COM egid != (gid_t)-1 || gid != (gid_t)-1 || iset != NULL ||
44112273SCasper.Dik@Sun.COM lset != NULL;
44212273SCasper.Dik@Sun.COM
44312273SCasper.Dik@Sun.COM /* If the real uid changes, we stop running under a profile shell */
44412273SCasper.Dik@Sun.COM res->pfr_clearflag = uid != (uid_t)-1 && uid != uuid;
44512273SCasper.Dik@Sun.COM free_execattr(exec);
44612273SCasper.Dik@Sun.COM ret:
44712273SCasper.Dik@Sun.COM (void) door_return((char *)res, mysz, NULL, 0);
44812273SCasper.Dik@Sun.COM return;
44912273SCasper.Dik@Sun.COM
45012273SCasper.Dik@Sun.COM stdexec:
451*12471SCasper.Dik@Sun.COM free_execattr(exec);
452*12471SCasper.Dik@Sun.COM
45312273SCasper.Dik@Sun.COM res->pfr_scrubenv = B_FALSE;
45412273SCasper.Dik@Sun.COM res->pfr_setcred = B_FALSE;
45512273SCasper.Dik@Sun.COM res->pfr_allowed = B_TRUE;
45612273SCasper.Dik@Sun.COM
45712273SCasper.Dik@Sun.COM (void) door_return((char *)res, mysz, NULL, 0);
45812273SCasper.Dik@Sun.COM }
45912273SCasper.Dik@Sun.COM
46012273SCasper.Dik@Sun.COM /* ARGSUSED */
46112273SCasper.Dik@Sun.COM static void
callback(void * cookie,char * argp,size_t asz,door_desc_t * dp,uint_t ndesc)46212273SCasper.Dik@Sun.COM callback(void *cookie, char *argp, size_t asz, door_desc_t *dp, uint_t ndesc)
46312273SCasper.Dik@Sun.COM {
46412273SCasper.Dik@Sun.COM /* LINTED ALIGNMENT */
46512273SCasper.Dik@Sun.COM pfexec_arg_t *pap = (pfexec_arg_t *)argp;
46612273SCasper.Dik@Sun.COM
46712273SCasper.Dik@Sun.COM if (asz < sizeof (pfexec_arg_t) || pap->pfa_vers != PFEXEC_ARG_VERS) {
46812273SCasper.Dik@Sun.COM (void) door_return(NULL, 0, NULL, 0);
46912273SCasper.Dik@Sun.COM return;
47012273SCasper.Dik@Sun.COM }
47112273SCasper.Dik@Sun.COM
47212273SCasper.Dik@Sun.COM switch (pap->pfa_call) {
47312273SCasper.Dik@Sun.COM case PFEXEC_EXEC_ATTRS:
47412273SCasper.Dik@Sun.COM callback_pfexec(pap);
47512273SCasper.Dik@Sun.COM break;
47612273SCasper.Dik@Sun.COM case PFEXEC_FORCED_PRIVS:
47712273SCasper.Dik@Sun.COM callback_forced_privs(pap);
47812273SCasper.Dik@Sun.COM break;
47912273SCasper.Dik@Sun.COM case PFEXEC_USER_PRIVS:
48012273SCasper.Dik@Sun.COM callback_user_privs(pap);
48112273SCasper.Dik@Sun.COM break;
48212273SCasper.Dik@Sun.COM default:
48312273SCasper.Dik@Sun.COM syslog(LOG_ERR, "Bad Call: %d\n", pap->pfa_call);
48412273SCasper.Dik@Sun.COM break;
48512273SCasper.Dik@Sun.COM }
48612273SCasper.Dik@Sun.COM
48712273SCasper.Dik@Sun.COM /*
48812273SCasper.Dik@Sun.COM * If the door_return(ptr, size, NULL, 0) fails, make sure we
48912273SCasper.Dik@Sun.COM * don't lose server threads.
49012273SCasper.Dik@Sun.COM */
49112273SCasper.Dik@Sun.COM (void) door_return(NULL, 0, NULL, 0);
49212273SCasper.Dik@Sun.COM }
49312273SCasper.Dik@Sun.COM
49412273SCasper.Dik@Sun.COM int
main(void)49512273SCasper.Dik@Sun.COM main(void)
49612273SCasper.Dik@Sun.COM {
49712273SCasper.Dik@Sun.COM const priv_impl_info_t *info;
49812273SCasper.Dik@Sun.COM
49912273SCasper.Dik@Sun.COM (void) signal(SIGINT, unregister_pfexec);
50012273SCasper.Dik@Sun.COM (void) signal(SIGQUIT, unregister_pfexec);
50112273SCasper.Dik@Sun.COM (void) signal(SIGTERM, unregister_pfexec);
50212273SCasper.Dik@Sun.COM (void) signal(SIGHUP, unregister_pfexec);
50312273SCasper.Dik@Sun.COM
50412273SCasper.Dik@Sun.COM info = getprivimplinfo();
50512273SCasper.Dik@Sun.COM if (info == NULL)
50612273SCasper.Dik@Sun.COM exit(1);
50712273SCasper.Dik@Sun.COM
50812273SCasper.Dik@Sun.COM if (fork() > 0)
50912273SCasper.Dik@Sun.COM _exit(0);
51012273SCasper.Dik@Sun.COM
51112273SCasper.Dik@Sun.COM openlog("pfexecd", LOG_PID, LOG_DAEMON);
51212273SCasper.Dik@Sun.COM setsz = info->priv_setsize * sizeof (priv_chunk_t);
51312273SCasper.Dik@Sun.COM repsz = 2 * setsz + sizeof (pfexec_reply_t);
51412273SCasper.Dik@Sun.COM
51512273SCasper.Dik@Sun.COM init_isa_regex();
51612273SCasper.Dik@Sun.COM
51712273SCasper.Dik@Sun.COM doorfd = door_create(callback, NULL, DOOR_REFUSE_DESC);
51812273SCasper.Dik@Sun.COM
51912273SCasper.Dik@Sun.COM if (doorfd == -1 || register_pfexec(doorfd) != 0) {
52012273SCasper.Dik@Sun.COM perror("doorfd");
52112273SCasper.Dik@Sun.COM exit(1);
52212273SCasper.Dik@Sun.COM }
52312273SCasper.Dik@Sun.COM
52412273SCasper.Dik@Sun.COM /* LINTED CONSTCOND */
52512273SCasper.Dik@Sun.COM while (1)
52612273SCasper.Dik@Sun.COM (void) sigpause(SIGINT);
52712273SCasper.Dik@Sun.COM
52812273SCasper.Dik@Sun.COM return (0);
52912273SCasper.Dik@Sun.COM }
530