/*
* 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
* 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.
*/
/*
* 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_ext.h>
#include "gssd.h"
#define _KERNEL
int gss_major_code;
int gss_minor_code;
int init_sec_context_phase = 0;
int accept_sec_context_phase = 0;
#ifdef _KERNEL
(s) == '\r' || (s) == '\v' || (s) == '\f')
static char *strdup(const char *s)
{
return (new);
}
#else /* !_KERNEL */
#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 ***);
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 **);
static void _gss_seal(int, char **);
static void _gss_unseal(int, char **);
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
{
int len;
/* read the next line. If cntl-d, return with zero char count */
return (0);
return (len);
}
int
main()
{
/* 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 {
if (len)
return (0);
}
#endif /* !_KERNEL */
static int
{
int i;
char *cmd;
argv = 0;
return (1);
}
if (argc == 0) {
usage();
/*LINTED*/
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;
argc--;
argv++;
if (argc < 1) {
usage();
return (0);
}
for (i = 0; i < LOOP_COUNTER; i++) {
/*
* if (i > 53)
* printf ("Loop counter is greater than 55\n");
*/
seal_argc = 2;
seal_argc = 1;
seal_argc = 2;
seal_argc = 1;
seal_argc = 2;
seal_argc = 1;
seal_argc = 2;
seal_argc = 1;
}
}
seal_argc = 2;
seal_argc = 1;
seal_argc = 2;
seal_argc = 1;
seal_argc = 2;
seal_argc = 1;
seal_argc = 2;
seal_argc = 1;
}
if (argc == 1)
}
return (1);
} else
usage();
/* free argv array */
return (0);
}
static void
int argc;
char **argv;
{
int cred_usage;
char * string;
char * inq_string;
/*
* First set up the command line independent input arguments.
*/
/* Parse the command line for the variable input arguments */
if (argc == 0) {
usage();
return;
}
/*
* Get the name of the principal.
*/
/*
* Now convert the string given by the first argument into internal
* form suitable for input to gss_acquire_cred()
*/
!= GSS_S_COMPLETE) {
"could not parse desired name: err (octal) %o (%s)\n"),
return;
}
argc--;
argv++;
/*
* The next argument is an OID in dotted decimal form.
*/
if (argc == 0) {
"The mech OID 1.2.840.113554.1.2.2 will be used\n"));
} else
return;
}
/*
* set up desired_mechs so it points to mech_type.
*/
&time_rec,
uid);
/* store major and minor status for gss_display_status() call */
if (status == GSS_S_COMPLETE) {
/* process returned values */
/*
* 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.
*/
} else {
}
if (cred_usage == GSS_C_BOTH)
if (cred_usage == GSS_C_INITIATE)
if (cred_usage == GSS_C_ACCEPT)
NULL,
&time_req,
uid);
if (status != GSS_S_COMPLETE)
else {
if ((inq_string =
("mechs from inquire == NULL\n\n"));
} else {
("mechs from inquiry = %s\n\n"),
}
}
} else {
}
/* free allocated memory */
/* actual mechs is allocated by clnt_stubs. Release it here */
if (actual_mechs != GSS_C_NULL_OID_SET)
if (inquire_mechs != GSS_C_NULL_OID_SET)
/* mech_type and desired_mechs are allocated above. Release it here */
}
static void
int argc;
char **argv;
{
int cred_usage;
char * string;
int i;
/*
* First set up the command line independent input arguments.
*/
initiator_time_req = (OM_uint32) 0;
acceptor_time_req = (OM_uint32) 0;
/* Parse the command line for the variable input arguments */
if (argc == 0) {
usage();
return;
}
/*
* Get the name of the principal.
*/
/*
* Now convert the string given by the first argument into internal
* form suitable for input to gss_acquire_cred()
*/
!= GSS_S_COMPLETE) {
"could not parse desired name: err (octal) %o (%s)\n"),
return;
}
argc--;
argv++;
/*
* The next argument is an OID in dotted decimal form.
*/
if (argc == 0) {
"The mech OID 1.3.6.1.4.1.42.2.26.1.2 will be used\n"));
} else
return;
}
/*
* set up desired_mechs so it points to mech_type.
*/
NULL,
NULL,
uid);
/* store major and minor status for gss_display_status() call */
if (status == GSS_S_COMPLETE) {
/* process returned values */
if (actual_mechs) {
for (i = 0; i < actual_mechs->count; i++) {
if ((string =
(&actual_mechs->elements[i])) == 0) {
("actual mechs == NULL\n\n"));
} else {
("actual mechs = %s\n\n"), string);
}
}
}
/*
* Try adding the cred again for the same mech
* We should get GSS_S_DUPLICATE_ELEMENT
* if not return an error
*/
NULL, /* &actual_mechs, */
NULL,
NULL,
uid);
if (status != GSS_S_DUPLICATE_ELEMENT) {
" (octal) %o (%s)\n"),
}
NULL,
&time_req,
uid);
if (status != GSS_S_COMPLETE)
else {
for (i = 0; i < inquire_mechs->count; i++) {
if ((string =
(&inquire_mechs->elements[i])) == 0) {
("inquire_mechs mechs == NULL\n\n"));
} else {
("inquire_cred mechs = %s\n\n"),
string);
+1);
}
}
}
} else {
}
/* Let us do inquire_cred_by_mech for both mechanisms */
uid);
if (status != GSS_S_COMPLETE)
else
uid);
if (status != GSS_S_COMPLETE)
("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)
if (inquire_mechs != GSS_C_NULL_OID_SET)
/* mech_type and desired_mechs are allocated above. Release it here */
}
/*ARGSUSED*/
static void
int argc;
char **argv;
{
/* set up input arguments here */
if (argc != 0) {
usage();
return;
}
uid);
/* store major and minor status for gss_display_status() call */
if (status == GSS_S_COMPLETE) {
} else {
}
}
static void
int argc;
char **argv;
{
int req_flags;
int ret_flags;
char * string;
/*
* If this is the first phase of the context establishment,
* clear initiator_context_handle and indicate next phase.
*/
if (init_sec_context_phase == 0) {
} else
/*
* First set up the non-variable command line independent input
* arguments
*/
/* Now parse the command line for the remaining input arguments */
if (argc == 0) {
usage();
return;
}
/*
* Get the name of the target.
*/
/*
* Now convert the string given by the first argument into a target
* name suitable for input to gss_init_sec_context()
*/
/* GSS_C_NULL_OID, &target_name)) */
!= GSS_S_COMPLETE) {
"could not parse target name: err (octal) %o (%s)\n"),
gettext("gss_init_sec_context error"));
if (input_token != GSS_C_NO_BUFFER)
return;
}
argc--;
argv++;
if (argc == 0) {
"The mech OID 1.2.840.113554.1.2.2 will be used\n"));
} else {
}
if (input_token != GSS_C_NO_BUFFER)
return;
}
/* call kgss_init_sec_context */
&time_rec,
uid);
/* store major and minor status for gss_display_status() call */
if (status != GSS_S_COMPLETE &&
status != GSS_S_CONTINUE_NEEDED) {
status, "gss_init_sec_context error");
if (status == GSS_S_NO_CRED)
if (input_token != GSS_C_NO_BUFFER)
&msg_token);
return;
} else if (status == GSS_S_COMPLETE) {
/* process returned values */
/* print out the actual mechanism type */
"gssapi internal err : actual "
"mech type null\n"));
if (input_token != GSS_C_NO_BUFFER)
&msg_token);
return;
} else {
}
/* print out value of ret_flags and time_req */
if (ret_flags & GSS_C_DELEG_FLAG)
else
if (ret_flags & GSS_C_MUTUAL_FLAG)
else
if (ret_flags & GSS_C_REPLAY_FLAG)
else
if (ret_flags & GSS_C_SEQUENCE_FLAG)
else
if (ret_flags & GSS_C_CONF_FLAG)
else
if (ret_flags & GSS_C_INTEG_FLAG)
else
/* free allocated memory */
/* these two were malloc'd by kgss_init_sec_context() */
if (input_token != GSS_C_NO_BUFFER)
/*
* if status == GSS_S_COMPLETE, reset the phase to 0 and
* release token in accept_token_buffer
*/
/* Save and restore the context */
if (status != GSS_S_COMPLETE) {
return;
}
if (status != GSS_S_COMPLETE) {
return;
}
/* gss_export & gss_import secxc_context worked, return */
} else {
}
}
/*ARGSUSED*/
static void
int argc;
char **argv;
{
int ret_flags;
char *string;
/*
* If this is the first phase of the context establishment,
* clear acceptor_context_handle and indicate next phase.
*/
if (accept_sec_context_phase == 0) {
}
/* Now set up the other command line independent input arguments */
if (argc != 0) {
usage();
return;
}
&src_name,
&time_rec,
uid);
/* store major and minor status for gss_display_status() call */
return;
} else if (status == GSS_S_COMPLETE) {
/* process returned values */
/*
* convert the exported name returned in src_name into
* a string and print it.
*/
!= GSS_S_COMPLETE) {
"could not import src name 0x%x\n"), status);
&output_token);
if (status == GSS_S_CONTINUE_NEEDED)
return;
}
"err (octal) %o (%s)\n"), status,
"gss_init_sec_context error");
&output_token);
if (status == GSS_S_CONTINUE_NEEDED)
return;
}
/* print out the mechanism type */
"gssapi internal err :"
" actual mech type null\n"));
&output_token);
if (status == GSS_S_CONTINUE_NEEDED)
return;
} else {
}
/* Save and restore the context */
if (status != GSS_S_COMPLETE) {
return;
}
if (status != GSS_S_COMPLETE) {
return;
}
/* gss_export & gss_import secxc_context worked, return */
/* print out value of ret_flags and time_req */
if (ret_flags & GSS_C_DELEG_FLAG)
else
if (ret_flags & GSS_C_MUTUAL_FLAG)
else
if (ret_flags & GSS_C_REPLAY_FLAG)
else
if (ret_flags & GSS_C_SEQUENCE_FLAG)
else
if (ret_flags & GSS_C_CONF_FLAG)
else
if (ret_flags & GSS_C_INTEG_FLAG)
else
/* free allocated memory */
} else {
}
/* free the input token in accept_token_buffer */
/* if status == GSS_S_COMPLETE, reset the phase to 0 */
if (status == GSS_S_COMPLETE)
/* gss_accept_sec_context worked, return */
}
void
int argc;
char **argv;
{
/* parse the command line to determine the variable input argument */
if (argc == 0) {
usage();
return;
}
else {
"must specify either \"initiator\" or \"acceptor\"\n"));
return;
}
argc--;
argv++;
if (argc != 0) {
usage();
return;
}
uid);
/* store major and minor status for gss_display_status() call */
if (status != GSS_S_COMPLETE) {
return;
} else {
return;
}
}
static void
int argc;
char **argv;
{
/* parse the command line to determine the variable input argument */
if (argc == 0) {
usage();
return;
}
} else {
"must specify either \"initiator\" or \"acceptor\"\n"));
return;
}
argc--;
argv++;
if (argc != 0) {
usage();
return;
}
/* store major and minor status for gss_display_status() call */
if (status != GSS_S_COMPLETE) {
return;
} else {
return;
}
}
/*ARGSUSED*/
static void
int argc;
char **argv;
{
/*
* set up input arguments here
* this function is unimplemented. Call usage() and return
*/
}
static void
int argc;
char **argv;
{
int qop_req;
/* specify the default quality of protection */
/* set up the arguments specified in the input parameters */
if (argc == 0) {
usage();
return;
}
else {
"must specify either \"initiator\" or \"acceptor\"\n"));
return;
}
argc--;
argv++;
if (argc == 0) {
usage();
return;
}
argc--;
argv++;
if (argc != 0) {
usage();
return;
}
uid);
/* store major and minor status for gss_display_status() call */
if (status != GSS_S_COMPLETE) {
return;
} else {
return;
}
}
static void
int argc;
char **argv;
{
int qop_state;
/* set up the arguments specified in the input parameters */
if (argc == 0) {
usage();
return;
}
else {
"must specify either \"initiator\" or \"acceptor\"\n"));
return;
}
argc--;
argv++;
if (argc != 0) {
usage();
return;
}
uid);
/* store major and minor status for gss_display_status() call */
if (status != GSS_S_COMPLETE) {
return;
} else {
/* print out the verified message */
/* print out the quality of protection returned */
/* free the message buffer and message token and return */
return;
}
}
static void
int argc;
char **argv;
{
int conf_req_flag;
int qop_req;
int conf_state;
/*
* specify the default confidentiality requested (both integrity
* and confidentiality) and quality of protection
*/
conf_req_flag = 1;
/* set up the arguments specified in the input parameters */
if (argc == 0) {
usage();
return;
}
else {
"must specify either \"initiator\" or \"acceptor\"\n"));
return;
}
argc--;
argv++;
if (argc == 0) {
usage();
return;
}
argc--;
argv++;
if (argc != 0) {
usage();
return;
}
uid);
/* store major and minor status for gss_display_status() call */
/* free the inputmessage buffer */
if (status != GSS_S_COMPLETE) {
return;
} else {
return;
}
}
static void
int argc;
char **argv;
{
int conf_state;
int qop_state;
/* set up the arguments specified in the input parameters */
if (argc == 0) {
usage();
return;
}
else {
"must specify either \"initiator\" or \"acceptor\"\n"));
return;
}
argc--;
argv++;
if (argc != 0) {
usage();
return;
}
uid);
/* store major and minor status for gss_display_status() call */
if (status == GSS_S_COMPLETE) {
if (conf_state)
else
} else {
}
/* free the message buffer and return */
}
static void
int argc;
char **argv;
{
int status_type;
int status_value;
int message_context;
/* initialize message context to zero */
message_context = 0;
if (argc == 0) {
"The mech OID 1.2.840.113554.1.2.2 will be used\n"));
} else
return;
}
/* Is this call for the major or minor status? */
} else {
return;
}
argc--;
argv++;
if (argc != 0) {
usage();
return;
}
uid);
if (status == GSS_S_COMPLETE) {
} else if (status == GSS_S_BAD_MECH) {
} else {
}
}
/*ARGSUSED*/
static void
int argc;
char **argv;
{
/* set up input arguments here */
if (argc != 0) {
usage();
return;
}
if (status == GSS_S_COMPLETE) {
int i;
char *string;
}
printf("\n");
} else {
}
if (oid_set)
}
/*ARGSUSED*/
static void
int argc;
char **argv;
{
/* set up input arguments here */
if (argc != 0) {
usage();
return;
}
/* this function is unimplemented. Call usage() and return */
}
static void
int argc;
char **argv;
{
"25000A2A864886F71201020101726F6F744053554E534F46"
"542E454E472E53554E2E434F4D00";
/* set up the arguments */
if (argc < 1) {
"Using principal name of root for krberos_v5\n"));
} else {
}
/* convert the name from hex to byte... */
byteStr++;
}
if (major == GSS_S_COMPLETE) {
if (gidsLen > 0)
else
" no supplementary group information\n"));
for (i = 0; i < gidsLen; i++)
if (gidsLen > 0) {
printf(">\n");
}
} else {
}
}
static void
int argc;
char **argv;
{
int gidsLen, i;
/* optional argument 1 - contains principal name */
if (argc > 0) {
} else {
}
/* optional argument 2 - contains name oid */
if (argc > 1)
else
return;
}
/* optional argument 3 - contains mech oid */
if (argc > 2)
else
return;
}
(char *)GSS_KRB5_MECH_OID "(Kerberos v5)");
/* convert the name to internal format */
major, "gss_import_name");
return;
}
if (argc > 1) {
}
if (major == GSS_S_COMPLETE) {
if (gidsLen > 0)
else
" no supplementary group information\n"));
for (i = 0; i < gidsLen; i++)
if (gidsLen > 0) {
printf(">\n");
}
} else {
}
}
static void
int argc;
char **argv;
{
int gidsLen, i;
/* set up the arguments */
if (argc < 1)
puid = 0;
else
if (major == GSS_S_COMPLETE) {
if (gidsLen > 0)
else
" no supplementary group information\n"));
for (i = 0; i < gidsLen; i++)
if (gidsLen > 0) {
printf(">\n");
}
} else {
major, "gss_get_group_info");
}
}
static gss_OID
char * string;
{
/*
* a convenient wrapper routine for gss_str_to_oid
* this can handle all valid oid strings.
*/
return (NULL);
return (oidOut);
}
static char *
{
/*
* a convenient wrapper for gss_oid_to_str
* this calls the GSS-API routine which should
* be able to handle all types of oids.
*/
return (NULL);
} /* gss_oid2str */
static void
{
"\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"));
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()
{
"\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
char *input_line;
int * argc;
char ***argv;
{
char * chptr;
int chr_cnt;
int arg_cnt = 0;
int ch_is_space;
/* Count the arguments in the input_line string */
*argc = 1;
if (ch_is_space && !ch_was_space) {
(*argc)++;
}
}
if (ch_was_space) {
(*argc)--;
} /* minus trailing spaces */
/* Now that we know how many args calloc the argv array */
chptr = (char *) (&input_line[0]);
if (ch_is_space) {
} else if (ch_was_space) { /* begining of word? */
}
}
return (chr_cnt);
}