1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26/*
27 *  Routines to set gssd value of uid and replace getuid libsys call.
28 */
29
30#include <sys/types.h>
31#include <unistd.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <libintl.h>
35#include <priv.h>
36#include <errno.h>
37#include <syslog.h>
38
39static uid_t krb5_cc_uid;
40#define	LOWPRIVS	"basic,!file_link_any,!proc_info,!proc_session," \
41			"!proc_fork,!proc_exec"
42
43static priv_set_t *lowprivs = NULL;
44static priv_set_t *highprivs = NULL;
45
46/*
47 * NOTE WELL: This assumes gssd is NOT multi-threaded.  Do NOT add -A to
48 * the rpcgen argument list in the Makefile unless you also remove this
49 * assumption.
50 */
51
52void
53set_gssd_uid(uid_t uid)
54{
55	/* Initialize */
56	if (lowprivs == NULL) {
57		/* L, P & I shall not change in gssd; we manipulate P though */
58		if ((highprivs = priv_allocset()) == NULL ||
59		    (lowprivs = priv_str_to_set(LOWPRIVS, ",", NULL)) == NULL) {
60			printf(gettext(
61			    "fatal: can't allocate privilege set (%s)\n"),
62			    strerror(ENOMEM));
63			syslog(LOG_ERR, "Fatal: can't allocate privilege "
64			    "set (%s)"), strerror(ENOMEM);
65			exit(1);
66		}
67		/* P has the privs we need when we need privs */
68		(void) getppriv(PRIV_PERMITTED, highprivs);
69
70		/*
71		 * In case "basic" grows privs not excluded in LOWPRIVS
72		 * but excluded in the service's method_context
73		 */
74		priv_intersect(highprivs, lowprivs);
75
76		(void) setpflags(PRIV_AWARE, 1);
77	}
78
79	printf(gettext("set_gssd_uid called with uid = %d\n"), uid);
80
81	/*
82	 * nfsd runs as UID 1, so upcalls triggered by nfsd will cause uid to
83	 * 1 here, but nfsd's upcalls need to run as root with privs here.
84	 */
85	if (uid == 1)
86		uid = 0;
87
88	/*
89	 * Set the value of krb5_cc_uid, so it can be retrieved when
90	 * app_krb5_user_uid() is called by the underlying mechanism
91	 * libraries.  This should go away soon.
92	 */
93	krb5_cc_uid = uid;
94
95	/* Claw privs back */
96	(void) setppriv(PRIV_SET, PRIV_EFFECTIVE, highprivs);
97
98	/*
99	 * Switch uid and set the saved set-uid to 0 so setuid(0) will work
100	 * later.
101	 */
102	if (setuid(0) != 0 ||
103	    (uid != 0 && setreuid(uid, -1) != 0) ||
104	    (uid != 0 && seteuid(uid) != 0)) {
105
106		/* Not enough privs, so bail! */
107		printf(gettext(
108		    "fatal: gssd is running with insufficient privilege\n"));
109		syslog(LOG_ERR, "Fatal: gssd is running with insufficient "
110		    "privilege.");
111		exit(1);
112	}
113
114	/* Temporarily drop privs, but only if uid != 0 */
115	if (uid != 0)
116		(void) setppriv(PRIV_SET, PRIV_EFFECTIVE, lowprivs);
117}
118
119uid_t
120app_krb5_user_uid(void)
121{
122	/*
123	 * return the value set when one of the gssd procedures was
124	 * entered. This is the value of the uid under which the
125	 * underlying mechanism library must operate in order to
126	 * get the user's credentials. This call is necessary since
127	 * gssd runs as root and credentials are many times stored
128	 * in files and directories specific to the user
129	 */
130	printf(gettext(
131	    "getuid called and returning krb5_cc_uid = %d\n"), krb5_cc_uid);
132	return (krb5_cc_uid);
133}
134