xref: /illumos-gate/usr/src/lib/libnsl/rpc/svc_auth.c (revision dd72704bd9e794056c558153663c739e2012d721)
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 /*
36  * svc_auth.c, Server-side rpc authenticator interface.
37  *
38  */
39 
40 #include "mt.h"
41 #include "rpc_mt.h"
42 #include <rpc/rpc.h>
43 #include <sys/types.h>
44 #include <stdlib.h>
45 
46 /*
47  * svcauthsw is the bdevsw of server side authentication.
48  *
49  * Server side authenticators are called from authenticate by
50  * using the client auth struct flavor field to index into svcauthsw.
51  * The server auth flavors must implement a routine that looks
52  * like:
53  *
54  *	enum auth_stat
55  *	flavorx_auth(rqst, msg)
56  *		struct svc_req *rqst;
57  *		struct rpc_msg *msg;
58  *
59  * The RPCSEC_GSS flavor is an exception.  Its routine takes an
60  * additional boolean parameter that gets set to TRUE when the call
61  * is not to be dispatched to the server.
62  */
63 
64 enum auth_stat __svcauth_null();	/* no authentication */
65 enum auth_stat __svcauth_sys();		/* (system) unix style (uid, gids) */
66 enum auth_stat __svcauth_short();	/* short hand unix style */
67 enum auth_stat __svcauth_des();		/* des style */
68 enum auth_stat __svcauth_loopback();	/* (loopback) unix style (uid, gids) */
69 extern enum auth_stat __svcrpcsec_gss();	/* GSS style */
70 
71 /* declarations to allow servers to specify new authentication flavors */
72 struct authsvc {
73 	int	flavor;
74 	enum	auth_stat (*handler)();
75 	struct	authsvc	  *next;
76 };
77 static struct authsvc *Auths = NULL;
78 
79 /*
80  * The call rpc message, msg has been obtained from the wire.  The msg contains
81  * the raw form of credentials and verifiers.  no_dispatch is used and
82  * dereferenced in subsequent gss function calls.  authenticate returns AUTH_OK
83  * if the msg is successfully authenticated.  If AUTH_OK then the routine also
84  * does the following things:
85  * set rqst->rq_xprt->verf to the appropriate response verifier;
86  * sets rqst->rq_client_cred to the "cooked" form of the credentials.
87  *
88  * NB: rqst->rq_cxprt->verf must be pre-alloctaed;
89  * its length is set appropriately.
90  *
91  * The caller still owns and is responsible for msg->u.cmb.cred and
92  * msg->u.cmb.verf.  The authentication system retains ownership of
93  * rqst->rq_client_cred, the cooked credentials.
94  *
95  * There is an assumption that any flavour less than AUTH_NULL is
96  * invalid.
97  */
98 enum auth_stat
99 __gss_authenticate(struct svc_req *rqst, struct rpc_msg *msg,
100 							bool_t *no_dispatch)
101 {
102 	int cred_flavor;
103 	struct authsvc *asp;
104 	extern mutex_t authsvc_lock;
105 
106 /* VARIABLES PROTECTED BY authsvc_lock: asp, Auths */
107 
108 	rqst->rq_cred = msg->rm_call.cb_cred;
109 	rqst->rq_xprt->xp_verf.oa_flavor = _null_auth.oa_flavor;
110 	rqst->rq_xprt->xp_verf.oa_length = 0;
111 	cred_flavor = rqst->rq_cred.oa_flavor;
112 	*no_dispatch = FALSE;
113 	switch (cred_flavor) {
114 	case AUTH_NULL:
115 		return (__svcauth_null(rqst, msg));
116 	case AUTH_SYS:
117 		return (__svcauth_sys(rqst, msg));
118 	case AUTH_SHORT:
119 		return (__svcauth_short(rqst, msg));
120 	case AUTH_DES:
121 		return (__svcauth_des(rqst, msg));
122 	case AUTH_LOOPBACK:
123 		return (__svcauth_loopback(rqst, msg));
124 	case RPCSEC_GSS:
125 		return (__svcrpcsec_gss(rqst, msg, no_dispatch));
126 	}
127 
128 	/* flavor doesn't match any of the builtin types, so try new ones */
129 	(void) mutex_lock(&authsvc_lock);
130 	for (asp = Auths; asp; asp = asp->next) {
131 		if (asp->flavor == cred_flavor) {
132 			enum auth_stat as;
133 
134 			as = (*asp->handler)(rqst, msg);
135 			(void) mutex_unlock(&authsvc_lock);
136 			return (as);
137 		}
138 	}
139 	(void) mutex_unlock(&authsvc_lock);
140 
141 	return (AUTH_REJECTEDCRED);
142 }
143 
144 /*
145  * The following function __authenticate(rqst, msg) is preserved for
146  * backward compatibility.
147  */
148 enum auth_stat
149 __authenticate(struct svc_req *rqst, struct rpc_msg *msg)
150 {
151 	bool_t no_dispatch;
152 
153 	return (__gss_authenticate(rqst, msg, &no_dispatch));
154 }
155 
156 /*ARGSUSED*/
157 enum auth_stat
158 __svcauth_null(struct svc_req *rqst, struct rpc_msg *msg)
159 {
160 	return (AUTH_OK);
161 }
162 
163 /*
164  *  Allow the rpc service to register new authentication types that it is
165  *  prepared to handle.  When an authentication flavor is registered,
166  *  the flavor is checked against already registered values.  If not
167  *  registered, then a new Auths entry is added on the list.
168  *
169  *  There is no provision to delete a registration once registered.
170  *
171  *  This routine returns:
172  *	 0 if registration successful
173  *	 1 if flavor already registered
174  *	-1 if can't register (errno set)
175  */
176 
177 int
178 svc_auth_reg(int cred_flavor, enum auth_stat (*handler)())
179 {
180 	struct authsvc *asp;
181 	extern mutex_t authsvc_lock;
182 
183 	switch (cred_flavor) {
184 	case AUTH_NULL:
185 	case AUTH_SYS:
186 	case AUTH_SHORT:
187 	case AUTH_DES:
188 	case AUTH_LOOPBACK:
189 	case RPCSEC_GSS:
190 		/* already registered */
191 		return (1);
192 	}
193 	(void) mutex_lock(&authsvc_lock);
194 	for (asp = Auths; asp; asp = asp->next) {
195 		if (asp->flavor == cred_flavor) {
196 			/* already registered */
197 			(void) mutex_unlock(&authsvc_lock);
198 			return (1);
199 		}
200 	}
201 
202 	/* this is a new one, so go ahead and register it */
203 	asp = malloc(sizeof (*asp));
204 	if (asp == NULL) {
205 		(void) mutex_unlock(&authsvc_lock);
206 		return (-1);
207 	}
208 	asp->flavor = cred_flavor;
209 	asp->handler = handler;
210 	asp->next = Auths;
211 	Auths = asp;
212 	(void) mutex_unlock(&authsvc_lock);
213 	return (0);
214 }
215