2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright (c) 1989, 2011, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
2N/A/* All Rights Reserved */
2N/A/*
2N/A * Portions of this source code were derived from Berkeley
2N/A * 4.3 BSD under license from the Regents of the University of
2N/A * California.
2N/A */
2N/A
2N/A/*
2N/A * auth_sys.c, Implements UNIX (system) style authentication parameters.
2N/A *
2N/A * The system is very weak. The client uses no encryption for its
2N/A * credentials and only sends null verifiers. The server sends backs
2N/A * null verifiers or optionally a verifier that suggests a new short hand
2N/A * for the credentials.
2N/A *
2N/A */
2N/A#include "mt.h"
2N/A#include "rpc_mt.h"
2N/A#include <alloca.h>
2N/A#include <stdio.h>
2N/A#include <syslog.h>
2N/A#include <stdlib.h>
2N/A#include <unistd.h>
2N/A#include <string.h>
2N/A#include <rpc/types.h>
2N/A#include <rpc/xdr.h>
2N/A#include <rpc/auth.h>
2N/A#include <rpc/auth_sys.h>
2N/A#include <synch.h>
2N/A
2N/Aextern bool_t xdr_opaque_auth(XDR *, struct opaque_auth *);
2N/A
2N/Astatic struct auth_ops *authsys_ops(void);
2N/A
2N/A/*
2N/A * This struct is pointed to by the ah_private field of an auth_handle.
2N/A */
2N/Astruct audata {
2N/A struct opaque_auth au_origcred; /* original credentials */
2N/A struct opaque_auth au_shcred; /* short hand cred */
2N/A uint_t au_shfaults; /* short hand cache faults */
2N/A char au_marshed[MAX_AUTH_BYTES];
2N/A uint_t au_mpos; /* xdr pos at end of marshed */
2N/A};
2N/A#define AUTH_PRIVATE(auth) ((struct audata *)auth->ah_private)
2N/A
2N/Astatic void marshal_new_auth();
2N/A
2N/Astatic const char auth_sys_str[] = "%s : %s";
2N/Astatic const char authsys_create_str[] = "authsys_create";
2N/Astatic const char __no_mem_auth[] = "out of memory";
2N/A
2N/A/*
2N/A * Create a (sys) unix style authenticator.
2N/A * Returns an auth handle with the given stuff in it.
2N/A */
2N/AAUTH *
2N/Aauthsys_create(const char *machname, const uid_t uid, const gid_t gid,
2N/A const int len, const gid_t *aup_gids)
2N/A{
2N/A struct authsys_parms aup;
2N/A char mymem[MAX_AUTH_BYTES];
2N/A struct timeval now;
2N/A XDR xdrs;
2N/A AUTH *auth;
2N/A struct audata *au;
2N/A
2N/A /*
2N/A * Allocate and set up auth handle
2N/A */
2N/A auth = malloc(sizeof (*auth));
2N/A if (auth == NULL) {
2N/A (void) syslog(LOG_ERR, auth_sys_str, authsys_create_str,
2N/A __no_mem_auth);
2N/A return (NULL);
2N/A }
2N/A au = malloc(sizeof (*au));
2N/A if (au == NULL) {
2N/A (void) syslog(LOG_ERR, auth_sys_str, authsys_create_str,
2N/A __no_mem_auth);
2N/A free(auth);
2N/A return (NULL);
2N/A }
2N/A auth->ah_ops = authsys_ops();
2N/A auth->ah_private = (caddr_t)au;
2N/A auth->ah_verf = au->au_shcred = _null_auth;
2N/A au->au_shfaults = 0;
2N/A
2N/A /*
2N/A * fill in param struct from the given params
2N/A */
2N/A (void) gettimeofday(&now, (struct timezone *)0);
2N/A aup.aup_time = now.tv_sec;
2N/A aup.aup_machname = (char *)machname;
2N/A aup.aup_uid = uid;
2N/A aup.aup_gid = gid;
2N/A aup.aup_len = (uint_t)len;
2N/A aup.aup_gids = (gid_t *)aup_gids;
2N/A
2N/A /*
2N/A * Serialize the parameters into origcred
2N/A */
2N/A xdrmem_create(&xdrs, mymem, MAX_AUTH_BYTES, XDR_ENCODE);
2N/A if (!xdr_authsys_parms(&xdrs, &aup)) {
2N/A (void) syslog(LOG_ERR, auth_sys_str, authsys_create_str,
2N/A ": xdr_authsys_parms failed");
2N/A return (NULL);
2N/A }
2N/A au->au_origcred.oa_length = XDR_GETPOS(&xdrs);
2N/A au->au_origcred.oa_flavor = AUTH_SYS;
2N/A if ((au->au_origcred.oa_base = malloc(au->au_origcred.oa_length)) ==
2N/A NULL) {
2N/A (void) syslog(LOG_ERR, auth_sys_str, authsys_create_str,
2N/A __no_mem_auth);
2N/A free(au);
2N/A free(auth);
2N/A return (NULL);
2N/A }
2N/A (void) memcpy(au->au_origcred.oa_base, mymem,
2N/A (size_t)au->au_origcred.oa_length);
2N/A
2N/A /*
2N/A * set auth handle to reflect new cred.
2N/A */
2N/A auth->ah_cred = au->au_origcred;
2N/A (void) marshal_new_auth(auth);
2N/A return (auth);
2N/A}
2N/A
2N/A/*
2N/A * authsys_create_default is a public interface.
2N/A *
2N/A * Returns an auth handle with parameters determined by doing lots of
2N/A * syscalls.
2N/A */
2N/A
2N/Astatic const char authsys_def_str[] =
2N/A "authsys_create_default: get%s failed: %m";
2N/A
2N/AAUTH *
2N/Aauthsys_create_default(void)
2N/A{
2N/A int len;
2N/A char machname[MAX_MACHINE_NAME + 1];
2N/A uid_t uid;
2N/A gid_t gid;
2N/A int maxgrp = getgroups(0, NULL);
2N/A gid_t *gids = alloca(maxgrp * sizeof (gid_t));
2N/A
2N/A if (gethostname(machname, MAX_MACHINE_NAME) == -1) {
2N/A (void) syslog(LOG_ERR, authsys_def_str, "hostname");
2N/A return (NULL);
2N/A }
2N/A machname[MAX_MACHINE_NAME] = 0;
2N/A uid = geteuid();
2N/A gid = getegid();
2N/A if ((len = getgroups(maxgrp, gids)) < 0) {
2N/A (void) syslog(LOG_ERR, authsys_def_str, "groups");
2N/A return (NULL);
2N/A }
2N/A if (len > NGRPS)
2N/A len = NGRPS;
2N/A return (authsys_create(machname, uid, gid, len, gids));
2N/A}
2N/A
2N/A/*
2N/A * authsys_create_ruid() is a private routine and is a
2N/A * variant of authsys_create_default().
2N/A *
2N/A * authsys_create_default() is using the effective uid.
2N/A * authsys_create_ruid() is using the real uid.
2N/A *
2N/A * This routine is used by key_call_ext() in key_call.c
2N/A */
2N/AAUTH *
2N/Aauthsys_create_ruid(void)
2N/A{
2N/A int len;
2N/A char machname[MAX_MACHINE_NAME + 1];
2N/A uid_t uid;
2N/A gid_t gid;
2N/A int maxgrp = getgroups(0, NULL);
2N/A gid_t *gids = alloca(maxgrp * sizeof (gid_t));
2N/A AUTH *res;
2N/A
2N/A if (gethostname(machname, MAX_MACHINE_NAME) == -1) {
2N/A (void) syslog(LOG_ERR,
2N/A "authsys_create_ruid:gethostname failed");
2N/A return (NULL);
2N/A }
2N/A machname[MAX_MACHINE_NAME] = 0;
2N/A uid = getuid();
2N/A gid = getgid();
2N/A if ((len = getgroups(maxgrp, gids)) < 0) {
2N/A (void) syslog(LOG_ERR,
2N/A "authsys_create_ruid:getgroups failed");
2N/A return (NULL);
2N/A }
2N/A if (len > NGRPS)
2N/A len = NGRPS;
2N/A res = authsys_create(machname, uid, gid, len, gids);
2N/A return (res);
2N/A}
2N/A
2N/A/*
2N/A * authsys operations
2N/A */
2N/A
2N/A/*ARGSUSED*/
2N/Astatic void
2N/Aauthsys_nextverf(AUTH *auth)
2N/A{
2N/A /* no action necessary */
2N/A}
2N/A
2N/Astatic bool_t
2N/Aauthsys_marshal(AUTH *auth, XDR *xdrs)
2N/A{
2N/A/* LINTED pointer alignment */
2N/A struct audata *au = AUTH_PRIVATE(auth);
2N/A
2N/A return (XDR_PUTBYTES(xdrs, au->au_marshed, au->au_mpos));
2N/A}
2N/A
2N/Astatic bool_t
2N/Aauthsys_validate(AUTH *auth, struct opaque_auth *verf)
2N/A{
2N/A struct audata *au;
2N/A XDR xdrs;
2N/A
2N/A if (verf->oa_flavor == AUTH_SHORT) {
2N/A/* LINTED pointer alignment */
2N/A au = AUTH_PRIVATE(auth);
2N/A xdrmem_create(&xdrs, verf->oa_base,
2N/A verf->oa_length, XDR_DECODE);
2N/A
2N/A if (au->au_shcred.oa_base != NULL) {
2N/A free(au->au_shcred.oa_base);
2N/A au->au_shcred.oa_base = NULL;
2N/A }
2N/A if (xdr_opaque_auth(&xdrs, &au->au_shcred)) {
2N/A auth->ah_cred = au->au_shcred;
2N/A } else {
2N/A xdrs.x_op = XDR_FREE;
2N/A (void) xdr_opaque_auth(&xdrs, &au->au_shcred);
2N/A au->au_shcred.oa_base = NULL;
2N/A auth->ah_cred = au->au_origcred;
2N/A }
2N/A (void) marshal_new_auth(auth);
2N/A }
2N/A return (TRUE);
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Astatic bool_t
2N/Aauthsys_refresh(AUTH *auth, void *dummy)
2N/A{
2N/A/* LINTED pointer alignment */
2N/A struct audata *au = AUTH_PRIVATE(auth);
2N/A struct authsys_parms aup;
2N/A struct timeval now;
2N/A XDR xdrs;
2N/A int stat;
2N/A
2N/A if (auth->ah_cred.oa_base == au->au_origcred.oa_base)
2N/A return (FALSE); /* there is no hope. Punt */
2N/A au->au_shfaults ++;
2N/A
2N/A /* first deserialize the creds back into a struct authsys_parms */
2N/A aup.aup_machname = NULL;
2N/A aup.aup_gids = NULL;
2N/A xdrmem_create(&xdrs, au->au_origcred.oa_base,
2N/A au->au_origcred.oa_length, XDR_DECODE);
2N/A stat = xdr_authsys_parms(&xdrs, &aup);
2N/A if (!stat)
2N/A goto done;
2N/A
2N/A /* update the time and serialize in place */
2N/A (void) gettimeofday(&now, (struct timezone *)0);
2N/A aup.aup_time = now.tv_sec;
2N/A xdrs.x_op = XDR_ENCODE;
2N/A XDR_SETPOS(&xdrs, 0);
2N/A stat = xdr_authsys_parms(&xdrs, &aup);
2N/A if (!stat)
2N/A goto done;
2N/A auth->ah_cred = au->au_origcred;
2N/A (void) marshal_new_auth(auth);
2N/Adone:
2N/A /* free the struct authsys_parms created by deserializing */
2N/A xdrs.x_op = XDR_FREE;
2N/A (void) xdr_authsys_parms(&xdrs, &aup);
2N/A XDR_DESTROY(&xdrs);
2N/A return (stat);
2N/A}
2N/A
2N/Astatic void
2N/Aauthsys_destroy(AUTH *auth)
2N/A{
2N/A/* LINTED pointer alignment */
2N/A struct audata *au = AUTH_PRIVATE(auth);
2N/A
2N/A free(au->au_origcred.oa_base);
2N/A if (au->au_shcred.oa_base != NULL)
2N/A free(au->au_shcred.oa_base);
2N/A free(auth->ah_private);
2N/A if (auth->ah_verf.oa_base != NULL)
2N/A free(auth->ah_verf.oa_base);
2N/A free(auth);
2N/A}
2N/A
2N/A/*
2N/A * Marshals (pre-serializes) an auth struct.
2N/A * sets private data, au_marshed and au_mpos
2N/A */
2N/A
2N/Astatic const char marshal_new_auth_str[] =
2N/A "marshal_new_auth - Fatal marshalling problem";
2N/Astatic void
2N/Amarshal_new_auth(AUTH *auth)
2N/A{
2N/A XDR xdr_stream;
2N/A XDR *xdrs = &xdr_stream;
2N/A/* LINTED pointer alignment */
2N/A struct audata *au = AUTH_PRIVATE(auth);
2N/A
2N/A xdrmem_create(xdrs, au->au_marshed, MAX_AUTH_BYTES, XDR_ENCODE);
2N/A if ((!xdr_opaque_auth(xdrs, &(auth->ah_cred))) ||
2N/A (!xdr_opaque_auth(xdrs, &(auth->ah_verf)))) {
2N/A (void) syslog(LOG_ERR, marshal_new_auth_str);
2N/A } else {
2N/A au->au_mpos = XDR_GETPOS(xdrs);
2N/A }
2N/A XDR_DESTROY(xdrs);
2N/A}
2N/A
2N/Astatic struct auth_ops *
2N/Aauthsys_ops(void)
2N/A{
2N/A static struct auth_ops ops;
2N/A extern mutex_t ops_lock;
2N/A
2N/A /* VARIABLES PROTECTED BY ops_lock: ops */
2N/A
2N/A (void) mutex_lock(&ops_lock);
2N/A if (ops.ah_nextverf == NULL) {
2N/A ops.ah_nextverf = authsys_nextverf;
2N/A ops.ah_marshal = authsys_marshal;
2N/A ops.ah_validate = authsys_validate;
2N/A ops.ah_refresh = authsys_refresh;
2N/A ops.ah_destroy = authsys_destroy;
2N/A }
2N/A (void) mutex_unlock(&ops_lock);
2N/A return (&ops);
2N/A}