diff options
| author | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
|---|---|---|
| committer | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
| commit | 7c478bd95313f5f23a4c958a745db2134aa03244 (patch) | |
| tree | c871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/cmd/gss | |
| download | illumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz | |
OpenSolaris Launch
Diffstat (limited to 'usr/src/cmd/gss')
30 files changed, 10847 insertions, 0 deletions
diff --git a/usr/src/cmd/gss/Makefile b/usr/src/cmd/gss/Makefile new file mode 100644 index 0000000000..612db7e41e --- /dev/null +++ b/usr/src/cmd/gss/Makefile @@ -0,0 +1,92 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright (c) 1997 - 1998 by Sun Microsystems, Inc. +# All rights reserved. +# +#ident "%Z%%M% %I% %E% SMI" +# +# cmd/gss/Makefile +# +# include global definitions +include ../../Makefile.master + +COMMON_SUBDIRS= \ + etc \ + gssd \ + gsscred \ + gsscred_clean + +i386_SUBDIRS= + +sparc_SUBDIRS= + +# +# commands that are messaged +# note that 'lp' comes first (see previous comment about 'lp') +# +MSGSUBDIRS= gssd gsscred + +# +# commands that use dcgettext for localized time, LC_TIME +# +DCSUBDIRS= + +# +# commands that belong only to the basic security module +# +BSMSUBDIRS= + +# +# commands not owned by the systems group +# +BWOSDIRS= + +all := TARGET= all +install := TARGET= install +install_h := TARGET= install_h +check := TARGET= check +clean := TARGET= clean +clobber := TARGET= clobber +lint := TARGET= lint +_msg := TARGET= _msg +_dc := TARGET= _dc + +.KEEP_STATE: + +SUBDIRS = $(COMMON_SUBDIRS) $($(MACH)_SUBDIRS) + +.PARALLEL: $(BWOSDIRS) $(SUBDIRS) $(MSGSUBDIRS) $(BSMSUBDIRS) + +all install clean clobber lint: $(SUBDIRS) $(BSMSUBDIRS) + +# those commands which install headers possibly needed by other commands. +install_h check: + +_msg: $(MSGSUBDIRS) _dc + +_dc: $(DCSUBDIRS) + +$(BWOSDIRS) $(SUBDIRS) $(BSMSUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +FRC: diff --git a/usr/src/cmd/gss/etc/Makefile b/usr/src/cmd/gss/etc/Makefile new file mode 100644 index 0000000000..5acf736148 --- /dev/null +++ b/usr/src/cmd/gss/etc/Makefile @@ -0,0 +1,79 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright (c) 1996-2000 by Sun Microsystems, Inc. +# All rights reserved. +# + +include ../../Makefile.cmd + +TXTS= +GSSTXTS= mech qop gsscred.conf +KRB5TXTS= warn.conf krb5.conf kdc.conf kpropd.acl kadm5.acl + +IETCFILES= $(TXTS:%=$(ROOTETC)/%) +IETCGSSFILES= $(GSSTXTS:%=$(ROOTETC)/gss/%) +IETCKRB5FILES= $(KRB5TXTS:%=$(ROOTETC)/krb5/%) +GSSDIR= $(ROOTETC)/gss +KRB5DIR= $(ROOTETC)/krb5 + +FILEMODE= 0644 +OWNER= root +GROUP= sys + + +.KEEP_STATE: + +all: $(TXTS) $(GSSTXTS) dummy_mech_token.conf + +dummy_mech_token.conf: dummy_mech_token.conf.sh + $(RM) $@ + sh dummy_mech_token.conf.sh + +install: all $(GSSDIR) $(KRB5DIR) $(IETCFILES) $(IETCGSSFILES) $(IETCKRB5FILES) + +install_h: + +$(GSSDIR): + $(INS.dir) + +$(KRB5DIR): + $(INS.dir) + +$(ROOTETC)/%: % + $(INS.file) + +$(ROOTETC)/gss/%: % + $(INS.file) + +$(ROOTETC)/krb5/%: % + $(INS.file) + +FRC: + +include ../../Makefile.targ + +CLOBBERFILES += dummy_mech_token.conf + +clean lint: diff --git a/usr/src/cmd/gss/etc/dummy_mech b/usr/src/cmd/gss/etc/dummy_mech new file mode 100644 index 0000000000..665be95aee --- /dev/null +++ b/usr/src/cmd/gss/etc/dummy_mech @@ -0,0 +1,33 @@ +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# ident "%Z%%M% %I% %E% SMI" +# +# This file contains the GSS-API based security mechanism names, +# its object identifier (OID) and a shared library that implements +# the services for that mechanism under GSS-API. +# +# Mechanism Name Object Identifier Shared Library Kernel Module +# +dummy 1.3.6.1.4.1.42.2.26.1.2 mech_dummy.so kmech_dummy diff --git a/usr/src/cmd/gss/etc/dummy_mech_token.conf.sh b/usr/src/cmd/gss/etc/dummy_mech_token.conf.sh new file mode 100644 index 0000000000..12d7e69fad --- /dev/null +++ b/usr/src/cmd/gss/etc/dummy_mech_token.conf.sh @@ -0,0 +1,33 @@ +#!/bin/sh +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 1997 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +cat << EOF > dummy_mech_token.conf.tmp +2 +EOF + +chmod 0644 dummy_mech_token.conf.tmp +mv dummy_mech_token.conf.tmp dummy_mech_token.conf diff --git a/usr/src/cmd/gss/etc/dummy_nfssec.conf b/usr/src/cmd/gss/etc/dummy_nfssec.conf new file mode 100644 index 0000000000..daa1a9adcc --- /dev/null +++ b/usr/src/cmd/gss/etc/dummy_nfssec.conf @@ -0,0 +1,53 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright (c) 1997, by Sun Microsystems, Inc. +# All rights reserved. +# +#ident "%Z%%M% %I% %E% SMI" +# +# The NFS Security Service Configuration File. +# +# Each entry is of the form: +# +# <NFS_security_mode_name> <NFS_security_mode_number> \ +# <GSS_mechanism_name> <GSS_quality_of_protection> <GSS_services> +# +# +# The "-" in <GSS_mechanism_name> signifies that this is not a GSS mechanism. +# A string entry in <GSS_mechanism_name> is required for using RPCSEC_GSS +# services. <GSS_quality_of_protection> and <GSS_services> are optional. +# White space is not an acceptable value. +# +# default security mode is defined at the end. It should be one of +# the flavor numbers defined above it. +# +none 0 - - - # AUTH_NONE +sys 1 - - - # AUTH_SYS +dh 3 - - - # AUTH_DH +krb4 4 - - - # AUTH_KERB + +dummy 390000 dummy default - # RPCSEC_GSS +dummyi 390001 dummy default integrity # RPCSEC_GSS +dummyp 390002 dummy default privacy # RPCSEC_GSS + +default 1 - - - # default is AUTH_SYS diff --git a/usr/src/cmd/gss/etc/gsscred.conf b/usr/src/cmd/gss/etc/gsscred.conf new file mode 100644 index 0000000000..ec39891e23 --- /dev/null +++ b/usr/src/cmd/gss/etc/gsscred.conf @@ -0,0 +1,43 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" +# +# gsscred configuration file +# +# This is an optional configuration file to select the +# underlying gsscred backend used to store the gsscred +# table and to set options for the GSS Cred subsystem. +# +# NOTE: The only gsscred backend currently supported is `files' and +# use of this file to select the backend is deprecated and future +# releases of Solaris may not use this file to select the backend. +# +# +files +# +# +# Syslog (auth.debug) a message for GSS cred to Unix cred mapping +#SYSLOG_UID_MAPPING=yes diff --git a/usr/src/cmd/gss/etc/kadm5.acl b/usr/src/cmd/gss/etc/kadm5.acl new file mode 100644 index 0000000000..14e0fe1c68 --- /dev/null +++ b/usr/src/cmd/gss/etc/kadm5.acl @@ -0,0 +1,27 @@ +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +#pragma ident "%Z%%M% %I% %E% SMI" + +*/admin@___default_realm___ * diff --git a/usr/src/cmd/gss/etc/kdc.conf b/usr/src/cmd/gss/etc/kdc.conf new file mode 100644 index 0000000000..3248586f11 --- /dev/null +++ b/usr/src/cmd/gss/etc/kdc.conf @@ -0,0 +1,41 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 1998-2002 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" + +[kdcdefaults] + kdc_ports = 88,750 + +[realms] + ___default_realm___ = { + profile = /etc/krb5/krb5.conf + database_name = /var/krb5/principal + admin_keytab = /etc/krb5/kadm5.keytab + acl_file = /etc/krb5/kadm5.acl + kadmind_port = 749 + max_life = 8h 0m 0s + max_renewable_life = 7d 0h 0m 0s + default_principal_flags = +preauth + } diff --git a/usr/src/cmd/gss/etc/kpropd.acl b/usr/src/cmd/gss/etc/kpropd.acl new file mode 100644 index 0000000000..202bbea73a --- /dev/null +++ b/usr/src/cmd/gss/etc/kpropd.acl @@ -0,0 +1,25 @@ +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +#pragma ident "%Z%%M% %I% %E% SMI" diff --git a/usr/src/cmd/gss/etc/krb5.conf b/usr/src/cmd/gss/etc/krb5.conf new file mode 100644 index 0000000000..499046db65 --- /dev/null +++ b/usr/src/cmd/gss/etc/krb5.conf @@ -0,0 +1,69 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +# krb5.conf template +# In order to complete this configuration file +# you will need to replace the __<name>__ placeholders +# with appropriate values for your network. +# +[libdefaults] + default_realm = ___default_realm___ + +[realms] + ___default_realm___ = { + kdc = ___master_kdc___ + kdc = ___slave_kdc1___ + kdc = ___slave_kdc2___ + kdc = ___slave_kdcN___ + admin_server = ___master_kdc___ + } + +[domain_realm] + ___domainname___ = ___default_realm___ + +[logging] + default = FILE:/var/krb5/kdc.log + kdc = FILE:/var/krb5/kdc.log + kdc_rotate = { + +# How often to rotate kdc.log. Logs will get rotated no more +# often than the period, and less often if the KDC is not used +# frequently. + + period = 1d + +# how many versions of kdc.log to keep around (kdc.log.0, kdc.log.1, ...) + + versions = 10 + } + +[appdefaults] + kinit = { + renewable = true + forwardable= true + } diff --git a/usr/src/cmd/gss/etc/mech b/usr/src/cmd/gss/etc/mech new file mode 100644 index 0000000000..1d85453341 --- /dev/null +++ b/usr/src/cmd/gss/etc/mech @@ -0,0 +1,36 @@ +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +#ident "%Z%%M% %I% %E% SMI" +# +# This file contains the GSS-API based security mechanism names, +# its object identifier (OID) and a shared library that implements +# the services for that mechanism under GSS-API. +# +# Mechanism Name Object Identifier Shared Library Kernel Module [Options] +# +kerberos_v5 1.2.840.113554.1.2.2 mech_krb5.so kmech_krb5 +spnego 1.3.6.1.5.5.2 mech_spnego.so.1 [msinterop] +diffie_hellman_640_0 1.3.6.4.1.42.2.26.2.4 dh640-0.so.1 +diffie_hellman_1024_0 1.3.6.4.1.42.2.26.2.5 dh1024-0.so.1 diff --git a/usr/src/cmd/gss/etc/qop b/usr/src/cmd/gss/etc/qop new file mode 100644 index 0000000000..151ebdad26 --- /dev/null +++ b/usr/src/cmd/gss/etc/qop @@ -0,0 +1,33 @@ +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +#ident "%Z%%M% %I% %E% SMI" +# +# This file contains information about the GSS-API based quality of +# protection (QOP), its string name and its value (32-bit integer). +# +# QOP string QOP Value Mechanism Name +# +GSS_KRB5_INTEG_C_QOP_DES_MD5 0 kerberos_v5 +GSS_KRB5_CONF_C_QOP_DES 0 kerberos_v5 diff --git a/usr/src/cmd/gss/etc/warn.conf b/usr/src/cmd/gss/etc/warn.conf new file mode 100644 index 0000000000..61ff3220aa --- /dev/null +++ b/usr/src/cmd/gss/etc/warn.conf @@ -0,0 +1,33 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#pragma ident "%Z%%M% %I% %E% SMI" +# +# <principal> [renew:<opt1,...optN>] syslog|terminal <time> +# or +# <principal> [renew:<opt1,...optN>] mail <time> [<e-mail address>] +# +# +* renew:log-failure terminal 30m diff --git a/usr/src/cmd/gss/gsscred/Makefile b/usr/src/cmd/gss/gsscred/Makefile new file mode 100644 index 0000000000..5d3de70fbd --- /dev/null +++ b/usr/src/cmd/gss/gsscred/Makefile @@ -0,0 +1,95 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +SBINPROG = gsscred + +INCDIRS = -I. -I$(ROOT)/usr/include + +LIBPATH = -L$(ROOT)/usr/lib + +PROG= $(SBINPROG) + +GSSCREDOBJS = gsscred.o gsscred_utils.o gsscred_file.o + +OBJS = $(GSSCREDOBJS) +SRCS = $(OBJS:.o=.c) + +include ../../Makefile.cmd + +TEXT_DOMAIN = SUNW_OST_NETRPC +POFILE = $(PROG).po +POFILES = generic.po + +ROOTBINPROG= $(BINPROG:%=$(ROOTBIN)/%) + +$(ROOTUSRSBIN)/gsscred := OWNER= root +$(ROOTUSRSBIN)/gsscred := GROUP= sys + +COPTFLAG += $(XESS) $(INCDIRS) $(LIBPATH) + +LDLIBS += -lgss + +$(GPROGS) := CPPFLAGS += -DSYSV -DSunOS=50 + +.KEEP_STATE: + +all: $(PROG) + +gsscred: $(OBJS) + $(LINK.c) $(OBJS) -o $@ $(LDLIBS) + $(POST_PROCESS) + +$(ROOTBINPROG): + $(INS.dir) + +$(ROOTUSRSBIN)/%: % + $(INS.file) + +install: all $(DIRS) $(ROOTBINPROG) $(ROOTUSRSBIN)/gsscred + +install_h: + +clean: + $(RM) $(OBJS) + $(RM) $(PROG) + +lint: lint_SRCS + +include ../../Makefile.targ + +$(POFILE): $(DERIVED_FILES) .WAIT $(POFILES) + $(RM) $@ + $(CAT) $(POFILES) > $@ + +generic.po: FRC + $(RM) messages.po + $(XGETTEXT) $(XGETFLAGS) `$(GREP) -l gettext *.[ch]` + $(SED) "/^domain/d" messages.po > $@ + $(RM) messages.po + +FRC: diff --git a/usr/src/cmd/gss/gsscred/gsscred.c b/usr/src/cmd/gss/gsscred/gsscred.c new file mode 100644 index 0000000000..17937778a6 --- /dev/null +++ b/usr/src/cmd/gss/gsscred/gsscred.c @@ -0,0 +1,753 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 1997-2002 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * gsscred utility + * Manages mapping between a security principal name and unix uid + */ + +#include <stdio.h> +#include <stdlib.h> +#include <pwd.h> +#include <unistd.h> +#include <string.h> +#include <gssapi/gssapi_ext.h> +#include "gsscred.h" + +#define MAX_STR_LEN 1024 + + +/* + * Internal Functions + */ +static void usage(void); +static void addUser(const char *name, const char *oid, const char *userUid, + const char *userComment, const char *userMech); +static int file_listUsers(const gss_OID mechOid, const char *userUid, + char **errDetails); +static int listUsers(const char *name, const char *nameTypeOid, + const char *uid, const char *mechOid); +static int file_removeUsers(const gss_OID mechOid, const char *userUid, + char **errDetails); +static int removeUsers(const char *name, const char *nameTypeOid, + const char *uid, const char *mechOid); + +/* + * Global variables + */ +static int tableSource; +static char *PROG_NAME = NULL; + +int +main(int argc, char *args[]) +{ + char *userName = NULL, *nameTypeOID = NULL, + *uid = NULL, *comment = NULL, *mech = NULL, + operation = '0'; + int c, errflag = 0; + extern char *optarg; + + PROG_NAME = *args; + + /* set locale and domain for internationalization */ + setlocale(LC_ALL, ""); + textdomain(TEXT_DOMAIN); + + if (argc < 2) + usage(); + + /* Process the input arguments */ + while ((c = getopt(argc, args, "arln:o:u:m:c:")) != EOF) { + + switch (c) { + case 'n': + userName = optarg; + break; + + case 'o': + nameTypeOID = optarg; + break; + + case 'u': + uid = optarg; + break; + + case 'm': + mech = optarg; + break; + + case 'c': + comment = optarg; + break; + + case 'a': + case 'r': + case 'l': + operation = c; + errflag++; + if (errflag > 1) + usage(); + break; + + default: + usage(); + } + } + + /* determine which back-end to use as the gsscred store */ + tableSource = gsscred_read_config_file(); + + /* perform the requested operation */ + switch (operation) { + case 'a': + addUser(userName, nameTypeOID, uid, comment, mech); + break; + + case 'r': + removeUsers(userName, nameTypeOID, uid, mech); + break; + + case 'l': + listUsers(userName, nameTypeOID, uid, mech); + break; + + default: + usage(); + } + fprintf(stdout, "\n"); + return (0); +} /* main */ + +/* + * Handles the addition of users to the gsscred table. + */ +static void +addUser(const char *name, const char *nameOidStr, + const char *userUid, const char *userComment, + const char *mechOidStr) +{ + gss_OID mechOid; + gss_buffer_desc fullName = GSS_C_EMPTY_BUFFER, + hexBufDesc = GSS_C_EMPTY_BUFFER, + hexMechOid = GSS_C_EMPTY_BUFFER; + char comment[MAX_STR_LEN+1], hexBuf[MAX_STR_LEN+MAX_STR_LEN+1], + hexMechOidBuf[MAX_STR_LEN+1], *commentPtr = NULL, + *errDetail = NULL, uidStr[256], *uidPtr; + struct passwd *aUser; + OM_uint32 minor; + int count = 0, retCode; + + hexMechOid.length = MAX_STR_LEN; + hexMechOid.value = (void*)hexMechOidBuf; + + /* addition of users can only be performed by super users */ + if (getuid()) { + fprintf(stderr, + gettext("\nUser addition requires" + " root privileges.")); + return; + } + + /* the mechanism OID is required */ + if (mechOidStr == NULL) { + fprintf(stderr, gettext("\nUnspecified mechanism.")); + usage(); + } + + /* Convert from string mechanism Oid to ASN.1 oid and then hex */ + if (__gss_mech_to_oid(mechOidStr, &mechOid) != GSS_S_COMPLETE) { + fprintf(stderr, + gettext("\nInvalid mechanism specified [%s]."), + mechOidStr); + return; + } + + hexBufDesc.length = mechOid->length; + hexBufDesc.value = mechOid->elements; + + if (!gsscred_AsHex(&hexBufDesc, &hexMechOid)) { + fprintf(stderr, + gettext("\nInternal error. " + "Conversion to hex failed.")); + return; + } + + /* + * if the name is specified, then do single addition. + * Might have to look up the uid. + */ + if (name != NULL) { + hexBufDesc.length = sizeof (hexBuf); + hexBufDesc.value = hexBuf; + + /* build the name as needed */ + if (!gsscred_MakeName(mechOid, name, nameOidStr, &fullName)) { + fprintf(stderr, + gettext("\nError adding user [%s]."), name); + return; + } + + /* convert it to hex */ + if (!gsscred_AsHex(&fullName, &hexBufDesc)) { + gss_release_buffer(&minor, &fullName); + fprintf(stderr, + gettext("\nInternal error. " + "Conversion to hex failed.")); + return; + } + + /* might require the lookup of the uid if one not specified */ + if (userUid == NULL) { + + if ((aUser = getpwnam(name)) == NULL) { + fprintf(stderr, + gettext("\nUnable to obtain password" + " information for [%s]."), + name); + gss_release_buffer(&minor, &fullName); + return; + } + sprintf(uidStr, "%ld", aUser->pw_uid); + uidPtr = uidStr; + } + else + uidPtr = (char *)userUid; + + if (userComment == NULL) { + sprintf(comment, "%s, %s", name, mechOidStr); + commentPtr = comment; + } else + commentPtr = (char *)userComment; + + if (tableSource == GSSCRED_FLAT_FILE) + retCode = file_addGssCredEntry(&hexBufDesc, + uidPtr, commentPtr, &errDetail); + else + /* other backends (ldap, dss) coming soon */ + retCode = 0; + + if (!retCode) { + fprintf(stderr, gettext("\nError adding user [%s]."), + commentPtr); + + if (errDetail) { + fprintf(stderr, "\n%s\n", errDetail); + free(errDetail); + errDetail = NULL; + } + } + + gss_release_buffer(&minor, &fullName); + return; + } + + /* + * since no name specified, then we will load everyone from + * password table. This means that -u and -o options are invalid. + * We just ignore it, but we could flag it as error. + */ + setpwent(); + + while ((aUser = getpwent()) != NULL) { + hexBufDesc.length = sizeof (hexBuf); + hexBufDesc.value = hexBuf; + + if (!gsscred_MakeName(mechOid, aUser->pw_name, + nameOidStr, &fullName)) { + fprintf(stderr, + gettext("\nError adding user [%s]."), + aUser->pw_name); + continue; + } + + if (!gsscred_AsHex(&fullName, &hexBufDesc)) { + gss_release_buffer(&minor, &fullName); + fprintf(stderr, + gettext("\nInternal error. " + "Conversion to hex failed.")); + continue; + } + + sprintf(uidStr, "%ld", aUser->pw_uid); + sprintf(comment, "%s, %s", aUser->pw_name, mechOidStr); + if (tableSource == GSSCRED_FLAT_FILE) + retCode = file_addGssCredEntry(&hexBufDesc, + uidStr, comment, &errDetail); + else + retCode = 0; + + if (!retCode) { + fprintf(stderr, + gettext("\nError adding user [%s]."), + comment); + + if (errDetail) { + fprintf(stderr, "\n%s\n", errDetail); + free(errDetail); + errDetail = NULL; + } + } else { + count++; + if ((count % 50) == 0) + fprintf(stdout, + gettext("\n[%d] users added..."), + count); + } + gss_release_buffer(&minor, &fullName); + } + endpwent(); +} /* addUser */ + + +/* + * Handles the searching of the gsscred table. + */ +static int listUsers(const char *name, const char *nameOidStr, + const char *uidStr, const char *mechOidStr) +{ + GssCredEntry *entryPtr, *entryTmpPtr; + char hexMech[256], + hexName[(MAX_STR_LEN *2) + 1]; + gss_OID anOid = NULL, userMechOid = NULL; + gss_OID_set mechSet = NULL; + gss_buffer_desc inBufDesc = GSS_C_EMPTY_BUFFER, + outBufDesc = GSS_C_EMPTY_BUFFER, + searchName = GSS_C_EMPTY_BUFFER; + int status = 1, numOfMechs, i; + OM_uint32 minor; + char *errDetails = NULL; + + /* Do we need to convert the mechanism oid? */ + if (mechOidStr != NULL) { + + if (__gss_mech_to_oid(mechOidStr, &userMechOid) != + GSS_S_COMPLETE) { + fprintf(stderr, + gettext("\nInvalid mechanism specified [%s]."), + mechOidStr); + return (0); + } + inBufDesc.length = userMechOid->length; + inBufDesc.value = userMechOid->elements; + outBufDesc.length = sizeof (hexMech); + outBufDesc.value = hexMech; + + if (!gsscred_AsHex(&inBufDesc, &outBufDesc)) { + fprintf(stderr, + gettext("\nInternal error. " + "Conversion to hex failed.")); + status = 0; + goto cleanup; + } + + } /* mechOidStr != NULL */ + + /* are we retrieving everyone ? or searching by mech ? */ + if ((name == NULL && uidStr == NULL && mechOidStr == NULL) || + (name == NULL && uidStr == NULL)) { + + if (tableSource == GSSCRED_FLAT_FILE) { + file_listUsers(userMechOid, NULL, &errDetails); + + if (errDetails) { + fprintf(stderr, + gettext("\nError searching gsscred" + " table [%s]."), + errDetails); + free(errDetails); + errDetails = NULL; + return (0); + } + return (1); + } + + } + + /* Are we searching by uid or uid and mech? */ + if (name == NULL && uidStr != NULL) { + + if (tableSource == GSSCRED_FLAT_FILE) + file_listUsers(userMechOid, uidStr, &errDetails); + else { + entryPtr = NULL; + while (entryPtr != NULL) { + fprintf(stdout, "\n%s\t%d\t%s", + entryPtr->principal_name, + entryPtr->unix_uid, entryPtr->comment); + free(entryPtr->principal_name); + free(entryPtr->comment); + entryTmpPtr = entryPtr->next; + free(entryPtr); + entryPtr = entryTmpPtr; + } + } + + /* check for any errors */ + if (errDetails) { + fprintf(stderr, + gettext("\nError searching gsscred table " + "[%s]."), + errDetails); + free(errDetails); + errDetails = NULL; + status = 0; + } + + goto cleanup; + } + + /* + * We are searching by name; + * how many mechs must we check? + */ + if (mechOidStr == NULL) { + + if (gss_indicate_mechs(&minor, &mechSet) != GSS_S_COMPLETE) { + fprintf(stderr, + gettext("\nInternal error. " + "GSS-API call failed.")); + return (0); + } + numOfMechs = mechSet->count; + } + else + numOfMechs = 1; + + /* now look through all the mechs searching */ + for (i = 0; i < numOfMechs; i++) { + + if (mechOidStr == NULL) { + anOid = &mechSet->elements[i]; + inBufDesc.length = anOid->length; + inBufDesc.value = anOid->elements; + outBufDesc.length = sizeof (hexMech); + outBufDesc.value = hexMech; + + if (!gsscred_AsHex(&inBufDesc, &outBufDesc)) + continue; + } else + anOid = userMechOid; + + /* create a gss name */ + if (!gsscred_MakeName(anOid, name, nameOidStr, &outBufDesc)) + continue; + + /* now convert it to hex, and find it */ + searchName.value = hexName; + searchName.length = sizeof (hexName); + status = gsscred_AsHex(&outBufDesc, &searchName); + free(outBufDesc.value); + + if (!status) + continue; + + if (tableSource == GSSCRED_FLAT_FILE) + file_getGssCredEntry(&searchName, uidStr, &errDetails); + else { + entryPtr = NULL; /* other backends coming soon */ + while (entryPtr != NULL) { + fprintf(stdout, "\n%s\t%d\t%s", + entryPtr->principal_name, + entryPtr->unix_uid, entryPtr->comment); + free(entryPtr->principal_name); + free(entryPtr->comment); + entryTmpPtr = entryPtr->next; + free(entryPtr); + entryPtr = entryTmpPtr; + } + } + + /* any errors to display */ + if (errDetails) { + fprintf(stderr, + gettext("\nError searching gsscred table " + "[%s]."), + errDetails); + free(errDetails); + errDetails = NULL; + status = 0; + } + } /* for */ + +cleanup: + if (mechSet != NULL) + gss_release_oid_set(&minor, &mechSet); + + return (status); +} /* listUsers */ + +/* + * Performs additional handling while searching for users + * stored in the flat file table. + */ +int +file_listUsers(const gss_OID mechOid, const char *unixUid, + char **errDetails) +{ + gss_buffer_desc mechBufDesc = GSS_C_EMPTY_BUFFER, + mechHexBufDesc = GSS_C_EMPTY_BUFFER; + char mechBuf[128], mechHexBuf[256]; + + if (mechOid != NULL) { + /* must make the name header whic contains mech oid */ + mechBufDesc.value = (void *) mechBuf; + mechBufDesc.length = sizeof (mechBuf); + mechHexBufDesc.value = (void*) mechHexBuf; + mechHexBufDesc.length = sizeof (mechHexBuf); + + if ((!gsscred_MakeNameHeader(mechOid, &mechBufDesc)) || + (!gsscred_AsHex(&mechBufDesc, &mechHexBufDesc))) { + (*errDetails) = strdup( + gettext("\nInternal error. " + " Conversion to hex failed.")); + return (0); + } + + return (file_getGssCredEntry(&mechHexBufDesc, + unixUid, errDetails)); + } + + return (file_getGssCredEntry(NULL, unixUid, errDetails)); +} /* file_listUsers */ + + +/* + * Handles the deletion of users. + */ +static int removeUsers(const char *name, const char *nameOidStr, + const char *uidStr, const char *mechOidStr) +{ + char hexMech[256], + hexName[(MAX_STR_LEN *2) + 1], + *errDetails = NULL; + gss_OID anOid = NULL, userMechOid = NULL; + gss_OID_set mechSet = NULL; + gss_buffer_desc inBufDesc = GSS_C_EMPTY_BUFFER, + outBufDesc = GSS_C_EMPTY_BUFFER, + searchName = GSS_C_EMPTY_BUFFER; + int status = 0, numOfMechs, i; + OM_uint32 minor; + + + /* user deletion can only be performed by super user */ + if (getuid()) { + + fprintf(stderr, + gettext("\nUser deletion requires" + " root privileges.")); + return (0); + } + + /* do we need to convert the mechanism oid? */ + if (mechOidStr != NULL) { + if (__gss_mech_to_oid(mechOidStr, &userMechOid) != + GSS_S_COMPLETE) { + fprintf(stderr, + gettext("\nInvalid mechanism specified [%s]."), + mechOidStr); + return (0); + } + + inBufDesc.length = userMechOid->length; + inBufDesc.value = userMechOid->elements; + outBufDesc.length = sizeof (hexMech); + outBufDesc.value = hexMech; + + if (!gsscred_AsHex(&inBufDesc, &outBufDesc)) { + fprintf(stderr, + gettext("\nInternal error." + " Conversion to hex failed.")); + status = 0; + goto cleanup; + } + + } /* mechOidStr != NULL */ + + /* are we deleting the entire table or an entire mech ? */ + if (name == NULL && uidStr == NULL) { + + if (tableSource == GSSCRED_FLAT_FILE) + status = file_removeUsers(userMechOid, + NULL, &errDetails); + else + status = 0; + + /* display any errors */ + if (errDetails) { + fprintf(stderr, + gettext("\nError deleting gsscred entry " + "[%s]."), + errDetails); + free(errDetails); + errDetails = NULL; + } + goto cleanup; + } + + /* are we deleting by uid or uid and mech? */ + if (name == NULL && uidStr != NULL) { + + if (tableSource == GSSCRED_FLAT_FILE) + status = file_removeUsers(userMechOid, uidStr, + &errDetails); + else + status = 0; + + /* check for any errors */ + if (errDetails) { + fprintf(stderr, + gettext("\nError deleting gsscred entry " + "[%s]."), + errDetails); + free(errDetails); + errDetails = NULL; + } + goto cleanup; + } + + /* + * We are deleting by name; + * how many mechs must we check? + */ + if (mechOidStr == NULL) { + + if (gss_indicate_mechs(&minor, &mechSet) != GSS_S_COMPLETE) { + fprintf(stderr, + gettext("\nInternal error. " + "GSS-API call failed.")); + status = 0; + goto cleanup; + } + numOfMechs = mechSet->count; + } + else + numOfMechs = 1; + + /* now look through all the mechs, deleting */ + for (i = 0; i < numOfMechs; i++) { + + if (mechOidStr == NULL) { + anOid = &mechSet->elements[i]; + inBufDesc.length = anOid->length; + inBufDesc.value = anOid->elements; + outBufDesc.length = sizeof (hexMech); + outBufDesc.value = hexMech; + if (!gsscred_AsHex(&inBufDesc, &outBufDesc)) + continue; + } else + anOid = userMechOid; + + /* create a gss name */ + if (!gsscred_MakeName(anOid, name, nameOidStr, &outBufDesc)) + continue; + + /* now convert it to hex, and delete it */ + searchName.value = hexName; + searchName.length = sizeof (hexName); + status = gsscred_AsHex(&outBufDesc, &searchName); + free(outBufDesc.value); + + if (!status) + continue; + + if (tableSource == GSSCRED_FLAT_FILE) + status = file_deleteGssCredEntry(&searchName, + uidStr, &errDetails); + else + status = 0; + + /* check for any errors */ + if (errDetails) { + fprintf(stderr, + gettext("\nError deleting gsscred entry" + " [%s]."), + errDetails); + free(errDetails); + errDetails = NULL; + } + } /* for */ + +cleanup: + if (mechSet != NULL) + gss_release_oid_set(&minor, &mechSet); + + return (status); +} /* removeUsers */ + + +/* + * Performs additional handling while deleting users + * stored in the flat file table. + */ +int file_removeUsers(const gss_OID mechOid, const char *unixUid, + char **errDetails) +{ + gss_buffer_desc mechBufDesc = GSS_C_EMPTY_BUFFER, + mechHexBufDesc = GSS_C_EMPTY_BUFFER; + char mechBuf[128], mechHexBuf[256]; + + if (mechOid != NULL) { + /* + * need to create the buffer header which contains + * the mechanism oid. + */ + mechBufDesc.value = (void*) mechBuf; + mechBufDesc.length = sizeof (mechBuf); + mechHexBufDesc.value = (void *) mechHexBuf; + mechHexBufDesc.length = sizeof (mechHexBuf); + + if ((!gsscred_MakeNameHeader(mechOid, &mechBufDesc)) || + (!gsscred_AsHex(&mechBufDesc, &mechHexBufDesc))) { + (*errDetails) = strdup( + gettext("\nInternal error." + " Conversion to hex failed.")); + return (0); + } + + return (file_deleteGssCredEntry(&mechHexBufDesc, unixUid, + errDetails)); + } + + return (file_deleteGssCredEntry(NULL, unixUid, errDetails)); +} /* file_removeUsers */ + + +/* + * Prints the usage string, and terminates. + */ +static void usage(void) +{ + + fprintf(stderr, + gettext("\nUsage:\t %s [-n user [-o oid] [-u uid]]" + " [-c comment] -m mech -a" + "\n\t %s [-n user [-o oid]] [-u uid] [-m mech] -r" + "\n\t %s [-n user [-o oid]] [-u uid] [-m mech] -l\n"), + PROG_NAME, PROG_NAME, PROG_NAME); + exit(1); +} /* usage */ diff --git a/usr/src/cmd/gss/gsscred/gsscred.h b/usr/src/cmd/gss/gsscred/gsscred.h new file mode 100644 index 0000000000..a1174df5e4 --- /dev/null +++ b/usr/src/cmd/gss/gsscred/gsscred.h @@ -0,0 +1,94 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 1997-2002 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * gsscred utility + * + * Manages mapping between a security principal + * name and unix uid. + */ + +#ifndef _GSSCRED_H +#define _GSSCRED_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <libintl.h> +#include <locale.h> +#include <gssapi/gssapi.h> +#include <pwd.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(TEXT_DOMAIN) +#define TEXT_DOMAIN "SUNW_OST_OSCMD" +#endif + +#define GSSCRED_FLAT_FILE -1 + +/* Structure to hold GSS credentials for each entry */ +typedef struct GssCredEntry_t { + char *principal_name; + int unix_uid; + char *comment; + struct GssCredEntry_t *next; +} GssCredEntry; + +/* + * Misc functions in gsscred. + */ +int gsscred_AsHex(const gss_buffer_t inBuf, gss_buffer_t outBuf); +int gsscred_MakeName(const gss_OID mechOid, const char *name, + const char *nameOid, gss_buffer_t OutName); +int gsscred_read_config_file(void); +int gsscred_MakeNameHeader(const gss_OID mechOid, gss_buffer_t outNameHdr); + + +/* + * Flat file based gsscred functions. + */ +int file_addGssCredEntry(const gss_buffer_t hexName, const char *uid, + const char *comment, char **errDetails); +int file_getGssCredEntry(const gss_buffer_t name, const char *uid, + char **errDetails); +int file_deleteGssCredEntry(const gss_buffer_t name, const char *uid, + char **errDetails); +int file_getGssCredUid(const gss_buffer_t name, uid_t *uidOut); + + +/* + * GSS entry point for retrieving user uid information based on + * exported name buffer. + */ +int gss_getGssCredEntry(const gss_buffer_t expName, uid_t *uid); + +#ifdef __cplusplus +} +#endif + +#endif /* _GSSCRED_H */ diff --git a/usr/src/cmd/gss/gsscred/gsscred_file.c b/usr/src/cmd/gss/gsscred/gsscred_file.c new file mode 100644 index 0000000000..2f569900ea --- /dev/null +++ b/usr/src/cmd/gss/gsscred/gsscred_file.c @@ -0,0 +1,296 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <ctype.h> +#include "gsscred.h" + +/* + * gsscred utility + * Manages mapping between a security principal name and unix uid. + * Implementation file for the file based gsscred utility. + */ + +#define MAX_ENTRY_LEN 1024 +static const char credFile[] = "/etc/gss/gsscred_db"; +static const char credFileTmp[] = "/etc/gss/gsscred_db.tmp"; + +static int matchEntry(const char *entry, const gss_buffer_t name, + const char *uid, uid_t *uidOut); + +/* + * file_addGssCredEntry + * + * Adds a new entry to the gsscred table. + * Does not check for duplicate entries. + */ +int file_addGssCredEntry(const gss_buffer_t hexName, const char *uid, + const char *comment, char **errDetails) +{ + FILE *fp; + char tmpBuf[256]; + + if ((fp = fopen(credFile, "a")) == NULL) { + if (errDetails) { + (void) snprintf(tmpBuf, sizeof (tmpBuf), + gettext("Unable to open gsscred file [%s]"), + credFile); + *errDetails = strdup(tmpBuf); + } + return (0); + } + + (void) fprintf(fp, + "%s\t%s\t%s\n", (char *)hexName->value, uid, comment); + (void) fclose(fp); + return (1); +} /* ******* file_addGssCredEntry ****** */ + + + +/* + * file_getGssCredEntry + * + * Searches the file for the file matching the name. Since the name + * contains a mechanism identifier, to search for all names for a given + * mechanism just supply the mechanism portion in the name buffer. + * To search by uid only, supply a non-null value of uid. + */ +int file_getGssCredEntry(const gss_buffer_t name, const char *uid, + char **errDetails) +{ + FILE *fp; + char entry[MAX_ENTRY_LEN+1]; + + if ((fp = fopen(credFile, "r")) == NULL) { + + if (errDetails) { + (void) snprintf(entry, sizeof (entry), + gettext("Unable to open gsscred file [%s]"), + credFile); + *errDetails = strdup(entry); + } + + return (0); + } + + /* go through the file in sequential order */ + while (fgets(entry, MAX_ENTRY_LEN, fp) != NULL) { + /* is there any search criteria */ + if (name == NULL && uid == NULL) { + (void) fprintf(stdout, "%s", entry); + continue; + } + + if (matchEntry(entry, name, uid, NULL)) + (void) fprintf(stdout, "%s", entry); + + } /* while */ + + (void) fclose(fp); + return (1); +} /* file_getGssCredEntry */ + +/* + * file_getGssCredUid + * + * GSS entry point for retrieving user uid information. + * We need to go through the entire file to ensure that + * the last matching entry is retrieved - this is because + * new entries are added to the end, and in case of + * duplicates we want to get the latest entry. + */ +int +file_getGssCredUid(const gss_buffer_t expName, uid_t *uidOut) +{ + FILE *fp; + char entry[MAX_ENTRY_LEN+1]; + int retVal = 0; + + if ((fp = fopen(credFile, "r")) == NULL) + return (0); + + /* go through the entire file in sequential order */ + while (fgets(entry, MAX_ENTRY_LEN, fp) != NULL) { + if (matchEntry(entry, expName, NULL, uidOut)) { + retVal = 1; + } + } /* while */ + + (void) fclose(fp); + return (retVal); +} /* file_getGssCredUid */ + + + +/* + * + * file_deleteGssCredEntry + * + * removes entries form file that match the delete criteria + */ +int file_deleteGssCredEntry(const gss_buffer_t name, const char *uid, + char **errDetails) +{ + FILE *fp, *tempFp; + char entry[MAX_ENTRY_LEN+1]; + int foundOne = 0; + + /* are we deleting everyone? */ + if (name == NULL && uid == NULL) { + + if ((fp = fopen(credFile, "w")) == NULL) { + + if (errDetails) { + (void) snprintf(entry, sizeof (entry), + gettext("Unable to open gsscred" + " file [%s]"), + credFile); + *errDetails = strdup(entry); + } + return (0); + } + + (void) fclose(fp); + return (1); + } + + /* selective delete - might still be everyone */ + if ((fp = fopen(credFile, "r")) == NULL) { + + if (errDetails) { + (void) snprintf(entry, sizeof (entry), + gettext("Unable to open gsscred file [%s]"), + credFile); + *errDetails = strdup(entry); + } + return (0); + } + + /* also need to open temp file */ + if ((tempFp = fopen(credFileTmp, "w")) == NULL) { + if (errDetails) { + (void) snprintf(entry, sizeof (entry), + gettext("Unable to open gsscred temporary" + " file [%s]"), + credFileTmp); + *errDetails = strdup(entry); + } + + (void) fclose(fp); + return (0); + } + + /* go through all the entries sequentially removing ones that match */ + while (fgets(entry, MAX_ENTRY_LEN, fp) != NULL) { + + if (!matchEntry(entry, name, uid, NULL)) + (void) fputs(entry, tempFp); + else + foundOne = 1; + } + (void) fclose(tempFp); + (void) fclose(fp); + + /* now make the tempfile the gsscred file */ + (void) rename(credFileTmp, credFile); + (void) unlink(credFileTmp); + + if (!foundOne) { + *errDetails = strdup(gettext("No users found")); + return (0); + } + return (1); +} /* file_deleteGssCredEntry */ + + + +/* + * + * match entry + * + * checks if the specified entry matches the supplied criteria + * returns 1 if yes, 0 if no + * uidOut value can be used to retrieve the uid from the entry + * when the uid string is passed in, the uidOut value is not set + */ +static int matchEntry(const char *entry, const gss_buffer_t name, + const char *uid, uid_t *uidOut) +{ + char fullEntry[MAX_ENTRY_LEN+1], *item; + char dilims[] = "\t \n"; + + + if (entry == NULL || isspace(*entry)) + return (0); + + /* save the entry since strtok will chop it up */ + (void) strcpy(fullEntry, entry); + + if ((item = strtok(fullEntry, dilims)) == NULL) + return (0); + + /* do wee need to search the name */ + if (name != NULL) { + /* we can match the prefix of the string */ + if (strlen(item) < name->length) + return (0); + + /* check if the prefix of the name matches */ + if (memcmp(item, name->value, name->length) != 0) + return (0); + + /* do we need to check the uid - if not then we found it */ + if (uid == NULL) { + /* do we ned to parse out the uid ? */ + if (uidOut) { + if ((item = strtok(NULL, dilims)) == NULL) + return (0); + *uidOut = atol(item); + } + return (1); + } + + /* continue with checking the uid */ + } + + if (uid == NULL) + return (1); + + /* get the next token from the string - the uid */ + if ((item = strtok(NULL, dilims)) == NULL) + return (0); + + if (strcmp(item, uid) == 0) + return (1); + + return (0); +} /* ******* matchEntry ****** */ diff --git a/usr/src/cmd/gss/gsscred/gsscred_utils.c b/usr/src/cmd/gss/gsscred/gsscred_utils.c new file mode 100644 index 0000000000..a5fc634238 --- /dev/null +++ b/usr/src/cmd/gss/gsscred/gsscred_utils.c @@ -0,0 +1,307 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * + * gsscred utility + * Manages mapping between a security principal name and unix uid + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <ctype.h> +#include "gsscred.h" + +/* From g_glue.c */ + +extern int +get_der_length(unsigned char **, unsigned int, unsigned int *); + +extern unsigned int +der_length_size(unsigned int); + +extern int +put_der_length(unsigned int, unsigned char **, unsigned int); + + + +/* + * GSS export name constants + */ +static const char *expNameTokId = "\x04\x01"; +static const int expNameTokIdLen = 2; +static const int mechOidLenLen = 2; +static const int mechOidTagLen = 1; + + +/* + * Internal utility routines. + */ + +/* + * gsscred_read_config_file + * + * function to read the optional gsscred configuration file + * which specifies which backend to use to store the gsscred + * table. + * + * we now only support flat files (btw, this file for backend is Obsoleted + * by PSARC) + */ +int +gsscred_read_config_file(void) +{ + return (GSSCRED_FLAT_FILE); +} /* gsscred_read_config_file */ + + +/* + * gsscred_MakeName + * + * construct a principal name in the GSS_C_NT_EXPORT_NAME format. + */ +int gsscred_MakeName(const gss_OID mechOid, const char *name, + const char *nameOidStr, gss_buffer_t nameOut) +{ + gss_OID nameOid; + gss_name_t intName; + OM_uint32 minor, major; + gss_buffer_desc aName = GSS_C_EMPTY_BUFFER, oidStr; + + nameOut->length = 0; + nameOut->value = NULL; + + /* we need to import the name, then canonicalize it, then export it */ + if (nameOidStr == NULL) + nameOid = (gss_OID)GSS_C_NT_USER_NAME; + else { + oidStr.length = strlen(nameOidStr); + oidStr.value = (void *)nameOidStr; + if (gss_str_to_oid(&minor, &oidStr, &nameOid) != + GSS_S_COMPLETE) { + (void) fprintf(stderr, + gettext("\nInvalid name oid supplied [%s].\n"), + nameOidStr); + return (0); + } + } + + /* first import the name */ + aName.length = strlen(name); + aName.value = (void*)name; + major = gss_import_name(&minor, &aName, nameOid, &intName); + if (nameOidStr != NULL) { + free(nameOid->elements); + free(nameOid); + } + + if (major != GSS_S_COMPLETE) { + (void) fprintf(stderr, + gettext("\nInternal error importing name [%s].\n"), + name); + return (0); + } + + /* now canonicalize the name */ + if (gss_canonicalize_name(&minor, intName, mechOid, NULL) + != GSS_S_COMPLETE) { + (void) fprintf(stderr, + gettext("\nInternal error canonicalizing name" + " [%s].\n"), + name); + (void) gss_release_name(&minor, &intName); + return (0); + } + + /* now convert to export format */ + if (gss_export_name(&minor, intName, nameOut) != GSS_S_COMPLETE) { + (void) fprintf(stderr, + gettext("\nInternal error exporting name [%s].\n"), + name); + (void) gss_release_name(&minor, &intName); + return (0); + } + + (void) gss_release_name(&minor, &intName); + return (1); +} /* ******* makeName ****** */ + + +/* + * Constructs a part of the GSS_NT_EXPORT_NAME + * Only the mechanism independent name part is created. + */ +int +gsscred_MakeNameHeader(const gss_OID mechOid, gss_buffer_t outNameHdr) +{ + unsigned char *buf = NULL; + int mechOidDERLength, mechOidLength; + + /* determine the length of buffer needed */ + mechOidDERLength = der_length_size(mechOid->length); + outNameHdr->length = mechOidLenLen + mechOidTagLen + + mechOidDERLength + expNameTokIdLen + mechOid->length; + if ((outNameHdr->value = (void*)malloc(outNameHdr->length)) == NULL) { + outNameHdr->length = 0; + return (0); + } + + /* start by putting the token id */ + buf = (unsigned char *) outNameHdr->value; + (void) memset(outNameHdr->value, '\0', outNameHdr->length); + (void) memcpy(buf, expNameTokId, expNameTokIdLen); + buf += expNameTokIdLen; + + /* + * next 2 bytes contain the mech oid length (includes + * DER encoding) + */ + mechOidLength = mechOidTagLen + mechOidDERLength + + mechOid->length; + + *buf++ = (mechOidLength & 0xFF00) >> 8; + *buf++ = (mechOidLength & 0x00FF); + *buf++ = 0x06; + if (put_der_length(mechOid->length, &buf, + mechOidDERLength) != 0) { + /* free the buffer */ + free(outNameHdr->value); + return (0); + } + + /* now add the mechanism oid */ + (void) memcpy(buf, mechOid->elements, mechOid->length); + + /* we stop here because the rest is mechanism specific */ + return (1); +} /* gsscred_MakeNameHeader */ + + +/* + * Converts the supplied string to HEX. + * The passed in buffer must be twice as long as the input buffer. + * Long form is used (i.e. '\0' will become '00'). This is needed + * to enable proper re-parsing of names. + */ +int +gsscred_AsHex(gss_buffer_t dataIn, gss_buffer_t dataOut) +{ + int i; + char *out, *in; + unsigned int tmp; + + if (dataOut->length < ((dataIn->length *2) + 1)) + return (0); + + out = (char *)dataOut->value; + in = (char *)dataIn->value; + dataOut->length = 0; + + for (i = 0; i < dataIn->length; i++) { + tmp = (unsigned int)(*in++)&0xff; + (void) sprintf(out, "%02X", tmp); + out++; + out++; + } + dataOut->length = out - (char *)dataOut->value; + *out = '\0'; + + return (1); +} /* ******* gsscred_AsHex ******* */ + + +/* + * GSS entry point for retrieving user uid mappings. + * The name buffer contains a principal name in exported format. + */ +int +gss_getGssCredEntry(const gss_buffer_t expName, uid_t *uid) +{ + int tableSource; + unsigned char *buf; + gss_buffer_desc mechOidDesc = GSS_C_EMPTY_BUFFER, + mechHexOidDesc = GSS_C_EMPTY_BUFFER, + expNameHexDesc = GSS_C_EMPTY_BUFFER; + char oidHexBuf[256], expNameHexBuf[1024]; + unsigned int dummy; + int len; + + tableSource = gsscred_read_config_file(); + + /* + * for xfn (ldap?), we must first construct, a hex mechansim oid string + */ + if (expName->length < (expNameTokIdLen + mechOidLenLen + + mechOidTagLen)) + return (0); + + buf = (unsigned char *)expName->value; + buf += expNameTokIdLen; + + /* skip oid length - get to der */ + buf++; + buf++; + + /* skip oid tag */ + buf++; + + /* get oid length */ + len = get_der_length(&buf, + (expName->length - expNameTokIdLen + - mechOidLenLen - mechOidTagLen), &dummy); + if (len == -1) + return (0); + else + mechOidDesc.length = len; + + if (expName->length < + (expNameTokIdLen + mechOidLenLen + mechOidDesc.length + + dummy+ mechOidTagLen)) + return (0); + + mechOidDesc.value = (void *)buf; + + /* convert the oid buffer to hex */ + mechHexOidDesc.value = (void*) oidHexBuf; + mechHexOidDesc.length = sizeof (oidHexBuf); + if (!gsscred_AsHex(&mechOidDesc, &mechHexOidDesc)) + return (0); + + /* also need to convert the name buffer into hex */ + expNameHexDesc.value = expNameHexBuf; + expNameHexDesc.length = sizeof (expNameHexBuf); + if (!gsscred_AsHex(expName, &expNameHexDesc)) + return (0); + + if (tableSource == GSSCRED_FLAT_FILE) + return (file_getGssCredUid(&expNameHexDesc, uid)); + + return (0); /* XXX for new backends (ldap, dss), 0->1 probably */ +} /* gss_getGssCredEntry */ diff --git a/usr/src/cmd/gss/gsscred_clean/Makefile b/usr/src/cmd/gss/gsscred_clean/Makefile new file mode 100644 index 0000000000..24e0ef7084 --- /dev/null +++ b/usr/src/cmd/gss/gsscred_clean/Makefile @@ -0,0 +1,88 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright (c) 1998 by Sun Microsystems, Inc. +# All rights reserved. +# +#ident "%Z%%M% %I% %E% SMI" +# +# cmd/gss/gsscred_clean/Makefile +# + +PROG= gsscred_clean + +SRCS= gsscred_clean.ksh + + +include ../../Makefile.cmd + +# +# Override $ROOTLIB +# +ROOTLIB= $(ROOT)/usr/lib/gss + +DIRS= $(ROOTLIB) + + +# +# Override $FILEMODE +# +FILEMODE=744 + + +# +# Set owner to root since it is executed out of crontab by root +# +OWNER=root +GROUP=sys + + +.KEEP_STATE: + +# +# Rule for ksh files +# +.SUFFIXES: .ksh + +.ksh: + $(RM) $@ + cat $< > $@ + chmod +x $@ + + +all: $(PROG) + +$(ROOTLIB): + $(INS.dir) + +$(ROOTLIB)/%: % + $(INS.file) + +install: all $(DIRS) $(ROOTLIBPROG) + +clean: + +clobber: + +lint: + +include ../../Makefile.targ diff --git a/usr/src/cmd/gss/gsscred_clean/gsscred_clean.ksh b/usr/src/cmd/gss/gsscred_clean/gsscred_clean.ksh new file mode 100644 index 0000000000..6ac5c35b2e --- /dev/null +++ b/usr/src/cmd/gss/gsscred_clean/gsscred_clean.ksh @@ -0,0 +1,74 @@ +#!/bin/ksh +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright (c) 1998 by Sun Microsystems, Inc. +# All rights reserved. +# +#pragma ident "%Z%%M% %I% %E% SMI" +# +# gsscred_db clean up script +# +# This file is used to remove duplicate entries from +# the gsscred_db file. It is activated as a root cron +# job once a day. It only performs cleanup when +# the gsscred_db file has changed since last operation. + +FILE_TO_CLEAN=/etc/gss/gsscred_db +CLEAN_TIME=/etc/gss/.gsscred_clean +TMP_FILE=/etc/gss/gsscred_clean$$ + +trap "rm -f $TMP_FILE; exit" 0 1 2 3 13 15 + + +if [ -s $FILE_TO_CLEAN ] && [ $FILE_TO_CLEAN -nt $CLEAN_TIME ] +then + +# +# The file being sorted has the following format: +# name uid comment +# +# We are trying to remove duplicate entries for the name +# which may have different uids. Entries lower in the file +# are newer since addition performs an append. We use cat -n +# in order to preserve the order of the duplicate entries and +# only keep the latest. We then sort on the name, and line +# number (line number in reverse). The line numbers are then +# removed and duplicate entries are cut out. +# + cat -n $FILE_TO_CLEAN | sort -k 2,2 -k 1,1nr 2> /dev/null \ + | cut -f2- | \ + awk ' (NR > 1 && $1 != key) || NR == 1 { + key = $1; + print $0; + } + ' > $TMP_FILE + + if [ $? -eq 0 ] && mv $TMP_FILE $FILE_TO_CLEAN; then +# +# update time stamp for this sort +# + touch -r $FILE_TO_CLEAN $CLEAN_TIME + else + rm -f $TMP_FILE + fi +fi diff --git a/usr/src/cmd/gss/gssd/Makefile b/usr/src/cmd/gss/gssd/Makefile new file mode 100644 index 0000000000..84484ffe7a --- /dev/null +++ b/usr/src/cmd/gss/gssd/Makefile @@ -0,0 +1,181 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +TESTPROG = gssdtest + +OUTPUT_OPTION = -I. + +PROG= gssd + +MANIFEST= gss.xml + +GSSD_BASEOBJS = gssd.o gssd_proc.o gssd_generic.o gssd_getuid.o +GSSC_BASEOBJS = gssdtest.o gssd_release_name_and_type.o gssd_clnt_stubs.o \ + gssd_handle.o + +GD_OBJS = gssd_svc.o +GC_OBJS = gssd_clnt.o +G_OBJS = gssd_xdr.o +GSSDOBJS = $(GSSD_BASEOBJS) $(GD_OBJS) $(G_OBJS) +GSSCOBJS = $(GSSC_BASEOBJS) $(GC_OBJS) $(G_OBJS) + +GSSD_LINTS = $(GSSD_BASEOBJS:.o=.c) +GSSC_LINTS = $(GSSC_BASEOBJS:.o=.c) + +ROBJS = $(GD_OBJS) $(GC_OBJS) $(G_OBJS) +OBJS = $(GSSD_BASEOBJS) $(GD_OBJS) $(GSSC_BASEOBJS) $(GC_OBJS) $(G_OBJS) +SRCS = $(OBJS:.o=.c) +RSRC = $(ROBJS:.o=.c) +RSRC += gssd.h + +CLOBBERFILES += $(TESTPROG) + +include ../../Makefile.cmd + +ROOTMANIFESTDIR= $(ROOTSVCNETWORKRPC) +$(ROOTMANIFEST) := FILEMODE= 444 + +TEXT_DOMAIN = SUNW_OST_NETRPC +POFILE = $(PROG).po +POFILES = generic.po + +# +# Override $ROOTLIB +# +ROOTLIB= $(ROOT)/usr/lib/gss + +DIRS= $(ROOTLIB) + +$(ROOTLIB)/gssd := OWNER= root +$(ROOTLIB)/gssd := GROUP= bin + +CPPFLAGS += -I$(SRC)/uts/common/gssapi/include +COPTFLAG += $(XESS) #-I$(KINCDIR) + +LDLIBS += -lgss -lnsl + +$(GPROGS) := CPPFLAGS += -DSYSV -DSunOS=50 + +.KEEP_STATE: + +all: $(PROG) $(TESTPROG) + +$(ROOTLIB): + $(INS.dir) + +$(ROOTLIB)/%: % + $(INS.file) + +gssd: $(GSSDOBJS) + $(LINK.c) $(GSSDOBJS) -o $@ $(LDLIBS) + $(POST_PROCESS) + +gssdtest: $(GSSCOBJS) + $(LINK.c) $(GSSCOBJS) -o $@ $(LDLIBS) + $(POST_PROCESS) + +GSSDX= $(SRC)/uts/common/gssapi/gssd.x +gssd.x: $(GSSDX) + rm -f $@ + cp $(GSSDX) $@ + +# Rules to generate derived rpcgen files from gssd.x spec file. + +gssd.h: gssd.x + $(RM) $@ + $(RPCGEN) -M -h gssd.x > $@ + +gssd_clnt.c: gssd.x + $(RM) $@ + $(RPCGEN) -M -l gssd.x > $@ + +gssd_svc.c: gssd.x + $(RM) $@ + $(RPCGEN) -M -m gssd.x > $@ + +gssd_xdr.c: gssd.x + $(RM) $@ + $(RPCGEN) -M -c gssd.x > $@ + +$(OBJS): gssd.h + +install: all $(DIRS) $(ROOTLIBPROG) $(ROOTMANIFEST) + +install_h: + +clean: + $(RM) $(OBJS) $(RSRC) gssd.x + +lint_gssd: + $(LINT.c) $(GSSD_LINTS) + +lint_gssc: + $(LINT.c) $(GSSC_LINTS) + +lint: lint_gssd lint_gssc + +check: $(CHKMANIFEST) + +include ../../Makefile.targ + +# EXPORT DELETE START +# Special targets to clean up the source tree for export distribution +# The WS target modifies the SCCS files as well, so a working workspace +# can be shipped. +# Warning: These targets change the source tree, the first only at the +# plain source level, but the second changes the guts! +EXPORT_SRC: + $(RM) Makefile+ gssd_clnt_stubs.c+ gssd_proc.c+ gssdtest.c+ + sed -e "/^# EXPORT DELETE START/,/^# EXPORT DELETE END/d" \ + < Makefile > Makefile+ + $(MV) Makefile+ Makefile + sed -e "/EXPORT DELETE START/,/EXPORT DELETE END/d" \ + < gssd_clnt_stubs.c > gssd_clnt_stubs.c+ + $(MV) gssd_clnt_stubs.c+ gssd_clnt_stubs.c + sed -e "/EXPORT DELETE START/,/EXPORT DELETE END/d" \ + < gssd_proc.c > gssd_proc.c+ + $(MV) gssd_proc.c+ gssd_proc.c + sed -e "/EXPORT DELETE START/,/EXPORT DELETE END/d" \ + < gssdtest.c > gssdtest.c+ + $(MV) gssdtest.c+ gssdtest.c + $(CHMOD) 444 Makefile gssd_clnt_stubs.c gssd_proc.c gssdtest.c + +# EXPORT DELETE END + +$(POFILE): $(DERIVED_FILES) .WAIT $(POFILES) + $(RM) $@ + $(CAT) $(POFILES) > $@ + +generic.po: FRC + $(RM) messages.po + $(XGETTEXT) $(XGETFLAGS) `$(GREP) -l gettext *.[ch]` + $(SED) "/^domain/d" messages.po > $@ + $(RM) messages.po + +FRC: + diff --git a/usr/src/cmd/gss/gssd/gss.xml b/usr/src/cmd/gss/gssd/gss.xml new file mode 100644 index 0000000000..04c3c408e8 --- /dev/null +++ b/usr/src/cmd/gss/gssd/gss.xml @@ -0,0 +1,120 @@ +<?xml version='1.0'?> +<!DOCTYPE service_bundle SYSTEM '/usr/share/lib/xml/dtd/service_bundle.dtd.1'> + +<!-- + Copyright 2005 Sun Microsystems, Inc. All rights reserved. + Use is subject to license terms. + + CDDL HEADER START + + The contents of this file are subject to the terms of the + Common Development and Distribution License, Version 1.0 only + (the "License"). You may not use this file except in compliance + with the License. + + You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + or http://www.opensolaris.org/os/licensing. + See the License for the specific language governing permissions + and limitations under the License. + + When distributing Covered Code, include this CDDL HEADER in each + file and include the License file at usr/src/OPENSOLARIS.LICENSE. + If applicable, add the following below this CDDL HEADER, with the + fields enclosed by brackets "[]" replaced with your own identifying + information: Portions Copyright [yyyy] [name of copyright owner] + + CDDL HEADER END + + ident "%Z%%M% %I% %E% SMI" + + NOTE: This service manifest is not editable; its contents will + be overwritten by package or patch operations, including + operating system upgrade. Make customizations in a different + file. + + Service manifest for gss +--> + +<service_bundle type='manifest' name='SUNWgssc:gss'> + +<service + name='network/rpc/gss' + type='service' + version='1'> + + <create_default_instance enabled='false' /> + + <restarter> + <service_fmri value='svc:/network/inetd:default' /> + </restarter> + + <dependency name='rpcbind' + grouping='require_all' + restart_on='restart' + type='service'> + <service_fmri value='svc:/network/rpc/bind' /> + </dependency> + + <dependency name='keyserv' + grouping='optional_all' + restart_on='none' + type='service'> + <service_fmri value='svc:/network/rpc/keyserv' /> + </dependency> + + <exec_method + type='method' + name='inetd_start' + exec='/usr/lib/gss/gssd' + timeout_seconds='0'> + <method_context> + <method_credential + user='root' + group='root' + privileges='basic,!file_link_any,!proc_info,!proc_session,net_privaddr,file_chown,file_dac_read,file_dac_write' + /> + </method_context> + </exec_method> + + <exec_method + type='method' + name='inetd_offline' + exec=':kill_process' + timeout_seconds='0'> + </exec_method> + + <exec_method + type='method' + name='inetd_disable' + exec=':kill' + timeout_seconds='0'> + </exec_method> + + <property_group name='inetd' type='framework'> + <stability value='Evolving' /> + <propval name='endpoint_type' type='astring' value='tli' /> + <propval name='name' type='astring' value='100234' /> + <propval name='proto' type='astring' value='ticotsord' /> + <propval name='isrpc' type='boolean' value='true' /> + <propval name='rpc_low_version' type='integer' value='1' /> + <propval name='rpc_high_version' type='integer' value='1' /> + <propval name='wait' type='boolean' value='true' /> + </property_group> + + <stability value='Unstable' /> + + <template> + <common_name> + <loctext xml:lang='C'> + Generic Security Service + </loctext> + </common_name> + <documentation> + <manpage title='gssd' section='1M' + manpath='/usr/share/man' /> + </documentation> + </template> + +</service> + +</service_bundle> diff --git a/usr/src/cmd/gss/gssd/gssd.c b/usr/src/cmd/gss/gssd/gssd.c new file mode 100644 index 0000000000..64dc128d05 --- /dev/null +++ b/usr/src/cmd/gss/gssd/gssd.c @@ -0,0 +1,300 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Usermode daemon which assists the kernel when handling gssapi calls. + * It is gssd that actually implements all gssapi calls. + * Some calls, such as gss_sign, are implemented in the kernel on a per + * mechanism basis. + */ + +#include <stdio.h> +#include <rpc/rpc.h> +#include <rpc/rpc_com.h> +#include <sys/syslog.h> +#include <sys/termios.h> +#include <unistd.h> +#include <sys/utsname.h> +#include <sys/systeminfo.h> +#include <stdlib.h> +#include <stropts.h> +#include <fcntl.h> +#include <strings.h> +#include <signal.h> +#include <syslog.h> +#include "gssd.h" + +int gssd_debug = 0; /* enable debugging printfs */ +extern void gsscred_set_options(void); + +void gssprog_1(); +void gssd_setup(char *); +static void usage(void); +static void daemonize_start(); +static void daemonize_ready(unsigned char status); +extern int svc_create_local_service(); + +/* following declarations needed in rpcgen-generated code */ +int _rpcpmstart = 0; /* Started by a port monitor ? */ +int _rpcfdtype; /* Whether Stream or Datagram ? */ +int _rpcsvcdirty; /* Still serving ? */ + + +static void +/* LINTED */ +catch_hup(int sig_num) +{ + sigset_t mask_set; /* used to set a signal masking set. */ + sigset_t old_set; /* used to store the old mask set. */ + + /* re-set the signal handler again to catch_hup, for next time */ + (void) signal(SIGHUP, catch_hup); + /* mask any further signals while we're inside the handler. */ + (void) sigfillset(&mask_set); + (void) sigprocmask(SIG_SETMASK, &mask_set, &old_set); + + gsscred_set_options(); + + /* let admin know the sighup was caught and conf file re-read */ + syslog(LOG_INFO, + "catch_hup: read gsscred.conf opts"); + if (gssd_debug) + (void) fprintf(stderr, + "catch_hup: read gsscred.conf opts"); + + (void) sigprocmask(SIG_SETMASK, &old_set, NULL); +} + + +int +main(argc, argv) +int argc; +char **argv; +{ + register SVCXPRT *transp; + int maxrecsz = RPC_MAXDATASIZE; + extern int optind; + int c; + char mname[FMNAMESZ + 1]; + extern int _getuid(); + + /* set locale and domain for internationalization */ + setlocale(LC_ALL, ""); + textdomain(TEXT_DOMAIN); + + + /* + * take special note that "_getuid()" is called here. This is necessary + * since we must fake out the mechanism libraries calls to getuid() + * with a special routine that is provided as part of gssd. However, + * the call below MUST call the real getuid() to ensure it is running + * as root. + */ + +#ifdef DEBUG + (void) setuid(0); /* DEBUG: set ruid to root */ +#endif /* DEBUG */ + if (_getuid()) { + (void) fprintf(stderr, + gettext("[%s] must be run as root\n"), argv[0]); +#ifdef DEBUG + (void) fprintf(stderr, gettext(" warning only\n")); +#else /* DEBUG */ + exit(1); +#endif /* DEBUG */ + } + + gssd_setup(argv[0]); + + while ((c = getopt(argc, argv, "d")) != -1) + switch (c) { + case 'd': + /* turn on debugging */ + gssd_debug = 1; + break; + default: + usage(); + } + + if (optind != argc) { + usage(); + } + + gsscred_set_options(); + (void) signal(SIGHUP, catch_hup); + + /* + * Started by inetd if name of module just below stream + * head is either a sockmod or timod. + */ + if (!ioctl(0, I_LOOK, mname) && + ((strcmp(mname, "sockmod") == 0) || + (strcmp(mname, "timod") == 0))) { + + char *netid; + struct netconfig *nconf; + + openlog("gssd", LOG_PID, LOG_DAEMON); + + if ((netid = getenv("NLSPROVIDER")) == NULL) { + netid = "ticotsord"; + } + + if ((nconf = getnetconfigent(netid)) == NULL) { + syslog(LOG_ERR, gettext("cannot get transport info")); + exit(1); + } + + if (strcmp(mname, "sockmod") == 0) { + if (ioctl(0, I_POP, 0) || ioctl(0, I_PUSH, "timod")) { + syslog(LOG_ERR, + gettext("could not get the " + "right module")); + exit(1); + } + } + if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrecsz)) { + syslog(LOG_ERR, + gettext("unable to set RPC max record size")); + exit(1); + } + /* XXX - is nconf even needed here? */ + if ((transp = svc_tli_create(0, nconf, NULL, 0, 0)) == NULL) { + syslog(LOG_ERR, gettext("cannot create server handle")); + exit(1); + } + + /* + * We use a NULL nconf because GSSPROG has already been + * registered with rpcbind. + */ + if (!svc_reg(transp, GSSPROG, GSSVERS, gssprog_1, NULL)) { + syslog(LOG_ERR, + gettext("unable to register " + "(GSSPROG, GSSVERS)")); + exit(1); + } + + if (nconf) + freenetconfigent(nconf); + } else { + if (!gssd_debug) + daemonize_start(); + + openlog("gssd", LOG_PID, LOG_DAEMON); + + if (svc_create_local_service(gssprog_1, GSSPROG, GSSVERS, + "netpath", "gssd") == 0) { + syslog(LOG_ERR, gettext("unable to create service")); + exit(1); + } + + /* service created, now the daemon parent can exit */ + daemonize_ready(0); + } + + + if (gssd_debug) { + fprintf(stderr, + gettext("gssd start: \n")); + } + svc_run(); + abort(); + /*NOTREACHED*/ +#ifdef lint + return (1); +#endif +} + +static void +usage(void) +{ + (void) fprintf(stderr, gettext("usage: gssd [-dg]\n")); + exit(1); +} + + +/* + * Fork, detach from tty, etc... + */ +static int write_pipe_fd = -1; +static +void +daemonize_start() +{ + int pipe_fds[2]; + unsigned char status = 1; + + closefrom(0); + + /* Open stdin/out/err, chdir, get a pipe */ + if (open("/dev/null", O_RDONLY) < 0 || + open("/dev/null", O_WRONLY) < 0 || dup(1) < 0 || + chdir("/") < 0 || pipe(pipe_fds) < 0) + exit(1); + + /* For daemonize_ready() */ + write_pipe_fd = pipe_fds[1]; + + switch (fork()) { + case -1: + exit(1); + /* NOTREACHED */ + case 0: + break; + default: + /* Wait for child to be ready befor exiting */ + (void) close(pipe_fds[1]); + (void) signal(SIGPIPE, SIG_DFL); + (void) read(pipe_fds[0], &status, sizeof (status)); + exit(status); + } + + (void) close(pipe_fds[0]); + (void) setsid(); +} + +static +void +daemonize_ready(unsigned char status) +{ + if (write_pipe_fd == -1) + return; + + (void) write(write_pipe_fd, &status, sizeof (status)); + (void) close(write_pipe_fd); + write_pipe_fd = -1; +} + +/*ARGSUSED*/ +int +gssprog_1_freeresult(SVCXPRT *transport, xdrproc_t xdr_res, caddr_t res) +{ + xdr_free(xdr_res, res); + return (1); +} diff --git a/usr/src/cmd/gss/gssd/gssd_clnt_stubs.c b/usr/src/cmd/gss/gssd/gssd_clnt_stubs.c new file mode 100644 index 0000000000..d7910ad9f1 --- /dev/null +++ b/usr/src/cmd/gss/gssd/gssd_clnt_stubs.c @@ -0,0 +1,2685 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * GSSAPI library stub module for gssd. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <mechglueP.h> +#include "gssd.h" +#include <rpc/rpc.h> + +#ifdef _KERNEL +#define MALLOC(n) kmem_alloc((n), KM_SLEEP) +#define FREE(x, n) kmem_free((x), (n)) +#define memcpy(dst, src, n) bcopy((src), (dst), (n)) +#define clnt_pcreateerror(srv) printf("Cannot connect to server on %s\n", srv) + +#ifdef DEBUG +#ifndef _SYS_CMN_ERR_H +#define _SYS_CMN_ERR_H +#define CE_NOTE 1 +#endif +#include <sys/types.h> +#include <sys/devops.h> +#include <sys/open.h> +#include <sys/stat.h> +#include <sys/conf.h> +#include <sys/ddi.h> +#include <sys/sunddi.h> +#include <sys/uio.h> +#endif /* DEBUG */ + +#else /* !_KERNEL */ +#define MALLOC(n) malloc(n) +#define FREE(x, n) free(x) +#endif /* _KERNEL */ +#define DEFAULT_MINOR_STAT ((OM_uint32) ~0) + +CLIENT *clnt, *getgssd_handle(); +char *server = "localhost"; + +OM_uint32 +kgss_acquire_cred_wrapped(minor_status, + desired_name, + time_req, + desired_mechs, + cred_usage, + output_cred_handle, + actual_mechs, + time_rec, + uid, + gssd_cred_verifier) + OM_uint32 *minor_status; + gss_name_t desired_name; + OM_uint32 time_req; + gss_OID_set desired_mechs; + int cred_usage; + gssd_cred_id_t *output_cred_handle; + gss_OID_set *actual_mechs; + OM_uint32 *time_rec; + uid_t uid; + OM_uint32 *gssd_cred_verifier; +{ + OM_uint32 minor_status_temp; + gss_buffer_desc external_name; + gss_OID name_type; + int i; + + gss_acquire_cred_arg arg; + gss_acquire_cred_res res; + + /* get the client handle to GSSD */ + + if ((clnt = getgssd_handle()) == NULL) { + clnt_pcreateerror(server); + return (GSS_S_FAILURE); + } + + /* convert the desired name from internal to external format */ + + if (gss_display_name(&minor_status_temp, desired_name, &external_name, + &name_type) != GSS_S_COMPLETE) { + + *minor_status = (OM_uint32) minor_status_temp; + gss_release_buffer(&minor_status_temp, &external_name); + return ((OM_uint32) GSS_S_FAILURE); + } + + + /* copy the procedure arguments into the rpc arg parameter */ + + arg.uid = (OM_uint32)uid; + + arg.desired_name.GSS_BUFFER_T_len = (uint_t)external_name.length; + arg.desired_name.GSS_BUFFER_T_val = (char *)external_name.value; + + arg.name_type.GSS_OID_len = + name_type == GSS_C_NULL_OID ? + 0 : (uint_t)name_type->length; + + arg.name_type.GSS_OID_val = + name_type == GSS_C_NULL_OID ? + (char *)NULL : (char *)name_type->elements; + + arg.time_req = time_req; + + if (desired_mechs != GSS_C_NULL_OID_SET) { + arg.desired_mechs.GSS_OID_SET_len = + (uint_t)desired_mechs->count; + arg.desired_mechs.GSS_OID_SET_val = (GSS_OID *) + MALLOC(sizeof (GSS_OID) * desired_mechs->count); + + for (i = 0; i < desired_mechs->count; i++) { + arg.desired_mechs.GSS_OID_SET_val[i].GSS_OID_len = + (uint_t)desired_mechs->elements[i].length; + arg.desired_mechs.GSS_OID_SET_val[i].GSS_OID_val = + (char *) + MALLOC(desired_mechs->elements[i].length); + memcpy(arg.desired_mechs.GSS_OID_SET_val[i].GSS_OID_val, + desired_mechs->elements[i].elements, + desired_mechs->elements[i].length); + } + } else + arg.desired_mechs.GSS_OID_SET_len = 0; + + arg.cred_usage = cred_usage; + + /* call the remote procedure */ + + memset(&res, 0, sizeof (res)); + if (gss_acquire_cred_1(&arg, &res, clnt) != RPC_SUCCESS) { + + /* + * if the RPC call times out, null out all return arguments, + * set minor_status to its maximum value, and return GSS_S_FAILURE + */ + + if (minor_status != NULL) + *minor_status = 0xffffffff; + if (output_cred_handle != NULL) + *output_cred_handle = NULL; + if (actual_mechs != NULL) + *actual_mechs = NULL; + if (time_rec != NULL) + *time_rec = 0; + + return (GSS_S_FAILURE); + } + + /* free the allocated memory for the flattened name and desire_mechs */ + + gss_release_buffer(&minor_status_temp, &external_name); + for (i = 0; i < desired_mechs->count; i++) + FREE(arg.desired_mechs.GSS_OID_SET_val[i].GSS_OID_val, + arg.desired_mechs.GSS_OID_SET_val[i].GSS_OID_len); + FREE(arg.desired_mechs.GSS_OID_SET_val, + arg.desired_mechs.GSS_OID_SET_len * sizeof (GSS_OID)); + + /* copy the rpc results into the return arguments */ + + if (minor_status != NULL) + *minor_status = res.minor_status; + + if (output_cred_handle != NULL) { + *output_cred_handle = + /*LINTED*/ + *((gssd_cred_id_t *)res.output_cred_handle.GSS_CRED_ID_T_val); + *gssd_cred_verifier = res.gssd_cred_verifier; + } + + if (res.status == GSS_S_COMPLETE && + res.actual_mechs.GSS_OID_SET_len != 0 && + actual_mechs != NULL) { + *actual_mechs = (gss_OID_set) MALLOC(sizeof (gss_OID_set_desc)); + (*actual_mechs)->count = + (int)res.actual_mechs.GSS_OID_SET_len; + (*actual_mechs)->elements = (gss_OID) + MALLOC(sizeof (gss_OID_desc) * (*actual_mechs)->count); + + for (i = 0; i < (*actual_mechs)->count; i++) { + (*actual_mechs)->elements[i].length = (OM_uint32) + res.actual_mechs.GSS_OID_SET_val[i].GSS_OID_len; + (*actual_mechs)->elements[i].elements = + (void *) MALLOC((*actual_mechs)->elements[i].length); + memcpy((*actual_mechs)->elements[i].elements, + res.actual_mechs.GSS_OID_SET_val[i].GSS_OID_val, + (*actual_mechs)->elements[i].length); + } + } else { + if (res.status == GSS_S_COMPLETE && actual_mechs != NULL) + (*actual_mechs)->count = 0; + } + + if (time_rec != NULL) + *time_rec = res.time_rec; + + /* + * free the memory allocated for the results and return with the status + * received in the rpc call + */ + + clnt_freeres(clnt, xdr_gss_acquire_cred_res, (caddr_t)&res); + return (res.status); +} + +OM_uint32 +kgss_acquire_cred(minor_status, + desired_name, + time_req, + desired_mechs, + cred_usage, + output_cred_handle, + actual_mechs, + time_rec, + uid) + OM_uint32 *minor_status; + gss_name_t desired_name; + OM_uint32 time_req; + gss_OID_set desired_mechs; + int cred_usage; + gss_cred_id_t *output_cred_handle; + gss_OID_set *actual_mechs; + OM_uint32 *time_rec; + uid_t uid; +{ + + OM_uint32 err; + struct kgss_cred *kcred; + + kcred = KGSS_CRED_ALLOC(); + *output_cred_handle = (gss_cred_id_t)kcred; + err = kgss_acquire_cred_wrapped(minor_status, + desired_name, time_req, + desired_mechs, cred_usage, + &kcred->gssd_cred, actual_mechs, + time_rec, uid, + &kcred->gssd_cred_verifier); + if (GSS_ERROR(err)) { + KGSS_CRED_FREE(kcred); + *output_cred_handle = GSS_C_NO_CREDENTIAL; + } + return (err); +} + +OM_uint32 +kgss_add_cred_wrapped(minor_status, + input_cred_handle, + gssd_cred_verifier, + desired_name, + desired_mech_type, + cred_usage, + initiator_time_req, + acceptor_time_req, + actual_mechs, + initiator_time_rec, + acceptor_time_rec, + uid) + OM_uint32 *minor_status; + gssd_cred_id_t input_cred_handle; + OM_uint32 gssd_cred_verifier; + gss_name_t desired_name; + gss_OID desired_mech_type; + int cred_usage; + int initiator_time_req; + int acceptor_time_req; + gss_OID_set *actual_mechs; + OM_uint32 *initiator_time_rec; + OM_uint32 *acceptor_time_rec; + uid_t uid; +{ + CLIENT *clnt; + + OM_uint32 minor_status_temp; + gss_buffer_desc external_name; + gss_OID name_type; + int i; + + gss_add_cred_arg arg; + gss_add_cred_res res; + + /* get the client handle to GSSD */ + + if ((clnt = getgssd_handle()) == NULL) { + clnt_pcreateerror(server); + return (GSS_S_FAILURE); + } + + + /* convert the desired name from internal to external format */ + + if (gss_display_name(&minor_status_temp, desired_name, &external_name, + &name_type) != GSS_S_COMPLETE) { + + *minor_status = (OM_uint32) minor_status_temp; + (void) gss_release_buffer(&minor_status_temp, &external_name); + clnt_pcreateerror(server); + return ((OM_uint32) GSS_S_FAILURE); + } + + + /* copy the procedure arguments into the rpc arg parameter */ + + arg.uid = (OM_uint32) uid; + arg.input_cred_handle.GSS_CRED_ID_T_len = + input_cred_handle == + (gssd_cred_id_t)GSS_C_NO_CREDENTIAL ? + 0 : (uint_t)sizeof (gssd_cred_id_t); + arg.input_cred_handle.GSS_CRED_ID_T_val = + (char *)&input_cred_handle; + arg.gssd_cred_verifier = gssd_cred_verifier; + arg.desired_name.GSS_BUFFER_T_len = (uint_t)external_name.length; + arg.desired_name.GSS_BUFFER_T_val = (char *)external_name.value; + arg.name_type.GSS_OID_len = + name_type == GSS_C_NULL_OID ? + 0 : (uint_t)name_type->length; + arg.name_type.GSS_OID_val = + name_type == GSS_C_NULL_OID ? + (char *)NULL : (char *)name_type->elements; + + arg.desired_mech_type.GSS_OID_len = + (uint_t)(desired_mech_type != GSS_C_NULL_OID ? + desired_mech_type->length : 0); + arg.desired_mech_type.GSS_OID_val = + (char *)(desired_mech_type != GSS_C_NULL_OID ? + desired_mech_type->elements : 0); + arg.cred_usage = cred_usage; + arg.initiator_time_req = initiator_time_req; + arg.acceptor_time_req = acceptor_time_req; + + /* call the remote procedure */ + + bzero((caddr_t)&res, sizeof (res)); + if (gss_add_cred_1(&arg, &res, clnt) != RPC_SUCCESS) { + + /* + * if the RPC call times out, null out all return arguments, + * set minor_status to its maximum value, and return + * GSS_S_FAILURE + */ + + if (minor_status != NULL) + *minor_status = DEFAULT_MINOR_STAT; + if (actual_mechs != NULL) + *actual_mechs = NULL; + if (initiator_time_rec != NULL) + *initiator_time_rec = 0; + if (acceptor_time_rec != NULL) + *acceptor_time_rec = 0; + return (GSS_S_FAILURE); + } + + /* free the allocated memory for the flattened name */ + + (void) gss_release_buffer(&minor_status_temp, &external_name); + + /* copy the rpc results into the return arguments */ + + if (minor_status != NULL) + *minor_status = res.minor_status; + + if (res.status == GSS_S_COMPLETE && + res.actual_mechs.GSS_OID_SET_len != 0 && + actual_mechs != NULL) { + *actual_mechs = (gss_OID_set) MALLOC(sizeof (gss_OID_set_desc)); + (*actual_mechs)->count = + (int)res.actual_mechs.GSS_OID_SET_len; + (*actual_mechs)->elements = (gss_OID) + MALLOC(sizeof (gss_OID_desc) * (*actual_mechs)->count); + + for (i = 0; i < (*actual_mechs)->count; i++) { + (*actual_mechs)->elements[i].length = (OM_uint32) + res.actual_mechs.GSS_OID_SET_val[i].GSS_OID_len; + (*actual_mechs)->elements[i].elements = + (void *) MALLOC((*actual_mechs)->elements[i].length); + memcpy((*actual_mechs)->elements[i].elements, + res.actual_mechs.GSS_OID_SET_val[i].GSS_OID_val, + (*actual_mechs)->elements[i].length); + } + } else { + if (res.status == GSS_S_COMPLETE && + actual_mechs != NULL) + (*actual_mechs)->count = 0; + } + if (initiator_time_rec != NULL) + *initiator_time_rec = res.initiator_time_rec; + if (acceptor_time_rec != NULL) + *acceptor_time_rec = res.acceptor_time_rec; + + /* + * free the memory allocated for the results and return with the status + * received in the rpc call + */ + + clnt_freeres(clnt, xdr_gss_add_cred_res, (caddr_t)&res); + return (res.status); + +} + +OM_uint32 +kgss_add_cred(minor_status, + input_cred_handle, + desired_name, + desired_mech_type, + cred_usage, + initiator_time_req, + acceptor_time_req, + actual_mechs, + initiator_time_rec, + acceptor_time_rec, + uid) + OM_uint32 *minor_status; + gss_cred_id_t input_cred_handle; + gss_name_t desired_name; + gss_OID desired_mech_type; + int cred_usage; + int initiator_time_req; + int acceptor_time_req; + gss_OID_set *actual_mechs; + OM_uint32 *initiator_time_rec; + OM_uint32 *acceptor_time_rec; + uid_t uid; +{ + + OM_uint32 err; + OM_uint32 gssd_cred_verifier; + gssd_cred_id_t gssd_input_cred_handle; + + + if (input_cred_handle != GSS_C_NO_CREDENTIAL) { + gssd_cred_verifier = KCRED_TO_CREDV(input_cred_handle); + gssd_input_cred_handle = KCRED_TO_CRED(input_cred_handle); + } else + gssd_input_cred_handle = (gssd_cred_id_t)GSS_C_NO_CREDENTIAL; + + err = kgss_add_cred_wrapped(minor_status, gssd_input_cred_handle, + gssd_cred_verifier, desired_name, desired_mech_type, + cred_usage, initiator_time_req, acceptor_time_req, + actual_mechs, initiator_time_rec, + acceptor_time_rec, uid); + return (err); +} + +OM_uint32 +kgss_release_cred_wrapped(minor_status, + cred_handle, + uid, + gssd_cred_verifier) +OM_uint32 *minor_status; +gssd_cred_id_t *cred_handle; +uid_t uid; +OM_uint32 gssd_cred_verifier; +{ + + gss_release_cred_arg arg; + gss_release_cred_res res; + + + /* get the client handle to GSSD */ + if ((clnt = getgssd_handle()) == NULL) { + clnt_pcreateerror(server); + return (GSS_S_FAILURE); + } + + /* copy the procedure arguments into the rpc arg parameter */ + + arg.uid = (OM_uint32) uid; + arg.gssd_cred_verifier = gssd_cred_verifier; + + if (cred_handle != NULL) { + arg.cred_handle.GSS_CRED_ID_T_len = + (uint_t)sizeof (gssd_cred_id_t); + arg.cred_handle.GSS_CRED_ID_T_val = (char *)cred_handle; + } else + arg.cred_handle.GSS_CRED_ID_T_len = 0; + + /* call the remote procedure */ + + memset(&res, 0, sizeof (res)); + if (gss_release_cred_1(&arg, &res, clnt) != RPC_SUCCESS) { + + /* + * if the RPC call times out, null out all return arguments, + * set minor_status to its max value, and return GSS_S_FAILURE + */ + + if (minor_status != NULL) + *minor_status = 0xffffffff; + if (cred_handle != NULL) + *cred_handle = NULL; + + return (GSS_S_FAILURE); + } + + /* if the release succeeded, null out the cred_handle */ + if (res.status == GSS_S_COMPLETE && cred_handle != NULL) + *cred_handle = NULL; + + /* copy the rpc results into the return arguments */ + if (minor_status != NULL) + *minor_status = res.minor_status; + + /* return with status returned in rpc call */ + return (res.status); +} + +OM_uint32 +kgss_release_cred(minor_status, + cred_handle, + uid) + OM_uint32 *minor_status; + gss_cred_id_t *cred_handle; + uid_t uid; + +{ + + OM_uint32 err; + struct kgss_cred *kcred; + + if (*cred_handle == GSS_C_NO_CREDENTIAL) + return (GSS_S_COMPLETE); + else + kcred = KCRED_TO_KGSS_CRED(*cred_handle); + + err = kgss_release_cred_wrapped(minor_status, &kcred->gssd_cred, + uid, kcred->gssd_cred_verifier); + KGSS_CRED_FREE(kcred); + *cred_handle = GSS_C_NO_CREDENTIAL; + return (err); +} + +OM_uint32 +kgss_init_sec_context_wrapped(minor_status, + claimant_cred_handle, + gssd_cred_verifier, + context_handle, + gssd_context_verifier, + target_name, + mech_type, + req_flags, + time_req, + input_chan_bindings, + input_token, + actual_mech_type, + output_token, + ret_flags, + time_rec, + uid) + OM_uint32 *minor_status; + gssd_cred_id_t claimant_cred_handle; + OM_uint32 gssd_cred_verifier; + OM_uint32 *context_handle; + OM_uint32 *gssd_context_verifier; + gss_name_t target_name; + gss_OID mech_type; + int req_flags; + OM_uint32 time_req; + gss_channel_bindings_t input_chan_bindings; + gss_buffer_t input_token; + gss_OID *actual_mech_type; + gss_buffer_t output_token; + int *ret_flags; + OM_uint32 *time_rec; + uid_t uid; +{ + OM_uint32 minor_status_temp; + gss_buffer_desc external_name; + gss_OID name_type; + gss_init_sec_context_arg arg; + gss_init_sec_context_res res; + + /* get the client handle to GSSD */ + + if ((clnt = getgssd_handle()) == NULL) { + clnt_pcreateerror(server); + return (GSS_S_FAILURE); + } + + /* convert the target name from internal to external format */ + + if (gss_display_name(&minor_status_temp, target_name, + &external_name, &name_type) != GSS_S_COMPLETE) { + + *minor_status = (OM_uint32) minor_status_temp; + return ((OM_uint32) GSS_S_FAILURE); + } + + +/* copy the procedure arguments into the rpc arg parameter */ + + arg.uid = (OM_uint32) uid; + + arg.context_handle.GSS_CTX_ID_T_len = + *context_handle == (OM_uint32) GSS_C_NO_CONTEXT ? 0 : + (uint_t)sizeof (OM_uint32); + arg.context_handle.GSS_CTX_ID_T_val = (char *)context_handle; + arg.gssd_context_verifier = *gssd_context_verifier; + + arg.claimant_cred_handle.GSS_CRED_ID_T_len = + claimant_cred_handle == (gssd_cred_id_t)GSS_C_NO_CREDENTIAL ? + 0 : (uint_t)sizeof (gssd_cred_id_t); + arg.claimant_cred_handle.GSS_CRED_ID_T_val = + (char *)&claimant_cred_handle; + arg.gssd_cred_verifier = gssd_cred_verifier; + + arg.target_name.GSS_BUFFER_T_len = (uint_t)external_name.length; + arg.target_name.GSS_BUFFER_T_val = (char *)external_name.value; + + arg.name_type.GSS_OID_len = + name_type == GSS_C_NULL_OID ? + 0 : (uint_t)name_type->length; + + arg.name_type.GSS_OID_val = + name_type == GSS_C_NULL_OID ? + (char *)NULL : (char *)name_type->elements; + + arg.mech_type.GSS_OID_len = (uint_t)(mech_type != GSS_C_NULL_OID ? + mech_type->length : 0); + arg.mech_type.GSS_OID_val = (char *)(mech_type != GSS_C_NULL_OID ? + mech_type->elements : 0); + + arg.req_flags = req_flags; + + arg.time_req = time_req; + + if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS) { + arg.input_chan_bindings.present = YES; + arg.input_chan_bindings.initiator_addrtype = + input_chan_bindings->initiator_addrtype; + arg.input_chan_bindings.initiator_address.GSS_BUFFER_T_len = + (uint_t)input_chan_bindings->initiator_address.length; + arg.input_chan_bindings.initiator_address.GSS_BUFFER_T_val = + (void *) input_chan_bindings->initiator_address.value; + arg.input_chan_bindings.acceptor_addrtype = + input_chan_bindings->acceptor_addrtype; + arg.input_chan_bindings.acceptor_address.GSS_BUFFER_T_len = + (uint_t)input_chan_bindings->acceptor_address.length; + arg.input_chan_bindings.acceptor_address.GSS_BUFFER_T_val = + (void *) input_chan_bindings->acceptor_address.value; + arg.input_chan_bindings.application_data.GSS_BUFFER_T_len = + (uint_t)input_chan_bindings->application_data.length; + arg.input_chan_bindings.application_data.GSS_BUFFER_T_val = + (void *) input_chan_bindings->application_data.value; + } else { + arg.input_chan_bindings.present = NO; + arg.input_chan_bindings.initiator_addrtype = 0; + arg.input_chan_bindings.initiator_address.GSS_BUFFER_T_len = 0; + arg.input_chan_bindings.initiator_address.GSS_BUFFER_T_val = 0; + arg.input_chan_bindings.acceptor_addrtype = 0; + arg.input_chan_bindings.acceptor_address.GSS_BUFFER_T_len = 0; + arg.input_chan_bindings.acceptor_address.GSS_BUFFER_T_val = 0; + arg.input_chan_bindings.application_data.GSS_BUFFER_T_len = 0; + arg.input_chan_bindings.application_data.GSS_BUFFER_T_val = 0; + } + + arg.input_token.GSS_BUFFER_T_len = (uint_t) + (input_token != GSS_C_NO_BUFFER ? input_token->length : 0); + arg.input_token.GSS_BUFFER_T_val = (char *) + (input_token != GSS_C_NO_BUFFER ? input_token->value : 0); + + /* initialize the output parameters to empty values */ + if (minor_status != NULL) + *minor_status = 0xffffffff; + if (actual_mech_type != NULL) + *actual_mech_type = NULL; + if (output_token != NULL) + output_token->length = 0; + if (ret_flags != NULL) + *ret_flags = 0; + if (time_rec != NULL) + *time_rec = 0; + + /* call the remote procedure */ + memset(&res, 0, sizeof (res)); + if (gss_init_sec_context_1(&arg, &res, clnt) != RPC_SUCCESS) { + + /* free the allocated memory for the flattened name */ + gss_release_buffer(&minor_status_temp, &external_name); + + return (GSS_S_FAILURE); + } + + + /* free the allocated memory for the flattened name */ + gss_release_buffer(&minor_status_temp, &external_name); + + /* if the call was successful, copy out the results */ + if (res.status == (OM_uint32) GSS_S_COMPLETE || + res.status == (OM_uint32) GSS_S_CONTINUE_NEEDED) { + /* + * copy the rpc results into the return arguments + * on CONTINUE_NEEDED only the output token, minor + * code and ctxt handle are ready. + */ + if (minor_status != NULL) + *minor_status = res.minor_status; + /*LINTED*/ + *context_handle = *((OM_uint32 *) + res.context_handle.GSS_CTX_ID_T_val); + + /*LINTED*/ + *context_handle = *((OM_uint32 *) + res.context_handle.GSS_CTX_ID_T_val); + *gssd_context_verifier = res.gssd_context_verifier; + + if (output_token != NULL) { + output_token->length = + (size_t)res.output_token.GSS_BUFFER_T_len; + output_token->value = + (void *)res.output_token.GSS_BUFFER_T_val; + res.output_token.GSS_BUFFER_T_val = NULL; + res.output_token.GSS_BUFFER_T_len = 0; + } + + /* the rest of the parameters is only ready on COMPLETE */ + if (res.status == GSS_S_COMPLETE) { + if (actual_mech_type != NULL) { + *actual_mech_type = (gss_OID) + MALLOC(sizeof (gss_OID_desc)); + (*actual_mech_type)->length = (OM_UINT32) + res.actual_mech_type.GSS_OID_len; + (*actual_mech_type)->elements = (void *) + MALLOC((*actual_mech_type)->length); + memcpy((*actual_mech_type)->elements, (void *) + res.actual_mech_type.GSS_OID_val, + (*actual_mech_type)->length); + } + + + if (ret_flags != NULL) + *ret_flags = res.ret_flags; + + if (time_rec != NULL) + *time_rec = res.time_rec; + } + } + + + /* + * free the memory allocated for the results and return with the + * status received in the rpc call. + */ + + clnt_freeres(clnt, xdr_gss_init_sec_context_res, (caddr_t)&res); + return (res.status); +} +OM_uint32 +kgss_init_sec_context( + OM_uint32 *minor_status, + gss_cred_id_t claimant_cred_handle, + gss_ctx_id_t *context_handle, + gss_name_t target_name, + gss_OID mech_type, + int req_flags, + OM_uint32 time_req, + gss_channel_bindings_t input_chan_bindings, + gss_buffer_t input_token, + gss_OID *actual_mech_type, + gss_buffer_t output_token, + int *ret_flags, + OM_uint32 *time_rec, + uid_t uid) +{ + OM_uint32 err; + struct kgss_ctx *kctx; + OM_uint32 gssd_cred_verifier; + gssd_cred_id_t gssd_cl_cred_handle; + + /* + * If this is an initial call, we'll need to create the + * wrapper struct that contains kernel state information, and + * a reference to the handle from gssd. + */ + if (*context_handle == GSS_C_NO_CONTEXT) { + kctx = KGSS_ALLOC(); + *context_handle = (gss_ctx_id_t)kctx; + kctx->gssd_ctx = (OM_uint32) GSS_C_NO_CONTEXT; + } else + kctx = (struct kgss_ctx *)*context_handle; + + if (claimant_cred_handle != GSS_C_NO_CREDENTIAL) { + gssd_cred_verifier = + KCRED_TO_CREDV(claimant_cred_handle); + gssd_cl_cred_handle = + KCRED_TO_CRED(claimant_cred_handle); + } else + gssd_cl_cred_handle = + (gssd_cred_id_t)GSS_C_NO_CREDENTIAL; + + err = kgss_init_sec_context_wrapped(minor_status, + gssd_cl_cred_handle, + gssd_cred_verifier, &kctx->gssd_ctx, + &kctx->gssd_ctx_verifier, + target_name, mech_type, req_flags, time_req, + input_chan_bindings, input_token, actual_mech_type, + output_token, ret_flags, time_rec, uid); + + if (GSS_ERROR(err)) { + KGSS_FREE(kctx); + *context_handle = GSS_C_NO_CONTEXT; + } + return (err); +} +OM_uint32 +kgss_accept_sec_context_wrapped(minor_status, + context_handle, + gssd_context_verifier, + verifier_cred_handle, + gssd_cred_verifier, + input_token, + input_chan_bindings, + src_name, + mech_type, + output_token, + ret_flags, + time_rec, + delegated_cred_handle, + uid) + OM_uint32 *minor_status; + gssd_ctx_id_t *context_handle; + OM_uint32 *gssd_context_verifier; + gssd_cred_id_t verifier_cred_handle; + OM_uint32 gssd_cred_verifier; + gss_buffer_t input_token; + gss_channel_bindings_t input_chan_bindings; + gss_buffer_t src_name; + gss_OID *mech_type; + gss_buffer_t output_token; + int *ret_flags; + OM_uint32 *time_rec; + gss_cred_id_t *delegated_cred_handle; + uid_t uid; +{ + gss_accept_sec_context_arg arg; + gss_accept_sec_context_res res; + struct kgss_cred *kcred; + + /* get the client handle to GSSD */ + if ((clnt = getgssd_handle()) == NULL) { + clnt_pcreateerror(server); + return (GSS_S_FAILURE); + } + + /* copy the procedure arguments into the rpc arg parameter */ + arg.uid = (OM_uint32) uid; + + arg.context_handle.GSS_CTX_ID_T_len = + *context_handle == (gssd_ctx_id_t)GSS_C_NO_CONTEXT ? + 0 : (uint_t)sizeof (gssd_ctx_id_t); + arg.context_handle.GSS_CTX_ID_T_val = (char *)context_handle; + arg.gssd_context_verifier = + *context_handle == (OM_uint32) GSS_C_NO_CONTEXT ? + 0 : *gssd_context_verifier; + + arg.verifier_cred_handle.GSS_CRED_ID_T_len = + verifier_cred_handle == + (gssd_cred_id_t)GSS_C_NO_CREDENTIAL ? + 0 : (uint_t)sizeof (gssd_cred_id_t); + arg.verifier_cred_handle.GSS_CRED_ID_T_val = + (char *)&verifier_cred_handle; + arg.gssd_cred_verifier = gssd_cred_verifier; + + arg.input_token_buffer.GSS_BUFFER_T_len = + (uint_t)(input_token != GSS_C_NO_BUFFER ? + input_token->length : 0); + arg.input_token_buffer.GSS_BUFFER_T_val = + (char *)(input_token != GSS_C_NO_BUFFER ? + input_token->value : 0); + + if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS) { + arg.input_chan_bindings.present = YES; + arg.input_chan_bindings.initiator_addrtype = + input_chan_bindings->initiator_addrtype; + arg.input_chan_bindings.initiator_address.GSS_BUFFER_T_len = + (uint_t)input_chan_bindings->initiator_address.length; + arg.input_chan_bindings.initiator_address.GSS_BUFFER_T_val = + (void *) input_chan_bindings->initiator_address.value; + arg.input_chan_bindings.acceptor_addrtype = + input_chan_bindings->acceptor_addrtype; + arg.input_chan_bindings.acceptor_address.GSS_BUFFER_T_len = + (uint_t)input_chan_bindings->acceptor_address.length; + arg.input_chan_bindings.acceptor_address.GSS_BUFFER_T_val = + (void *) input_chan_bindings->acceptor_address.value; + arg.input_chan_bindings.application_data.GSS_BUFFER_T_len = + (uint_t)input_chan_bindings->application_data.length; + arg.input_chan_bindings.application_data.GSS_BUFFER_T_val = + (void *) input_chan_bindings->application_data.value; + } else { + arg.input_chan_bindings.present = NO; + arg.input_chan_bindings.initiator_addrtype = 0; + arg.input_chan_bindings.initiator_address.GSS_BUFFER_T_len = 0; + arg.input_chan_bindings.initiator_address.GSS_BUFFER_T_val = 0; + arg.input_chan_bindings.acceptor_addrtype = 0; + arg.input_chan_bindings.acceptor_address.GSS_BUFFER_T_len = 0; + arg.input_chan_bindings.acceptor_address.GSS_BUFFER_T_val = 0; + arg.input_chan_bindings.application_data.GSS_BUFFER_T_len = 0; + arg.input_chan_bindings.application_data.GSS_BUFFER_T_val = 0; + } + + /* set the output parameters to empty values.... */ + if (minor_status != NULL) + *minor_status = 0xffffffff; + if (src_name != NULL) { + src_name->length = 0; + src_name->value = NULL; + } + if (mech_type != NULL) + *mech_type = NULL; + if (output_token != NULL) + output_token->length = 0; + if (ret_flags != NULL) + *ret_flags = 0; + if (time_rec != NULL) + *time_rec = 0; + if (delegated_cred_handle != NULL) + *delegated_cred_handle = NULL; + + /* call the remote procedure */ + memset(&res, 0, sizeof (res)); + if (gss_accept_sec_context_1(&arg, &res, clnt) != RPC_SUCCESS) { + return (GSS_S_FAILURE); + } + + + if (res.status == (OM_uint32) GSS_S_COMPLETE || + res.status == (OM_uint32) GSS_S_CONTINUE_NEEDED) { + /* + * when gss returns CONTINUE_NEEDED we can only + * use the context, minor, and output token + * parameters. + */ + /*LINTED*/ + *context_handle = *((gssd_ctx_id_t *) + res.context_handle.GSS_CTX_ID_T_val); + *gssd_context_verifier = res.gssd_context_verifier; + + if (output_token != NULL) { + output_token->length = + res.output_token.GSS_BUFFER_T_len; + output_token->value = + (void *) res.output_token.GSS_BUFFER_T_val; + res.output_token.GSS_BUFFER_T_val = 0; + res.output_token.GSS_BUFFER_T_len = 0; + } + + if (minor_status != NULL) + *minor_status = res.minor_status; + + /* the other parameters are ready on for COMPLETE */ + if (res.status == GSS_S_COMPLETE) + { + + /* + * The src_name is in external format. + */ + if (src_name != NULL) { + src_name->length = res.src_name.GSS_BUFFER_T_len; + src_name->value = res.src_name.GSS_BUFFER_T_val; + res.src_name.GSS_BUFFER_T_val = NULL; + res.src_name.GSS_BUFFER_T_len = 0; + } + /* + * move mech type returned to mech_type + * for gss_import_name_for_mech() + */ + if (mech_type != NULL) { + *mech_type = + (gss_OID) MALLOC(sizeof (gss_OID_desc)); + (*mech_type)->length = + (OM_UINT32) res.mech_type.GSS_OID_len; + (*mech_type)->elements = + (void *) MALLOC((*mech_type)->length); + memcpy((*mech_type)->elements, + res.mech_type.GSS_OID_val, + (*mech_type)->length); + } + + if (ret_flags != NULL) + *ret_flags = res.ret_flags; + + if (time_rec != NULL) + *time_rec = res.time_rec; + + if ((delegated_cred_handle != NULL) && + (res.delegated_cred_handle.GSS_CRED_ID_T_len + != 0)) { + kcred = KGSS_CRED_ALLOC(); + /*LINTED*/ + kcred->gssd_cred = *((gssd_cred_id_t *) + res.delegated_cred_handle.GSS_CRED_ID_T_val); + kcred->gssd_cred_verifier = + res.gssd_context_verifier; + *delegated_cred_handle = (gss_cred_id_t)kcred; + } + } /* res.status == GSS_S_COMPLETE */ + } /* res.status == GSS_S_COMPLETE or GSS_CONTINUE_NEEDED */ + + + /* + * free the memory allocated for the results and return with the status + * received in the rpc call + */ + + clnt_freeres(clnt, xdr_gss_accept_sec_context_res, (caddr_t)&res); + return (res.status); +} + +OM_uint32 +kgss_accept_sec_context( + OM_uint32 *minor_status, + gss_ctx_id_t *context_handle, + gss_cred_id_t verifier_cred_handle, + gss_buffer_t input_token, + gss_channel_bindings_t input_chan_bindings, + gss_buffer_t src_name, + gss_OID *mech_type, + gss_buffer_t output_token, + int *ret_flags, + OM_uint32 *time_rec, + gss_cred_id_t *delegated_cred_handle, + uid_t uid) +{ + OM_uint32 err; + struct kgss_ctx *kctx; + OM_uint32 gssd_cred_verifier; + gssd_cred_id_t gssd_ver_cred_handle; + + + if (*context_handle == GSS_C_NO_CONTEXT) { + kctx = KGSS_ALLOC(); + *context_handle = (gss_ctx_id_t)kctx; + kctx->gssd_ctx = (gssd_ctx_id_t)GSS_C_NO_CONTEXT; + } else + kctx = (struct kgss_ctx *)*context_handle; + + if (verifier_cred_handle != GSS_C_NO_CREDENTIAL) { + gssd_cred_verifier = + KCRED_TO_CREDV(verifier_cred_handle); + gssd_ver_cred_handle = + KCRED_TO_CRED(verifier_cred_handle); + } else + gssd_ver_cred_handle = (gssd_cred_id_t)GSS_C_NO_CREDENTIAL; + + err = kgss_accept_sec_context_wrapped(minor_status, + &kctx->gssd_ctx, + &kctx->gssd_ctx_verifier, gssd_ver_cred_handle, + gssd_cred_verifier, input_token, input_chan_bindings, + src_name, mech_type, output_token, ret_flags, + time_rec, delegated_cred_handle, uid); + + if (GSS_ERROR(err)) { + KGSS_FREE(kctx); + *context_handle = GSS_C_NO_CONTEXT; + + } + + return (err); +} + +OM_uint32 +kgss_process_context_token(minor_status, + context_handle, + token_buffer, + uid) + OM_uint32 *minor_status; + gss_ctx_id_t context_handle; + gss_buffer_t token_buffer; + uid_t uid; +{ + OM_uint32 gssd_context_verifier; + + gss_process_context_token_arg arg; + gss_process_context_token_res res; + + gssd_context_verifier = KGSS_CTX_TO_GSSD_CTXV(context_handle); + + /* get the client handle to GSSD */ + + if ((clnt = getgssd_handle()) == NULL) { + clnt_pcreateerror(server); + return (GSS_S_FAILURE); + } + + /* copy the procedure arguments into the rpc arg parameter */ + arg.uid = (OM_uint32) uid; + + arg.context_handle.GSS_CTX_ID_T_len = (uint_t)sizeof (gss_ctx_id_t); + arg.context_handle.GSS_CTX_ID_T_val = (char *)&context_handle; + arg.gssd_context_verifier = gssd_context_verifier; + arg.token_buffer.GSS_BUFFER_T_len = (uint_t)token_buffer; + arg.token_buffer.GSS_BUFFER_T_val = (char *)token_buffer->value; + + /* call the remote procedure */ + + memset(&res, 0, sizeof (res)); + if (gss_process_context_token_1(&arg, &res, clnt) != RPC_SUCCESS) { + + /* + * if the RPC call times out, null out all return arguments, + * set minor_status to its maximum value, and return GSS_S_FAILURE + */ + + if (minor_status != NULL) + *minor_status = 0xffffffff; + + return (GSS_S_FAILURE); + } + + /* copy the rpc results into the return arguments */ + + if (minor_status != NULL) + *minor_status = res.minor_status; + + /* return with status returned in rpc call */ + + return (res.status); +} + +OM_uint32 +kgss_delete_sec_context_wrapped(minor_status, + context_handle, + gssd_context_verifier, + output_token) + OM_uint32 *minor_status; + gssd_ctx_id_t *context_handle; + OM_uint32 gssd_context_verifier; + gss_buffer_t output_token; +{ + gss_delete_sec_context_arg arg; + gss_delete_sec_context_res res; + + + /* get the client handle to GSSD */ + if ((clnt = getgssd_handle()) == NULL) { + clnt_pcreateerror(server); + return (GSS_S_FAILURE); + } + + /* copy the procedure arguments into the rpc arg parameter */ + + arg.context_handle.GSS_CTX_ID_T_len = + *context_handle == (OM_uint32) GSS_C_NO_CONTEXT ? 0 : + (uint_t)sizeof (OM_uint32); + arg.context_handle.GSS_CTX_ID_T_val = (char *)context_handle; + + arg.gssd_context_verifier = gssd_context_verifier; + + /* call the remote procedure */ + + memset(&res, 0, sizeof (res)); + if (gss_delete_sec_context_1(&arg, &res, clnt) != RPC_SUCCESS) { + + /* + * if the RPC call times out, null out all return arguments, + * set minor_status to its max value, and return GSS_S_FAILURE + */ + + if (minor_status != NULL) + *minor_status = 0xffffffff; + if (context_handle != NULL) + *context_handle = NULL; + if (output_token != NULL) + output_token->length = 0; + + return (GSS_S_FAILURE); + } + + /* copy the rpc results into the return arguments */ + + if (minor_status != NULL) + *minor_status = res.minor_status; + + if (res.context_handle.GSS_CTX_ID_T_len == 0) + *context_handle = NULL; + else + /*LINTED*/ + *context_handle = *((gssd_ctx_id_t *) + res.context_handle.GSS_CTX_ID_T_val); + + if (output_token != NULL) { + output_token->length = res.output_token.GSS_BUFFER_T_len; + output_token->value = res.output_token.GSS_BUFFER_T_val; + res.output_token.GSS_BUFFER_T_len = 0; + res.output_token.GSS_BUFFER_T_val = NULL; + } + + /* + * free the memory allocated for the results and return with the status + * received in the rpc call + */ + + clnt_freeres(clnt, xdr_gss_delete_sec_context_res, (caddr_t)&res); + return (res.status); +} + +/*ARGSUSED*/ +OM_uint32 +kgss_delete_sec_context( + OM_uint32 *minor_status, + gss_ctx_id_t *context_handle, + gss_buffer_t output_token) +{ + OM_uint32 err; + struct kgss_ctx *kctx; + + if (*context_handle == GSS_C_NO_CONTEXT) { + return (GSS_S_NO_CONTEXT); + } else + kctx = KCTX_TO_KGSS_CTX(*context_handle); + + err = kgss_delete_sec_context_wrapped(minor_status, + &kctx->gssd_ctx, kctx->gssd_ctx_verifier, + output_token); + + if (kctx->gssd_ctx != (gssd_ctx_id_t)GSS_C_NO_CONTEXT) + err = GSS_S_FAILURE; + else + err = GSS_S_COMPLETE; + + KGSS_FREE(kctx); + *context_handle = GSS_C_NO_CONTEXT; + return (err); +} + +/*ARGSUSED*/ +OM_uint32 +kgss_context_time(minor_status, + context_handle, + time_rec, + uid) + OM_uint32 *minor_status; + gss_ctx_id_t context_handle; + OM_uint32 *time_rec; + uid_t uid; +{ + return (GSS_S_FAILURE); +} + +OM_uint32 +kgss_sign_wrapped(minor_status, + context_handle, + qop_req, + message_buffer, + msg_token, + gssd_context_verifier) + OM_uint32 *minor_status; + gssd_ctx_id_t context_handle; + OM_uint32 gssd_context_verifier; + int qop_req; + gss_buffer_t message_buffer; + gss_buffer_t msg_token; +{ + + gss_sign_arg arg; + gss_sign_res res; + + /* get the client handle to GSSD */ + + if ((clnt = getgssd_handle()) == NULL) { + clnt_pcreateerror(server); + return (GSS_S_FAILURE); + } + + /* copy the procedure arguments into the rpc arg parameter */ + + + arg.context_handle.GSS_CTX_ID_T_len = (uint_t)sizeof (gssd_ctx_id_t); + arg.context_handle.GSS_CTX_ID_T_val = (char *)&context_handle; + arg.gssd_context_verifier = gssd_context_verifier; + + arg.qop_req = qop_req; + arg.message_buffer.GSS_BUFFER_T_len = (uint_t)message_buffer->length; + arg.message_buffer.GSS_BUFFER_T_val = (char *)message_buffer->value; + + /* call the remote procedure */ + + memset(&res, 0, sizeof (res)); + if (gss_sign_1(&arg, &res, clnt) != RPC_SUCCESS) { + + /* + * if the RPC call times out, null out all return arguments, + * set minor_status to its maximum value, and return GSS_S_FAILURE + */ + + if (minor_status != NULL) + *minor_status = 0xffffffff; + if (msg_token != NULL) + msg_token->length = 0; + + return (GSS_S_FAILURE); + } + + /* copy the rpc results into the return arguments */ + + if (minor_status != NULL) + *minor_status = res.minor_status; + + if (msg_token != NULL) { + msg_token->length = res.msg_token.GSS_BUFFER_T_len; + msg_token->value = (void *) MALLOC(msg_token->length); + memcpy(msg_token->value, res.msg_token.GSS_BUFFER_T_val, + msg_token->length); + } + + /* + * free the memory allocated for the results and return with the status + * received in the rpc call + */ + + clnt_freeres(clnt, xdr_gss_sign_res, (caddr_t)&res); + return (res.status); +} + +OM_uint32 +kgss_sign( + OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + int qop_req, + gss_buffer_t message_buffer, + gss_buffer_t msg_token) +{ + if (context_handle == GSS_C_NO_CONTEXT) + return (GSS_S_FAILURE); + + return (KGSS_SIGN(minor_status, + context_handle, qop_req, message_buffer, + msg_token)); +} + +OM_uint32 +kgss_verify_wrapped( + minor_status, + context_handle, + message_buffer, + token_buffer, + qop_state, + gssd_context_verifier) + OM_uint32 *minor_status; + gssd_ctx_id_t context_handle; + OM_uint32 gssd_context_verifier; + gss_buffer_t message_buffer; + gss_buffer_t token_buffer; + int *qop_state; +{ + gss_verify_arg arg; + gss_verify_res res; + +/* get the client handle to GSSD */ + + if ((clnt = getgssd_handle()) == NULL) { + clnt_pcreateerror(server); + return (GSS_S_FAILURE); + } + + /* copy the procedure arguments into the rpc arg parameter */ + + arg.context_handle.GSS_CTX_ID_T_len = (uint_t)sizeof (gssd_ctx_id_t); + arg.context_handle.GSS_CTX_ID_T_val = (char *)&context_handle; + + arg.gssd_context_verifier = gssd_context_verifier; + + arg.message_buffer.GSS_BUFFER_T_len = (uint_t)message_buffer->length; + arg.message_buffer.GSS_BUFFER_T_val = (char *)message_buffer->value; + + arg.token_buffer.GSS_BUFFER_T_len = (uint_t)token_buffer->length; + arg.token_buffer.GSS_BUFFER_T_val = (char *)token_buffer->value; + + /* call the remote procedure */ + + memset(&res, 0, sizeof (res)); + if (gss_verify_1(&arg, &res, clnt) != RPC_SUCCESS) { + + /* + * if the RPC call times out, null out all return arguments, + * set minor_status to its maximum value, and return GSS_S_FAILURE + */ + + if (minor_status != NULL) + *minor_status = 0xffffffff; + if (qop_state != NULL) + *qop_state = 0; + + return (GSS_S_FAILURE); + } + + /* copy the rpc results into the return arguments */ + + if (minor_status != NULL) + *minor_status = res.minor_status; + + if (qop_state != NULL) + *qop_state = res.qop_state; + + /* return with status returned in rpc call */ + + return (res.status); +} + +OM_uint32 +kgss_verify(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + gss_buffer_t message_buffer, + gss_buffer_t token_buffer, + int *qop_state) +{ + if (context_handle == GSS_C_NO_CONTEXT) + return (GSS_S_FAILURE); + + return (KGSS_VERIFY(minor_status, context_handle, + message_buffer, + token_buffer, qop_state)); +} + + +/* EXPORT DELETE START */ + +OM_uint32 +kgss_seal_wrapped( + minor_status, + context_handle, + conf_req_flag, + qop_req, + input_message_buffer, + conf_state, + output_message_buffer, + gssd_context_verifier) + + OM_uint32 *minor_status; + gssd_ctx_id_t context_handle; + OM_uint32 gssd_context_verifier; + int conf_req_flag; + int qop_req; + gss_buffer_t input_message_buffer; + int *conf_state; + gss_buffer_t output_message_buffer; +{ + gss_seal_arg arg; + gss_seal_res res; + + /* get the client handle to GSSD */ + + if ((clnt = getgssd_handle()) == NULL) { + clnt_pcreateerror(server); + return (GSS_S_FAILURE); + } + + /* copy the procedure arguments into the rpc arg parameter */ + + + arg.context_handle.GSS_CTX_ID_T_len = (uint_t)sizeof (gssd_ctx_id_t); + arg.context_handle.GSS_CTX_ID_T_val = (char *)&context_handle; + arg.gssd_context_verifier = gssd_context_verifier; + + arg.conf_req_flag = conf_req_flag; + + arg.qop_req = qop_req; + + arg.input_message_buffer.GSS_BUFFER_T_len = + (uint_t)input_message_buffer->length; + + arg.input_message_buffer.GSS_BUFFER_T_val = + (char *)input_message_buffer->value; + + /* call the remote procedure */ + + memset(&res, 0, sizeof (res)); + if (gss_seal_1(&arg, &res, clnt) != RPC_SUCCESS) { + + /* + * if the RPC call times out, null out all return arguments, + * set minor_status to its maximum value, and return GSS_S_FAILURE + */ + + if (minor_status != NULL) + *minor_status = 0xffffffff; + if (conf_state != NULL) + *conf_state = 0; + if (output_message_buffer != NULL) + output_message_buffer->length = 0; + + return (GSS_S_FAILURE); + } + + /* copy the rpc results into the return arguments */ + + if (minor_status != NULL) + *minor_status = res.minor_status; + + if (conf_state != NULL) + *conf_state = res.conf_state; + + if (output_message_buffer != NULL) { + output_message_buffer->length = + res.output_message_buffer.GSS_BUFFER_T_len; + + output_message_buffer->value = + (void *) MALLOC(output_message_buffer->length); + memcpy(output_message_buffer->value, + res.output_message_buffer.GSS_BUFFER_T_val, + output_message_buffer->length); + } + + /* + * free the memory allocated for the results and return with the status + * received in the rpc call + */ + + clnt_freeres(clnt, xdr_gss_seal_res, (caddr_t)&res); + return (res.status); +} + +OM_uint32 +kgss_seal(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + int conf_req_flag, + int qop_req, + gss_buffer_t input_message_buffer, + int *conf_state, + gss_buffer_t output_message_buffer) + +{ + if (context_handle == GSS_C_NO_CONTEXT) + return (GSS_S_FAILURE); + + return (KGSS_SEAL(minor_status, context_handle, + conf_req_flag, qop_req, + input_message_buffer, + conf_state, output_message_buffer)); +} + +OM_uint32 +kgss_unseal_wrapped(minor_status, + context_handle, + input_message_buffer, + output_message_buffer, + conf_state, + qop_state, + gssd_context_verifier) + OM_uint32 *minor_status; + gssd_ctx_id_t context_handle; + OM_uint32 gssd_context_verifier; + gss_buffer_t input_message_buffer; + gss_buffer_t output_message_buffer; + int *conf_state; + int *qop_state; +{ + gss_unseal_arg arg; + gss_unseal_res res; + + /* get the client handle to GSSD */ + + if ((clnt = getgssd_handle()) == NULL) { + clnt_pcreateerror(server); + return (GSS_S_FAILURE); + } + + /* copy the procedure arguments into the rpc arg parameter */ + + + arg.context_handle.GSS_CTX_ID_T_len = (uint_t)sizeof (gssd_ctx_id_t); + arg.context_handle.GSS_CTX_ID_T_val = (char *)&context_handle; + arg.gssd_context_verifier = gssd_context_verifier; + + arg.input_message_buffer.GSS_BUFFER_T_len = + (uint_t)input_message_buffer->length; + + arg.input_message_buffer.GSS_BUFFER_T_val = + (char *)input_message_buffer->value; + +/* call the remote procedure */ + + memset(&res, 0, sizeof (res)); + if (gss_unseal_1(&arg, &res, clnt) != RPC_SUCCESS) { + + /* + * if the RPC call times out, null out all return arguments, + * set minor_status to its maximum value, and return GSS_S_FAILURE + */ + + if (minor_status != NULL) + *minor_status = 0xffffffff; + if (output_message_buffer != NULL) + output_message_buffer->length = 0; + if (conf_state != NULL) + *conf_state = 0; + if (qop_state != NULL) + *qop_state = 0; + + return (GSS_S_FAILURE); + } + + /* copy the rpc results into the return arguments */ + + if (minor_status != NULL) + *minor_status = res.minor_status; + + if (output_message_buffer != NULL) { + output_message_buffer->length = + res.output_message_buffer.GSS_BUFFER_T_len; + + output_message_buffer->value = + (void *) MALLOC(output_message_buffer->length); + memcpy(output_message_buffer->value, + res.output_message_buffer.GSS_BUFFER_T_val, + output_message_buffer->length); + } + + if (conf_state != NULL) + *conf_state = res.conf_state; + + if (qop_state != NULL) + *qop_state = res.qop_state; + + /* + * free the memory allocated for the results and return with the status + * received in the rpc call + */ + + clnt_freeres(clnt, xdr_gss_unseal_res, (caddr_t)&res); + return (res.status); +} + +OM_uint32 +kgss_unseal(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + gss_buffer_t input_message_buffer, + gss_buffer_t output_message_buffer, + int *conf_state, + int *qop_state) +{ + if (context_handle == GSS_C_NO_CONTEXT) + return (GSS_S_FAILURE); + + return (KGSS_UNSEAL(minor_status, context_handle, + input_message_buffer, + output_message_buffer, + conf_state, qop_state)); +} + +/* EXPORT DELETE END */ + +OM_uint32 +kgss_display_status(minor_status, + status_value, + status_type, + mech_type, + message_context, + status_string, + uid) + OM_uint32 *minor_status; + OM_uint32 status_value; + int status_type; + gss_OID mech_type; + int *message_context; + gss_buffer_t status_string; + uid_t uid; +{ + gss_display_status_arg arg; + gss_display_status_res res; + + /* get the client handle to GSSD */ + + if ((clnt = getgssd_handle()) == NULL) { + clnt_pcreateerror(server); + return (GSS_S_FAILURE); + } + + /* copy the procedure arguments into the rpc arg parameter */ + + arg.uid = (OM_uint32) uid; + + arg.status_value = status_value; + arg.status_type = status_type; + + arg.mech_type.GSS_OID_len = (uint_t)(mech_type != GSS_C_NULL_OID ? + mech_type->length : 0); + arg.mech_type.GSS_OID_val = (char *)(mech_type != GSS_C_NULL_OID ? + mech_type->elements : 0); + + arg.message_context = *message_context; + + /* call the remote procedure */ + + if (message_context != NULL) + *message_context = 0; + if (status_string != NULL) { + status_string->length = 0; + status_string->value = NULL; + } + + memset(&res, 0, sizeof (res)); + if (gss_display_status_1(&arg, &res, clnt) != RPC_SUCCESS) { + + /* + * if the RPC call times out, null out all return arguments, + * set minor_status to its maximum value, and return GSS_S_FAILURE + */ + + if (minor_status != NULL) + *minor_status = 0xffffffff; + + return (GSS_S_FAILURE); + } + + + /* now process the results and pass them back to the caller */ + + if (res.status == GSS_S_COMPLETE) { + if (minor_status != NULL) + *minor_status = res.minor_status; + if (message_context != NULL) + *message_context = res.message_context; + if (status_string != NULL) { + status_string->length = + (size_t)res.status_string.GSS_BUFFER_T_len; + status_string->value = + (void *)MALLOC(status_string->length); + memcpy(status_string->value, + res.status_string.GSS_BUFFER_T_val, + status_string->length); + } + } + + clnt_freeres(clnt, xdr_gss_display_status_res, (caddr_t)&res); + return (res.status); +} + +/*ARGSUSED*/ +OM_uint32 +kgss_indicate_mechs(minor_status, + mech_set, + uid) + OM_uint32 *minor_status; + gss_OID_set *mech_set; + uid_t uid; +{ + void *arg; + gss_indicate_mechs_res res; + int i; + + /* get the client handle to GSSD */ + + if ((clnt = getgssd_handle()) == NULL) { + clnt_pcreateerror(server); + return (GSS_S_FAILURE); + } + + memset(&res, 0, sizeof (res)); + if (gss_indicate_mechs_1(&arg, &res, clnt) != RPC_SUCCESS) { + + /* + * if the RPC call times out, null out all return arguments, + * set minor_status to its maximum value, and return GSS_S_FAILURE + */ + + if (minor_status != NULL) + *minor_status = 0xffffffff; + if (mech_set != NULL) + *mech_set = NULL; + + return (GSS_S_FAILURE); + } + + /* copy the rpc results into the return arguments */ + + if (minor_status != NULL) + *minor_status = res.minor_status; + + if (mech_set != NULL) { + *mech_set = (gss_OID_set) MALLOC(sizeof (gss_OID_set_desc)); + (*mech_set)->count = res.mech_set.GSS_OID_SET_len; + (*mech_set)->elements = (void *) + MALLOC ((*mech_set)->count * sizeof (gss_OID_desc)); + for (i = 0; i < (*mech_set)->count; i++) { + (*mech_set)->elements[i].length = + res.mech_set.GSS_OID_SET_val[i].GSS_OID_len; + (*mech_set)->elements[i].elements = (void *) + MALLOC ((*mech_set)->elements[i].length); + memcpy ((*mech_set)->elements[i].elements, + res.mech_set.GSS_OID_SET_val[i].GSS_OID_val, + (*mech_set)->elements[i].length); + } + } + + /* + * free the memory allocated for the results and return with the status + * received in the rpc call + */ + + clnt_freeres(clnt, xdr_gss_indicate_mechs_res, (caddr_t)&res); + return (res.status); +} + + +OM_uint32 +kgss_inquire_cred_wrapped(minor_status, + cred_handle, + gssd_cred_verifier, + name, + lifetime, + cred_usage, + mechanisms, + uid) + OM_uint32 *minor_status; + gssd_cred_id_t cred_handle; + OM_uint32 gssd_cred_verifier; + gss_name_t *name; + OM_uint32 *lifetime; + int *cred_usage; + gss_OID_set *mechanisms; + uid_t uid; +{ + OM_uint32 minor_status_temp; + gss_buffer_desc external_name; + gss_OID name_type; + int i; + + gss_inquire_cred_arg arg; + gss_inquire_cred_res res; + + /* get the client handle to GSSD */ + + if ((clnt = getgssd_handle()) == NULL) { + clnt_pcreateerror(server); + return (GSS_S_FAILURE); + } + + + /* copy the procedure arguments into the rpc arg parameter */ + + arg.uid = (OM_uint32) uid; + + arg.cred_handle.GSS_CRED_ID_T_len = + cred_handle == (gssd_cred_id_t)GSS_C_NO_CREDENTIAL ? + 0 : (uint_t)sizeof (gssd_cred_id_t); + arg.cred_handle.GSS_CRED_ID_T_val = (char *)&cred_handle; + arg.gssd_cred_verifier = gssd_cred_verifier; + + /* call the remote procedure */ + + memset(&res, 0, sizeof (res)); + if (gss_inquire_cred_1(&arg, &res, clnt) != RPC_SUCCESS) { + + /* + * if the RPC call times out, null out all return arguments, + * set minor_status to its maximum value, and return GSS_S_FAILURE + */ + + if (minor_status != NULL) + *minor_status = 0xffffffff; + if (name != NULL) + *name = NULL; + if (lifetime != NULL) + *lifetime = 0; + if (cred_usage != NULL) + *cred_usage = 0; + if (mechanisms != NULL) + *mechanisms = NULL; + + return (GSS_S_FAILURE); + } + + /* copy the rpc results into the return arguments */ + + if (minor_status != NULL) + *minor_status = res.minor_status; + + /* convert name from external to internal format */ + + if (name != NULL) { + external_name.length = res.name.GSS_BUFFER_T_len; + external_name.value = res.name.GSS_BUFFER_T_val; + + /* + * we have to allocate a name_type descriptor and + * elements storage, since gss_import_name() only + * stores a pointer to the name_type info in the + * union_name struct + */ + + name_type = (gss_OID) MALLOC(sizeof (gss_OID_desc)); + + name_type->length = res.name_type.GSS_OID_len; + name_type->elements = (void *) MALLOC(name_type->length); + memcpy(name_type->elements, res.name_type.GSS_OID_val, + name_type->length); + + if (gss_import_name(&minor_status_temp, &external_name, + name_type, name) != GSS_S_COMPLETE) { + + *minor_status = (OM_uint32) minor_status_temp; + gss_release_buffer(&minor_status_temp, &external_name); + + clnt_freeres(clnt, xdr_gss_inquire_cred_res, + (caddr_t)&res); + return ((OM_uint32) GSS_S_FAILURE); + } + } + + if (lifetime != NULL) + *lifetime = res.lifetime; + + if (cred_usage != NULL) + *cred_usage = res.cred_usage; + + if (mechanisms != NULL) { + *mechanisms = + (gss_OID_set) MALLOC(sizeof (gss_OID_set_desc)); + if (res.mechanisms.GSS_OID_SET_len != 0) { + (*mechanisms)->count = + (int)res.mechanisms.GSS_OID_SET_len; + (*mechanisms)->elements = (gss_OID) + MALLOC(sizeof (gss_OID) * (*mechanisms)->count); + + for (i = 0; i < (*mechanisms)->count; i++) { + (*mechanisms)->elements[i].length = (OM_uint32) + res.mechanisms.GSS_OID_SET_val[i].GSS_OID_len; + (*mechanisms)->elements[i].elements = (void *) + MALLOC((*mechanisms)->elements[i].length); + memcpy((*mechanisms)->elements[i].elements, + res.mechanisms.GSS_OID_SET_val[i].GSS_OID_val, + (*mechanisms)->elements[i].length); + } + } else + (*mechanisms)->count = 0; + } + + /* + * free the memory allocated for the results and return with the status + * received in the rpc call + */ + + clnt_freeres(clnt, xdr_gss_inquire_cred_res, (caddr_t)&res); + return (res.status); +} + + +OM_uint32 +kgss_inquire_cred(minor_status, + cred_handle, + name, + lifetime, + cred_usage, + mechanisms, + uid) + OM_uint32 *minor_status; + gss_cred_id_t cred_handle; + gss_name_t *name; + OM_uint32 *lifetime; + int *cred_usage; + gss_OID_set * mechanisms; + uid_t uid; +{ + + OM_uint32 gssd_cred_verifier; + gssd_cred_id_t gssd_cred_handle; + + gssd_cred_verifier = KCRED_TO_CREDV(cred_handle); + gssd_cred_handle = KCRED_TO_CRED(cred_handle); + + return (kgss_inquire_cred_wrapped(minor_status, + gssd_cred_handle, gssd_cred_verifier, + name, lifetime, cred_usage, mechanisms, uid)); +} + + +OM_uint32 +kgss_inquire_cred_by_mech_wrapped(minor_status, + cred_handle, + gssd_cred_verifier, + mech_type, + uid) + OM_uint32 *minor_status; + gssd_cred_id_t cred_handle; + OM_uint32 gssd_cred_verifier; + gss_OID mech_type; + uid_t uid; +{ + OM_uint32 minor_status_temp; + + gss_inquire_cred_by_mech_arg arg; + gss_inquire_cred_by_mech_res res; + + /* get the client handle to GSSD */ + + if ((clnt = getgssd_handle()) == NULL) { + clnt_pcreateerror(server); + return (GSS_S_FAILURE); + } + + + /* copy the procedure arguments into the rpc arg parameter */ + + arg.uid = (OM_uint32) uid; + + arg.cred_handle.GSS_CRED_ID_T_len = + cred_handle == (gssd_cred_id_t)GSS_C_NO_CREDENTIAL ? + 0 : (uint_t)sizeof (gssd_cred_id_t); + arg.cred_handle.GSS_CRED_ID_T_val = (char *)&cred_handle; + arg.gssd_cred_verifier = gssd_cred_verifier; + + arg.mech_type.GSS_OID_len = + (uint_t)(mech_type != GSS_C_NULL_OID ? + mech_type->length : 0); + arg.mech_type.GSS_OID_val = + (char *)(mech_type != GSS_C_NULL_OID ? + mech_type->elements : 0); + /* call the remote procedure */ + + memset(&res, 0, sizeof (res)); + if (gss_inquire_cred_by_mech_1(&arg, &res, clnt) != RPC_SUCCESS) { + + /* + * if the RPC call times out, null out all return arguments, + * set minor_status to its maximum value, and return GSS_S_FAILURE + */ + + if (minor_status != NULL) + *minor_status = 0xffffffff; + return (GSS_S_FAILURE); + } + + /* copy the rpc results into the return arguments */ + + if (minor_status != NULL) + *minor_status = res.minor_status; + + /* convert name from external to internal format */ + + /* + * free the memory allocated for the results and return with the status + * received in the rpc call + */ + + clnt_freeres(clnt, xdr_gss_inquire_cred_by_mech_res, (caddr_t)&res); + return (res.status); +} + + +OM_uint32 +kgss_inquire_cred_by_mech(minor_status, + cred_handle, + mech_type, + uid) + OM_uint32 *minor_status; + gss_cred_id_t cred_handle; + gss_OID mech_type; + uid_t uid; +{ + + OM_uint32 gssd_cred_verifier; + gssd_cred_id_t gssd_cred_handle; + + gssd_cred_verifier = KCRED_TO_CREDV(cred_handle); + gssd_cred_handle = KCRED_TO_CRED(cred_handle); + + return (kgss_inquire_cred_by_mech_wrapped(minor_status, + gssd_cred_handle, gssd_cred_verifier, + mech_type, uid)); +} + +OM_uint32 +kgsscred_expname_to_unix_cred(expName, uidOut, gidOut, gids, gidsLen, uid) + const gss_buffer_t expName; + uid_t *uidOut; + gid_t *gidOut; + gid_t *gids[]; + int *gidsLen; + uid_t uid; +{ + gsscred_expname_to_unix_cred_arg args; + gsscred_expname_to_unix_cred_res res; + + /* check input/output parameters */ + if (expName == NULL || expName->value == NULL) + return (GSS_S_CALL_INACCESSIBLE_READ); + + if (uidOut == NULL) + return (GSS_S_CALL_INACCESSIBLE_WRITE); + + /* NULL out output parameters */ + *uidOut = 0; + if (gidsLen) + *gidsLen = 0; + + if (gids) + *gids = NULL; + + /* get the client handle to gssd */ + if ((clnt = getgssd_handle()) == NULL) + { + clnt_pcreateerror(server); + return (GSS_S_FAILURE); + } + + /* copy the procedure arguments */ + args.uid = uid; + args.expname.GSS_BUFFER_T_val = expName->value; + args.expname.GSS_BUFFER_T_len = expName->length; + + /* null out the return buffer and call the remote proc */ + memset(&res, 0, sizeof (res)); + + if (gsscred_expname_to_unix_cred_1(&args, &res, clnt) != RPC_SUCCESS) + { + return (GSS_S_FAILURE); + } + + /* copy the results into the result parameters */ + if (res.major == GSS_S_COMPLETE) + { + *uidOut = res.uid; + if (gidOut) + *gidOut = res.gid; + if (gids && gidsLen) + { + *gids = res.gids.GSSCRED_GIDS_val; + *gidsLen = res.gids.GSSCRED_GIDS_len; + res.gids.GSSCRED_GIDS_val = NULL; + res.gids.GSSCRED_GIDS_len = 0; + } + } + + /* free RPC results */ + clnt_freeres(clnt, xdr_gsscred_expname_to_unix_cred_res, (caddr_t)&res); + + return (res.major); +} /* kgsscred_expname_to_unix_cred */ + +OM_uint32 +kgsscred_name_to_unix_cred(intName, mechType, uidOut, gidOut, gids, + gidsLen, uid) + const gss_name_t intName; + const gss_OID mechType; + uid_t *uidOut; + gid_t *gidOut; + gid_t *gids[]; + int *gidsLen; + uid_t uid; +{ + gsscred_name_to_unix_cred_arg args; + gsscred_name_to_unix_cred_res res; + OM_uint32 major, minor; + gss_OID nameOid; + gss_buffer_desc flatName = GSS_C_EMPTY_BUFFER; + + + /* check the input/output parameters */ + if (intName == NULL || mechType == NULL) + return (GSS_S_CALL_INACCESSIBLE_READ); + + if (uidOut == NULL) + return (GSS_S_CALL_INACCESSIBLE_WRITE); + + /* NULL out the output parameters */ + *uidOut = 0; + if (gids) + *gids = NULL; + + if (gidsLen) + *gidsLen = 0; + + /* get the client handle to gssd */ + if ((clnt = getgssd_handle()) == NULL) + { + clnt_pcreateerror(server); + return (GSS_S_FAILURE); + } + + /* convert the name to flat representation */ + if ((major = gss_display_name(&minor, intName, &flatName, &nameOid)) + != GSS_S_COMPLETE) + { + return (major); + } + + /* set the rpc parameters */ + args.uid = uid; + args.pname.GSS_BUFFER_T_len = flatName.length; + args.pname.GSS_BUFFER_T_val = flatName.value; + args.name_type.GSS_OID_len = nameOid->length; + args.name_type.GSS_OID_val = nameOid->elements; + args.mech_type.GSS_OID_len = mechType->length; + args.mech_type.GSS_OID_val = mechType->elements; + + /* call the remote procedure */ + memset(&res, 0, sizeof (res)); + if (gsscred_name_to_unix_cred_1(&args, &res, clnt) != RPC_SUCCESS) + { + gss_release_buffer(&minor, &flatName); + return (GSS_S_FAILURE); + } + + gss_release_buffer(&minor, &flatName); + /* copy the output parameters on output */ + if (res.major == GSS_S_COMPLETE) + { + *uidOut = res.uid; + if (gidOut) + *gidOut = res.gid; + if (gids && gidsLen) + { + *gids = res.gids.GSSCRED_GIDS_val; + *gidsLen = res.gids.GSSCRED_GIDS_len; + res.gids.GSSCRED_GIDS_val = NULL; + res.gids.GSSCRED_GIDS_len = 0; + } + } + + /* delete RPC allocated memory */ + clnt_freeres(clnt, xdr_gsscred_name_to_unix_cred_res, (caddr_t)&res); + + return (res.major); +} /* kgsscred_name_to_unix_cred */ + +OM_uint32 +kgss_get_group_info(puid, gidOut, gids, gidsLen, uid) + const uid_t puid; + gid_t *gidOut; + gid_t *gids[]; + int *gidsLen; + uid_t uid; +{ + gss_get_group_info_arg args; + gss_get_group_info_res res; + + + /* check the output parameters */ + if (gidOut == NULL || gids == NULL || gidsLen == NULL) + return (GSS_S_CALL_INACCESSIBLE_WRITE); + + /* get the client GSSD handle */ + if ((clnt = getgssd_handle()) == NULL) + { + clnt_pcreateerror(server); + return (GSS_S_FAILURE); + } + + /* set the input parameters */ + args.uid = uid; + args.puid = puid; + + + /* call the remote procedure */ + memset(&res, 0, sizeof (res)); + if (gss_get_group_info_1(&args, &res, clnt) != RPC_SUCCESS) + { + return (GSS_S_FAILURE); + } + + /* copy the results */ + if (res.major == GSS_S_COMPLETE) + { + *gidOut = res.gid; + *gids = res.gids.GSSCRED_GIDS_val; + *gidsLen = res.gids.GSSCRED_GIDS_len; + res.gids.GSSCRED_GIDS_val = NULL; + res.gids.GSSCRED_GIDS_len = 0; + } + + /* nothing to free */ + + return (res.major); +} /* kgss_get_group_info */ + +OM_uint32 +kgss_export_sec_context_wrapped(minor_status, + context_handle, + output_token, + gssd_context_verifier) + OM_uint32 *minor_status; + gssd_ctx_id_t *context_handle; + gss_buffer_t output_token; + OM_uint32 gssd_context_verifier; +{ + CLIENT *clnt; + gss_export_sec_context_arg arg; + gss_export_sec_context_res res; + + +/* get the client handle to GSSD */ + + if ((clnt = getgssd_handle()) == NULL) { + clnt_pcreateerror(server); + return (GSS_S_FAILURE); + } + +/* copy the procedure arguments into the rpc arg parameter */ + + arg.context_handle.GSS_CTX_ID_T_len = (uint_t)sizeof (gssd_ctx_id_t); + arg.context_handle.GSS_CTX_ID_T_val = (char *)context_handle; + arg.gssd_context_verifier = gssd_context_verifier; + +/* call the remote procedure */ + + memset(&res, 0, sizeof (res)); + if (gss_export_sec_context_1(&arg, &res, clnt) != RPC_SUCCESS) { + +/* + * if the RPC call times out, null out all return arguments, set minor_status + * to its maximum value, and return GSS_S_FAILURE + */ + + if (minor_status != NULL) + *minor_status = DEFAULT_MINOR_STAT; + if (context_handle != NULL) + *context_handle = NULL; + if (output_token != NULL) + output_token->length = 0; + + return (GSS_S_FAILURE); + } + +/* copy the rpc results into the return arguments */ + + if (minor_status != NULL) + *minor_status = res.minor_status; + + if (res.context_handle.GSS_CTX_ID_T_len == 0) + *context_handle = NULL; + else + *context_handle = + *((gssd_ctx_id_t *)res.context_handle.GSS_CTX_ID_T_val); + + if (output_token != NULL) { + output_token->length = res.output_token.GSS_BUFFER_T_len; + output_token->value = + (void *) MALLOC(output_token->length); + memcpy(output_token->value, + res.output_token.GSS_BUFFER_T_val, + output_token->length); + } + +/* + * free the memory allocated for the results and return with the status + * received in the rpc call + */ + + clnt_freeres(clnt, xdr_gss_export_sec_context_res, (caddr_t)&res); + return (res.status); + +} + +OM_uint32 +kgss_export_sec_context(minor_status, + context_handle, + output_token) + OM_uint32 *minor_status; + gss_ctx_id_t *context_handle; + gss_buffer_t output_token; +{ + OM_uint32 err; + struct kgss_ctx *kctx; + + if (*context_handle == GSS_C_NO_CONTEXT) { + return (GSS_S_NO_CONTEXT); + } else + kctx = KCTX_TO_KGSS_CTX(*context_handle); + + err = kgss_export_sec_context_wrapped(minor_status, + &kctx->gssd_ctx, output_token, + kctx->gssd_ctx_verifier); + + if (GSS_ERROR(err)) + return (err); + else { + KGSS_FREE(kctx); + *context_handle = GSS_C_NO_CONTEXT; + return (err); + } + +} + +OM_uint32 +kgss_import_sec_context_wrapped(minor_status, + input_token, + context_handle, + gssd_context_verifier) + OM_uint32 *minor_status; + gss_buffer_t input_token; + gss_ctx_id_t *context_handle; + OM_uint32 gssd_context_verifier; +{ + CLIENT *clnt; + gss_import_sec_context_arg arg; + gss_import_sec_context_res res; + + +/* get the client handle to GSSD */ + + if ((clnt = getgssd_handle()) == NULL) { + clnt_pcreateerror(server); + return (GSS_S_FAILURE); + } + +/* copy the procedure arguments into the rpc arg parameter */ + arg.input_token.GSS_BUFFER_T_len = (uint_t) + (input_token != GSS_C_NO_BUFFER ? input_token->length : 0); + arg.input_token.GSS_BUFFER_T_val = (char *) + (input_token != GSS_C_NO_BUFFER ? input_token->value : 0); + arg.gssd_context_verifier = gssd_context_verifier; + + +/* call the remote procedure */ + + memset(&res, 0, sizeof (res)); + if (gss_import_sec_context_1(&arg, &res, clnt) != RPC_SUCCESS) { + +/* + * if the RPC call times out, null out all return arguments, set minor_status + * to its maximum value, and return GSS_S_FAILURE + */ + + if (minor_status != NULL) + *minor_status = DEFAULT_MINOR_STAT; + if (context_handle != NULL) + *context_handle = NULL; + + return (GSS_S_FAILURE); + } + +/* copy the rpc results into the return arguments */ + + if (minor_status != NULL) + *minor_status = res.minor_status; + + if (res.context_handle.GSS_CTX_ID_T_len == 0) + *context_handle = NULL; + else + *context_handle = + *((gss_ctx_id_t *)res.context_handle.GSS_CTX_ID_T_val); + + +/* + * free the memory allocated for the results and return with the status + * received in the rpc call + */ + + clnt_freeres(clnt, xdr_gss_import_sec_context_res, (caddr_t)&res); + return (res.status); +} + +OM_uint32 +kgss_import_sec_context(minor_status, + input_token, + context_handle) + OM_uint32 *minor_status; + gss_buffer_t input_token; + gss_ctx_id_t *context_handle; +{ + struct kgss_ctx *kctx; + + if (*context_handle == GSS_C_NO_CONTEXT) { + kctx = KGSS_ALLOC(); + *context_handle = (gss_ctx_id_t)kctx; + kctx->gssd_ctx = (OM_uint32) GSS_C_NO_CONTEXT; + } else + kctx = (struct kgss_ctx *)*context_handle; + return (kgss_import_sec_context_wrapped(minor_status, + input_token, &kctx->gssd_ctx, + KCTX_TO_CTXV(context_handle))); +} + +#ifdef _KERNEL +#include <sys/modctl.h> + +static void *gss_clnt = NULL; + +#ifdef DEBUG +typedef struct { + char *name; /* just put something here */ +} gssd_devstate_t; + + +static void *gssd_state; + +static int gssd_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) +{ + /* cmn_err(CE_NOTE, "In gssd_attach"); */ + switch (cmd) { + case DDI_ATTACH: + if (ddi_create_minor_node(dip, "gssd", S_IFCHR, 0, "gssd", 0) + == DDI_FAILURE) { + ddi_remove_minor_node(dip, NULL); + return (DDI_FAILURE); + } + return (DDI_SUCCESS); + + default: + return (DDI_FAILURE); + } +} + +static int gssd_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, + void *arg, void **result) +{ + dev_t dev; + int error; + +/* cmn_err(CE_NOTE, "In gssd_getinfo"); */ + + switch (infocmd) { + case DDI_INFO_DEVT2INSTANCE: + dev = (dev_t)arg; + *result = (void *) getminor(dev); + error = DDI_SUCCESS; + break; + + case DDI_INFO_DEVT2DEVINFO: + /* cmn_err(CE_NOTE, "getinfo wants devinfo"); */ + default: + error = DDI_FAILURE; + break; + } + return (error); +} + +static int gssd_identify(dev_info_t *dip) +{ + /* cmn_err(CE_NOTE, "in gssd_identify"); */ + if (strcmp(ddi_get_name(dip), "gssd") == 0) + return (DDI_IDENTIFIED); + else + return (DDI_NOT_IDENTIFIED); +} + +static int gssd_probe(dev_info_t *dip) +{ + /* cmn_err(CE_NOTE, "In gssd_probe"); */ + + return (DDI_PROBE_SUCCESS); +} + +static int gssd_open(dev_t *devp, int flag, int otyp, cred_t *credp) +{ + /* cmn_err (CE_NOTE, "In gssd_open"); */ + if (otyp != OTYP_CHR) + return (EINVAL); + + gss_clnt = getgssd_handle(); + return (0); +} + +static int gssd_close(dev_t dev, int flag, int otyp, cred_t *credp) +{ + /* cmn_err(CE_NOTE, "In gssd_close"); */ + killgssd_handle(gss_clnt); + return (0); +} + +static int gssd_write(dev_t dev, struct uio *uiop, cred_t *credp) +{ + char buffer[1024]; + int len; + + /* cmn_err(CE_NOTE, "In gssd_write"); */ + bzero(buffer, 1024); + + uiomove(buffer, 1024, UIO_WRITE, uiop); + len = strlen(buffer); + + if (buffer[len-1] == '\n') + buffer[--len] = '\0'; + + cmn_err(CE_NOTE, "Got command: (%d) \"%s\"", len, buffer); + do_gssdtest(buffer); + return (0); +} + +static struct cb_ops gssd_cb_ops = { + gssd_open, /* cb_open */ + gssd_close, /* cb_close */ + nodev, /* cb_strategy */ + nodev, /* cb_print */ + nodev, /* cb_dump */ + nulldev, /* cb_read */ + gssd_write, /* cb_write */ + nodev, /* cb_ioctl */ + nodev, /* cb_devmap */ + nodev, /* cb_mmap */ + nodev, /* cb_segmap */ + nochpoll, /* cb_chpoll */ + ddi_prop_op, /* cb_prop_op */ + NULL, /* cb_stream */ + (int)(D_NEW|D_MP) /* cb_flag */ +}; + +static struct dev_ops gssd_ops = { + DEVO_REV, /* devo_rev */ + 0, /* devo_refcnt */ + gssd_getinfo, /* devo_getinfo */ + gssd_identify, /* devo_identify */ + nulldev, /* devo_probe */ + gssd_attach, /* devo_attach */ + nulldev, /* devo_detach */ + nodev, /* devo_reset */ + &gssd_cb_ops, /* devo_cb_ops */ + (struct bus_ops *)NULL /* devo_bus_ops */ +}; + +extern struct mod_ops mod_driverops; + +static struct modldrv modlmisc = { + &mod_driverops, + "GSSD DRV Client Module", + &gssd_ops + +#else /* !DEBUG */ + +static struct modlmisc modlmisc = { + &mod_miscops, + "GSSD Client Module" +#endif /* DEBUG */ +}; + +static struct modlinkage modlinkage = { + MODREV_1, + (void *)&modlmisc, + NULL +}; + +char _depends_on[] = "strmod/rpcmod misc/tlimod"; + +_init(void) +{ + int status; + + if ((status = ddi_soft_state_init(&gssd_state, + sizeof (gssd_devstate_t), 1)) != 0) + return (status); + + if ((status = mod_install((struct modlinkage *)&modlinkage)) != 0) + ddi_soft_state_fini(&gssd_state); + + cmn_err(CE_NOTE, "gssd: I'm in the kernel: %d.", status); + return (status); +} + +_fini() +{ + int status; + + killgssd_handle(gss_clnt); + cmn_err(CE_NOTE, "gssd: Handle destroyed.. leaving module."); + + if ((status = mod_remove(&modlinkage)) != 0) + return (status); + + ddi_soft_state_fini(&gssd_state); + return (status); +} + +_info(modinfop) +struct modinfo *modinfop; +{ + return (mod_info(&modlinkage, modinfop)); +} + +#endif diff --git a/usr/src/cmd/gss/gssd/gssd_generic.c b/usr/src/cmd/gss/gssd/gssd_generic.c new file mode 100644 index 0000000000..5abfffe090 --- /dev/null +++ b/usr/src/cmd/gss/gssd/gssd_generic.c @@ -0,0 +1,152 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 1988-1997, by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <stdlib.h> +#include <rpc/rpc.h> +#include <errno.h> +#include <syslog.h> +#include <rpc/nettype.h> +#include <netconfig.h> +#include <netdir.h> +#include <tiuser.h> +#include <fcntl.h> +#include <string.h> +#include <rpc/svc.h> +#include <locale.h> + +extern int __rpc_negotiate_uid(int); + +/* + * The highest level interface for server creation. + * Copied from svc_generic.c and cmd/keyserv/key_generic.c, but adapted + * to work only for TPI_CLTS semantics, and to be called only once + * from gssd.c. Returns 1 (interface created) on success and 0 + * (no interfaces created) on failure. + */ +int +svc_create_local_service(dispatch, prognum, versnum, nettype, servname) +void (*dispatch) (); /* Dispatch function */ +u_long prognum; /* Program number */ +u_long versnum; /* Version number */ +char *nettype; /* Networktype token */ +char *servname; /* name of the service */ +{ + int num = 0; + SVCXPRT *xprt; + struct netconfig *nconf; + struct t_bind *bind_addr; + void *net; + int fd; + struct nd_hostserv ns; + struct nd_addrlist *nas; + + if ((net = __rpc_setconf(nettype)) == 0) { + (void) syslog(LOG_ERR, + gettext("svc_create: could not read netconfig database")); + return (0); + } + while (nconf = __rpc_getconf(net)) { + if ((strcmp(nconf->nc_protofmly, NC_LOOPBACK)) || + (nconf->nc_semantics != NC_TPI_COTS_ORD)) + continue; + + if ((fd = t_open(nconf->nc_device, O_RDWR, NULL)) < 0) { + (void) syslog(LOG_ERR, + gettext("svc_create: %s: cannot open connection: %s"), + nconf->nc_netid, t_errlist[t_errno]); + break; + } + + /* + * Negotiate for returning the uid of the caller. + * This should be done before enabling the endpoint for + * service via t_bind() (called in svc_tli_create()) + * so that requests to gssd contain the uid. + */ + if (__rpc_negotiate_uid(fd) != 0) { + syslog(LOG_ERR, + gettext("Could not negotiate for" + " uid with loopback transport %s"), + nconf->nc_netid); + t_close(fd); + break; + } + + /* LINTED pointer alignment */ + bind_addr = (struct t_bind *) t_alloc(fd, T_BIND, T_ADDR); + if ((bind_addr == NULL)) { + (void) t_close(fd); + (void) syslog(LOG_ERR, + gettext("svc_create: t_alloc failed\n")); + break; + } + ns.h_host = HOST_SELF; + ns.h_serv = servname; + if (!netdir_getbyname(nconf, &ns, &nas)) { + /* Copy the address */ + bind_addr->addr.len = nas->n_addrs->len; + (void) memcpy(bind_addr->addr.buf, nas->n_addrs->buf, + (int) nas->n_addrs->len); + bind_addr->qlen = 8; + netdir_free((char *) nas, ND_ADDRLIST); + } else { + (void) syslog(LOG_ERR, + gettext("svc_create: no well known " + "address for %s on %s\n"), + servname, nconf->nc_netid); + (void) t_free((char *) bind_addr, T_BIND); + bind_addr = NULL; + } + + xprt = svc_tli_create(fd, nconf, bind_addr, 0, 0); + if (bind_addr) + (void) t_free((char *) bind_addr, T_BIND); + if (xprt == NULL) { + (void) t_close(fd); + (void) syslog(LOG_ERR, + gettext("svc_create: svc_tli_create failed\n")); + break; + } else { + (void) rpcb_unset(prognum, versnum, nconf); + if (svc_reg(xprt, prognum, versnum, dispatch, nconf) + == FALSE) { + (void) syslog(LOG_ERR, + gettext("svc_create: cannot" + " register %d vers %d on %s"), + prognum, versnum, nconf->nc_netid); + SVC_DESTROY(xprt); /* also t_closes fd */ + break; + } + num = 1; + break; + } + } + __rpc_endconf(net); + return (num); +} diff --git a/usr/src/cmd/gss/gssd/gssd_getuid.c b/usr/src/cmd/gss/gssd/gssd_getuid.c new file mode 100644 index 0000000000..370b1f81af --- /dev/null +++ b/usr/src/cmd/gss/gssd/gssd_getuid.c @@ -0,0 +1,70 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 1995,1997, by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Routines to set gssd value of uid and replace getuid libsys call. + */ + +#include <sys/types.h> +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <libintl.h> + +uid_t gssd_uid; + +void +set_gssd_uid(uid) + uid_t uid; +{ + + /* + * set the value of gssd_uid, so it can be retrieved when getuid() + * is called by the underlying mechanism libraries + */ + printf(gettext("set_gssd_uid called with uid = %d\n"), uid); + gssd_uid = uid; +} + +uid_t +getuid(void) + +{ + + /* + * return the value set when one of the gssd procedures was + * entered. This is the value of the uid under which the + * underlying mechanism library must operate in order to + * get the user's credentials. This call is necessary since + * gssd runs as root and credentials are many times stored + * in files and directories specific to the user + */ + printf(gettext( + "getuid called and returning gsssd_uid = %d\n"), gssd_uid); + return (gssd_uid); +} diff --git a/usr/src/cmd/gss/gssd/gssd_handle.c b/usr/src/cmd/gss/gssd/gssd_handle.c new file mode 100644 index 0000000000..fa0c5840d4 --- /dev/null +++ b/usr/src/cmd/gss/gssd/gssd_handle.c @@ -0,0 +1,145 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * Copyright (c) 1982, 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T + * All Rights Reserved + * + * Portions of this source code were derived from Berkeley + * 4.3 BSD under license from the Regents of the University of + * California. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" +/* from kerbd_handle.c 1.3 92/01/29 SMI */ + +/* + * gssd_handle.c, Interface to gssd + * + */ + +#include <unistd.h> +#include <rpc/rpc.h> +#include <rpc/clnt.h> +#include <stdio.h> +#include <string.h> +#include <netconfig.h> +#include <sys/utsname.h> +#include "gssd.h" + +#ifdef DEBUG +#define dprt(msg) (void) fprintf(stderr, "%s\n", msg); +#else +#define dprt(msg) +#endif /* DEBUG */ + + +/* + * Keep the handle cached. This call may be made quite often. + */ + +CLIENT * +getgssd_handle() +{ + void *localhandle; + struct netconfig *nconf; + struct netconfig *tpconf; + static CLIENT *clnt; + struct timeval wait_time; + struct utsname u; + static char *hostname; + static bool_t first_time = TRUE; + +#define TOTAL_TIMEOUT 1000 /* total timeout talking to gssd */ +#define TOTAL_TRIES 1 /* Number of tries */ + + if (clnt) + return (clnt); + if (!(localhandle = setnetconfig())) + return (NULL); + tpconf = NULL; + if (first_time == TRUE) { + if (uname(&u) == -1) + return ((CLIENT *) NULL); + if ((hostname = strdup(u.nodename)) == (char *) NULL) + return ((CLIENT *) NULL); + first_time = FALSE; + } + while (nconf = getnetconfig(localhandle)) { + if (strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) { + if (nconf->nc_semantics == NC_TPI_COTS_ORD) { + clnt = clnt_tp_create(hostname, + GSSPROG, GSSVERS, nconf); + if (clnt) { + dprt("got COTS_ORD\n"); + break; + } + } else { + tpconf = nconf; + } + } + } + if ((clnt == NULL) && (tpconf)) { + + /* Now, try the connection-oriented loopback transport */ + + clnt = clnt_tp_create(hostname, GSSPROG, GSSVERS, tpconf); +#ifdef DEBUG + if (clnt) { + dprt("got COTS\n"); + } +#endif DEBUG + } + endnetconfig(localhandle); + + /* + * This bit of code uses an as yet unimplemented argument to + * clnt_control(). CLSET_SVC_PRIV specifies that the underlying + * loopback transport should be checked to ensure it is + * connected to a process running as root. If so, the clnt_control() + * call returns TRUE. If not, it returns FALSE. + */ + +#ifdef CLSET_SVC_PRIV + + if (clnt_control(clnt, CLSET_SVC_PRIV, NULL) != TRUE) { + clnt_destroy(clnt); + clnt = NULL; + return (NULL); + { +#endif + if (clnt == NULL) + return (NULL); + + clnt->cl_auth = authsys_create("", getuid(), 0, 0, NULL); + if (clnt->cl_auth == NULL) { + clnt_destroy(clnt); + clnt = NULL; + return (NULL); + } + wait_time.tv_sec = TOTAL_TIMEOUT/TOTAL_TRIES; + wait_time.tv_usec = 0; + (void) clnt_control(clnt, CLSET_RETRY_TIMEOUT, (char *)&wait_time); + + return (clnt); +} diff --git a/usr/src/cmd/gss/gssd/gssd_proc.c b/usr/src/cmd/gss/gssd/gssd_proc.c new file mode 100644 index 0000000000..1cb640ca89 --- /dev/null +++ b/usr/src/cmd/gss/gssd/gssd_proc.c @@ -0,0 +1,2598 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * RPC server procedures for the gssapi usermode daemon gssd. + */ + +#include <stdio.h> +#include <unistd.h> +#include <pwd.h> +#include <grp.h> +#include <strings.h> +#include <limits.h> +#include <sys/param.h> +#include <sys/syslog.h> +#include <mechglueP.h> +#include "gssd.h" +#include <gssapi/gssapi.h> +#include <rpc/rpc.h> +#include <stdlib.h> +#include <syslog.h> +#include <sys/resource.h> + +#define SRVTAB "" +#define FDCACHE_PERCENTAGE .75 /* Percentage of total FD limit */ +#define FDCACHE_DEFAULT 16 /* Default LRU cache size */ +#define GSSD_FD_LIMIT 255 /* Increase number of fds allowed */ + +extern int gssd_debug; /* declared in gssd.c */ +static OM_uint32 gssd_time_verf; /* verifies same gssd */ +static OM_uint32 context_verf; /* context sequence numbers */ + +struct gssd_ctx_slot { + struct gssd_ctx_slot *lru_next; + struct gssd_ctx_slot *lru_prev; + bool_t inuse; + OM_uint32 create_time; + OM_uint32 verf; + gss_ctx_id_t ctx; + gss_ctx_id_t rpcctx; +}; + +struct gssd_ctx_slot *gssd_ctx_slot_tbl; +struct gssd_ctx_slot *gssd_lru_head; + +static int max_contexts; + +static int checkfrom(struct svc_req *, uid_t *); +extern void set_gssd_uid(uid_t); +extern int __rpc_get_local_uid(SVCXPRT *, uid_t *); + +void +gssd_setup(char *arg) +{ + int i; + struct rlimit rl; + hrtime_t high_res_time; + + gssd_time_verf = (OM_uint32)time(NULL); + max_contexts = FDCACHE_DEFAULT; + + /* + * Use low order bits of high resolution time to get a reasonably + * random number to start the context sequencing. This alternative + * to using a time value avoid clock resets via NTP or ntpdate. + */ + high_res_time = gethrtime(); + context_verf = (OM_uint32)high_res_time; + + /* + * Increase resource limit of FDs in case we get alot accept/init_ + * sec_context calls before we're able to export them. This can + * happen in very heavily load environments where gssd doesn't get + * much time to work on its backlog. + */ + if ((getrlimit(RLIMIT_NOFILE, &rl)) == 0) { + rl.rlim_cur = (rl.rlim_max >= GSSD_FD_LIMIT) ? + GSSD_FD_LIMIT : rl.rlim_max; + if ((setrlimit(RLIMIT_NOFILE, &rl)) == 0) + max_contexts = rl.rlim_cur * FDCACHE_PERCENTAGE; + } + + gssd_ctx_slot_tbl = (struct gssd_ctx_slot *) + malloc(sizeof (struct gssd_ctx_slot) * max_contexts); + + if (gssd_ctx_slot_tbl == NULL) { + (void) fprintf(stderr, + gettext("[%s] could not allocate %d byte context table" + "\n"), arg, + (sizeof (struct gssd_ctx_slot) * max_contexts)); + exit(1); + } + + for (i = 1; i < max_contexts; i++) { + gssd_ctx_slot_tbl[i-1].lru_next = &gssd_ctx_slot_tbl[i]; + gssd_ctx_slot_tbl[i].lru_prev = &gssd_ctx_slot_tbl[i-1]; + gssd_ctx_slot_tbl[i].inuse = FALSE; + gssd_ctx_slot_tbl[i].verf = 0; + gssd_ctx_slot_tbl[i].create_time = 0; + gssd_ctx_slot_tbl[i].rpcctx = (gss_ctx_id_t)(i + 1); + } + + gssd_ctx_slot_tbl[max_contexts - 1].lru_next = &gssd_ctx_slot_tbl[0]; + gssd_ctx_slot_tbl[0].lru_prev = &gssd_ctx_slot_tbl[max_contexts - 1]; + gssd_ctx_slot_tbl[0].inuse = FALSE; + gssd_ctx_slot_tbl[0].verf = 0; + gssd_ctx_slot_tbl[0].create_time = 0; + gssd_ctx_slot_tbl[0].rpcctx = (gss_ctx_id_t)1; + + gssd_lru_head = &gssd_ctx_slot_tbl[0]; +} + +static OM_uint32 syslog_interval = 60; + +static struct gssd_ctx_slot * +gssd_alloc_slot(gss_ctx_id_t ctx) +{ + struct gssd_ctx_slot *lru; + OM_uint32 current_time; + static OM_uint32 last_syslog = 0; + static bool_t first_take = TRUE; + static int tooks; + OM_uint32 minor_status; + + lru = gssd_lru_head; + gssd_lru_head = lru->lru_next; + + current_time = (OM_uint32) time(NULL); + + if (last_syslog == 0) + last_syslog = current_time; /* Save 1st alloc time */ + + if (lru->inuse) { + if (lru->ctx != GSS_C_NO_CONTEXT) + (void) gss_delete_sec_context(&minor_status, + &lru->ctx, NULL); + tooks++; + + if (((current_time - last_syslog) > syslog_interval) || + first_take) { + syslog(LOG_WARNING, gettext("re-used an existing " + "context slot of age %u seconds (%d slots re-" + "used during last %u seconds)"), + current_time - lru->create_time, tooks, + current_time - last_syslog); + + last_syslog = current_time; + tooks = 0; + first_take = FALSE; + } + } + + /* + * Assign the next context verifier to the context (avoiding zero). + */ + context_verf++; + if (context_verf == 0) + context_verf = 1; + lru->verf = context_verf; + + lru->create_time = current_time; + lru->ctx = ctx; + lru->inuse = TRUE; + return (lru); +} + +/* + * We always add 1 because we don't want slot 0 to be confused + * with GSS_C_NO_CONTEXT. + */ + +static struct gssd_ctx_slot * +gssd_handle_to_slot(GSS_CTX_ID_T *h) +{ + intptr_t i; + + if (h->GSS_CTX_ID_T_len == 0) { + return (NULL); + } + if (h->GSS_CTX_ID_T_len != sizeof (i)) + return (NULL); + + i = (*(intptr_t *)(h->GSS_CTX_ID_T_val)) - 1; + + if (i < 0 || i >= max_contexts) + return (NULL); + + return (&gssd_ctx_slot_tbl[i]); +} + +static void +gssd_rel_slot(struct gssd_ctx_slot *lru) +{ + struct gssd_ctx_slot *prev, *next; + + if (lru == NULL) + return; + + lru->inuse = FALSE; + + /* + * Remove entry from its current location in list + */ + prev = lru->lru_prev; + next = lru->lru_next; + prev->lru_next = next; + next->lru_prev = prev; + + /* + * Since it is no longer in use, it is the least recently + * used. + */ + prev = gssd_lru_head->lru_prev; + next = gssd_lru_head; + + prev->lru_next = lru; + lru->lru_prev = prev; + + next->lru_prev = lru; + lru->lru_next = next; + + gssd_lru_head = lru; +} + +static void +gssd_convert_context_handle(GSS_CTX_ID_T *h, + gss_ctx_id_t *context_handle, + OM_uint32 verf, + bool_t *context_verf_ok, + struct gssd_ctx_slot **slotp) +{ + struct gssd_ctx_slot *slot; + + *context_verf_ok = FALSE; + *context_handle = (gss_ctx_id_t)1; + if (slotp != NULL) + *slotp = NULL; + + if (h->GSS_CTX_ID_T_len == 0) { + *context_handle = GSS_C_NO_CONTEXT; + *context_verf_ok = TRUE; + return; + } + + slot = gssd_handle_to_slot(h); + + if (slot == NULL) + return; + + if (verf != slot->verf) + return; + + *context_verf_ok = TRUE; + *context_handle = slot->ctx; + if (slotp != NULL) + *slotp = slot; +} + +bool_t +gss_acquire_cred_1_svc(argp, res, rqstp) + gss_acquire_cred_arg *argp; + gss_acquire_cred_res *res; + struct svc_req *rqstp; +{ + OM_uint32 minor_status; + gss_name_t desired_name; + gss_OID_desc name_type_desc; + gss_OID name_type = &name_type_desc; + OM_uint32 time_req; + gss_OID_set_desc desired_mechs_desc; + gss_OID_set desired_mechs; + int cred_usage; + gss_cred_id_t output_cred_handle; + gss_OID_set actual_mechs; + gss_buffer_desc external_name; + uid_t uid; + int i, j; + + if (gssd_debug) + fprintf(stderr, gettext("gss_acquire_cred\n")); + + memset(res, 0, sizeof (*res)); + + /* + * if the request isn't from root, null out the result pointer + * entries, so the next time through xdr_free won't try to + * free unmalloc'd memory and then return NULL + */ + + if (checkfrom(rqstp, &uid) == 0) { + res->output_cred_handle.GSS_CRED_ID_T_val = NULL; + res->actual_mechs.GSS_OID_SET_val = NULL; + return (FALSE); + } + +/* set the uid sent as the RPC argument */ + + uid = argp->uid; + set_gssd_uid(uid); + +/* convert the desired name from external to internal format */ + + external_name.length = argp->desired_name.GSS_BUFFER_T_len; + external_name.value = (void *)malloc(external_name.length); + if (!external_name.value) + return (GSS_S_FAILURE); + memcpy(external_name.value, argp->desired_name.GSS_BUFFER_T_val, + external_name.length); + + if (argp->name_type.GSS_OID_len == 0) { + name_type = GSS_C_NULL_OID; + } else { + name_type->length = argp->name_type.GSS_OID_len; + name_type->elements = (void *)malloc(name_type->length); + if (!name_type->elements) { + free(external_name.value); + return (GSS_S_FAILURE); + } + memcpy(name_type->elements, argp->name_type.GSS_OID_val, + name_type->length); + } + + if (gss_import_name(&minor_status, &external_name, name_type, + &desired_name) != GSS_S_COMPLETE) { + + res->status = (OM_uint32) GSS_S_FAILURE; + res->minor_status = minor_status; + + free(external_name.value); + if (name_type != GSS_C_NULL_OID) + free(name_type->elements); + + return (TRUE); + } + +/* + * copy the XDR structured arguments into their corresponding local GSSAPI + * variables. + */ + + cred_usage = argp->cred_usage; + time_req = argp->time_req; + + if (argp->desired_mechs.GSS_OID_SET_len != 0) { + desired_mechs = &desired_mechs_desc; + desired_mechs->count = + (int)argp->desired_mechs.GSS_OID_SET_len; + desired_mechs->elements = (gss_OID) + malloc(sizeof (gss_OID_desc) * desired_mechs->count); + if (!desired_mechs->elements) { + free(external_name.value); + free(name_type->elements); + return (GSS_S_FAILURE); + } + for (i = 0; i < desired_mechs->count; i++) { + desired_mechs->elements[i].length = + (OM_uint32)argp->desired_mechs. + GSS_OID_SET_val[i].GSS_OID_len; + desired_mechs->elements[i].elements = + (void *)malloc(desired_mechs->elements[i]. + length); + if (!desired_mechs->elements[i].elements) { + free(external_name.value); + free(name_type->elements); + for (j = 0; j < (i -1); j++) { + free + (desired_mechs->elements[j].elements); + } + free(desired_mechs->elements); + return (GSS_S_FAILURE); + } + memcpy(desired_mechs->elements[i].elements, + argp->desired_mechs.GSS_OID_SET_val[i]. + GSS_OID_val, + desired_mechs->elements[i].length); + } + } else + desired_mechs = GSS_C_NULL_OID_SET; + + /* call the gssapi routine */ + + res->status = (OM_uint32)gss_acquire_cred(&res->minor_status, + desired_name, + time_req, + desired_mechs, + cred_usage, + &output_cred_handle, + &actual_mechs, + &res->time_rec); + + /* + * convert the output args from the parameter given in the call to the + * variable in the XDR result + */ + + res->output_cred_handle.GSS_CRED_ID_T_len = sizeof (gss_cred_id_t); + res->output_cred_handle.GSS_CRED_ID_T_val = + (void *)malloc(sizeof (gss_cred_id_t)); + if (!res->output_cred_handle.GSS_CRED_ID_T_val) { + free(external_name.value); + free(name_type->elements); + for (i = 0; i < desired_mechs->count; i++) { + free(desired_mechs->elements[i].elements); + } + free(desired_mechs->elements); + return (GSS_S_FAILURE); + } + memcpy(res->output_cred_handle.GSS_CRED_ID_T_val, &output_cred_handle, + sizeof (gss_cred_id_t)); + + if (actual_mechs != GSS_C_NULL_OID_SET) { + res->actual_mechs.GSS_OID_SET_len = + (uint_t)actual_mechs->count; + res->actual_mechs.GSS_OID_SET_val = (GSS_OID *) + malloc(sizeof (GSS_OID) * actual_mechs->count); + if (!res->actual_mechs.GSS_OID_SET_val) { + free(external_name.value); + free(name_type->elements); + for (i = 0; i < desired_mechs->count; i++) { + free(desired_mechs->elements[i].elements); + } + free(desired_mechs->elements); + free(res->output_cred_handle.GSS_CRED_ID_T_val); + return (GSS_S_FAILURE); + } + for (i = 0; i < actual_mechs->count; i++) { + res->actual_mechs.GSS_OID_SET_val[i].GSS_OID_len = + (uint_t)actual_mechs->elements[i].length; + res->actual_mechs.GSS_OID_SET_val[i].GSS_OID_val = + (char *)malloc(actual_mechs->elements[i]. + length); + if (!res->actual_mechs.GSS_OID_SET_val[i].GSS_OID_val) { + free(external_name.value); + free(name_type->elements); + free(desired_mechs->elements); + for (j = 0; j < desired_mechs->count; j++) { + free + (desired_mechs->elements[i].elements); + } + free(res->actual_mechs.GSS_OID_SET_val); + for (j = 0; j < (i - 1); j++) { + free + (res->actual_mechs. + GSS_OID_SET_val[j].GSS_OID_val); + } + return (GSS_S_FAILURE); + } + memcpy(res->actual_mechs.GSS_OID_SET_val[i].GSS_OID_val, + actual_mechs->elements[i].elements, + actual_mechs->elements[i].length); + } + } else + res->actual_mechs.GSS_OID_SET_len = 0; + + /* + * set the time verifier for credential handle. To ensure that the + * timestamp is not the same as previous gssd process, verify that + * time is not the same as set earlier at start of process. If it + * is, sleep one second and reset. (due to one second granularity) + */ + + if (res->status == GSS_S_COMPLETE) { + res->gssd_cred_verifier = (OM_uint32)time(NULL); + if (res->gssd_cred_verifier == gssd_time_verf) { + sleep(1); + gssd_time_verf = (OM_uint32)time(NULL); + } + res->gssd_cred_verifier = gssd_time_verf; + } + + /* + * now release the space allocated by the underlying gssapi mechanism + * library for actual_mechs as well as by this routine for + * external_name, name_type and desired_name + */ + + free(external_name.value); + if (name_type != GSS_C_NULL_OID) + free(name_type->elements); + gss_release_name(&minor_status, &desired_name); + + if (actual_mechs != GSS_C_NULL_OID_SET) { + for (i = 0; i < actual_mechs->count; i++) + free(actual_mechs->elements[i].elements); + free(actual_mechs->elements); + free(actual_mechs); + } + + if (desired_mechs != GSS_C_NULL_OID_SET) { + for (i = 0; i < desired_mechs->count; i++) + free(desired_mechs->elements[i].elements); + free(desired_mechs->elements); + + } + +/* return to caller */ + + return (TRUE); +} + +bool_t +gss_add_cred_1_svc(argp, res, rqstp) + gss_add_cred_arg *argp; + gss_add_cred_res *res; + struct svc_req *rqstp; +{ + + OM_uint32 minor_status; + gss_name_t desired_name; + gss_OID_desc name_type_desc; + gss_OID name_type = &name_type_desc; + gss_OID_desc desired_mech_type_desc; + gss_OID desired_mech_type = &desired_mech_type_desc; + int cred_usage; + gss_cred_id_t input_cred_handle; + gss_OID_set actual_mechs; + gss_buffer_desc external_name; + uid_t uid; + int i, j; + + if (gssd_debug) + fprintf(stderr, gettext("gss_add_cred\n")); + + if (argp->gssd_cred_verifier != gssd_time_verf) { + res->status = (OM_uint32)GSS_S_DEFECTIVE_CREDENTIAL; + res->minor_status = 0; + res->actual_mechs.GSS_OID_SET_len = 0; + res->actual_mechs.GSS_OID_SET_val = NULL; + res->initiator_time_rec = 0; + res->acceptor_time_rec = 0; + fprintf(stderr, gettext("gss_add_cred defective cred\n")); + return (TRUE); + } + memset(res, 0, sizeof (*res)); + + /* + * if the request isn't from root, null out the result pointer + * entries, so the next time through xdr_free won't try to + * free unmalloc'd memory and then return NULL + */ + + if (checkfrom(rqstp, &uid) == 0) { + return (FALSE); + } + +/* set the uid sent as the RPC argument */ + + uid = argp->uid; + set_gssd_uid(uid); + +/* convert the desired name from external to internal format */ + + external_name.length = argp->desired_name.GSS_BUFFER_T_len; + external_name.value = (void *)argp->desired_name.GSS_BUFFER_T_val; + name_type->length = argp->name_type.GSS_OID_len; + name_type->elements = (void *)argp->name_type.GSS_OID_val; + + if (gss_import_name(&minor_status, &external_name, name_type, + &desired_name) != GSS_S_COMPLETE) { + + if (gssd_debug) + fprintf(stderr, + gettext("gss_add_cred:import name"), + gettext(" failed status %d \n"), + res->status); + res->status = (OM_uint32)GSS_S_FAILURE; + res->minor_status = minor_status; + return (TRUE); + } + +/* + * copy the XDR structured arguments into their corresponding local GSSAPI + * variables. + */ + + cred_usage = argp->cred_usage; + if (argp->desired_mech_type.GSS_OID_len == 0) + desired_mech_type = GSS_C_NULL_OID; + else { + desired_mech_type->length = + (OM_uint32)argp->desired_mech_type.GSS_OID_len; + desired_mech_type->elements = + (void *)malloc(desired_mech_type->length); + if (!desired_mech_type->elements) { + return (GSS_S_FAILURE); + } + memcpy(desired_mech_type->elements, + argp->desired_mech_type.GSS_OID_val, + desired_mech_type->length); + } + input_cred_handle = + (argp->input_cred_handle.GSS_CRED_ID_T_len == 0 ? + GSS_C_NO_CREDENTIAL : + /*LINTED*/ + *((gss_cred_id_t *)argp->input_cred_handle. + GSS_CRED_ID_T_val)); + + if (input_cred_handle != GSS_C_NO_CREDENTIAL) + /* verify the input_cred_handle */ + if (argp->gssd_cred_verifier != gssd_time_verf) { + res->status = (OM_uint32)GSS_S_DEFECTIVE_CREDENTIAL; + res->minor_status = 0; + return (TRUE); + } + + /* call the gssapi routine */ + + res->status = (OM_uint32)gss_add_cred(&res->minor_status, + input_cred_handle, + desired_name, + desired_mech_type, + cred_usage, + argp->initiator_time_req, + argp->acceptor_time_req, + NULL, + &actual_mechs, + &res->initiator_time_rec, + &res->acceptor_time_rec); + + if ((res->status != GSS_S_COMPLETE) && + (res->status != GSS_S_DUPLICATE_ELEMENT) && + (gssd_debug)) + fprintf(stderr, gettext("gss_add_cred failed status %d \n"), + res->status); + /* + * convert the output args from the parameter given in the call to the + * variable in the XDR result + */ + if (actual_mechs != GSS_C_NULL_OID_SET) { + res->actual_mechs.GSS_OID_SET_len = + (uint_t)actual_mechs->count; + res->actual_mechs.GSS_OID_SET_val = (GSS_OID *) + malloc(sizeof (GSS_OID) * actual_mechs->count); + if (!res->actual_mechs.GSS_OID_SET_val) { + free(desired_mech_type->elements); + free(desired_mech_type); + return (GSS_S_FAILURE); + } + for (i = 0; i < actual_mechs->count; i++) { + res->actual_mechs.GSS_OID_SET_val[i].GSS_OID_len = + (uint_t)actual_mechs->elements[i].length; + res->actual_mechs.GSS_OID_SET_val[i].GSS_OID_val = + (char *)malloc(actual_mechs->elements[i]. + length); + if (!res->actual_mechs.GSS_OID_SET_val[i].GSS_OID_val) { + free(desired_mech_type->elements); + free(desired_mech_type); + free(res->actual_mechs.GSS_OID_SET_val); + for (j = 0; j < (i - 1); j++) { + free + (res->actual_mechs. + GSS_OID_SET_val[j].GSS_OID_val); + } + return (GSS_S_FAILURE); + } + memcpy(res->actual_mechs.GSS_OID_SET_val[i].GSS_OID_val, + actual_mechs->elements[i].elements, + actual_mechs->elements[i].length); + } + } else + res->actual_mechs.GSS_OID_SET_len = 0; + + /* + * now release the space allocated for + * desired_name and desired_mech_type + */ + + gss_release_name(&minor_status, &desired_name); + free(desired_mech_type->elements); + gss_release_oid_set(&minor_status, &actual_mechs); + /* + * if (actual_mechs != GSS_C_NULL_OID_SET) { + * for (i = 0; i < actual_mechs->count; i++) + * free(actual_mechs->elements[i].elements); + * free(actual_mechs->elements); + * free(actual_mechs); + * } + */ + + +/* return to caller */ + + return (TRUE); +} + +bool_t +gss_release_cred_1_svc(argp, res, rqstp) +gss_release_cred_arg *argp; +gss_release_cred_res *res; +struct svc_req *rqstp; +{ + + uid_t uid; + gss_cred_id_t cred_handle; + + memset(res, 0, sizeof (*res)); + + if (gssd_debug) + fprintf(stderr, gettext("gss_release_cred\n")); + + if (checkfrom(rqstp, &uid) == 0) + return (FALSE); + + /* set the uid sent as the RPC argument */ + + uid = argp->uid; + set_gssd_uid(uid); + + /* + * if the cred_handle verifier is not correct, + * set status to GSS_S_DEFECTIVE_CREDENTIAL and return + */ + + if (argp->gssd_cred_verifier != gssd_time_verf) { + res->status = (OM_uint32)GSS_S_DEFECTIVE_CREDENTIAL; + return (TRUE); + } + + /* + * if the cred_handle length is 0 + * set cred_handle argument to GSS_S_NO_CREDENTIAL + */ + + if (argp->cred_handle.GSS_CRED_ID_T_len == 0) + cred_handle = GSS_C_NO_CREDENTIAL; + else + cred_handle = + (gss_cred_id_t)argp->cred_handle.GSS_CRED_ID_T_val; + + /* call the gssapi routine */ + + res->status = (OM_uint32)gss_release_cred(&res->minor_status, + &cred_handle); + + /* return to caller */ + + return (TRUE); +} + +bool_t +gss_init_sec_context_1_svc(argp, res, rqstp) +gss_init_sec_context_arg *argp; +gss_init_sec_context_res *res; +struct svc_req *rqstp; +{ + + OM_uint32 minor_status; + gss_ctx_id_t context_handle; + bool_t context_verf_ok; + gss_cred_id_t claimant_cred_handle; + gss_buffer_desc external_name; + gss_OID_desc name_type_desc; + gss_OID name_type = &name_type_desc; + gss_name_t internal_name; + + gss_OID_desc mech_type_desc; + gss_OID mech_type = &mech_type_desc; + struct gss_channel_bindings_struct + input_chan_bindings; + gss_channel_bindings_t input_chan_bindings_ptr; + gss_buffer_desc input_token; + gss_buffer_desc output_token; + gss_buffer_t input_token_ptr; + gss_OID actual_mech_type; + struct gssd_ctx_slot *slot = NULL; + + uid_t uid; + + memset(res, 0, sizeof (*res)); + + if (gssd_debug) + fprintf(stderr, gettext("gss_init_sec_context\n")); + + /* + * if the request isn't from root, null out the result pointer + * entries, so the next time through xdr_free won't try to + * free unmalloc'd memory and then return NULL + */ + + if (checkfrom(rqstp, &uid) == 0) { + res->context_handle.GSS_CTX_ID_T_val = NULL; + res->actual_mech_type.GSS_OID_val = NULL; + res->output_token.GSS_BUFFER_T_val = NULL; + return (FALSE); + } + +/* set the uid sent as the RPC argument */ + + uid = argp->uid; + set_gssd_uid(uid); + +/* + * copy the supplied context handle into the local context handle, so it + * can be supplied to the gss_init_sec_context call + */ + + gssd_convert_context_handle(&argp->context_handle, &context_handle, + argp->gssd_context_verifier, &context_verf_ok, &slot); + + claimant_cred_handle = + (argp->claimant_cred_handle.GSS_CRED_ID_T_len == 0 ? + GSS_C_NO_CREDENTIAL : + /*LINTED*/ + *((gss_cred_id_t *)argp->claimant_cred_handle. + GSS_CRED_ID_T_val)); + + if (claimant_cred_handle != GSS_C_NO_CREDENTIAL) { + /* verify the verifier_cred_handle */ + if (argp->gssd_cred_verifier != gssd_time_verf) { + res->context_handle.GSS_CTX_ID_T_val = NULL; + res->output_token.GSS_BUFFER_T_val = NULL; + res->actual_mech_type.GSS_OID_val = NULL; + res->context_handle.GSS_CTX_ID_T_len = 0; + res->output_token.GSS_BUFFER_T_len = 0; + res->actual_mech_type.GSS_OID_len = 0; + res->status = (OM_uint32)GSS_S_DEFECTIVE_CREDENTIAL; + res->minor_status = 0; + return (TRUE); + } + } + + if (context_handle != GSS_C_NO_CONTEXT) { + /* verify the verifier_context_handle */ + + if (!context_verf_ok) { + res->context_handle.GSS_CTX_ID_T_val = NULL; + res->output_token.GSS_BUFFER_T_val = NULL; + res->actual_mech_type.GSS_OID_val = NULL; + res->context_handle.GSS_CTX_ID_T_len = 0; + res->output_token.GSS_BUFFER_T_len = 0; + res->actual_mech_type.GSS_OID_len = 0; + res->status = (OM_uint32)GSS_S_NO_CONTEXT; + res->minor_status = 0; + return (TRUE); + } + } + + /* convert the target name from external to internal format */ + + external_name.length = argp->target_name.GSS_BUFFER_T_len; + external_name.value = (void *)argp->target_name.GSS_BUFFER_T_val; + + if (argp->name_type.GSS_OID_len == 0) { + name_type = GSS_C_NULL_OID; + } else { + name_type->length = argp->name_type.GSS_OID_len; + name_type->elements = (void *)malloc(name_type->length); + if (!name_type->elements) + return (GSS_S_FAILURE); + memcpy(name_type->elements, argp->name_type.GSS_OID_val, + name_type->length); + } + + if (argp->mech_type.GSS_OID_len == 0) + mech_type = GSS_C_NULL_OID; + else { + mech_type->length = (OM_uint32)argp->mech_type.GSS_OID_len; + mech_type->elements = (void *)argp->mech_type.GSS_OID_val; + } + + if (gss_import_name(&minor_status, &external_name, name_type, + &internal_name) != GSS_S_COMPLETE) { + + if (name_type != GSS_C_NULL_OID) + free(name_type->elements); + res->status = (OM_uint32)GSS_S_FAILURE; + res->minor_status = minor_status; + + return (TRUE); + } +/* + * copy the XDR structured arguments into their corresponding local GSSAPI + * variables. + */ + + if (argp->input_chan_bindings.present == YES) { + input_chan_bindings_ptr = &input_chan_bindings; + input_chan_bindings.initiator_addrtype = + (OM_uint32)argp->input_chan_bindings. + initiator_addrtype; + input_chan_bindings.initiator_address.length = + (uint_t)argp->input_chan_bindings.initiator_address. + GSS_BUFFER_T_len; + input_chan_bindings.initiator_address.value = + (void *)argp->input_chan_bindings.initiator_address. + GSS_BUFFER_T_val; + input_chan_bindings.acceptor_addrtype = + (OM_uint32)argp->input_chan_bindings.acceptor_addrtype; + input_chan_bindings.acceptor_address.length = + (uint_t)argp->input_chan_bindings.acceptor_address. + GSS_BUFFER_T_len; + input_chan_bindings.acceptor_address.value = + (void *)argp->input_chan_bindings.acceptor_address. + GSS_BUFFER_T_val; + input_chan_bindings.application_data.length = + (uint_t)argp->input_chan_bindings.application_data. + GSS_BUFFER_T_len; + input_chan_bindings.application_data.value = + (void *)argp->input_chan_bindings.application_data. + GSS_BUFFER_T_val; + } else { + input_chan_bindings_ptr = GSS_C_NO_CHANNEL_BINDINGS; + input_chan_bindings.initiator_addrtype = 0; + input_chan_bindings.initiator_address.length = 0; + input_chan_bindings.initiator_address.value = 0; + input_chan_bindings.acceptor_addrtype = 0; + input_chan_bindings.acceptor_address.length = 0; + input_chan_bindings.acceptor_address.value = 0; + input_chan_bindings.application_data.length = 0; + input_chan_bindings.application_data.value = 0; + } + + if (argp->input_token.GSS_BUFFER_T_len == 0) { + input_token_ptr = GSS_C_NO_BUFFER; + } else { + input_token_ptr = &input_token; + input_token.length = (size_t) + argp->input_token.GSS_BUFFER_T_len; + input_token.value = (void *)argp->input_token.GSS_BUFFER_T_val; + } + +/* call the gssapi routine */ + + res->status = (OM_uint32)gss_init_sec_context(&res->minor_status, + (gss_cred_id_t)argp->claimant_cred_handle. + GSS_CRED_ID_T_val, + &context_handle, + internal_name, + mech_type, + argp->req_flags, + argp->time_req, + input_chan_bindings_ptr, + input_token_ptr, + &actual_mech_type, + &output_token, + &res->ret_flags, + &res->time_rec); + + /* + * convert the output args from the parameter given in the call to the + * variable in the XDR result + */ + + if (res->status == (OM_uint32)GSS_S_COMPLETE || + res->status == (OM_uint32)GSS_S_CONTINUE_NEEDED) { + + if (slot == NULL || slot->ctx != context_handle) { + /* + * Note that gssd_alloc_slot() will delete ctx's as long + * as we don't call gssd_rel_slot(). + */ + slot = gssd_alloc_slot(context_handle); + } + + res->gssd_context_verifier = slot->verf; + + res->context_handle.GSS_CTX_ID_T_len = sizeof (gss_ctx_id_t); + res->context_handle.GSS_CTX_ID_T_val = + (void *)malloc(sizeof (gss_ctx_id_t)); + if (!res->context_handle.GSS_CTX_ID_T_val) { + free(name_type->elements); + return (GSS_S_FAILURE); + } + + memcpy(res->context_handle.GSS_CTX_ID_T_val, &slot->rpcctx, + sizeof (gss_ctx_id_t)); + + res->output_token.GSS_BUFFER_T_len = + (uint_t)output_token.length; + res->output_token.GSS_BUFFER_T_val = + (char *)output_token.value; + + /* + * the actual mech type parameter + * is ready only upon GSS_S_COMPLETE + */ + if (res->status == GSS_S_COMPLETE) { + res->actual_mech_type.GSS_OID_len = + (uint_t)actual_mech_type->length; + res->actual_mech_type.GSS_OID_val = + (void *)malloc(actual_mech_type->length); + if (!res->actual_mech_type.GSS_OID_val) { + free(name_type->elements); + free(res->context_handle.GSS_CTX_ID_T_val); + return (GSS_S_FAILURE); + } + memcpy(res->actual_mech_type.GSS_OID_val, + (char *)actual_mech_type->elements, + actual_mech_type->length); + } else + res->actual_mech_type.GSS_OID_len = 0; + } else { + if (context_handle != GSS_C_NO_CONTEXT) { + (void) gss_delete_sec_context(&minor_status, + &context_handle, NULL); + } + res->context_handle.GSS_CTX_ID_T_len = 0; + res->actual_mech_type.GSS_OID_len = 0; + res->output_token.GSS_BUFFER_T_len = 0; + } + + /* + * now release the space allocated by the underlying gssapi mechanism + * library for internal_name and for the name_type. + */ + + gss_release_name(&minor_status, &internal_name); + if (name_type != GSS_C_NULL_OID) + free(name_type->elements); + + + /* return to caller */ + return (TRUE); +} + +bool_t +gss_accept_sec_context_1_svc(argp, res, rqstp) +gss_accept_sec_context_arg *argp; +gss_accept_sec_context_res *res; +struct svc_req *rqstp; +{ + uid_t uid; + OM_uint32 minor_status; + gss_ctx_id_t context_handle = NULL; + gss_cred_id_t verifier_cred_handle; + gss_buffer_desc external_name; + gss_name_t internal_name = NULL; + + gss_buffer_desc input_token_buffer; + gss_buffer_t input_token_buffer_ptr; + struct gss_channel_bindings_struct + input_chan_bindings; + gss_channel_bindings_t input_chan_bindings_ptr; + gss_OID mech_type; + gss_buffer_desc output_token; + gss_cred_id_t delegated_cred_handle; + bool_t context_verf_ok; + struct gssd_ctx_slot *slot = NULL; + + memset(res, 0, sizeof (*res)); + + if (gssd_debug) + fprintf(stderr, gettext("gss_accept_sec_context\n")); + + /* + * if the request isn't from root, null out the result pointer + * entries, so the next time through xdr_free won't try to + * free unmalloc'd memory and then return NULL + */ + + if (checkfrom(rqstp, &uid) == 0) { + res->context_handle.GSS_CTX_ID_T_val = NULL; + res->src_name.GSS_BUFFER_T_val = NULL; + res->mech_type.GSS_OID_val = NULL; + res->output_token.GSS_BUFFER_T_val = NULL; + res->delegated_cred_handle.GSS_CRED_ID_T_val = NULL; + return (FALSE); + } + + /* set the uid sent as the RPC argument */ + + uid = argp->uid; + set_gssd_uid(uid); + + /* + * copy the supplied context handle into the local context handle, so + * it can be supplied to the gss_accept_sec_context call + */ + + gssd_convert_context_handle(&argp->context_handle, &context_handle, + argp->gssd_context_verifier, &context_verf_ok, &slot); + + if (context_handle != GSS_C_NO_CONTEXT) + /* verify the context_handle */ + if (!context_verf_ok) { + res->context_handle.GSS_CTX_ID_T_val = NULL; + res->src_name.GSS_BUFFER_T_val = NULL; + res->mech_type.GSS_OID_val = NULL; + res->output_token.GSS_BUFFER_T_val = NULL; + res->delegated_cred_handle.GSS_CRED_ID_T_val = NULL; + res->src_name.GSS_BUFFER_T_len = 0; + res->context_handle.GSS_CTX_ID_T_len = 0; + res->delegated_cred_handle.GSS_CRED_ID_T_len = 0; + res->output_token.GSS_BUFFER_T_len = 0; + res->mech_type.GSS_OID_len = 0; + res->status = (OM_uint32)GSS_S_NO_CONTEXT; + res->minor_status = 0; + return (TRUE); + } + + /* + * copy the XDR structured arguments into their corresponding local + * GSSAPI variable equivalents. + */ + + + verifier_cred_handle = + (argp->verifier_cred_handle.GSS_CRED_ID_T_len == 0 ? + GSS_C_NO_CREDENTIAL : + /*LINTED*/ + *((gss_cred_id_t *)argp->verifier_cred_handle. + GSS_CRED_ID_T_val)); + + if (verifier_cred_handle != GSS_C_NO_CREDENTIAL) + /* verify the verifier_cred_handle */ + if (argp->gssd_cred_verifier != gssd_time_verf) { + res->context_handle.GSS_CTX_ID_T_val = NULL; + res->src_name.GSS_BUFFER_T_val = NULL; + res->mech_type.GSS_OID_val = NULL; + res->output_token.GSS_BUFFER_T_val = NULL; + res->delegated_cred_handle.GSS_CRED_ID_T_val = NULL; + res->src_name.GSS_BUFFER_T_len = 0; + res->context_handle.GSS_CTX_ID_T_len = 0; + res->delegated_cred_handle.GSS_CRED_ID_T_len = 0; + res->output_token.GSS_BUFFER_T_len = 0; + res->mech_type.GSS_OID_len = 0; + res->status = (OM_uint32)GSS_S_DEFECTIVE_CREDENTIAL; + res->minor_status = 0; + return (TRUE); + } + + if (argp->input_token_buffer.GSS_BUFFER_T_len == 0) { + input_token_buffer_ptr = GSS_C_NO_BUFFER; + } else { + input_token_buffer_ptr = &input_token_buffer; + input_token_buffer.length = (size_t)argp->input_token_buffer. + GSS_BUFFER_T_len; + input_token_buffer.value = (void *)argp->input_token_buffer. + GSS_BUFFER_T_val; + } + + if (argp->input_chan_bindings.present == YES) { + input_chan_bindings_ptr = &input_chan_bindings; + input_chan_bindings.initiator_addrtype = + (OM_uint32)argp->input_chan_bindings. + initiator_addrtype; + input_chan_bindings.initiator_address.length = + (uint_t)argp->input_chan_bindings.initiator_address. + GSS_BUFFER_T_len; + input_chan_bindings.initiator_address.value = + (void *)argp->input_chan_bindings.initiator_address. + GSS_BUFFER_T_val; + input_chan_bindings.acceptor_addrtype = + (OM_uint32)argp->input_chan_bindings. + acceptor_addrtype; + input_chan_bindings.acceptor_address.length = + (uint_t)argp->input_chan_bindings.acceptor_address. + GSS_BUFFER_T_len; + input_chan_bindings.acceptor_address.value = + (void *)argp->input_chan_bindings.acceptor_address. + GSS_BUFFER_T_val; + input_chan_bindings.application_data.length = + (uint_t)argp->input_chan_bindings.application_data. + GSS_BUFFER_T_len; + input_chan_bindings.application_data.value = + (void *)argp->input_chan_bindings.application_data. + GSS_BUFFER_T_val; + } else { + input_chan_bindings_ptr = GSS_C_NO_CHANNEL_BINDINGS; + input_chan_bindings.initiator_addrtype = 0; + input_chan_bindings.initiator_address.length = 0; + input_chan_bindings.initiator_address.value = 0; + input_chan_bindings.acceptor_addrtype = 0; + input_chan_bindings.acceptor_address.length = 0; + input_chan_bindings.acceptor_address.value = 0; + input_chan_bindings.application_data.length = 0; + input_chan_bindings.application_data.value = 0; + } + + + /* call the gssapi routine */ + + res->status = (OM_uint32)gss_accept_sec_context(&res->minor_status, + &context_handle, + verifier_cred_handle, + input_token_buffer_ptr, + input_chan_bindings_ptr, + &internal_name, + &mech_type, + &output_token, + &res->ret_flags, + &res->time_rec, + &delegated_cred_handle); + + /* convert the src name from internal to external format */ + + if (res->status == (OM_uint32)GSS_S_COMPLETE || + res->status == (OM_uint32)GSS_S_CONTINUE_NEEDED) { + + /* + * upon GSS_S_CONTINUE_NEEDED only the following + * parameters are ready: minor, ctxt, and output token + */ + res->context_handle.GSS_CTX_ID_T_len = sizeof (gss_ctx_id_t); + res->context_handle.GSS_CTX_ID_T_val = + (void *)malloc(sizeof (gss_ctx_id_t)); + if (!res->context_handle.GSS_CTX_ID_T_val) { + res->status = (OM_uint32)GSS_S_FAILURE; + res->minor_status = 0; + return (TRUE); + } + + if (slot == NULL || slot->ctx != context_handle) { + /* + * Note that gssd_alloc_slot() will delete ctx's as long + * as we don't call gssd_rel_slot(). + */ + slot = gssd_alloc_slot(context_handle); + } + + memcpy(res->context_handle.GSS_CTX_ID_T_val, &slot->rpcctx, + sizeof (gss_ctx_id_t)); + res->gssd_context_verifier = slot->verf; + + res->output_token.GSS_BUFFER_T_len = + (uint_t)output_token.length; + res->output_token.GSS_BUFFER_T_val = + (char *)output_token.value; + + if (res->status == GSS_S_COMPLETE) { + if (gss_export_name(&minor_status, internal_name, + &external_name) + != GSS_S_COMPLETE) { + + res->status = (OM_uint32)GSS_S_FAILURE; + res->minor_status = minor_status; + gss_release_name(&minor_status, &internal_name); + gss_delete_sec_context(&minor_status, + &context_handle, NULL); + free(res->context_handle.GSS_CTX_ID_T_val); + res->context_handle.GSS_CTX_ID_T_val = NULL; + res->context_handle.GSS_CTX_ID_T_len = 0; + gss_release_buffer(&minor_status, + &output_token); + res->output_token.GSS_BUFFER_T_len = 0; + res->output_token.GSS_BUFFER_T_val = NULL; + return (TRUE); + } + res->src_name.GSS_BUFFER_T_len = + (uint_t)external_name.length; + res->src_name.GSS_BUFFER_T_val = + (void *)external_name.value; + + res->delegated_cred_handle.GSS_CRED_ID_T_len = + sizeof (gss_cred_id_t); + res->delegated_cred_handle.GSS_CRED_ID_T_val = + (void *)malloc(sizeof (gss_cred_id_t)); + if (!res->delegated_cred_handle.GSS_CRED_ID_T_val) { + free(res->context_handle.GSS_CTX_ID_T_val); + gss_release_name(&minor_status, &internal_name); + gss_delete_sec_context(&minor_status, + &context_handle, NULL); + gss_release_buffer(&minor_status, + &external_name); + res->status = (OM_uint32)GSS_S_FAILURE; + res->minor_status = 0; + return (TRUE); + } + memcpy(res->delegated_cred_handle.GSS_CRED_ID_T_val, + &delegated_cred_handle, + sizeof (gss_cred_id_t)); + + res->mech_type.GSS_OID_len = (uint_t)mech_type->length; + res->mech_type.GSS_OID_val = + (void *)malloc(mech_type->length); + if (!res->mech_type.GSS_OID_val) { + free(res->context_handle.GSS_CTX_ID_T_val); + free(res->delegated_cred_handle.GSS_CRED_ID_T_val); + gss_release_name(&minor_status, &internal_name); + gss_delete_sec_context(&minor_status, + &context_handle, NULL); + gss_release_buffer(&minor_status, &external_name); + res->status = (OM_uint32)GSS_S_FAILURE; + res->minor_status = 0; + return (TRUE); + } + memcpy(res->mech_type.GSS_OID_val, mech_type->elements, + mech_type->length); + + /* release the space allocated for internal_name */ + gss_release_name(&minor_status, &internal_name); + + } else { /* GSS_S_CONTINUE_NEEDED */ + res->src_name.GSS_BUFFER_T_len = 0; + res->delegated_cred_handle.GSS_CRED_ID_T_len = 0; + res->mech_type.GSS_OID_len = 0; + } + } else { + if (context_handle != GSS_C_NO_CONTEXT) { + (void) gss_delete_sec_context(&minor_status, + &context_handle, NULL); + } + res->src_name.GSS_BUFFER_T_len = 0; + res->context_handle.GSS_CTX_ID_T_len = 0; + res->delegated_cred_handle.GSS_CRED_ID_T_len = 0; + res->output_token.GSS_BUFFER_T_len = 0; + res->mech_type.GSS_OID_len = 0; + } + +/* return to caller */ + + return (TRUE); +} + +bool_t +gss_process_context_token_1_svc(argp, res, rqstp) +gss_process_context_token_arg *argp; +gss_process_context_token_res *res; +struct svc_req *rqstp; +{ + + uid_t uid; + gss_buffer_desc token_buffer; + gss_ctx_id_t context_handle; + bool_t context_verf_ok; + + memset(res, 0, sizeof (*res)); + + if (gssd_debug) + fprintf(stderr, gettext("gss_process_context_token\n")); + + if (checkfrom(rqstp, &uid) == 0) + return (FALSE); + + gssd_convert_context_handle(&argp->context_handle, &context_handle, + argp->gssd_context_verifier, &context_verf_ok, NULL); + + /* verify the context_handle */ + + if (!context_verf_ok) { + res->status = (OM_uint32) GSS_S_NO_CONTEXT; + res->minor_status = 0; + return (TRUE); + } + + /* set the uid sent as the RPC argument */ + + uid = argp->uid; + set_gssd_uid(uid); + + /* + * copy the XDR structured arguments into their corresponding local + * GSSAPI variable equivalents. + */ + + token_buffer.length = (size_t)argp->token_buffer.GSS_BUFFER_T_len; + token_buffer.value = (void *)argp->token_buffer.GSS_BUFFER_T_val; + + + /* call the gssapi routine */ + + res->status = (OM_uint32)gss_process_context_token(&res->minor_status, + context_handle, + &token_buffer); + + + /* return to caller */ + + return (TRUE); +} + +bool_t +gss_delete_sec_context_1_svc(argp, res, rqstp) +gss_delete_sec_context_arg *argp; +gss_delete_sec_context_res *res; +struct svc_req *rqstp; +{ + uid_t uid; + gss_ctx_id_t context_handle; + gss_buffer_desc output_token; + bool_t context_verf_ok; + struct gssd_ctx_slot *slot = NULL; + + memset(res, 0, sizeof (*res)); + + if (gssd_debug) + fprintf(stderr, gettext("gss_delete_sec_context\n")); + + + /* + * copy the supplied context handle into the local context handle, so it + * can be supplied to the gss_delete_sec_context call + */ + gssd_convert_context_handle(&argp->context_handle, &context_handle, + argp->gssd_context_verifier, &context_verf_ok, &slot); + + /* verify the context_handle */ + if (!context_verf_ok) { + res->context_handle.GSS_CTX_ID_T_val = NULL; + res->context_handle.GSS_CTX_ID_T_len = 0; + res->output_token.GSS_BUFFER_T_val = NULL; + res->output_token.GSS_BUFFER_T_len = 0; + res->status = (OM_uint32)GSS_S_NO_CONTEXT; + res->minor_status = 0; + return (TRUE); + } + + /* + * if the request isn't from root, null out the result pointer + * entries, so the next time through xdr_free won't try to + * free unmalloc'd memory and then return NULL + */ + + if (checkfrom(rqstp, &uid) == 0) { + res->context_handle.GSS_CTX_ID_T_val = NULL; + res->output_token.GSS_BUFFER_T_val = NULL; + return (FALSE); + } + + /* call the gssapi routine */ + + res->status = (OM_uint32)gss_delete_sec_context(&res->minor_status, + &context_handle, + &output_token); + + /* + * convert the output args from the parameter given in the call to the + * variable in the XDR result. If the delete succeeded, return a zero + * context handle. + */ + + if (res->status == GSS_S_COMPLETE) { + if (context_handle != GSS_C_NO_CONTEXT) + return (GSS_S_FAILURE); + res->context_handle.GSS_CTX_ID_T_len = 0; + res->context_handle.GSS_CTX_ID_T_val = NULL; + res->output_token.GSS_BUFFER_T_len = + (uint_t)output_token.length; + res->output_token.GSS_BUFFER_T_val = + (char *)output_token.value; + + if (slot != NULL) { + /* + * gss_delete_sec_context deletes the context if it + * succeeds so clear slot->ctx to avoid a dangling + * reference. + */ + slot->ctx = GSS_C_NO_CONTEXT; + gssd_rel_slot(slot); + } + } else { + res->context_handle.GSS_CTX_ID_T_len = sizeof (gss_ctx_id_t); + res->context_handle.GSS_CTX_ID_T_val = + (void *)malloc(sizeof (gss_ctx_id_t)); + if (!res->context_handle.GSS_CTX_ID_T_val) { + return (GSS_S_FAILURE); + } + + if (slot == NULL || slot->ctx != context_handle) { + /* + * Note that gssd_alloc_slot() will delete ctx's as long + * as we don't call gssd_rel_slot(). + */ + slot = gssd_alloc_slot(context_handle); + /* + * Note that no verifier is returned in the .x + * protocol. So if the context changes, we won't + * be able to release it now. So it will have to + * be LRUed out. + */ + } + + memcpy(res->context_handle.GSS_CTX_ID_T_val, &slot->rpcctx, + sizeof (gss_ctx_id_t)); + + res->output_token.GSS_BUFFER_T_len = 0; + res->output_token.GSS_BUFFER_T_val = NULL; + } + + /* return to caller */ + + return (TRUE); +} + + +bool_t +gss_export_sec_context_1_svc(argp, res, rqstp) + gss_export_sec_context_arg *argp; + gss_export_sec_context_res *res; + struct svc_req *rqstp; +{ + + uid_t uid; + gss_ctx_id_t context_handle; + gss_buffer_desc output_token; + bool_t context_verf_ok; + struct gssd_ctx_slot *slot = NULL; + + memset(res, 0, sizeof (*res)); + + if (gssd_debug) + fprintf(stderr, "gss_export_sec_context\n"); + + /* + * if the request isn't from root, null out the result pointer + * entries, so the next time through xdr_free won't try to + * free unmalloc'd memory and then return NULL + */ + + if (checkfrom(rqstp, &uid) == 0) { + res->context_handle.GSS_CTX_ID_T_val = NULL; + res->output_token.GSS_BUFFER_T_val = NULL; + return (FALSE); + } + +/* + * copy the supplied context handle into the local context handle, so it + * can be supplied to the gss_export_sec_context call + */ + + gssd_convert_context_handle(&argp->context_handle, &context_handle, + argp->gssd_context_verifier, &context_verf_ok, &slot); + + /* verify the context_handle */ + + if (!context_verf_ok) { + res->status = (OM_uint32)GSS_S_NO_CONTEXT; + /* the rest of "res" was cleared by a previous memset() */ + return (TRUE); + } + + /* call the gssapi routine */ + + res->status = (OM_uint32)gss_export_sec_context(&res->minor_status, + &context_handle, + &output_token); + +/* + * convert the output args from the parameter given in the call to the + * variable in the XDR result. If the delete succeeded, return a zero context + * handle. + */ + if (res->status == GSS_S_COMPLETE) { + if (context_handle != GSS_C_NO_CONTEXT) + return (GSS_S_FAILURE); + res->context_handle.GSS_CTX_ID_T_len = 0; + res->context_handle.GSS_CTX_ID_T_val = NULL; + res->output_token.GSS_BUFFER_T_len = + (uint_t)output_token.length; + res->output_token.GSS_BUFFER_T_val = + (char *)output_token.value; + + if (slot != NULL) { + /* + * gss_export_sec_context deletes the context if it + * succeeds so set slot->ctx to avoid a dangling + * reference. + */ + slot->ctx = GSS_C_NO_CONTEXT; + gssd_rel_slot(slot); + } + } else { + res->context_handle.GSS_CTX_ID_T_len = sizeof (gss_ctx_id_t); + res->context_handle.GSS_CTX_ID_T_val = + (void *)malloc(sizeof (gss_ctx_id_t)); + + if (slot == NULL || slot->ctx != context_handle) { + /* + * Note that gssd_alloc_slot() will delete ctx's as long + * as we don't call gssd_rel_slot(). + */ + slot = gssd_alloc_slot(context_handle); + /* + * Note that no verifier is returned in the .x + * protocol. So if the context changes, we won't + * be able to release it now. So it will have to + * be LRUed out. + */ + } + + memcpy(res->context_handle.GSS_CTX_ID_T_val, &slot->rpcctx, + sizeof (gss_ctx_id_t)); + res->output_token.GSS_BUFFER_T_len = 0; + res->output_token.GSS_BUFFER_T_val = NULL; + } + + + /* return to caller */ + + return (TRUE); +} + +/* + * This routine doesn't appear to ever be called. + */ +bool_t +gss_import_sec_context_1_svc(argp, res, rqstp) + gss_import_sec_context_arg *argp; + gss_import_sec_context_res *res; + struct svc_req *rqstp; +{ + + uid_t uid; + gss_ctx_id_t context_handle; + gss_buffer_desc input_token; + gss_buffer_t input_token_ptr; + + memset(res, 0, sizeof (*res)); + + if (gssd_debug) + fprintf(stderr, "gss_export_sec_context\n"); + + /* + * if the request isn't from root, null out the result pointer + * entries, so the next time through xdr_free won't try to + * free unmalloc'd memory and then return NULL + */ + + if (checkfrom(rqstp, &uid) == 0) { + res->context_handle.GSS_CTX_ID_T_val = NULL; + return (FALSE); + } + + + if (argp->input_token.GSS_BUFFER_T_len == 0) { + input_token_ptr = GSS_C_NO_BUFFER; + } else { + input_token_ptr = &input_token; + input_token.length = (size_t) + argp->input_token.GSS_BUFFER_T_len; + input_token.value = (void *) argp->input_token.GSS_BUFFER_T_val; + } + + +/* call the gssapi routine */ + + res->status = (OM_uint32) gss_import_sec_context(&res->minor_status, + input_token_ptr, + &context_handle); + +/* + * convert the output args from the parameter given in the call to the + * variable in the XDR result. If the delete succeeded, return a zero context + * handle. + */ + if (res->status == GSS_S_COMPLETE) { + res->context_handle.GSS_CTX_ID_T_len = sizeof (gss_ctx_id_t); + res->context_handle.GSS_CTX_ID_T_val = + (void *) malloc(sizeof (gss_ctx_id_t)); + memcpy(res->context_handle.GSS_CTX_ID_T_val, &context_handle, + sizeof (gss_ctx_id_t)); + } else { + res->context_handle.GSS_CTX_ID_T_len = 0; + res->context_handle.GSS_CTX_ID_T_val = NULL; + } + + + /* return to caller */ + + return (TRUE); +} + +bool_t +gss_context_time_1_svc(argp, res, rqstp) +gss_context_time_arg *argp; +gss_context_time_res *res; +struct svc_req *rqstp; +{ + uid_t uid; + + memset(res, 0, sizeof (*res)); + + if (gssd_debug) + fprintf(stderr, gettext("gss_context_time\n")); + + /* + * if the request isn't from root, null out the result pointer + * entries, so the next time through xdr_free won't try to + * free unmalloc'd memory and then return NULL + */ + + if (checkfrom(rqstp, &uid) == 0) + return (FALSE); + + /* set the uid sent as the RPC argument */ + + uid = argp->uid; + set_gssd_uid(uid); + + /* Semantics go here */ + + return (TRUE); +} + +bool_t +gss_sign_1_svc(argp, res, rqstp) +gss_sign_arg *argp; +gss_sign_res *res; +struct svc_req *rqstp; +{ + + uid_t uid; + + gss_buffer_desc message_buffer; + gss_buffer_desc msg_token; + gss_ctx_id_t context_handle; + bool_t context_verf_ok; + + memset(res, 0, sizeof (*res)); + + if (gssd_debug) + fprintf(stderr, gettext("gss_sign\n")); + + gssd_convert_context_handle(&argp->context_handle, &context_handle, + argp->gssd_context_verifier, &context_verf_ok, NULL); + + /* verify the context_handle */ + if (!context_verf_ok) { + res->msg_token.GSS_BUFFER_T_val = NULL; + res->msg_token.GSS_BUFFER_T_len = 0; + res->status = (OM_uint32) GSS_S_NO_CONTEXT; + res->minor_status = 0; + return (TRUE); + } + + + /* + * if the request isn't from root, null out the result pointer + * entries, so the next time through xdr_free won't try to + * free unmalloc'd memory and then return NULL + */ + + if (checkfrom(rqstp, &uid) == 0) { + res->msg_token.GSS_BUFFER_T_val = NULL; + return (FALSE); + } + + /* + * copy the XDR structured arguments into their corresponding local + * GSSAPI variable equivalents. + */ + + message_buffer.length = (size_t)argp->message_buffer.GSS_BUFFER_T_len; + message_buffer.value = (void *)argp->message_buffer.GSS_BUFFER_T_val; + + /* call the gssapi routine */ + + res->status = (OM_uint32)gss_sign(&res->minor_status, + context_handle, + argp->qop_req, + (gss_buffer_t)&message_buffer, + (gss_buffer_t)&msg_token); + /* + * convert the output args from the parameter given in the call to + * the variable in the XDR result + */ + + if (res->status == GSS_S_COMPLETE) { + res->msg_token.GSS_BUFFER_T_len = (uint_t)msg_token.length; + res->msg_token.GSS_BUFFER_T_val = (char *)msg_token.value; + } + + /* return to caller */ + + return (TRUE); +} + +bool_t +gss_verify_1_svc(argp, res, rqstp) +gss_verify_arg *argp; +gss_verify_res *res; +struct svc_req *rqstp; +{ + + uid_t uid; + + gss_buffer_desc message_buffer; + gss_buffer_desc token_buffer; + gss_ctx_id_t context_handle; + bool_t context_verf_ok; + + memset(res, 0, sizeof (*res)); + + if (gssd_debug) + fprintf(stderr, gettext("gss_verify\n")); + + gssd_convert_context_handle(&argp->context_handle, &context_handle, + argp->gssd_context_verifier, &context_verf_ok, NULL); + + /* verify the context_handle */ + if (!context_verf_ok) { + res->status = (OM_uint32) GSS_S_NO_CONTEXT; + res->minor_status = 0; + return (TRUE); + } + + /* + * if the request isn't from root, null out the result pointer + * entries, so the next time through xdr_free won't try to + * free unmalloc'd memory and then return NULL + */ + + if (checkfrom(rqstp, &uid) == 0) + return (FALSE); + + /* + * copy the XDR structured arguments into their corresponding local + * GSSAPI variable equivalents. + */ + + message_buffer.length = (size_t)argp->message_buffer.GSS_BUFFER_T_len; + message_buffer.value = (void *)argp->message_buffer.GSS_BUFFER_T_val; + + token_buffer.length = (size_t)argp->token_buffer.GSS_BUFFER_T_len; + token_buffer.value = (void *)argp->token_buffer.GSS_BUFFER_T_val; + + /* call the gssapi routine */ + + res->status = (OM_uint32)gss_verify(&res->minor_status, + context_handle, + &message_buffer, + &token_buffer, + &res->qop_state); + + /* return to caller */ + + return (TRUE); +} + +/* EXPORT DELETE START */ + +bool_t +gss_seal_1_svc(argp, res, rqstp) +gss_seal_arg *argp; +gss_seal_res *res; +struct svc_req *rqstp; +{ + uid_t uid; + + gss_buffer_desc input_message_buffer; + gss_buffer_desc output_message_buffer; + gss_ctx_id_t context_handle; + bool_t context_verf_ok; + + memset(res, 0, sizeof (*res)); + + if (gssd_debug) + fprintf(stderr, gettext("gss_seal\n")); + + gssd_convert_context_handle(&argp->context_handle, &context_handle, + argp->gssd_context_verifier, &context_verf_ok, NULL); + + /* verify the context_handle */ + + if (!context_verf_ok) { + res->output_message_buffer.GSS_BUFFER_T_val = NULL; + res->output_message_buffer.GSS_BUFFER_T_len = 0; + res->status = (OM_uint32) GSS_S_NO_CONTEXT; + res->minor_status = 0; + return (TRUE); + } + + /* + * if the request isn't from root, null out the result pointer + * entries, so the next time through xdr_free won't try to + * free unmalloc'd memory and then return NULL + */ + + if (checkfrom(rqstp, &uid) == 0) { + res->output_message_buffer.GSS_BUFFER_T_val = NULL; + return (FALSE); + + } + + + /* + * copy the XDR structured arguments into their corresponding local + * GSSAPI variable equivalents. + */ + + input_message_buffer.length = (size_t)argp->input_message_buffer. + GSS_BUFFER_T_len; + input_message_buffer.value = (void *)argp->input_message_buffer. + GSS_BUFFER_T_val; + + + /* call the gssapi routine */ + + res->status = (OM_uint32)gss_seal(&res->minor_status, + context_handle, + argp->conf_req_flag, + argp->qop_req, + &input_message_buffer, + &res->conf_state, + &output_message_buffer); + /* + * convert the output args from the parameter given in the call to the + * variable in the XDR result + */ + + if (res->status == GSS_S_COMPLETE) { + res->output_message_buffer.GSS_BUFFER_T_len = + (uint_t)output_message_buffer.length; + res->output_message_buffer.GSS_BUFFER_T_val = + (char *)output_message_buffer.value; + } + +/* return to caller */ + + return (TRUE); +} + +bool_t +gss_unseal_1_svc(argp, res, rqstp) +gss_unseal_arg *argp; +gss_unseal_res *res; +struct svc_req *rqstp; +{ + + uid_t uid; + + gss_buffer_desc input_message_buffer; + gss_buffer_desc output_message_buffer; + gss_ctx_id_t context_handle; + bool_t context_verf_ok; + + memset(res, 0, sizeof (*res)); + + if (gssd_debug) + fprintf(stderr, gettext("gss_unseal\n")); + + /* verify the context_handle */ + gssd_convert_context_handle(&argp->context_handle, &context_handle, + argp->gssd_context_verifier, &context_verf_ok, NULL); + + /* verify the context_handle */ + if (!context_verf_ok) { + res->output_message_buffer.GSS_BUFFER_T_val = NULL; + res->output_message_buffer.GSS_BUFFER_T_len = 0; + res->status = (OM_uint32)GSS_S_NO_CONTEXT; + res->minor_status = 0; + return (TRUE); + } + + /* + * if the request isn't from root, null out the result pointer + * entries, so the next time through xdr_free won't try to + * free unmalloc'd memory and then return NULL + */ + + if (checkfrom(rqstp, &uid) == 0) { + res->output_message_buffer.GSS_BUFFER_T_val = NULL; + return (FALSE); + } + + + /* + * copy the XDR structured arguments into their corresponding local + * GSSAPI variable equivalents. + */ + + input_message_buffer.length = (size_t)argp->input_message_buffer. + GSS_BUFFER_T_len; + input_message_buffer.value = (void *)argp->input_message_buffer. + GSS_BUFFER_T_val; + + /* call the gssapi routine */ + + res->status = (OM_uint32)gss_unseal(&res->minor_status, + context_handle, + &input_message_buffer, + &output_message_buffer, + &res->conf_state, + &res->qop_state); + + /* + * convert the output args from the parameter given in the call to the + * variable in the XDR result + */ + + if (res->status == GSS_S_COMPLETE) { + res->output_message_buffer.GSS_BUFFER_T_len = + (uint_t)output_message_buffer.length; + res->output_message_buffer.GSS_BUFFER_T_val = + (char *)output_message_buffer.value; + } + + + /* return to caller */ + + return (TRUE); +} + +/* EXPORT DELETE END */ + +bool_t +gss_display_status_1_svc(argp, res, rqstp) +gss_display_status_arg *argp; +gss_display_status_res *res; +struct svc_req *rqstp; +{ + uid_t uid; + gss_OID mech_type; + gss_OID_desc mech_type_desc; + gss_buffer_desc status_string; + + memset(res, 0, sizeof (*res)); + + if (gssd_debug) + fprintf(stderr, gettext("gss_display_status\n")); + + /* + * if the request isn't from root, null out the result pointer + * entries, so the next time through xdr_free won't try to + * free unmalloc'd memory and then return NULL + */ + + if (checkfrom(rqstp, &uid) == 0) { + res->status_string.GSS_BUFFER_T_val = NULL; + return (FALSE); + } + + /* set the uid sent as the RPC argument */ + + uid = argp->uid; + set_gssd_uid(uid); + + /* + * copy the XDR structured arguments into their corresponding local + * GSSAPI variables. + */ + + if (argp->mech_type.GSS_OID_len == 0) + mech_type = GSS_C_NULL_OID; + else { + mech_type = &mech_type_desc; + mech_type_desc.length = (OM_uint32) argp->mech_type.GSS_OID_len; + mech_type_desc.elements = (void *) argp->mech_type.GSS_OID_val; + } + + + /* call the gssapi routine */ + + res->status = (OM_uint32) gss_display_status(&res->minor_status, + argp->status_value, + argp->status_type, + mech_type, + (OM_uint32 *)&res->message_context, + &status_string); + + /* + * convert the output args from the parameter given in the call to the + * variable in the XDR result + */ + + if (res->status == GSS_S_COMPLETE) { + res->status_string.GSS_BUFFER_T_len = + (uint_t)status_string.length; + res->status_string.GSS_BUFFER_T_val = + (char *)status_string.value; + } + + return (TRUE); + +} + +/*ARGSUSED*/ +bool_t +gss_indicate_mechs_1_svc(argp, res, rqstp) + void *argp; + gss_indicate_mechs_res *res; + struct svc_req *rqstp; +{ + gss_OID_set oid_set; + uid_t uid; + + memset(res, 0, sizeof (*res)); + + if (gssd_debug) + fprintf(stderr, gettext("gss_indicate_mechs\n")); + + res->mech_set.GSS_OID_SET_val = NULL; + + /* + * if the request isn't from root, null out the result pointer + * entries, so the next time through xdr_free won't try to + * free unmalloc'd memory and then return NULL + */ + + if (checkfrom(rqstp, &uid) == 0) { + return (FALSE); + } + + res->status = gss_indicate_mechs(&res->minor_status, &oid_set); + + if (res->status == GSS_S_COMPLETE) { + int i, j; + + res->mech_set.GSS_OID_SET_len = oid_set->count; + res->mech_set.GSS_OID_SET_val = (void *) + malloc(oid_set->count * sizeof (GSS_OID)); + if (!res->mech_set.GSS_OID_SET_val) { + return (GSS_S_FAILURE); + } + for (i = 0; i < oid_set->count; i++) { + res->mech_set.GSS_OID_SET_val[i].GSS_OID_len = + oid_set->elements[i].length; + res->mech_set.GSS_OID_SET_val[i].GSS_OID_val = + (char *)malloc(oid_set->elements[i].length); + if (!res->mech_set.GSS_OID_SET_val[i].GSS_OID_val) { + for (j = 0; j < (i -1); j++) { + free + (res->mech_set.GSS_OID_SET_val[i].GSS_OID_val); + } + free(res->mech_set.GSS_OID_SET_val); + return (GSS_S_FAILURE); + } + memcpy(res->mech_set.GSS_OID_SET_val[i].GSS_OID_val, + oid_set->elements[i].elements, + oid_set->elements[i].length); + } + } + + return (TRUE); +} + +bool_t +gss_inquire_cred_1_svc(argp, res, rqstp) +gss_inquire_cred_arg *argp; +gss_inquire_cred_res *res; +struct svc_req *rqstp; +{ + + uid_t uid; + + OM_uint32 minor_status; + gss_cred_id_t cred_handle; + gss_buffer_desc external_name; + gss_OID name_type; + gss_name_t internal_name; + gss_OID_set mechanisms; + int i, j; + + memset(res, 0, sizeof (*res)); + + if (gssd_debug) + fprintf(stderr, gettext("gss_inquire_cred\n")); + + /* verify the verifier_cred_handle */ + + if (argp->gssd_cred_verifier != gssd_time_verf) { + res->name.GSS_BUFFER_T_val = NULL; + res->name_type.GSS_OID_val = NULL; + res->mechanisms.GSS_OID_SET_val = NULL; + res->status = (OM_uint32) GSS_S_DEFECTIVE_CREDENTIAL; + res->minor_status = 0; + return (TRUE); + } + + /* + * if the request isn't from root, null out the result pointer + * entries, so the next time through xdr_free won't try to + * free unmalloc'd memory and then return NULL + */ + + if (checkfrom(rqstp, &uid) == 0) { + res->name.GSS_BUFFER_T_val = NULL; + res->name_type.GSS_OID_val = NULL; + res->mechanisms.GSS_OID_SET_val = NULL; + return (FALSE); + } + + /* set the uid sent as the RPC argument */ + + uid = argp->uid; + set_gssd_uid(uid); + + cred_handle = (argp->cred_handle.GSS_CRED_ID_T_len == 0 ? + GSS_C_NO_CREDENTIAL : + /*LINTED*/ + *((gss_cred_id_t *)argp->cred_handle. + GSS_CRED_ID_T_val)); + + /* call the gssapi routine */ + + res->status = (OM_uint32)gss_inquire_cred(&res->minor_status, + cred_handle, + &internal_name, + &res->lifetime, + &res->cred_usage, + &mechanisms); + + if (res->status != GSS_S_COMPLETE) + return (TRUE); + + /* convert the returned name from internal to external format */ + + if (gss_display_name(&minor_status, internal_name, + &external_name, &name_type) + != GSS_S_COMPLETE) { + + res->status = (OM_uint32)GSS_S_FAILURE; + res->minor_status = minor_status; + + gss_release_name(&minor_status, &internal_name); + + if (mechanisms != GSS_C_NULL_OID_SET) { + for (i = 0; i < mechanisms->count; i++) + free(mechanisms->elements[i].elements); + free(mechanisms->elements); + free(mechanisms); + } + + return (TRUE); + } + + /* + * convert the output args from the parameter given in the call to the + * variable in the XDR result + */ + + + res->name.GSS_BUFFER_T_len = (uint_t)external_name.length; + res->name.GSS_BUFFER_T_val = (void *)external_name.value; + + /* + * we have to allocate storage for name_type here, since the value + * returned from gss_display_name points to the underlying mechanism + * static storage. If we didn't allocate storage, the next time + * through this routine, the xdr_free() call at the beginning would + * try to free up that static storage. + */ + + res->name_type.GSS_OID_len = (uint_t)name_type->length; + res->name_type.GSS_OID_val = (void *)malloc(name_type->length); + if (!res->name_type.GSS_OID_val) { + return (GSS_S_FAILURE); + } + memcpy(res->name_type.GSS_OID_val, name_type->elements, + name_type->length); + + if (mechanisms != GSS_C_NULL_OID_SET) { + res->mechanisms.GSS_OID_SET_len = + (uint_t)mechanisms->count; + res->mechanisms.GSS_OID_SET_val = (GSS_OID *) + malloc(sizeof (GSS_OID) * mechanisms->count); + if (!res->mechanisms.GSS_OID_SET_val) { + free(res->name_type.GSS_OID_val); + return (GSS_S_FAILURE); + } + for (i = 0; i < mechanisms->count; i++) { + res->mechanisms.GSS_OID_SET_val[i].GSS_OID_len = + (uint_t)mechanisms->elements[i].length; + res->mechanisms.GSS_OID_SET_val[i].GSS_OID_val = + (char *)malloc(mechanisms->elements[i]. + length); + if (!res->mechanisms.GSS_OID_SET_val[i].GSS_OID_val) { + free(res->name_type.GSS_OID_val); + for (j = 0; j < i; j++) { + free(res->mechanisms. + GSS_OID_SET_val[i].GSS_OID_val); + } + free(res->mechanisms.GSS_OID_SET_val); + return (GSS_S_FAILURE); + } + memcpy(res->mechanisms.GSS_OID_SET_val[i].GSS_OID_val, + mechanisms->elements[i].elements, + mechanisms->elements[i].length); + } + } else + res->mechanisms.GSS_OID_SET_len = 0; + + /* release the space allocated for internal_name and mechanisms */ + gss_release_name(&minor_status, &internal_name); + + if (mechanisms != GSS_C_NULL_OID_SET) { + for (i = 0; i < mechanisms->count; i++) + free(mechanisms->elements[i].elements); + free(mechanisms->elements); + free(mechanisms); + } + + /* return to caller */ + return (TRUE); +} + + +bool_t +gss_inquire_cred_by_mech_1_svc(argp, res, rqstp) +gss_inquire_cred_by_mech_arg *argp; +gss_inquire_cred_by_mech_res *res; +struct svc_req *rqstp; +{ + + uid_t uid; + + gss_cred_id_t cred_handle; + gss_OID_desc mech_type_desc; + gss_OID mech_type = &mech_type_desc; + + memset(res, 0, sizeof (*res)); + + if (gssd_debug) + fprintf(stderr, gettext("gss_inquire_cred\n")); + + /* verify the verifier_cred_handle */ + + if (argp->gssd_cred_verifier != gssd_time_verf) { + res->status = (OM_uint32) GSS_S_DEFECTIVE_CREDENTIAL; + res->minor_status = 0; + return (TRUE); + } + + /* + * if the request isn't from root, null out the result pointer + * entries, so the next time through xdr_free won't try to + * free unmalloc'd memory and then return NULL + */ + + if (checkfrom(rqstp, &uid) == 0) { + return (FALSE); + } + + /* set the uid sent as the RPC argument */ + + uid = argp->uid; + set_gssd_uid(uid); + + cred_handle = (argp->cred_handle.GSS_CRED_ID_T_len == 0 ? + GSS_C_NO_CREDENTIAL : + /*LINTED*/ + *((gss_cred_id_t *)argp->cred_handle. + GSS_CRED_ID_T_val)); + + /* call the gssapi routine */ + + if (argp->mech_type.GSS_OID_len == 0) + mech_type = GSS_C_NULL_OID; + else { + mech_type->length = + (OM_uint32)argp->mech_type.GSS_OID_len; + mech_type->elements = + (void *)malloc(mech_type->length); + if (!mech_type->elements) { + return (GSS_S_FAILURE); + } + memcpy(mech_type->elements, + argp->mech_type.GSS_OID_val, + mech_type->length); + } + res->status = (OM_uint32)gss_inquire_cred_by_mech( + &res->minor_status, cred_handle, + mech_type, NULL, NULL, + NULL, NULL); + + /* return to caller */ + return (TRUE); +} + + +bool_t +gsscred_name_to_unix_cred_1_svc(argsp, res, rqstp) +gsscred_name_to_unix_cred_arg *argsp; +gsscred_name_to_unix_cred_res *res; +struct svc_req *rqstp; +{ + uid_t uid; + gss_OID_desc oid; + gss_name_t gssName; + gss_buffer_desc gssBuf = GSS_C_EMPTY_BUFFER; + OM_uint32 minor; + int gidsLen; + gid_t *gids, gidOut; + + if (gssd_debug) + fprintf(stderr, gettext("gsscred_name_to_unix_cred\n")); + + memset(res, 0, sizeof (*res)); + + /* + * check the request originator + */ + if (checkfrom(rqstp, &uid) == 0) + return (FALSE); + + /* set the uid from the rpc request */ + uid = argsp->uid; + set_gssd_uid(uid); + + /* + * convert the principal name to gss internal format + * need not malloc the input parameters + */ + gssBuf.length = argsp->pname.GSS_BUFFER_T_len; + gssBuf.value = (void*)argsp->pname.GSS_BUFFER_T_val; + oid.length = argsp->name_type.GSS_OID_len; + oid.elements = (void*)argsp->name_type.GSS_OID_val; + + res->major = gss_import_name(&minor, &gssBuf, &oid, &gssName); + if (res->major != GSS_S_COMPLETE) + return (TRUE); + + /* retrieve the mechanism type from the arguments */ + oid.length = argsp->mech_type.GSS_OID_len; + oid.elements = (void*)argsp->mech_type.GSS_OID_val; + + /* call the gss extensions to map the principal name to unix creds */ + res->major = gsscred_name_to_unix_cred(gssName, &oid, &uid, &gidOut, + &gids, &gidsLen); + gss_release_name(&minor, &gssName); + + if (res->major == GSS_S_COMPLETE) { + res->uid = uid; + res->gid = gidOut; + res->gids.GSSCRED_GIDS_val = gids; + res->gids.GSSCRED_GIDS_len = gidsLen; + } + + return (TRUE); +} /* gsscred_name_to_unix_cred_svc_1 */ + +bool_t +gsscred_expname_to_unix_cred_1_svc(argsp, res, rqstp) +gsscred_expname_to_unix_cred_arg *argsp; +gsscred_expname_to_unix_cred_res *res; +struct svc_req *rqstp; +{ + uid_t uid; + gss_buffer_desc expName = GSS_C_EMPTY_BUFFER; + int gidsLen; + gid_t *gids, gidOut; + + if (gssd_debug) + fprintf(stderr, gettext("gsscred_expname_to_unix_cred\n")); + + memset(res, 0, sizeof (*res)); + + /* + * check the request originator + */ + if (checkfrom(rqstp, &uid) == 0) + return (FALSE); + + /* set the uid from the rpc request */ + uid = argsp->uid; + set_gssd_uid(uid); + + /* + * extract the export name from arguments + * need not malloc the input parameters + */ + expName.length = argsp->expname.GSS_BUFFER_T_len; + expName.value = (void*)argsp->expname.GSS_BUFFER_T_val; + + res->major = gsscred_expname_to_unix_cred(&expName, &uid, + &gidOut, &gids, &gidsLen); + + if (res->major == GSS_S_COMPLETE) { + res->uid = uid; + res->gid = gidOut; + res->gids.GSSCRED_GIDS_val = gids; + res->gids.GSSCRED_GIDS_len = gidsLen; + } + + return (TRUE); +} /* gsscred_expname_to_unix_cred_1_svc */ + +bool_t +gss_get_group_info_1_svc(argsp, res, rqstp) +gss_get_group_info_arg *argsp; +gss_get_group_info_res *res; +struct svc_req *rqstp; +{ + uid_t uid; + int gidsLen; + gid_t *gids, gidOut; + + if (gssd_debug) + fprintf(stderr, gettext("gss_get_group_info\n")); + + memset(res, 0, sizeof (*res)); + + /* + * check the request originator + */ + if (checkfrom(rqstp, &uid) == 0) + return (FALSE); + + /* set the uid from the rpc request */ + uid = argsp->uid; + set_gssd_uid(uid); + + /* + * extract the uid from the arguments + */ + uid = argsp->puid; + res->major = gss_get_group_info(uid, &gidOut, &gids, &gidsLen); + if (res->major == GSS_S_COMPLETE) { + res->gid = gidOut; + res->gids.GSSCRED_GIDS_val = gids; + res->gids.GSSCRED_GIDS_len = gidsLen; + } + + return (TRUE); +} /* gss_get_group_info_1_svc */ + +/*ARGSUSED*/ +bool_t +gss_get_kmod_1_svc(argsp, res, rqstp) + gss_get_kmod_arg *argsp; + gss_get_kmod_res *res; + struct svc_req *rqstp; +{ + gss_OID_desc oid; + char *kmodName; + + if (gssd_debug) + fprintf(stderr, gettext("gss_get_kmod\n")); + + res->module_follow = FALSE; + oid.length = argsp->mech_oid.GSS_OID_len; + oid.elements = (void *)argsp->mech_oid.GSS_OID_val; + kmodName = __gss_get_kmodName(&oid); + + if (kmodName != NULL) { + res->module_follow = TRUE; + res->gss_get_kmod_res_u.modname = kmodName; + } + + return (TRUE); +} + +/* + * Returns 1 if caller is ok, else 0. + * If caller ok, the uid is returned in uidp. + */ +static int +checkfrom(rqstp, uidp) +struct svc_req *rqstp; +uid_t *uidp; +{ + SVCXPRT *xprt = rqstp->rq_xprt; + struct authunix_parms *aup; + uid_t uid; + + /* check client agent uid to ensure it is privileged */ + if (__rpc_get_local_uid(xprt, &uid) < 0) { + syslog(LOG_ERR, gettext("__rpc_get_local_uid failed %s %s"), + xprt->xp_netid, xprt->xp_tp); + goto weakauth; + } + if (gssd_debug) + fprintf(stderr, gettext("checkfrom: local_uid %d\n"), uid); + if (uid != 0) { + syslog(LOG_ERR, + gettext("checkfrom: caller (uid %d) not privileged"), + uid); + goto weakauth; + } + + /* + * Request came from local privileged process. + * Proceed to get uid of client if needed by caller. + */ + if (uidp) { + if (rqstp->rq_cred.oa_flavor != AUTH_SYS) { + syslog(LOG_ERR, gettext("checkfrom: not UNIX credentials")); + goto weakauth; + } + /*LINTED*/ + aup = (struct authunix_parms *)rqstp->rq_clntcred; + *uidp = aup->aup_uid; + if (gssd_debug) { + fprintf(stderr, + gettext("checkfrom: caller's uid %d\n"), *uidp); + } + } + return (1); + + weakauth: + svcerr_weakauth(xprt); + return (0); +} diff --git a/usr/src/cmd/gss/gssd/gssd_release_name_and_type.c b/usr/src/cmd/gss/gssd/gssd_release_name_and_type.c new file mode 100644 index 0000000000..9fa368d7bf --- /dev/null +++ b/usr/src/cmd/gss/gssd/gssd_release_name_and_type.c @@ -0,0 +1,100 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 1995,1997, by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * glue routine for gssd_release_name_and_type -- this is a hack, + * it is only used by the client-side rpc library. Perhaps it should + * be in there? Perhaps this should be a part of the release_name + * function? Or perhaps it should always allocate it? I don't know + * the right answer. + */ + +#include <sys/types.h> +#include <stdlib.h> +#include <mechglueP.h> + +/*ARGSUSED*/ +OM_uint32 +gssd_release_name_and_type(minor_status, input_name) + OM_uint32 * minor_status; + gss_name_t * input_name; + +{ + + gss_union_name_t union_name; + + if (input_name == NULL) + return (GSS_S_COMPLETE); + + /* + * free up the space for the external_name and also the name + * type data. Then free the union_name descriptor. + */ + + union_name = (gss_union_name_t) *input_name; + *input_name = NULL; + + if (union_name == NULL) + return (GSS_S_COMPLETE); + + FREE(union_name->external_name->value, + union_name->external_name->length); + FREE(union_name->external_name, sizeof (gss_buffer_desc)); + FREE(union_name->name_type->elements, union_name->name_type->length); + FREE(union_name->name_type, sizeof (gss_OID_desc)); + FREE(union_name, sizeof (gss_union_name_desc)); + + return (GSS_S_COMPLETE); +} + +OM_uint32 +gss_release_oid_set_and_oids(minor_status, set) + OM_uint32 * minor_status; + gss_OID_set * set; +{ + int i; + + if (minor_status) + *minor_status = 0; + + if (set == NULL) + return (GSS_S_COMPLETE); + + if (*set == GSS_C_NULL_OID_SET) + return (GSS_S_COMPLETE); + + for (i = 0; i < (*set)->count; i++) + FREE((*set)->elements[i].elements, (*set)->elements[i].length); + + FREE((*set)->elements, (*set)->count * sizeof (gss_OID_desc)); + FREE(*set, sizeof (gss_OID_set_desc)); + + *set = GSS_C_NULL_OID_SET; + + return (GSS_S_COMPLETE); +} diff --git a/usr/src/cmd/gss/gssd/gssdtest.c b/usr/src/cmd/gss/gssd/gssdtest.c new file mode 100644 index 0000000000..95959cf033 --- /dev/null +++ b/usr/src/cmd/gss/gssd/gssdtest.c @@ -0,0 +1,2192 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Test client for gssd. This program is not shipped on the binary + * release. + */ + +#include <stdio.h> +#include <strings.h> +#include <ctype.h> +#include <stdlib.h> +#include <gssapi/gssapi.h> +#include <gssapi/gssapi_ext.h> +#include "gssd.h" +#include <rpc/rpc.h> + +#define _KERNEL +#include <gssapi/gssapi.h> +#undef _KERNEL + +int gss_major_code; +int gss_minor_code; + +int init_sec_context_phase = 0; +int accept_sec_context_phase = 0; + +gss_ctx_id_t initiator_context_handle; +gss_ctx_id_t acceptor_context_handle; +gss_cred_id_t acceptor_credentials; +gss_buffer_desc init_token_buffer; +gss_buffer_desc accept_token_buffer; +gss_buffer_desc delete_token_buffer; +gss_buffer_desc message_buffer; +gss_buffer_desc msg_token; + +#define LOOP_COUNTER 100 +#define GSS_KRB5_MECH_OID "1.2.840.113554.1.2.2" +#define GSS_DUMMY_MECH_OID "1.3.6.1.4.1.42.2.26.1.2" +#ifdef _KERNEL +#define OCTAL_MACRO "%03o." +#define MALLOC(n) kmem_alloc((n), KM_SLEEP) +#define CALLOC(n, s) kmem_zalloc((n)*(s), KM_SLEEP) +#define FREE(x, n) kmem_free((x), (n)) +#define memcpy(dst, src, n) bcopy((src), (dst), (n)) +#define fprintf(s, m) printf(m) +#define isspace(s) ((s) == ' ' || (s) == '\t' || (s) == '\n' || \ + (s) == '\r' || (s) == '\v' || (s) == '\f') + +static char *strdup(const char *s) +{ + int len = strlen(s); + char *new = MALLOC(len+1); + strcpy(new, s); + return (new); +} + +#else /* !_KERNEL */ +#define OCTAL_MACRO "%03.3o." +#define MALLOC(n) malloc(n) +#define CALLOC(n, s) calloc((n), (s)) +#define FREE(x, n) free(x) +#endif /* _KERNEL */ + +static gss_OID gss_str2oid(char *); +static char * gss_oid2str(gss_OID); +static void instructs(); +static void usage(); +static int parse_input_line(char *, int *, char ***); +extern uid_t getuid(); + +static void _gss_init_sec_context(int, char **); +static void _gss_acquire_cred(int, char **); +static void _gss_add_cred(int, char **); +static void _gss_sign(int, char **); +static void _gss_release_cred(int, char **); +static void _gss_accept_sec_context(int, char **); +static void _gss_process_context_token(int, char **); +static void _gss_delete_sec_context(int, char **); +static void _gss_context_time(int, char **); +static void _gss_verify(int, char **); +/* EXPORT DELETE START */ +static void _gss_seal(int, char **); +static void _gss_unseal(int, char **); +/* EXPORT DELETE END */ +static void _gss_display_status(int, char **); +static void _gss_indicate_mechs(int, char **); +static void _gss_inquire_cred(int, char **); +static void _gssd_expname_to_unix_cred(int, char **); +static void _gssd_name_to_unix_cred(int, char **); +static void _gssd_get_group_info(int, char **); + +static int do_gssdtest(char *buf); + + +#ifndef _KERNEL +static int read_line(char *buf, int size) +{ + int len; + + /* read the next line. If cntl-d, return with zero char count */ + printf(gettext("\n> ")); + + if (fgets(buf, size, stdin) == NULL) + return (0); + + len = strlen(buf); + buf[--len] = '\0'; + return (len); +} + +int +main() +{ + char buf[512]; + int len, ret; + + /* Print out usage and instructions to start off the session */ + + instructs(); + usage(); + + /* + * Loop, repeatedly calling parse_input_line() to get the + * next line and parse it into argc and argv. Act on the + * arguements found on the line. + */ + + do { + len = read_line(buf, 512); + if (len) + ret = do_gssdtest(buf); + } while (len && !ret); + + return (0); +} +#endif /* !_KERNEL */ + +static int +do_gssdtest(char *buf) +{ + int argc, seal_argc; + int i; + char **argv, **argv_array; + + char *cmd; + char *seal_ini_array [] = { "initiator", " Hello"}; + char *seal_acc_array [] = { "acceptor", " Hello"}; + char *unseal_acc_array [] = {"acceptor"}; + char *unseal_ini_array [] = {"initiator"}; + char *delet_acc_array [] = {"acceptor"}; + char *delet_ini_array [] = {"initiator"}; + + argv = 0; + + if (parse_input_line(buf, &argc, &argv) == 0) { + printf(gettext("\n")); + return (1); + } + + if (argc == 0) { + usage(); + /*LINTED*/ + FREE(argv_array, (argc+1)*sizeof (char *)); + return (0); + } + + /* + * remember argv_array address, which is memory calloc'd by + * parse_input_line, so it can be free'd at the end of the loop. + */ + + argv_array = argv; + + cmd = argv[0]; + + argc--; + argv++; + + if (strcmp(cmd, "gss_loop") == 0 || + strcmp(cmd, "loop") == 0) { + + if (argc < 1) { + usage(); + FREE(argv_array, (argc+2) * sizeof (char *)); + return (0); + } + for (i = 0; i < LOOP_COUNTER; i++) { + printf(gettext("Loop Count is %d \n"), i); + /* + * if (i > 53) + * printf ("Loop counter is greater than 55\n"); + */ + _gss_acquire_cred(argc, argv); + _gss_init_sec_context(argc, argv); + _gss_accept_sec_context(0, argv); + _gss_init_sec_context(argc, argv); +/* EXPORT DELETE START */ + seal_argc = 2; + _gss_seal(seal_argc, seal_ini_array); + seal_argc = 1; + _gss_unseal(seal_argc, unseal_acc_array); + seal_argc = 2; + _gss_seal(seal_argc, seal_acc_array); + seal_argc = 1; + _gss_unseal(seal_argc, unseal_ini_array); +/* EXPORT DELETE END */ + seal_argc = 2; + _gss_sign(seal_argc, seal_ini_array); + seal_argc = 1; + _gss_verify(seal_argc, unseal_acc_array); + seal_argc = 2; + _gss_sign(seal_argc, seal_acc_array); + seal_argc = 1; + _gss_verify(seal_argc, unseal_ini_array); + _gss_delete_sec_context(argc, delet_acc_array); + _gss_delete_sec_context(argc, delet_ini_array); + } + } + if (strcmp(cmd, "gss_all") == 0 || + strcmp(cmd, "all") == 0) { + _gss_acquire_cred(argc, argv); + _gss_init_sec_context(argc, argv); + _gss_accept_sec_context(0, argv); + _gss_init_sec_context(argc, argv); +/* EXPORT DELETE START */ + seal_argc = 2; + _gss_seal(seal_argc, seal_acc_array); + seal_argc = 1; + _gss_unseal(seal_argc, unseal_ini_array); + seal_argc = 2; + _gss_seal(seal_argc, seal_ini_array); + seal_argc = 1; + _gss_unseal(seal_argc, unseal_acc_array); +/* EXPORT DELETE END */ + seal_argc = 2; + _gss_sign(seal_argc, seal_ini_array); + seal_argc = 1; + _gss_verify(seal_argc, unseal_acc_array); + seal_argc = 2; + _gss_sign(seal_argc, seal_acc_array); + seal_argc = 1; + _gss_verify(seal_argc, unseal_ini_array); + + } + if (strcmp(cmd, "gss_acquire_cred") == 0 || + strcmp(cmd, "acquire") == 0) { + _gss_acquire_cred(argc, argv); + if (argc == 1) + _gss_add_cred(argc, argv); + } + + else if (strcmp(cmd, "gss_release_cred") == 0 || + strcmp(cmd, "release") == 0) + _gss_release_cred(argc, argv); + else if (strcmp(cmd, "gss_init_sec_context") == 0 || + strcmp(cmd, "init") == 0) + _gss_init_sec_context(argc, argv); + else if (strcmp(cmd, "gss_accept_sec_context") == 0 || + strcmp(cmd, "accept") == 0) + _gss_accept_sec_context(argc, argv); + else if (strcmp(cmd, "gss_process_context_token") == 0 || + strcmp(cmd, "process") == 0) + _gss_process_context_token(argc, argv); + else if (strcmp(cmd, "gss_delete_sec_context") == 0 || + strcmp(cmd, "delete") == 0) + _gss_delete_sec_context(argc, argv); + else if (strcmp(cmd, "gss_context_time") == 0 || + strcmp(cmd, "time") == 0) + _gss_context_time(argc, argv); + else if (strcmp(cmd, "gss_sign") == 0 || + strcmp(cmd, "sign") == 0) + _gss_sign(argc, argv); + else if (strcmp(cmd, "gss_verify") == 0 || + strcmp(cmd, "verify") == 0) + _gss_verify(argc, argv); +/* EXPORT DELETE START */ + else if (strcmp(cmd, "gss_seal") == 0 || + strcmp(cmd, "seal") == 0) + _gss_seal(argc, argv); + else if (strcmp(cmd, "gss_unseal") == 0 || + strcmp(cmd, "unseal") == 0) + _gss_unseal(argc, argv); +/* EXPORT DELETE END */ + else if (strcmp(cmd, "gss_display_status") == 0|| + strcmp(cmd, "status") == 0) + _gss_display_status(argc, argv); + else if (strcmp(cmd, "gss_indicate_mechs") == 0 || + strcmp(cmd, "indicate") == 0) + _gss_indicate_mechs(argc, argv); + else if (strcmp(cmd, "gss_inquire_cred") == 0 || + strcmp(cmd, "inquire") == 0) + _gss_inquire_cred(argc, argv); + else if (strcmp(cmd, "expname2unixcred") == 0 || + strcmp(cmd, "gsscred_expname_to_unix_cred") == 0) + _gssd_expname_to_unix_cred(argc, argv); + else if (strcmp(cmd, "name2unixcred") == 0 || + strcmp(cmd, "gsscred_name_to_unix_cred") == 0) + _gssd_name_to_unix_cred(argc, argv); + else if (strcmp(cmd, "grpinfo") == 0 || + strcmp(cmd, "gss_get_group_info") == 0) + _gssd_get_group_info(argc, argv); + else if (strcmp(cmd, "exit") == 0) { + printf(gettext("\n")); + FREE(argv_array, (argc+2) * sizeof (char *)); + return (1); + } else + usage(); + + /* free argv array */ + + FREE(argv_array, (argc+2) * sizeof (char *)); + return (0); +} + +static void +_gss_acquire_cred(argc, argv) +int argc; +char **argv; +{ + + OM_UINT32 status, minor_status; + gss_buffer_desc name; + gss_name_t desired_name = (gss_name_t) 0; + OM_uint32 time_req; + gss_OID_set_desc desired_mechs_desc; + gss_OID_set desired_mechs = &desired_mechs_desc; + int cred_usage; + gss_OID_set actual_mechs = GSS_C_NULL_OID_SET; + gss_OID_set inquire_mechs = GSS_C_NULL_OID_SET; + OM_UINT32 time_rec; + char * string; + char * inq_string; + uid_t uid; + gss_OID mech_type; + + /* + * First set up the command line independent input arguments. + */ + + time_req = (OM_uint32) 0; + cred_usage = GSS_C_ACCEPT; + uid = getuid(); + + /* Parse the command line for the variable input arguments */ + + if (argc == 0) { + usage(); + return; + } + + /* + * Get the name of the principal. + */ + + name.length = strlen(argv[0])+1; + name.value = argv[0]; + + /* + * Now convert the string given by the first argument into internal + * form suitable for input to gss_acquire_cred() + */ + + if ((status = gss_import_name(&minor_status, &name, + (gss_OID)GSS_C_NT_HOSTBASED_SERVICE, &desired_name)) + != GSS_S_COMPLETE) { + printf(gettext( + "could not parse desired name: err (octal) %o (%s)\n"), + status, gettext("gss_acquire_cred error")); + return; + } + + argc--; + argv++; + + /* + * The next argument is an OID in dotted decimal form. + */ + + if (argc == 0) { + printf(gettext("Assuming Kerberos V5 as the mechanism\n")); + printf(gettext( + "The mech OID 1.2.840.113554.1.2.2 will be used\n")); + mech_type = gss_str2oid((char *)GSS_KRB5_MECH_OID); + } else + mech_type = gss_str2oid(argv[0]); + + if (mech_type == 0 || mech_type->length == 0) { + printf(gettext("improperly formated mechanism OID\n")); + return; + } + + /* + * set up desired_mechs so it points to mech_type. + */ + + desired_mechs = (gss_OID_set) MALLOC(sizeof (gss_OID_desc)); + + desired_mechs->count = 1; + desired_mechs->elements = mech_type; + + status = kgss_acquire_cred( + &minor_status, + desired_name, + time_req, + desired_mechs, + cred_usage, + &acceptor_credentials, + &actual_mechs, + &time_rec, + uid); + + /* store major and minor status for gss_display_status() call */ + + gss_major_code = status; + gss_minor_code = minor_status; + + if (status == GSS_S_COMPLETE) { + /* process returned values */ + + printf(gettext("\nacquire succeeded\n\n")); + + /* + * print out the actual mechs returned NB: Since only one + * mechanism is specified in desired_mechs, only one + * can be returned in actual_mechs. Consequently, + * actual_mechs->elements points to an array of only one + * element. + */ + + if ((string = gss_oid2str(actual_mechs->elements)) == 0) { + printf(gettext("actual mechs == NULL\n\n")); + } else { + printf(gettext("actual mechs = %s\n\n"), string); + FREE(string, (actual_mechs->elements->length+1)*4+1); + } + + if (cred_usage == GSS_C_BOTH) + printf(gettext("GSS_C_BOTH\n\n")); + + if (cred_usage == GSS_C_INITIATE) + printf(gettext("GSS_C_INITIATE\n\n")); + + if (cred_usage == GSS_C_ACCEPT) + printf(gettext("GSS_C_ACCEPT\n\n")); + status = kgss_inquire_cred( + &minor_status, + acceptor_credentials, + NULL, + &time_req, + &cred_usage, + &inquire_mechs, + uid); + + if (status != GSS_S_COMPLETE) + printf(gettext("server ret err (octal) %o (%s)\n"), + status, gettext("gss_inquire_cred error")); + else { + if ((inq_string = + gss_oid2str(inquire_mechs->elements)) == 0) { + printf(gettext + ("mechs from inquire == NULL\n\n")); + } else { + printf(gettext + ("mechs from inquiry = %s\n\n"), + inq_string); + FREE(inq_string, + (inquire_mechs->elements->length+1)*4+1); + } + printf(gettext("inquire_cred successful \n\n")); + } + + } else { + printf(gettext("server ret err (octal) %o (%s)\n"), + status, gettext("gss_acquire_cred error")); + } + + /* free allocated memory */ + + /* actual mechs is allocated by clnt_stubs. Release it here */ + if (actual_mechs != GSS_C_NULL_OID_SET) + gss_release_oid_set_and_oids(&minor_status, &actual_mechs); + if (inquire_mechs != GSS_C_NULL_OID_SET) + gss_release_oid_set_and_oids(&minor_status, &inquire_mechs); + + gss_release_name(&minor_status, &desired_name); + + /* mech_type and desired_mechs are allocated above. Release it here */ + + FREE(mech_type->elements, mech_type->length); + FREE(mech_type, sizeof (gss_OID_desc)); + FREE(desired_mechs, sizeof (gss_OID_desc)); +} + +static void +_gss_add_cred(argc, argv) +int argc; +char **argv; +{ + + OM_UINT32 status, minor_status; + gss_buffer_desc name; + gss_name_t desired_name = (gss_name_t) 0; + OM_uint32 time_req; + OM_uint32 initiator_time_req; + OM_uint32 acceptor_time_req; + int cred_usage; + gss_OID_set actual_mechs = GSS_C_NULL_OID_SET; + gss_OID_set inquire_mechs = GSS_C_NULL_OID_SET; + char * string; + uid_t uid; + gss_OID mech_type; + int i; + + /* + * First set up the command line independent input arguments. + */ + + initiator_time_req = (OM_uint32) 0; + acceptor_time_req = (OM_uint32) 0; + cred_usage = GSS_C_ACCEPT; + uid = getuid(); + + /* Parse the command line for the variable input arguments */ + + if (argc == 0) { + usage(); + return; + } + + /* + * Get the name of the principal. + */ + + name.length = strlen(argv[0])+1; + name.value = argv[0]; + + /* + * Now convert the string given by the first argument into internal + * form suitable for input to gss_acquire_cred() + */ + + if ((status = gss_import_name(&minor_status, &name, + (gss_OID)GSS_C_NT_HOSTBASED_SERVICE, &desired_name)) + != GSS_S_COMPLETE) { + printf(gettext( + "could not parse desired name: err (octal) %o (%s)\n"), + status, gettext("gss_acquire_cred error")); + return; + } + + argc--; + argv++; + + /* + * The next argument is an OID in dotted decimal form. + */ + + if (argc == 0) { + printf(gettext("Assuming dummy as the mechanism\n")); + printf(gettext( + "The mech OID 1.3.6.1.4.1.42.2.26.1.2 will be used\n")); + mech_type = gss_str2oid((char *)GSS_DUMMY_MECH_OID); + } else + mech_type = gss_str2oid(argv[0]); + + if (mech_type == 0 || mech_type->length == 0) { + printf(gettext("improperly formated mechanism OID\n")); + return; + } + + /* + * set up desired_mechs so it points to mech_type. + */ + + status = kgss_add_cred( + &minor_status, + acceptor_credentials, + desired_name, + mech_type, + cred_usage, + initiator_time_req, + acceptor_time_req, + &actual_mechs, + NULL, + NULL, + uid); + + /* store major and minor status for gss_display_status() call */ + + gss_major_code = status; + gss_minor_code = minor_status; + if (status == GSS_S_COMPLETE) { + /* process returned values */ + + printf(gettext("\nadd succeeded\n\n")); + if (actual_mechs) { + for (i = 0; i < actual_mechs->count; i++) { + if ((string = + gss_oid2str + (&actual_mechs->elements[i])) == 0) { + printf(gettext + ("actual mechs == NULL\n\n")); + } else { + printf(gettext + ("actual mechs = %s\n\n"), string); + FREE(string, + (actual_mechs->elements->length+1)*4+1); + } + } + } + /* + * Try adding the cred again for the same mech + * We should get GSS_S_DUPLICATE_ELEMENT + * if not return an error + */ + status = kgss_add_cred( + &minor_status, + acceptor_credentials, + desired_name, + mech_type, + cred_usage, + initiator_time_req, + acceptor_time_req, + NULL, /* &actual_mechs, */ + NULL, + NULL, + uid); + if (status != GSS_S_DUPLICATE_ELEMENT) { + printf(gettext("Expected duplicate element, Got " + " (octal) %o (%s)\n"), + status, gettext("gss_add_cred error")); + } + status = kgss_inquire_cred( + &minor_status, + acceptor_credentials, + NULL, + &time_req, + &cred_usage, + &inquire_mechs, + uid); + + if (status != GSS_S_COMPLETE) + printf(gettext("server ret err (octal) %o (%s)\n"), + status, gettext("gss_inquire_cred error")); + else { + for (i = 0; i < inquire_mechs->count; i++) { + if ((string = + gss_oid2str + (&inquire_mechs->elements[i])) == 0) { + printf(gettext + ("inquire_mechs mechs == NULL\n\n")); + } else { + printf(gettext + ("inquire_cred mechs = %s\n\n"), + string); + FREE(string, + (inquire_mechs->elements->length+1)*4 + +1); + } + } + printf(gettext("inquire_cred successful \n\n")); + } + + } else { + printf(gettext("server ret err (octal) %o (%s)\n"), + status, gettext("gss_acquire_cred error")); + } + + /* Let us do inquire_cred_by_mech for both mechanisms */ + status = kgss_inquire_cred_by_mech( + &minor_status, + acceptor_credentials, + mech_type, + uid); + if (status != GSS_S_COMPLETE) + printf(gettext("server ret err (octal) %o (%s)\n"), + status, gettext("gss_inquire_cred_by_mech")); + else + printf(gettext("gss_inquire_cred_by_mech successful")); + + + FREE(mech_type->elements, mech_type->length); + FREE(mech_type, sizeof (gss_OID_desc)); + mech_type = gss_str2oid((char *)GSS_KRB5_MECH_OID); + status = kgss_inquire_cred_by_mech( + &minor_status, + acceptor_credentials, + mech_type, + uid); + if (status != GSS_S_COMPLETE) + printf(gettext("server ret err (octal) %o (%s)\n"), + status, gettext + ("gss_inquire_cred_by_mech for dummy mech error")); + + /* free allocated memory */ + + /* actual mechs is allocated by clnt_stubs. Release it here */ + if (actual_mechs != GSS_C_NULL_OID_SET) + gss_release_oid_set_and_oids(&minor_status, &actual_mechs); + if (inquire_mechs != GSS_C_NULL_OID_SET) + gss_release_oid_set_and_oids(&minor_status, &inquire_mechs); + + gss_release_name(&minor_status, &desired_name); + + /* mech_type and desired_mechs are allocated above. Release it here */ + + FREE(mech_type->elements, mech_type->length); + FREE(mech_type, sizeof (gss_OID_desc)); +} + +/*ARGSUSED*/ +static void +_gss_release_cred(argc, argv) +int argc; +char **argv; +{ + OM_UINT32 status; + OM_UINT32 minor_status; + uid_t uid; + + /* set up input arguments here */ + + if (argc != 0) { + usage(); + return; + } + + uid = getuid(); + + status = kgss_release_cred( + &minor_status, + &acceptor_credentials, + uid); + + /* store major and minor status for gss_display_status() call */ + + gss_major_code = status; + gss_minor_code = minor_status; + + if (status == GSS_S_COMPLETE) { + printf(gettext("\nrelease succeeded\n\n")); + } else { + printf(gettext("server ret err (octal) %o (%s)\n"), + status, gettext("gss_release_cred error")); + } +} + +static void +_gss_init_sec_context(argc, argv) +int argc; +char **argv; +{ + + OM_uint32 status; + + OM_uint32 minor_status; + gss_cred_id_t claimant_cred_handle; + gss_name_t target_name = (gss_name_t) 0; + gss_OID mech_type = (gss_OID) 0; + int req_flags; + OM_uint32 time_req; + gss_channel_bindings_t input_chan_bindings; + gss_buffer_t input_token; + gss_buffer_desc context_token; + gss_OID actual_mech_type; + int ret_flags; + OM_uint32 time_rec; + uid_t uid; + char * string; + gss_buffer_desc name; + + /* + * If this is the first phase of the context establishment, + * clear initiator_context_handle and indicate next phase. + */ + + if (init_sec_context_phase == 0) { + initiator_context_handle = GSS_C_NO_CONTEXT; + input_token = GSS_C_NO_BUFFER; + init_sec_context_phase = 1; + } else + input_token = &init_token_buffer; + + /* + * First set up the non-variable command line independent input + * arguments + */ + + claimant_cred_handle = GSS_C_NO_CREDENTIAL; + + req_flags = GSS_C_MUTUAL_FLAG; + time_req = (OM_uint32) 0; + input_chan_bindings = GSS_C_NO_CHANNEL_BINDINGS; + uid = getuid(); + + /* Now parse the command line for the remaining input arguments */ + + if (argc == 0) { + usage(); + return; + } + + /* + * Get the name of the target. + */ + + name.length = strlen(argv[0])+1; + name.value = argv[0]; + + /* + * Now convert the string given by the first argument into a target + * name suitable for input to gss_init_sec_context() + */ + + if ((status = gss_import_name(&minor_status, &name, + /* GSS_C_NULL_OID, &target_name)) */ + (gss_OID)GSS_C_NT_HOSTBASED_SERVICE, &target_name)) + != GSS_S_COMPLETE) { + printf(gettext( + "could not parse target name: err (octal) %o (%s)\n"), + status, + gettext("gss_init_sec_context error")); + if (input_token != GSS_C_NO_BUFFER) + gss_release_buffer(&minor_status, &init_token_buffer); + init_sec_context_phase = 0; + return; + } + + argc--; + argv++; + + if (argc == 0) { + printf(gettext("Assuming Kerberos V5 as the mechanism\n")); + printf(gettext( + "The mech OID 1.2.840.113554.1.2.2 will be used\n")); + mech_type = gss_str2oid((char *)GSS_KRB5_MECH_OID); + } else { + mech_type = gss_str2oid(argv[0]); + } + + if (mech_type == 0 || mech_type->length == 0) { + printf(gettext("improperly formated mechanism OID\n")); + if (input_token != GSS_C_NO_BUFFER) + gss_release_buffer(&minor_status, &init_token_buffer); + init_sec_context_phase = 0; + return; + } + + /* call kgss_init_sec_context */ + + status = kgss_init_sec_context(&minor_status, + claimant_cred_handle, + &initiator_context_handle, + target_name, + mech_type, + req_flags, + time_req, + input_chan_bindings, + input_token, + &actual_mech_type, + &accept_token_buffer, + &ret_flags, + &time_rec, + uid); + + /* store major and minor status for gss_display_status() call */ + gss_major_code = status; + gss_minor_code = minor_status; + + if (status != GSS_S_COMPLETE && + status != GSS_S_CONTINUE_NEEDED) { + + printf(gettext("server ret err (octal) %o (%s)\n"), + status, "gss_init_sec_context error"); + init_sec_context_phase = 0; + if (status == GSS_S_NO_CRED) + printf(gettext(" : no credentials")); + if (input_token != GSS_C_NO_BUFFER) + gss_release_buffer(&minor_status, &init_token_buffer); + if (status != GSS_S_FAILURE && minor_status != 0xffffffff) + status = kgss_delete_sec_context(&minor_status, + &initiator_context_handle, + &msg_token); + return; + + } else if (status == GSS_S_COMPLETE) { + + /* process returned values */ + + printf(gettext("\ninit succeeded\n\n")); + + /* print out the actual mechanism type */ + + if ((string = gss_oid2str(actual_mech_type)) == 0) { + + printf(gettext( + "gssapi internal err : actual " + "mech type null\n")); + init_sec_context_phase = 0; + if (input_token != GSS_C_NO_BUFFER) + gss_release_buffer(&minor_status, + &init_token_buffer); + gss_release_buffer(&minor_status, &accept_token_buffer); + status = kgss_delete_sec_context(&minor_status, + &initiator_context_handle, + &msg_token); + return; + } else { + printf(gettext("actual mech type = %s\n\n"), string); + FREE(string, (actual_mech_type->length+1)*4+1); + } + + /* print out value of ret_flags and time_req */ + + if (ret_flags & GSS_C_DELEG_FLAG) + printf(gettext("GSS_C_DELEG_FLAG = True\n")); + else + printf(gettext("GSS_C_DELEG_FLAG = False\n")); + + if (ret_flags & GSS_C_MUTUAL_FLAG) + printf(gettext("GSS_C_MUTUAL_FLAG = True\n")); + else + printf(gettext("GSS_C_MUTUAL_FLAG = False\n")); + + if (ret_flags & GSS_C_REPLAY_FLAG) + printf(gettext("GSS_C_REPLAY_FLAG = True\n")); + else + printf(gettext("GSS_C_REPLAY_FLAG = False\n")); + + if (ret_flags & GSS_C_SEQUENCE_FLAG) + printf(gettext("GSS_C_SEQUENCE_FLAG = True\n")); + else + printf(gettext("GSS_C_SEQUENCE_FLAG = False\n")); + + if (ret_flags & GSS_C_CONF_FLAG) + printf(gettext("GSS_C_CONF_FLAG = True\n")); + else + printf(gettext("GSS_C_CONF_FLAG = False\n")); + + if (ret_flags & GSS_C_INTEG_FLAG) + printf(gettext("GSS_C_INTEG_FLAG = True\n\n")); + else + printf(gettext("GSS_C_INTEG_FLAG = False\n\n")); + + printf(gettext("time_req = %u seconds\n\n"), time_rec); + + /* free allocated memory */ + + FREE(mech_type->elements, mech_type->length); + FREE(mech_type, sizeof (gss_OID_desc)); + + /* these two were malloc'd by kgss_init_sec_context() */ + + FREE(actual_mech_type->elements, actual_mech_type->length); + FREE(actual_mech_type, sizeof (gss_OID_desc)); + + gss_release_name(&minor_status, &target_name); + + if (input_token != GSS_C_NO_BUFFER) + gss_release_buffer(&minor_status, &init_token_buffer); + + /* + * if status == GSS_S_COMPLETE, reset the phase to 0 and + * release token in accept_token_buffer + */ + + init_sec_context_phase = 0; + /* Save and restore the context */ + status = kgss_export_sec_context(&minor_status, + &initiator_context_handle, + &context_token); + if (status != GSS_S_COMPLETE) { + printf(gettext("server ret err (octal) %o (%s)\n"), + status, gettext("gss_export_sec_context_error")); + return; + } + status = kgss_import_sec_context(&minor_status, + &context_token, + &initiator_context_handle); + if (status != GSS_S_COMPLETE) { + printf(gettext("server ret err (octal) %o (%s)\n"), + status, gettext("gss_import_sec_context_error")); + return; + } + (void) gss_release_buffer(&minor_status, &context_token); + + /* gss_export & gss_import secxc_context worked, return */ + printf(gettext("\nexport and import of contexts succeeded\n")); + printf(gettext("\ninit completed")); + + } else { + printf(gettext("\nfirst phase of init succeeded")); + printf(gettext("\ninit must be called again\n\n")); + } + +} + +/*ARGSUSED*/ +static void +_gss_accept_sec_context(argc, argv) +int argc; +char **argv; +{ + OM_UINT32 status; + + OM_uint32 minor_status; + gss_channel_bindings_t input_chan_bindings; + gss_OID mech_type; + int ret_flags; + OM_uint32 time_rec; + gss_cred_id_t delegated_cred_handle; + uid_t uid; + char *string; + gss_buffer_desc src_name, src_name_string; + gss_buffer_desc output_token; + gss_name_t gss_name; + gss_buffer_desc context_token; + + /* + * If this is the first phase of the context establishment, + * clear acceptor_context_handle and indicate next phase. + */ + + if (accept_sec_context_phase == 0) { + acceptor_context_handle = GSS_C_NO_CONTEXT; + accept_sec_context_phase = 1; + } + + /* Now set up the other command line independent input arguments */ + + input_chan_bindings = GSS_C_NO_CHANNEL_BINDINGS; + + uid = (uid_t) getuid(); + + if (argc != 0) { + usage(); + return; + } + + status = kgss_accept_sec_context(&minor_status, + &acceptor_context_handle, + acceptor_credentials, + &accept_token_buffer, + input_chan_bindings, + &src_name, + &mech_type, + &init_token_buffer, + &ret_flags, + &time_rec, + &delegated_cred_handle, + uid); + + /* store major and minor status for gss_display_status() call */ + + gss_major_code = status; + gss_minor_code = minor_status; + + if (status != GSS_S_COMPLETE && status != GSS_S_CONTINUE_NEEDED) { + printf(gettext("server ret err (octal) %o (%s)\n"), + status, gettext("gss_accept_sec_context error")); + gss_release_buffer(&minor_status, &accept_token_buffer); + return; + } else if (status == GSS_S_COMPLETE) { + + /* process returned values */ + + printf(gettext("\naccept succeeded\n\n")); + + /* + * convert the exported name returned in src_name into + * a string and print it. + */ + if ((status = gss_import_name(&minor_status, &src_name, + (gss_OID) GSS_C_NT_EXPORT_NAME, &gss_name)) + != GSS_S_COMPLETE) { + printf(gettext( + "could not import src name 0x%x\n"), status); + accept_sec_context_phase = 0; + status = kgss_delete_sec_context(&minor_status, + &acceptor_context_handle, + &output_token); + gss_release_buffer(&minor_status, &accept_token_buffer); + if (status == GSS_S_CONTINUE_NEEDED) + gss_release_buffer(&minor_status, + &init_token_buffer); + gss_release_buffer(&minor_status, &src_name); + return; + } + + memset(&src_name_string, 0, sizeof (src_name_string)); + if ((status = gss_display_name(&minor_status, gss_name, + &src_name_string, NULL)) != GSS_S_COMPLETE) { + printf(gettext("could not display src name: " + "err (octal) %o (%s)\n"), status, + "gss_init_sec_context error"); + accept_sec_context_phase = 0; + status = kgss_delete_sec_context(&minor_status, + &acceptor_context_handle, + &output_token); + gss_release_buffer(&minor_status, &accept_token_buffer); + if (status == GSS_S_CONTINUE_NEEDED) + gss_release_buffer(&minor_status, + &init_token_buffer); + gss_release_buffer(&minor_status, &src_name); + return; + } + printf(gettext("src name = %s\n"), src_name_string.value); + gss_release_name(&minor_status, &gss_name); + gss_release_buffer(&minor_status, &src_name_string); + gss_release_buffer(&minor_status, &src_name); + + /* print out the mechanism type */ + + if ((string = gss_oid2str(mech_type)) == 0) { + + printf(gettext( + "gssapi internal err :" + " actual mech type null\n")); + accept_sec_context_phase = 0; + status = kgss_delete_sec_context(&minor_status, + &acceptor_context_handle, + &output_token); + gss_release_buffer(&minor_status, &accept_token_buffer); + if (status == GSS_S_CONTINUE_NEEDED) + gss_release_buffer(&minor_status, + &init_token_buffer); + return; + } else { + + printf(gettext("actual mech type = %s\n\n"), string); + FREE(string, (mech_type->length+1)*4+1); + } + + /* Save and restore the context */ + status = kgss_export_sec_context(&minor_status, + &initiator_context_handle, + &context_token); + if (status != GSS_S_COMPLETE) { + printf(gettext("server ret err (octal) %o (%s)\n"), + status, gettext("gss_export_sec_context_error")); + return; + } + status = kgss_import_sec_context(&minor_status, + &context_token, + &initiator_context_handle); + if (status != GSS_S_COMPLETE) { + printf(gettext("server ret err (octal) %o (%s)\n"), + status, gettext("gss_import_sec_context_error")); + return; + } + (void) gss_release_buffer(&minor_status, &context_token); + + /* gss_export & gss_import secxc_context worked, return */ + + /* print out value of ret_flags and time_req */ + + if (ret_flags & GSS_C_DELEG_FLAG) + printf(gettext("GSS_C_DELEG_FLAG = True\n")); + else + printf(gettext("GSS_C_DELEG_FLAG = False\n")); + + if (ret_flags & GSS_C_MUTUAL_FLAG) + printf(gettext("GSS_C_MUTUAL_FLAG = True\n")); + else + printf(gettext("GSS_C_MUTUAL_FLAG = False\n")); + + if (ret_flags & GSS_C_REPLAY_FLAG) + printf(gettext("GSS_C_REPLAY_FLAG = True\n")); + else + printf(gettext("GSS_C_REPLAY_FLAG = False\n")); + + if (ret_flags & GSS_C_SEQUENCE_FLAG) + printf(gettext("GSS_C_SEQUENCE_FLAG = True\n")); + else + printf(gettext("GSS_C_SEQUENCE_FLAG = False\n")); + + if (ret_flags & GSS_C_CONF_FLAG) + printf(gettext("GSS_C_CONF_FLAG = True\n")); + else + printf(gettext("GSS_C_CONF_FLAG = False\n")); + + if (ret_flags & GSS_C_INTEG_FLAG) + printf(gettext("GSS_C_INTEG_FLAG = True\n\n")); + else + printf(gettext("GSS_C_INTEG_FLAG = False\n\n")); + + printf(gettext("time_rec = %d seconds\n\n"), time_rec); + + /* free allocated memory */ + + printf(gettext("\nexport and import of contexts succeeded\n")); + + FREE(mech_type->elements, mech_type->length); + FREE(mech_type, sizeof (gss_OID_desc)); + } else { + printf(gettext("\nfirst phase of accept succeeded")); + printf(gettext("\naccept must be called again\n\n")); + } + + + /* free the input token in accept_token_buffer */ + gss_release_buffer(&minor_status, &accept_token_buffer); + + /* if status == GSS_S_COMPLETE, reset the phase to 0 */ + + if (status == GSS_S_COMPLETE) + accept_sec_context_phase = 0; + + /* gss_accept_sec_context worked, return */ +} + +void +_gss_process_context_token(argc, argv) +int argc; +char **argv; +{ + OM_UINT32 status; + + gss_ctx_id_t context_handle; + OM_uint32 minor_status; + uid_t uid; + + uid = (uid_t) getuid(); + + /* parse the command line to determine the variable input argument */ + + if (argc == 0) { + usage(); + return; + } + + if (strcmp(argv[0], "initiator") == 0) + context_handle = initiator_context_handle; + else if (strcmp(argv[0], "acceptor") == 0) + context_handle = acceptor_context_handle; + else { + printf(gettext( + "must specify either \"initiator\" or \"acceptor\"\n")); + return; + } + + argc--; + argv++; + + if (argc != 0) { + usage(); + return; + } + + status = kgss_process_context_token(&minor_status, + context_handle, + delete_token_buffer, + uid); + + /* store major and minor status for gss_display_status() call */ + + gss_major_code = status; + gss_minor_code = minor_status; + + if (status != GSS_S_COMPLETE) { + printf(gettext("server ret err (octal) %o (%s)\n"), + status, gettext("gss_process_context_token error")); + return; + + } else { + printf(gettext("\nprocess succeeded\n\n")); + return; + } +} + +static void +_gss_delete_sec_context(argc, argv) +int argc; +char **argv; +{ + OM_UINT32 status; + gss_ctx_id_t *context_handle; + OM_uint32 minor_status; + uid_t uid; + + uid = (uid_t) getuid(); + + /* parse the command line to determine the variable input argument */ + + if (argc == 0) { + usage(); + return; + } + + if (strcmp(argv[0], "initiator") == 0) { + context_handle = &initiator_context_handle; + } else if (strcmp(argv[0], "acceptor") == 0) { + context_handle = &acceptor_context_handle; + } else { + printf(gettext( + "must specify either \"initiator\" or \"acceptor\"\n")); + return; + } + + argc--; + argv++; + + if (argc != 0) { + usage(); + return; + } + + + status = kgss_delete_sec_context(&minor_status, + context_handle, + &delete_token_buffer); + + + /* store major and minor status for gss_display_status() call */ + + gss_major_code = status; + gss_minor_code = minor_status; + + if (status != GSS_S_COMPLETE) { + + printf(gettext("server ret err (octal) %o (%s)\n"), + status, gettext("gss_delete_sec_context error")); + return; + + } else { + printf(gettext("\ndelete succeeded\n\n")); + return; + } +} + +/*ARGSUSED*/ +static void +_gss_context_time(argc, argv) +int argc; +char **argv; +{ + /* + * set up input arguments here + * this function is unimplemented. Call usage() and return + */ + + printf(gettext("\nunimplemented function")); +} + +static void +_gss_sign(argc, argv) +int argc; +char **argv; +{ + OM_UINT32 status; + OM_uint32 minor_status; + gss_ctx_id_t context_handle; + int qop_req; + uid_t uid; + + uid = (uid_t) getuid(); + + /* specify the default quality of protection */ + + qop_req = GSS_C_QOP_DEFAULT; + + /* set up the arguments specified in the input parameters */ + + if (argc == 0) { + usage(); + return; + } + + + if (strcmp(argv[0], "initiator") == 0) + context_handle = initiator_context_handle; + else if (strcmp(argv[0], "acceptor") == 0) + context_handle = acceptor_context_handle; + else { + printf(gettext( + "must specify either \"initiator\" or \"acceptor\"\n")); + return; + } + + argc--; + argv++; + + if (argc == 0) { + usage(); + return; + } + + message_buffer.length = strlen(argv[0])+1; + message_buffer.value = (void *) MALLOC(message_buffer.length); + strcpy(message_buffer.value, argv[0]); + + argc--; + argv++; + + if (argc != 0) { + usage(); + return; + } + + status = kgss_sign(&minor_status, + context_handle, + qop_req, + &message_buffer, + &msg_token, + uid); + + /* store major and minor status for gss_display_status() call */ + + gss_major_code = status; + gss_minor_code = minor_status; + + if (status != GSS_S_COMPLETE) { + printf(gettext("server ret err (octal) %o (%s)\n"), + status, gettext("gss_sign error")); + return; + + } else { + printf(gettext("\nsign succeeded\n\n")); + return; + } +} + +static void +_gss_verify(argc, argv) +int argc; +char **argv; +{ + OM_UINT32 status, minor_status; + gss_ctx_id_t context_handle; + int qop_state; + uid_t uid; + + uid = (uid_t) getuid(); + + /* set up the arguments specified in the input parameters */ + + if (argc == 0) { + usage(); + return; + } + + + if (strcmp(argv[0], "initiator") == 0) + context_handle = initiator_context_handle; + else if (strcmp(argv[0], "acceptor") == 0) + context_handle = acceptor_context_handle; + else { + printf(gettext( + "must specify either \"initiator\" or \"acceptor\"\n")); + return; + } + + argc--; + argv++; + + if (argc != 0) { + usage(); + return; + } + + status = kgss_verify(&minor_status, + context_handle, + &message_buffer, + &msg_token, + &qop_state, + uid); + + /* store major and minor status for gss_display_status() call */ + + gss_major_code = status; + gss_minor_code = minor_status; + + if (status != GSS_S_COMPLETE) { + printf(gettext("server ret err (octal) %o (%s)\n"), + status, gettext("gss_verify error")); + return; + } else { + + /* print out the verified message */ + + printf(gettext( + "verified message = \"%s\"\n\n"), message_buffer.value); + + /* print out the quality of protection returned */ + + printf(gettext("quality of protection = %d \n\n"), qop_state); + + /* free the message buffer and message token and return */ + + gss_release_buffer(&minor_status, &message_buffer); + gss_release_buffer(&minor_status, &msg_token); + + return; + } +} + +/* EXPORT DELETE START */ +static void +_gss_seal(argc, argv) +int argc; +char **argv; +{ + OM_UINT32 status; + + OM_uint32 minor_status; + gss_ctx_id_t context_handle; + int conf_req_flag; + int qop_req; + gss_buffer_desc input_message_buffer; + int conf_state; + uid_t uid; + + uid = (uid_t) getuid(); + + /* + * specify the default confidentiality requested (both integrity + * and confidentiality) and quality of protection + */ + + conf_req_flag = 1; + qop_req = GSS_C_QOP_DEFAULT; + + /* set up the arguments specified in the input parameters */ + + if (argc == 0) { + usage(); + return; + } + + + if (strcmp(argv[0], "initiator") == 0) + context_handle = initiator_context_handle; + else if (strcmp(argv[0], "acceptor") == 0) + context_handle = acceptor_context_handle; + else { + printf(gettext( + "must specify either \"initiator\" or \"acceptor\"\n")); + return; + } + + argc--; + argv++; + + if (argc == 0) { + usage(); + return; + } + + + input_message_buffer.length = strlen(argv[0])+1; + input_message_buffer.value = + (void *) MALLOC(input_message_buffer.length); + strcpy(input_message_buffer.value, argv[0]); + + argc--; + argv++; + + if (argc != 0) { + usage(); + return; + } + + status = kgss_seal(&minor_status, + context_handle, + conf_req_flag, + qop_req, + &input_message_buffer, + &conf_state, + &message_buffer, + uid); + + /* store major and minor status for gss_display_status() call */ + + gss_major_code = status; + gss_minor_code = minor_status; + + /* free the inputmessage buffer */ + + gss_release_buffer(&minor_status, &input_message_buffer); + + if (status != GSS_S_COMPLETE) { + printf(gettext("server ret err (octal) %o (%s)\n"), + status, gettext("gss_seal error")); + return; + } else { + printf(gettext("\nseal succeeded\n\n")); + return; + } +} + +static void +_gss_unseal(argc, argv) +int argc; +char **argv; +{ + OM_UINT32 status; + + OM_uint32 minor_status; + gss_ctx_id_t context_handle; + gss_buffer_desc output_message_buffer; + int conf_state; + int qop_state; + uid_t uid; + + uid = (uid_t) getuid(); + + /* set up the arguments specified in the input parameters */ + + if (argc == 0) { + usage(); + return; + } + + + if (strcmp(argv[0], "initiator") == 0) + context_handle = initiator_context_handle; + else if (strcmp(argv[0], "acceptor") == 0) + context_handle = acceptor_context_handle; + else { + printf(gettext( + "must specify either \"initiator\" or \"acceptor\"\n")); + return; + } + + argc--; + argv++; + + if (argc != 0) { + usage(); + return; + } + + status = kgss_unseal(&minor_status, + context_handle, + &message_buffer, + &output_message_buffer, + &conf_state, + &qop_state, + uid); + + /* store major and minor status for gss_display_status() call */ + + gss_major_code = status; + gss_minor_code = minor_status; + + if (status == GSS_S_COMPLETE) { + printf(gettext("\nunseal succeeded\n\n")); + printf(gettext("unsealed message = \"%s\"\n\n"), + output_message_buffer.value); + if (conf_state) + printf(gettext("confidentiality and integrity used\n")); + else + printf(gettext("only integrity used\n")); + printf(gettext("quality of protection = %d\n\n"), qop_state); + gss_release_buffer(&minor_status, &output_message_buffer); + } else { + printf(gettext("server ret err (octal) %o (%s)\n"), + status, gettext("gss_unseal error")); + } + + /* free the message buffer and return */ + + gss_release_buffer(&minor_status, &message_buffer); +} +/* EXPORT DELETE END */ + +static void +_gss_display_status(argc, argv) +int argc; +char **argv; +{ + OM_UINT32 status; + OM_uint32 minor_status; + int status_type; + int status_value; + gss_OID mech_type = (gss_OID) 0; + int message_context; + gss_buffer_desc status_string; + uid_t uid; + + uid = (uid_t) getuid(); + + /* initialize message context to zero */ + + message_context = 0; + + if (argc == 0) { + printf(gettext("Assuming Kerberos V5 as the mechanism\n")); + printf(gettext( + "The mech OID 1.2.840.113554.1.2.2 will be used\n")); + mech_type = gss_str2oid((char *)GSS_KRB5_MECH_OID); + } else + mech_type = gss_str2oid(argv[0]); + + if (mech_type == 0 || mech_type->length == 0) { + printf(gettext("improperly formated mechanism OID\n")); + return; + } + + /* Is this call for the major or minor status? */ + + if (strcmp(argv[0], "major") == 0) { + status_type = GSS_C_GSS_CODE; + status_value = gss_major_code; + } else if (strcmp(argv[0], "minor") == 0) { + status_type = GSS_C_MECH_CODE; + status_value = gss_minor_code; + } else { + printf(gettext("must specify either \"major\" or \"minor\"\n")); + return; + } + + argc--; + argv++; + + if (argc != 0) { + usage(); + return; + } + + status = kgss_display_status(&minor_status, + status_value, + status_type, + mech_type, + &message_context, + &status_string, + uid); + + if (status == GSS_S_COMPLETE) { + printf(gettext("status =\n %s\n\n"), status_string.value); + } else if (status == GSS_S_BAD_MECH) { + printf(gettext("invalide mechanism OID\n\n")); + } else { + printf(gettext("server ret err (octal) %o (%s)\n"), + status, gettext("gss_display_status error")); + } +} + +/*ARGSUSED*/ +static void +_gss_indicate_mechs(argc, argv) +int argc; +char **argv; +{ + OM_UINT32 status; + OM_UINT32 minor_status; + gss_OID_set oid_set = GSS_C_NULL_OID_SET; + uid_t uid; + + uid = (uid_t) getuid(); + + /* set up input arguments here */ + + if (argc != 0) { + usage(); + return; + } + + status = kgss_indicate_mechs(&minor_status, &oid_set, uid); + + if (status == GSS_S_COMPLETE) { + int i; + char *string; + + printf(gettext("%d supported mechanism%s%s\n"), oid_set->count, + (oid_set->count == 1) ? "" : "s", + (oid_set->count > 0) ? ":" : ""); + + for (i = 0; i < oid_set->count; i++) { + string = gss_oid2str(&oid_set->elements[i]); + printf(gettext("\t%s\n"), string); + FREE(string, ((oid_set->elements[i].length+1)*4)+1); + } + printf("\n"); + + } else { + printf(gettext("server ret err (octal) %o (%s)\n"), + status, gettext("gss_indicate_mechs error")); + } + + if (oid_set) + gss_release_oid_set_and_oids(&minor_status, &oid_set); +} + +/*ARGSUSED*/ +static void +_gss_inquire_cred(argc, argv) +int argc; +char **argv; +{ + /* set up input arguments here */ + + if (argc != 0) { + usage(); + return; + } + + + /* this function is unimplemented. Call usage() and return */ + + printf(gettext("\nUnsupported function")); +} + +static char hexChars[] = "0123456789ABCDEF"; + +static void +_gssd_expname_to_unix_cred(argc, argv) +int argc; +char **argv; +{ + OM_uint32 major; + gss_buffer_desc expName; + char krb5_root_name[] = "040100092A864886F712010202000000" + "25000A2A864886F71201020101726F6F744053554E534F46" + "542E454E472E53554E2E434F4D00"; + unsigned char *byteStr, *hexStr; + uid_t uidOut, uidIn; + gid_t *gids, gidOut; + int gidsLen, i, newLen; + + /* set up the arguments */ + uidIn = (uid_t) getuid(); + + if (argc < 1) { + printf(gettext( + "Using principal name of root for krberos_v5\n")); + expName.value = (void*)krb5_root_name; + expName.length = strlen(krb5_root_name); + } else { + expName.value = (void*)argv[0]; + expName.length = strlen(argv[0]); + } + + /* convert the name from hex to byte... */ + hexStr = (unsigned char *)expName.value; + newLen = expName.length/2; + byteStr = (unsigned char *)MALLOC(newLen+1); + expName.value = (char *)byteStr; + for (i = 0; i < expName.length; i += 2) { + *byteStr = (strchr(hexChars, *hexStr++) - hexChars) << 4; + *byteStr += (strchr(hexChars, *hexStr++) - hexChars); + byteStr++; + } + expName.length = newLen; + + major = kgsscred_expname_to_unix_cred(&expName, &uidOut, &gidOut, + &gids, &gidsLen, uidIn); + + FREE(expName.value, newLen); + + if (major == GSS_S_COMPLETE) { + printf(gettext("uid = <%d>\tgid = <%d>\t"), uidOut, gidOut); + if (gidsLen > 0) + printf(gettext(" %d gids <"), gidsLen); + else + printf(gettext( + " no supplementary group information\n")); + for (i = 0; i < gidsLen; i++) + printf(" %d ", gids[i]); + if (gidsLen > 0) { + printf(">\n"); + FREE(gids, gidsLen * sizeof (gid_t)); + } + } else { + printf(gettext("server ret err (octal) %o (%s)\n"), + major, gettext("gsscred_expname_to_unix_cred")); + } +} + +static void +_gssd_name_to_unix_cred(argc, argv) +int argc; +char **argv; +{ + OM_uint32 major, minor; + gss_name_t gssName; + gss_buffer_desc gssBuf = GSS_C_EMPTY_BUFFER; + int gidsLen, i; + gid_t *gids, gidOut; + uid_t uidOut, uid; + char defaultPrincipal[] = "root"; + gss_OID mechType, nameType; + + uid = getuid(); + + /* optional argument 1 - contains principal name */ + if (argc > 0) { + gssBuf.value = (void *)argv[0]; + gssBuf.length = strlen((char *)argv[0]); + } else { + gssBuf.value = (void *)defaultPrincipal; + gssBuf.length = strlen(defaultPrincipal); + } + printf(gettext( + "Using <%s> as the principal name.\n"), (char *)gssBuf.value); + + + /* optional argument 2 - contains name oid */ + if (argc > 1) + nameType = gss_str2oid((char *) argv[1]); + else + nameType = (gss_OID)GSS_C_NT_USER_NAME; + + if (nameType == NULL || nameType->length == 0) { + printf(gettext("improperly formated name OID\n")); + return; + } + printf(gettext("Principal name of type: <%s>.\n"), + (argc > 1) ? argv[1] : "GSS_C_NT_USER_NAME"); + + + /* optional argument 3 - contains mech oid */ + if (argc > 2) + mechType = gss_str2oid(argv[2]); + else + mechType = gss_str2oid((char *)GSS_KRB5_MECH_OID); + + if (mechType == NULL || mechType->length == NULL) { + FREE(nameType->elements, nameType->length); + FREE(nameType, sizeof (gss_OID_desc)); + printf(gettext("improperly formated mech OID\n")); + return; + } + printf(gettext("Mechanism oid: <%s>.\n"), + (argc > 2) ? argv[2] : + (char *)GSS_KRB5_MECH_OID "(Kerberos v5)"); + + + /* convert the name to internal format */ + if ((major = gss_import_name(&minor, &gssBuf, + nameType, &gssName)) != GSS_S_COMPLETE) { + printf(gettext("could not parse name: err (octal) %o (%s)\n"), + major, "gss_import_name"); + + FREE(nameType->elements, nameType->length); + FREE(nameType, sizeof (gss_OID_desc)); + return; + } + + major = kgsscred_name_to_unix_cred(gssName, mechType, &uidOut, + &gidOut, &gids, &gidsLen, uid); + + gss_release_name(&minor, &gssName); + FREE(mechType->elements, mechType->length); + FREE(mechType, sizeof (gss_OID_desc)); + if (argc > 1) { + FREE(nameType->elements, nameType->length); + FREE(nameType, sizeof (gss_OID_desc)); + } + + if (major == GSS_S_COMPLETE) { + printf("uid = <%d>\tgid = <%d>\t", uidOut, gidOut); + if (gidsLen > 0) + printf(gettext(" %d gids <"), gidsLen); + else + printf(gettext( + " no supplementary group information\n")); + for (i = 0; i < gidsLen; i++) + printf(" %d ", gids[i]); + if (gidsLen > 0) { + printf(">\n"); + FREE(gids, gidsLen * sizeof (gid_t)); + } + } else { + printf(gettext("server ret err (octal) %o (%s)\n"), + major, gettext("gsscred_name_to_unix_cred")); + } +} + +static void +_gssd_get_group_info(argc, argv) +int argc; +char **argv; +{ + OM_uint32 major; + uid_t puid, uidIn; + gid_t *gids, gidOut; + int gidsLen, i; + + /* set up the arguments */ + uidIn = (uid_t) getuid(); + + if (argc < 1) + puid = 0; + else + puid = atol(argv[0]); + + printf(gettext("Retrieving group info for uid of <%d>\n"), puid); + + major = kgss_get_group_info(puid, &gidOut, &gids, &gidsLen, uidIn); + + if (major == GSS_S_COMPLETE) { + printf(gettext("group id = <%d>\t"), gidOut); + if (gidsLen > 0) + printf(gettext(" %d gids <"), gidsLen); + else + printf(gettext( + " no supplementary group information\n")); + for (i = 0; i < gidsLen; i++) + printf(" %d ", gids[i]); + if (gidsLen > 0) { + printf(">\n"); + FREE(gids, gidsLen * sizeof (gid_t)); + } + } else { + printf(gettext("server ret err (octal) %o (%s)\n"), + major, "gss_get_group_info"); + } +} + +static gss_OID +gss_str2oid(string) +char * string; +{ + /* + * a convenient wrapper routine for gss_str_to_oid + * this can handle all valid oid strings. + */ + OM_uint32 minor; + gss_buffer_desc abuf; + gss_OID oidOut; + + abuf.value = (void*)string; + abuf.length = strlen(string); + + if (gss_str_to_oid(&minor, &abuf, &oidOut) != GSS_S_COMPLETE) + return (NULL); + + return (oidOut); +} + +static char * +gss_oid2str(oid) +gss_OID oid; +{ + /* + * a convenient wrapper for gss_oid_to_str + * this calls the GSS-API routine which should + * be able to handle all types of oids. + */ + OM_uint32 minor; + gss_buffer_desc oidStr; + + if (gss_oid_to_str(&minor, oid, &oidStr) != GSS_S_COMPLETE) + return (NULL); + + return ((char *)oidStr.value); +} /* gss_oid2str */ + +static void +instructs() +{ + fprintf(stderr, + gettext( +"\nThis program must be run as root. Root must be installed on the KDC\n" +"and exist in srvtab as root/<hostname>, where <hostname> is the machine on\n" +"which the test runs. Before running gssdtest for Kerberos mechanism, the\n" +"operator running as root must kinit as some other principal, e.g., test.\n" +"There are two mechanisms avaialble: dummy and Kerberos(default).\n" +"The OID for dummy mechanism is 1.3.6.1.4.1.42.2.26.1.2.\n" +"The OID for Kerberos mechanism is 1.2.840.113554.1.2.2.\n" +"The order of context establishment calls is important. First, acquire must" +"\nbe called. This obtains the credentials used by accept. Acquire need\n" +"only be called once, since the credentials it returns are used each time\n" +"accept is called. Then init is called, followed by accept. Calling init\n" +"twice without calling accept or calling these in a different order gives\n" +"erroneous results and will cause memory leaks in the gssapi daemon. \n" +"Finally, after calling init and accept, init must be called again to\n" +"finish context establishment. So an example sequence (with data valid for\n" +"the Kerberos mechanism and running on the machine \"elrond\" in the realm\n" +"FOO.BAR.SUN.COM is :\n")); + fprintf(stderr, + gettext("\nacquire service@host 1.2.840.113554.1.2.2\n" + "init service@host 1.2.840.113554.1.2.2\n" + "accept\ninit service@host 1.2.840.113554.1.2.2\n" + "\nAfter a context is established, sign, seal,\n" + "verify and unseal may be called. Here are some examples\n" + "for these routines : \n\n" + "sign initiator ThisTestMessageIsForSigning\n" + "verify acceptor\nseal initiator ThisTestMessageIsForSealing\n" + "unseal acceptor\n\nEach input line is terminated by <cr>.\n" + "The program is terminated by cntl-d\nor the command \"exit\"" + "\nfrom the prompt\n\n")); +} + +static void +usage() +{ + fprintf(stderr, + gettext( + "\nusage:\t[acquire | gss_acquire_cred]" + "desired_name mech_type\n" + "\t[release | gss_release_cred]\n" + "\t[init | gss_init_sec_context] target_name mech_type\n" + "\t[accept | gss_accept_sec_context]\n" + "\t[process | gss_process_context_token] initiator | acceptor\n" + "\t[delete | gss_delete_sec_context] initiator | acceptor\n" + "\t[time | gss_context_time] {not yet implemented}\n" + "\t[sign | gss_sign] initiator | acceptor message-to-sign\n" + "\t[verify | gss_verify] initiator | acceptor\n" + "\t[seal | gss_seal] initiator | acceptor message-to-seal\n" + "\t[unseal | gss_unseal] initiator | acceptor\n" + "\t[status | gss_display_status] mech_type [major | minor] \n" + "\t[indicate | gss_indicate_mechs]\n" + "\t[inquire | gss_inquire_cred] {not yet implemented}\n" + "\t[expname2unixcred | gsscred_expname_to_unix_cred]" + " export-name\n" + "\t[name2unixcred | gsscred_name_to_unix_cred] " + "pname [name_type mech_type]\n" + "\t[grpinfo | gss_get_group_info] uid\n" + "\t[gss_all | all] desired_name\n" + "\t[gss_loop | loop] desired_name\n" + "\texit\n\n")); +} + +/* Copied from parse_argv(), then modified */ + +static int +parse_input_line(input_line, argc, argv) +char *input_line; +int * argc; +char ***argv; +{ + const char nil = '\0'; + char * chptr; + int chr_cnt; + int arg_cnt = 0; + int ch_was_space = 1; + int ch_is_space; + + chr_cnt = strlen(input_line); + + /* Count the arguments in the input_line string */ + + *argc = 1; + + for (chptr = &input_line[0]; *chptr != nil; chptr++) { + ch_is_space = isspace(*chptr); + if (ch_is_space && !ch_was_space) { + (*argc)++; + } + ch_was_space = ch_is_space; + } + + if (ch_was_space) { + (*argc)--; + } /* minus trailing spaces */ + + /* Now that we know how many args calloc the argv array */ + + *argv = (char **) CALLOC((*argc)+1, sizeof (char *)); + chptr = (char *) (&input_line[0]); + + for (ch_was_space = 1; *chptr != nil; chptr++) { + ch_is_space = isspace(*chptr); + if (ch_is_space) { + *chptr = nil; /* replace each space with nil */ + } else if (ch_was_space) { /* begining of word? */ + (*argv)[arg_cnt++] = chptr; /* new argument ? */ + } + + ch_was_space = ch_is_space; + } + + return (chr_cnt); +} |
