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