1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  *
22*0Sstevel@tonic-gate  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
23*0Sstevel@tonic-gate  * Use is subject to license terms.
24*0Sstevel@tonic-gate  */
25*0Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
26*0Sstevel@tonic-gate /* All Rights Reserved */
27*0Sstevel@tonic-gate /*
28*0Sstevel@tonic-gate  * Portions of this source code were derived from Berkeley
29*0Sstevel@tonic-gate  * 4.3 BSD under license from the Regents of the University of
30*0Sstevel@tonic-gate  * California.
31*0Sstevel@tonic-gate  */
32*0Sstevel@tonic-gate 
33*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
34*0Sstevel@tonic-gate 
35*0Sstevel@tonic-gate /*
36*0Sstevel@tonic-gate  * svc_auth.c, Server-side rpc authenticator interface.
37*0Sstevel@tonic-gate  *
38*0Sstevel@tonic-gate  */
39*0Sstevel@tonic-gate 
40*0Sstevel@tonic-gate #include "mt.h"
41*0Sstevel@tonic-gate #include "rpc_mt.h"
42*0Sstevel@tonic-gate #include <rpc/rpc.h>
43*0Sstevel@tonic-gate #include <sys/types.h>
44*0Sstevel@tonic-gate #include <rpc/trace.h>
45*0Sstevel@tonic-gate #include <stdlib.h>
46*0Sstevel@tonic-gate 
47*0Sstevel@tonic-gate /*
48*0Sstevel@tonic-gate  * svcauthsw is the bdevsw of server side authentication.
49*0Sstevel@tonic-gate  *
50*0Sstevel@tonic-gate  * Server side authenticators are called from authenticate by
51*0Sstevel@tonic-gate  * using the client auth struct flavor field to index into svcauthsw.
52*0Sstevel@tonic-gate  * The server auth flavors must implement a routine that looks
53*0Sstevel@tonic-gate  * like:
54*0Sstevel@tonic-gate  *
55*0Sstevel@tonic-gate  *	enum auth_stat
56*0Sstevel@tonic-gate  *	flavorx_auth(rqst, msg)
57*0Sstevel@tonic-gate  *		struct svc_req *rqst;
58*0Sstevel@tonic-gate  *		struct rpc_msg *msg;
59*0Sstevel@tonic-gate  *
60*0Sstevel@tonic-gate  * The RPCSEC_GSS flavor is an exception.  Its routine takes an
61*0Sstevel@tonic-gate  * additional boolean parameter that gets set to TRUE when the call
62*0Sstevel@tonic-gate  * is not to be dispatched to the server.
63*0Sstevel@tonic-gate  */
64*0Sstevel@tonic-gate 
65*0Sstevel@tonic-gate enum auth_stat __svcauth_null();	/* no authentication */
66*0Sstevel@tonic-gate enum auth_stat __svcauth_sys();		/* (system) unix style (uid, gids) */
67*0Sstevel@tonic-gate enum auth_stat __svcauth_short();	/* short hand unix style */
68*0Sstevel@tonic-gate enum auth_stat __svcauth_des();		/* des style */
69*0Sstevel@tonic-gate enum auth_stat __svcauth_loopback();	/* (loopback) unix style (uid, gids) */
70*0Sstevel@tonic-gate extern enum auth_stat __svcrpcsec_gss();	/* GSS style */
71*0Sstevel@tonic-gate 
72*0Sstevel@tonic-gate /* declarations to allow servers to specify new authentication flavors */
73*0Sstevel@tonic-gate struct authsvc {
74*0Sstevel@tonic-gate 	int	flavor;
75*0Sstevel@tonic-gate 	enum	auth_stat (*handler)();
76*0Sstevel@tonic-gate 	struct	authsvc	  *next;
77*0Sstevel@tonic-gate };
78*0Sstevel@tonic-gate static struct authsvc *Auths = NULL;
79*0Sstevel@tonic-gate 
80*0Sstevel@tonic-gate /*
81*0Sstevel@tonic-gate  * The call rpc message, msg has been obtained from the wire.  The msg contains
82*0Sstevel@tonic-gate  * the raw form of credentials and verifiers.  no_dispatch is used and
83*0Sstevel@tonic-gate  * dereferenced in subsequent gss function calls.  authenticate returns AUTH_OK
84*0Sstevel@tonic-gate  * if the msg is successfully authenticated.  If AUTH_OK then the routine also
85*0Sstevel@tonic-gate  * does the following things:
86*0Sstevel@tonic-gate  * set rqst->rq_xprt->verf to the appropriate response verifier;
87*0Sstevel@tonic-gate  * sets rqst->rq_client_cred to the "cooked" form of the credentials.
88*0Sstevel@tonic-gate  *
89*0Sstevel@tonic-gate  * NB: rqst->rq_cxprt->verf must be pre-alloctaed;
90*0Sstevel@tonic-gate  * its length is set appropriately.
91*0Sstevel@tonic-gate  *
92*0Sstevel@tonic-gate  * The caller still owns and is responsible for msg->u.cmb.cred and
93*0Sstevel@tonic-gate  * msg->u.cmb.verf.  The authentication system retains ownership of
94*0Sstevel@tonic-gate  * rqst->rq_client_cred, the cooked credentials.
95*0Sstevel@tonic-gate  *
96*0Sstevel@tonic-gate  * There is an assumption that any flavour less than AUTH_NULL is
97*0Sstevel@tonic-gate  * invalid.
98*0Sstevel@tonic-gate  */
99*0Sstevel@tonic-gate enum auth_stat
100*0Sstevel@tonic-gate __gss_authenticate(rqst, msg, no_dispatch)
101*0Sstevel@tonic-gate 	struct svc_req *rqst;
102*0Sstevel@tonic-gate 	struct rpc_msg *msg;
103*0Sstevel@tonic-gate 	bool_t *no_dispatch;
104*0Sstevel@tonic-gate {
105*0Sstevel@tonic-gate 	int cred_flavor;
106*0Sstevel@tonic-gate 	struct authsvc *asp;
107*0Sstevel@tonic-gate 	enum auth_stat dummy;
108*0Sstevel@tonic-gate 	extern mutex_t authsvc_lock;
109*0Sstevel@tonic-gate 
110*0Sstevel@tonic-gate /* VARIABLES PROTECTED BY authsvc_lock: asp, Auths */
111*0Sstevel@tonic-gate 
112*0Sstevel@tonic-gate 	trace1(TR___gss_authenticate, 0);
113*0Sstevel@tonic-gate 	rqst->rq_cred = msg->rm_call.cb_cred;
114*0Sstevel@tonic-gate 	rqst->rq_xprt->xp_verf.oa_flavor = _null_auth.oa_flavor;
115*0Sstevel@tonic-gate 	rqst->rq_xprt->xp_verf.oa_length = 0;
116*0Sstevel@tonic-gate 	cred_flavor = rqst->rq_cred.oa_flavor;
117*0Sstevel@tonic-gate 	*no_dispatch = FALSE;
118*0Sstevel@tonic-gate 	switch (cred_flavor) {
119*0Sstevel@tonic-gate 	case AUTH_NULL:
120*0Sstevel@tonic-gate 		dummy = __svcauth_null(rqst, msg);
121*0Sstevel@tonic-gate 		trace1(TR___gss_authenticate, 1);
122*0Sstevel@tonic-gate 		return (dummy);
123*0Sstevel@tonic-gate 	case AUTH_SYS:
124*0Sstevel@tonic-gate 		dummy = __svcauth_sys(rqst, msg);
125*0Sstevel@tonic-gate 		trace1(TR___gss_authenticate, 1);
126*0Sstevel@tonic-gate 		return (dummy);
127*0Sstevel@tonic-gate 	case AUTH_SHORT:
128*0Sstevel@tonic-gate 		dummy = __svcauth_short(rqst, msg);
129*0Sstevel@tonic-gate 		trace1(TR___gss_authenticate, 1);
130*0Sstevel@tonic-gate 		return (dummy);
131*0Sstevel@tonic-gate 	case AUTH_DES:
132*0Sstevel@tonic-gate 		dummy = __svcauth_des(rqst, msg);
133*0Sstevel@tonic-gate 		trace1(TR___gss_authenticate, 1);
134*0Sstevel@tonic-gate 		return (dummy);
135*0Sstevel@tonic-gate 	case AUTH_LOOPBACK:
136*0Sstevel@tonic-gate 		dummy = __svcauth_loopback(rqst, msg);
137*0Sstevel@tonic-gate 		trace1(TR___gss_authenticate, 1);
138*0Sstevel@tonic-gate 		return (dummy);
139*0Sstevel@tonic-gate 	case RPCSEC_GSS:
140*0Sstevel@tonic-gate 		dummy = __svcrpcsec_gss(rqst, msg, no_dispatch);
141*0Sstevel@tonic-gate 		trace1(TR___gss_authenticate, 1);
142*0Sstevel@tonic-gate 		return (dummy);
143*0Sstevel@tonic-gate 	}
144*0Sstevel@tonic-gate 
145*0Sstevel@tonic-gate 	/* flavor doesn't match any of the builtin types, so try new ones */
146*0Sstevel@tonic-gate 	mutex_lock(&authsvc_lock);
147*0Sstevel@tonic-gate 	for (asp = Auths; asp; asp = asp->next) {
148*0Sstevel@tonic-gate 		if (asp->flavor == cred_flavor) {
149*0Sstevel@tonic-gate 			enum auth_stat as;
150*0Sstevel@tonic-gate 
151*0Sstevel@tonic-gate 			as = (*asp->handler)(rqst, msg);
152*0Sstevel@tonic-gate 			mutex_unlock(&authsvc_lock);
153*0Sstevel@tonic-gate 			trace1(TR___gss_authenticate, 1);
154*0Sstevel@tonic-gate 			return (as);
155*0Sstevel@tonic-gate 		}
156*0Sstevel@tonic-gate 	}
157*0Sstevel@tonic-gate 	mutex_unlock(&authsvc_lock);
158*0Sstevel@tonic-gate 
159*0Sstevel@tonic-gate 	trace1(TR___gss_authenticate, 1);
160*0Sstevel@tonic-gate 	return (AUTH_REJECTEDCRED);
161*0Sstevel@tonic-gate }
162*0Sstevel@tonic-gate 
163*0Sstevel@tonic-gate /*
164*0Sstevel@tonic-gate  * The following function __authenticate(rqst, msg) is preserved for
165*0Sstevel@tonic-gate  * backward compatibility.
166*0Sstevel@tonic-gate  */
167*0Sstevel@tonic-gate enum auth_stat
168*0Sstevel@tonic-gate __authenticate(rqst, msg)
169*0Sstevel@tonic-gate 	struct svc_req *rqst;
170*0Sstevel@tonic-gate 	struct rpc_msg *msg;
171*0Sstevel@tonic-gate {
172*0Sstevel@tonic-gate 	bool_t no_dispatch;
173*0Sstevel@tonic-gate 	enum auth_stat st;
174*0Sstevel@tonic-gate 
175*0Sstevel@tonic-gate 	trace1(TR___authenticate, 0);
176*0Sstevel@tonic-gate 
177*0Sstevel@tonic-gate 	st = __gss_authenticate(rqst, msg, &no_dispatch);
178*0Sstevel@tonic-gate 
179*0Sstevel@tonic-gate 	trace1(TR___authenticate, 1);
180*0Sstevel@tonic-gate 	return (st);
181*0Sstevel@tonic-gate }
182*0Sstevel@tonic-gate 
183*0Sstevel@tonic-gate /*ARGSUSED*/
184*0Sstevel@tonic-gate enum auth_stat
185*0Sstevel@tonic-gate __svcauth_null(rqst, msg)
186*0Sstevel@tonic-gate 	struct svc_req *rqst;
187*0Sstevel@tonic-gate 	struct rpc_msg *msg;
188*0Sstevel@tonic-gate {
189*0Sstevel@tonic-gate 	trace1(TR___svcauth_null, 0);
190*0Sstevel@tonic-gate 	trace1(TR___svcauth_null, 1);
191*0Sstevel@tonic-gate 	return (AUTH_OK);
192*0Sstevel@tonic-gate }
193*0Sstevel@tonic-gate 
194*0Sstevel@tonic-gate /*
195*0Sstevel@tonic-gate  *  Allow the rpc service to register new authentication types that it is
196*0Sstevel@tonic-gate  *  prepared to handle.  When an authentication flavor is registered,
197*0Sstevel@tonic-gate  *  the flavor is checked against already registered values.  If not
198*0Sstevel@tonic-gate  *  registered, then a new Auths entry is added on the list.
199*0Sstevel@tonic-gate  *
200*0Sstevel@tonic-gate  *  There is no provision to delete a registration once registered.
201*0Sstevel@tonic-gate  *
202*0Sstevel@tonic-gate  *  This routine returns:
203*0Sstevel@tonic-gate  *	 0 if registration successful
204*0Sstevel@tonic-gate  *	 1 if flavor already registered
205*0Sstevel@tonic-gate  *	-1 if can't register (errno set)
206*0Sstevel@tonic-gate  */
207*0Sstevel@tonic-gate 
208*0Sstevel@tonic-gate int
209*0Sstevel@tonic-gate svc_auth_reg(cred_flavor, handler)
210*0Sstevel@tonic-gate 	int cred_flavor;
211*0Sstevel@tonic-gate 	enum auth_stat (*handler)();
212*0Sstevel@tonic-gate {
213*0Sstevel@tonic-gate 	struct authsvc *asp;
214*0Sstevel@tonic-gate 	extern mutex_t authsvc_lock;
215*0Sstevel@tonic-gate 
216*0Sstevel@tonic-gate 	trace2(TR_svc_auth_reg, 0, cred_flavor);
217*0Sstevel@tonic-gate 	switch (cred_flavor) {
218*0Sstevel@tonic-gate 	    case AUTH_NULL:
219*0Sstevel@tonic-gate 	    case AUTH_SYS:
220*0Sstevel@tonic-gate 	    case AUTH_SHORT:
221*0Sstevel@tonic-gate 	    case AUTH_DES:
222*0Sstevel@tonic-gate 	    case AUTH_LOOPBACK:
223*0Sstevel@tonic-gate 	    case RPCSEC_GSS:
224*0Sstevel@tonic-gate 		/* already registered */
225*0Sstevel@tonic-gate 		trace1(TR_svc_auth_reg, 1);
226*0Sstevel@tonic-gate 		return (1);
227*0Sstevel@tonic-gate 
228*0Sstevel@tonic-gate 	    default:
229*0Sstevel@tonic-gate 		mutex_lock(&authsvc_lock);
230*0Sstevel@tonic-gate 		for (asp = Auths; asp; asp = asp->next) {
231*0Sstevel@tonic-gate 			if (asp->flavor == cred_flavor) {
232*0Sstevel@tonic-gate 				/* already registered */
233*0Sstevel@tonic-gate 				mutex_unlock(&authsvc_lock);
234*0Sstevel@tonic-gate 				trace1(TR_svc_auth_reg, 1);
235*0Sstevel@tonic-gate 				return (1);
236*0Sstevel@tonic-gate 			}
237*0Sstevel@tonic-gate 		}
238*0Sstevel@tonic-gate 
239*0Sstevel@tonic-gate 		/* this is a new one, so go ahead and register it */
240*0Sstevel@tonic-gate 		asp = (struct authsvc *)mem_alloc(sizeof (*asp));
241*0Sstevel@tonic-gate 		if (asp == NULL) {
242*0Sstevel@tonic-gate 			mutex_unlock(&authsvc_lock);
243*0Sstevel@tonic-gate 			trace1(TR_svc_auth_reg, 1);
244*0Sstevel@tonic-gate 			return (-1);
245*0Sstevel@tonic-gate 		}
246*0Sstevel@tonic-gate 		asp->flavor = cred_flavor;
247*0Sstevel@tonic-gate 		asp->handler = handler;
248*0Sstevel@tonic-gate 		asp->next = Auths;
249*0Sstevel@tonic-gate 		Auths = asp;
250*0Sstevel@tonic-gate 		mutex_unlock(&authsvc_lock);
251*0Sstevel@tonic-gate 		break;
252*0Sstevel@tonic-gate 	}
253*0Sstevel@tonic-gate 	trace1(TR_svc_auth_reg, 1);
254*0Sstevel@tonic-gate 	return (0);
255*0Sstevel@tonic-gate }
256