summaryrefslogtreecommitdiff
path: root/usr/src/cmd/gss
diff options
context:
space:
mode:
authorstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
committerstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
commit7c478bd95313f5f23a4c958a745db2134aa03244 (patch)
treec871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/cmd/gss
downloadillumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz
OpenSolaris Launch
Diffstat (limited to 'usr/src/cmd/gss')
-rw-r--r--usr/src/cmd/gss/Makefile92
-rw-r--r--usr/src/cmd/gss/etc/Makefile79
-rw-r--r--usr/src/cmd/gss/etc/dummy_mech33
-rw-r--r--usr/src/cmd/gss/etc/dummy_mech_token.conf.sh33
-rw-r--r--usr/src/cmd/gss/etc/dummy_nfssec.conf53
-rw-r--r--usr/src/cmd/gss/etc/gsscred.conf43
-rw-r--r--usr/src/cmd/gss/etc/kadm5.acl27
-rw-r--r--usr/src/cmd/gss/etc/kdc.conf41
-rw-r--r--usr/src/cmd/gss/etc/kpropd.acl25
-rw-r--r--usr/src/cmd/gss/etc/krb5.conf69
-rw-r--r--usr/src/cmd/gss/etc/mech36
-rw-r--r--usr/src/cmd/gss/etc/qop33
-rw-r--r--usr/src/cmd/gss/etc/warn.conf33
-rw-r--r--usr/src/cmd/gss/gsscred/Makefile95
-rw-r--r--usr/src/cmd/gss/gsscred/gsscred.c753
-rw-r--r--usr/src/cmd/gss/gsscred/gsscred.h94
-rw-r--r--usr/src/cmd/gss/gsscred/gsscred_file.c296
-rw-r--r--usr/src/cmd/gss/gsscred/gsscred_utils.c307
-rw-r--r--usr/src/cmd/gss/gsscred_clean/Makefile88
-rw-r--r--usr/src/cmd/gss/gsscred_clean/gsscred_clean.ksh74
-rw-r--r--usr/src/cmd/gss/gssd/Makefile181
-rw-r--r--usr/src/cmd/gss/gssd/gss.xml120
-rw-r--r--usr/src/cmd/gss/gssd/gssd.c300
-rw-r--r--usr/src/cmd/gss/gssd/gssd_clnt_stubs.c2685
-rw-r--r--usr/src/cmd/gss/gssd/gssd_generic.c152
-rw-r--r--usr/src/cmd/gss/gssd/gssd_getuid.c70
-rw-r--r--usr/src/cmd/gss/gssd/gssd_handle.c145
-rw-r--r--usr/src/cmd/gss/gssd/gssd_proc.c2598
-rw-r--r--usr/src/cmd/gss/gssd/gssd_release_name_and_type.c100
-rw-r--r--usr/src/cmd/gss/gssd/gssdtest.c2192
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);
+}