xref: /illumos-gate/usr/src/lib/libnsl/rpc/auth_sys.c (revision 6d02032db7b674f185405d42cc8bf10a46a9ab3a)
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 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
28 /*
29  * Portions of this source code were derived from Berkeley
30  * 4.3 BSD under license from the Regents of the University of
31  * California.
32  */
33 
34 /*
35  * auth_sys.c, Implements UNIX (system) style authentication parameters.
36  *
37  * The system is very weak.  The client uses no encryption for its
38  * credentials and only sends null verifiers.  The server sends backs
39  * null verifiers or optionally a verifier that suggests a new short hand
40  * for the credentials.
41  *
42  */
43 #include "mt.h"
44 #include "rpc_mt.h"
45 #include <alloca.h>
46 #include <stdio.h>
47 #include <syslog.h>
48 #include <stdlib.h>
49 #include <unistd.h>
50 #include <string.h>
51 #include <rpc/types.h>
52 #include <rpc/xdr.h>
53 #include <rpc/auth.h>
54 #include <rpc/auth_sys.h>
55 #include <synch.h>
56 
57 extern int gethostname(char *, int);
58 extern bool_t xdr_opaque_auth(XDR *, struct opaque_auth *);
59 
60 static struct auth_ops *authsys_ops(void);
61 
62 /*
63  * This struct is pointed to by the ah_private field of an auth_handle.
64  */
65 struct audata {
66 	struct opaque_auth	au_origcred;	/* original credentials */
67 	struct opaque_auth	au_shcred;	/* short hand cred */
68 	uint_t			au_shfaults;	/* short hand cache faults */
69 	char			au_marshed[MAX_AUTH_BYTES];
70 	uint_t			au_mpos;	/* xdr pos at end of marshed */
71 };
72 #define	AUTH_PRIVATE(auth)	((struct audata *)auth->ah_private)
73 
74 static void marshal_new_auth();
75 
76 static const char auth_sys_str[] = "%s : %s";
77 static const char authsys_create_str[] = "authsys_create";
78 static const char __no_mem_auth[] = "out of memory";
79 
80 /*
81  * Create a (sys) unix style authenticator.
82  * Returns an auth handle with the given stuff in it.
83  */
84 AUTH *
85 authsys_create(const char *machname, const uid_t uid, const gid_t gid,
86 	const int len, const gid_t *aup_gids)
87 {
88 	struct authsys_parms aup;
89 	char mymem[MAX_AUTH_BYTES];
90 	struct timeval now;
91 	XDR xdrs;
92 	AUTH *auth;
93 	struct audata *au;
94 
95 	/*
96 	 * Allocate and set up auth handle
97 	 */
98 	auth = malloc(sizeof (*auth));
99 	if (auth == NULL) {
100 		(void) syslog(LOG_ERR, auth_sys_str, authsys_create_str,
101 		    __no_mem_auth);
102 		return (NULL);
103 	}
104 	au = malloc(sizeof (*au));
105 	if (au == NULL) {
106 		(void) syslog(LOG_ERR, auth_sys_str, authsys_create_str,
107 		    __no_mem_auth);
108 		free(auth);
109 		return (NULL);
110 	}
111 	auth->ah_ops = authsys_ops();
112 	auth->ah_private = (caddr_t)au;
113 	auth->ah_verf = au->au_shcred = _null_auth;
114 	au->au_shfaults = 0;
115 
116 	/*
117 	 * fill in param struct from the given params
118 	 */
119 	(void) gettimeofday(&now,  (struct timezone *)0);
120 	aup.aup_time = now.tv_sec;
121 	aup.aup_machname = (char *)machname;
122 	aup.aup_uid = uid;
123 	aup.aup_gid = gid;
124 	aup.aup_len = (uint_t)len;
125 	aup.aup_gids = (gid_t *)aup_gids;
126 
127 	/*
128 	 * Serialize the parameters into origcred
129 	 */
130 	xdrmem_create(&xdrs, mymem, MAX_AUTH_BYTES, XDR_ENCODE);
131 	if (!xdr_authsys_parms(&xdrs, &aup)) {
132 		(void) syslog(LOG_ERR, auth_sys_str, authsys_create_str,
133 		    ":  xdr_authsys_parms failed");
134 		return (NULL);
135 	}
136 	au->au_origcred.oa_length = XDR_GETPOS(&xdrs);
137 	au->au_origcred.oa_flavor = AUTH_SYS;
138 	if ((au->au_origcred.oa_base = malloc(au->au_origcred.oa_length)) ==
139 	    NULL) {
140 		(void) syslog(LOG_ERR, auth_sys_str, authsys_create_str,
141 		    __no_mem_auth);
142 		free(au);
143 		free(auth);
144 		return (NULL);
145 	}
146 	(void) memcpy(au->au_origcred.oa_base, mymem,
147 	    (size_t)au->au_origcred.oa_length);
148 
149 	/*
150 	 * set auth handle to reflect new cred.
151 	 */
152 	auth->ah_cred = au->au_origcred;
153 	(void) marshal_new_auth(auth);
154 	return (auth);
155 }
156 
157 /*
158  * authsys_create_default is a public interface.
159  *
160  * Returns an auth handle with parameters determined by doing lots of
161  * syscalls.
162  */
163 
164 static const char authsys_def_str[] =
165 	"authsys_create_default:  get%s failed:  %m";
166 
167 AUTH *
168 authsys_create_default(void)
169 {
170 	int len;
171 	char machname[MAX_MACHINE_NAME + 1];
172 	uid_t uid;
173 	gid_t gid;
174 	int maxgrp = getgroups(0, NULL);
175 	gid_t *gids = alloca(maxgrp * sizeof (gid_t));
176 
177 	if (gethostname(machname, MAX_MACHINE_NAME) == -1) {
178 		(void) syslog(LOG_ERR, authsys_def_str, "hostname");
179 		return (NULL);
180 	}
181 	machname[MAX_MACHINE_NAME] = 0;
182 	uid = geteuid();
183 	gid = getegid();
184 	if ((len = getgroups(maxgrp, gids)) < 0) {
185 		(void) syslog(LOG_ERR, authsys_def_str, "groups");
186 		return (NULL);
187 	}
188 	if (len > NGRPS)
189 		len = NGRPS;
190 	return (authsys_create(machname, uid, gid, len, gids));
191 }
192 
193 /*
194  * authsys_create_ruid() is a private routine and is a
195  * variant of authsys_create_default().
196  *
197  * authsys_create_default() is using the effective uid.
198  * authsys_create_ruid() is using the real uid.
199  *
200  * This routine is used by key_call_ext() in key_call.c
201  */
202 AUTH *
203 authsys_create_ruid(void)
204 {
205 	int len;
206 	char machname[MAX_MACHINE_NAME + 1];
207 	uid_t uid;
208 	gid_t gid;
209 	int maxgrp = getgroups(0, NULL);
210 	gid_t *gids = alloca(maxgrp * sizeof (gid_t));
211 	AUTH *res;
212 
213 	if (gethostname(machname, MAX_MACHINE_NAME) == -1) {
214 		(void) syslog(LOG_ERR,
215 		    "authsys_create_ruid:gethostname failed");
216 		return (NULL);
217 	}
218 	machname[MAX_MACHINE_NAME] = 0;
219 	uid = getuid();
220 	gid = getgid();
221 	if ((len = getgroups(maxgrp, gids)) < 0) {
222 		(void) syslog(LOG_ERR,
223 		    "authsys_create_ruid:getgroups failed");
224 		return (NULL);
225 	}
226 	if (len > NGRPS)
227 		len = NGRPS;
228 	res = authsys_create(machname, uid, gid, len, gids);
229 	return (res);
230 }
231 
232 /*
233  * authsys operations
234  */
235 
236 /*ARGSUSED*/
237 static void
238 authsys_nextverf(AUTH *auth)
239 {
240 	/* no action necessary */
241 }
242 
243 static bool_t
244 authsys_marshal(AUTH *auth, XDR *xdrs)
245 {
246 /* LINTED pointer alignment */
247 	struct audata *au = AUTH_PRIVATE(auth);
248 
249 	return (XDR_PUTBYTES(xdrs, au->au_marshed, au->au_mpos));
250 }
251 
252 static bool_t
253 authsys_validate(AUTH *auth, struct opaque_auth *verf)
254 {
255 	struct audata *au;
256 	XDR xdrs;
257 
258 	if (verf->oa_flavor == AUTH_SHORT) {
259 /* LINTED pointer alignment */
260 		au = AUTH_PRIVATE(auth);
261 		xdrmem_create(&xdrs, verf->oa_base,
262 		    verf->oa_length, XDR_DECODE);
263 
264 		if (au->au_shcred.oa_base != NULL) {
265 			free(au->au_shcred.oa_base);
266 			au->au_shcred.oa_base = NULL;
267 		}
268 		if (xdr_opaque_auth(&xdrs, &au->au_shcred)) {
269 			auth->ah_cred = au->au_shcred;
270 		} else {
271 			xdrs.x_op = XDR_FREE;
272 			(void) xdr_opaque_auth(&xdrs, &au->au_shcred);
273 			au->au_shcred.oa_base = NULL;
274 			auth->ah_cred = au->au_origcred;
275 		}
276 		(void) marshal_new_auth(auth);
277 	}
278 	return (TRUE);
279 }
280 
281 /*ARGSUSED*/
282 static bool_t
283 authsys_refresh(AUTH *auth, void *dummy)
284 {
285 /* LINTED pointer alignment */
286 	struct audata *au = AUTH_PRIVATE(auth);
287 	struct authsys_parms aup;
288 	struct timeval now;
289 	XDR xdrs;
290 	int stat;
291 
292 	if (auth->ah_cred.oa_base == au->au_origcred.oa_base)
293 		return (FALSE);	/* there is no hope.  Punt */
294 	au->au_shfaults ++;
295 
296 	/* first deserialize the creds back into a struct authsys_parms */
297 	aup.aup_machname = NULL;
298 	aup.aup_gids = NULL;
299 	xdrmem_create(&xdrs, au->au_origcred.oa_base,
300 	    au->au_origcred.oa_length, XDR_DECODE);
301 	stat = xdr_authsys_parms(&xdrs, &aup);
302 	if (!stat)
303 		goto done;
304 
305 	/* update the time and serialize in place */
306 	(void) gettimeofday(&now, (struct timezone *)0);
307 	aup.aup_time = now.tv_sec;
308 	xdrs.x_op = XDR_ENCODE;
309 	XDR_SETPOS(&xdrs, 0);
310 	stat = xdr_authsys_parms(&xdrs, &aup);
311 	if (!stat)
312 		goto done;
313 	auth->ah_cred = au->au_origcred;
314 	(void) marshal_new_auth(auth);
315 done:
316 	/* free the struct authsys_parms created by deserializing */
317 	xdrs.x_op = XDR_FREE;
318 	(void) xdr_authsys_parms(&xdrs, &aup);
319 	XDR_DESTROY(&xdrs);
320 	return (stat);
321 }
322 
323 static void
324 authsys_destroy(AUTH *auth)
325 {
326 /* LINTED pointer alignment */
327 	struct audata *au = AUTH_PRIVATE(auth);
328 
329 	free(au->au_origcred.oa_base);
330 	if (au->au_shcred.oa_base != NULL)
331 		free(au->au_shcred.oa_base);
332 	free(auth->ah_private);
333 	if (auth->ah_verf.oa_base != NULL)
334 		free(auth->ah_verf.oa_base);
335 	free(auth);
336 }
337 
338 /*
339  * Marshals (pre-serializes) an auth struct.
340  * sets private data, au_marshed and au_mpos
341  */
342 
343 static const char marshal_new_auth_str[] =
344 		"marshal_new_auth - Fatal marshalling problem";
345 static void
346 marshal_new_auth(AUTH *auth)
347 {
348 	XDR	xdr_stream;
349 	XDR	*xdrs = &xdr_stream;
350 /* LINTED pointer alignment */
351 	struct audata *au = AUTH_PRIVATE(auth);
352 
353 	xdrmem_create(xdrs, au->au_marshed, MAX_AUTH_BYTES, XDR_ENCODE);
354 	if ((!xdr_opaque_auth(xdrs, &(auth->ah_cred))) ||
355 	    (!xdr_opaque_auth(xdrs, &(auth->ah_verf)))) {
356 		(void) syslog(LOG_ERR, marshal_new_auth_str);
357 	} else {
358 		au->au_mpos = XDR_GETPOS(xdrs);
359 	}
360 	XDR_DESTROY(xdrs);
361 }
362 
363 static struct auth_ops *
364 authsys_ops(void)
365 {
366 	static struct auth_ops ops;
367 	extern mutex_t ops_lock;
368 
369 	/* VARIABLES PROTECTED BY ops_lock: ops */
370 
371 	(void) mutex_lock(&ops_lock);
372 	if (ops.ah_nextverf == NULL) {
373 		ops.ah_nextverf = authsys_nextverf;
374 		ops.ah_marshal = authsys_marshal;
375 		ops.ah_validate = authsys_validate;
376 		ops.ah_refresh = authsys_refresh;
377 		ops.ah_destroy = authsys_destroy;
378 	}
379 	(void) mutex_unlock(&ops_lock);
380 	return (&ops);
381 }
382