/*
*/
/*
* Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
*/
/*
* Copyright (C) 1998 by the FundsXpress, INC.
*
* All rights reserved.
*
* Export of this software from the United States of America may require
* a specific license from the United States Government. It is the
* responsibility of any person or organization contemplating export to
* obtain such a license before exporting.
*
* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
* distribute this software and its documentation for any purpose and
* without fee is hereby granted, provided that the above copyright
* notice appear in all copies and that both that copyright notice and
* this permission notice appear in supporting documentation, and that
* the name of FundsXpress. not be used in advertising or publicity pertaining
* to distribution of the software without specific, written prior
* permission. FundsXpress makes no representations about the suitability of
* this software for any purpose. It is provided "as is" without express
* or implied warranty.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#include <stdio.h>
#include <netdb.h>
#include "autoconf.h"
#ifdef HAVE_MEMORY_H
#include <memory.h>
#endif
#include <string.h>
#include <com_err.h>
#include <k5-int.h> /* for KRB5_ADM_DEFAULT_PORT */
#include <krb5.h>
#ifdef __STDC__
#include <stdlib.h>
#endif
#include <libintl.h>
#include <kadm5/kadm_rpc.h>
#include "client_internal.h"
#include <syslog.h>
#include <gssapi_krb5.h>
#include <gssapiP_krb5.h>
#include <iprop_hdr.h>
#include "iprop.h"
static int old_auth_gssapi = 0;
/* connection timeout to kadmind in seconds */
int _kadm5_check_handle();
char *client_name,
char *pass,
char **service_names,
char **db_args,
void **server_handle);
char *client_name,
char **service_names,
char **db_args,
void **server_handle)
{
}
char *pass, char **service_names,
char **db_args,
void **server_handle)
{
}
char **service_names,
char **db_args,
void **server_handle)
{
}
/* Solaris Kerberos: don't need this */
#if 0 /* ************ Begin IFDEF'ed OUT ***************************** */
char **service_names,
char **db_args,
void **server_handle)
{
}
#endif /* ************** END IFDEF'ed OUT ***************************** */
char *keytab, char **service_names,
char **db_args,
void **server_handle)
{
}
static void
char *m;
int type;
{
msg_ctx = 0;
/* LINTED */
while (1) {
if (maj_stat != GSS_S_COMPLETE) {
"error in gss_display_status"
" called from <%s>\n"), m);
break;
} else
"GSS-API error : %s\n"),
m);
"GSS-API error : %s\n"),
if (!msg_ctx)
break;
}
}
/*
* Function: display_status
*
* Purpose: displays GSS-API messages
*
* Arguments:
*
* msg a string to be displayed with the message
* maj_stat the GSS-API major status code
* min_stat the GSS-API minor status code
* mech kerberos mech
* Effects:
*
* The GSS-API messages associated with maj_stat and min_stat are
* displayed on stderr, each preceeded by "GSS-API error <msg>: " and
* followed by a newline.
*/
void
char *msg;
char *mech;
{
return;
}
}
/*
* Open an fd for the given address and connect asynchronously. Wait
* KADMIND_CONNECT_TIMEOUT seconds or till it succeeds. If it succeeds
* change fd to blocking and return it, else return -1.
*/
static int
{
int connect_time;
int flags;
int fd;
/* we'l open with O_NONBLOCK and avoid an fcntl */
if (fd == -1) {
return (-1);
}
return (-1);
}
/* we can't connect unless fd is in IDLE state */
return (-1);
}
/* setup connect parameters */
/* we wait for KADMIND_CONNECT_TIMEOUT seconds from now */
return (-1);
}
}
/* loop till success or timeout */
for (;;) {
break;
/* we have either timed out or caught an error */
return (-1);
}
sleep(1);
}
/* make the fd blocking (synchronous) */
return (fd);
}
/*
* Open an RPCSEC_GSS connection and
* get a client handle to use for future RPCSEC calls.
*
* This function is only used when changing passwords and
* the kpasswd_protocol is RPCSEC_GSS
*/
static int
char *client_name,
char *service_name)
{
int fd;
int code = 0;
generic_ret *r;
/* Solaris Kerberos */
char *iprop_svc;
void *handlep;
char *server;
/* service name is service@host */
if (!server) {
goto cleanup;
}
goto cleanup;
}
#ifdef DEBUG
printf("addr: sin_port: %d, sin_family: %d, sin_zero %s\n",
#endif
"cannot get any transport information"));
goto error;
}
break;
}
goto error;
/* Transform addr to netbuf */
/* get an fd connected to the given address */
if (fd == -1) {
"unable to open connection to ADMIN server "
"(t_error %i)"), t_errno);
goto error;
}
#ifdef DEBUG
printf("nconf: nc_netid: %s, nc_semantics: %d, nc_flag: %d, "
"nc_protofmly: %s\n",
printf("nc_proto: %s, nc_device: %s, nc_nlookups: %d, nc_used: %d\n",
#endif
/*
* Tell clnt_tli_create that given fd is already connected
*
* If the service_name and client_name are iprop-centric,
* we need to clnt_tli_create to the appropriate RPC prog
*/
return (ENOMEM);
KRB5_IPROP_PROG, KRB5_IPROP_VERS, 0, 0);
}
else
if (iprop_svc)
"clnt_tli_create failed\n"));
goto error;
}
/*
* The rpc-handle was created on an fd opened and connected
* by us, so we have to explicitly tell rpc to close it.
*/
clnt_pcreateerror("ERROR:");
"clnt_control failed to set CLSET_FD_CLOSE"));
goto error;
}
/* now that handle->clnt is set, we can check the handle */
goto error;
/*
* The RPC connection is open; establish the GSS-API
* authentication context.
*/
/* use the kadm5 cache */
if (ccname_orig)
if (gssstat != GSS_S_COMPLETE) {
goto error;
}
goto error;
}
if (gssstat != GSS_S_COMPLETE) {
goto error;
}
options_req.time_req = 0;
#ifndef INIT_TEST
mech,
NULL,
&options_ret);
#endif /* ! INIT_TEST */
if (ccname_orig) {
/* Solaris Kerberos */
} else
(void) krb5_unsetenv("KRB5CCNAME");
"rpc_gss_seccreate failed\n"),
mech);
goto error;
}
/*
* Bypass the remainder of the code and return straightaway
* if the gss service requested is kiprop
*/
if (iprop_enable == B_TRUE) {
code = 0;
goto cleanup;
}
/* Solaris Kerberos: 163 resync */
if (r == NULL) {
goto error;
}
/* Drop down to v2 wire protocol if server does not support v3 */
if (r->code == KADM5_NEW_SERVER_API_VERSION &&
if (r == NULL) {
goto error;
}
}
if (r->code) {
goto error;
}
/* Solaris Kerberos */
if (ccname_orig != NULL)
(void) endnetconfig(handlep);
/*
* gss_client_creds is freed only when there is an error condition,
* given that rpc_gss_seccreate() will assign the cred pointer to the
* my_cred member in the auth handle's private data structure.
*/
return (code);
}
/* Solaris Kerberos: utility function used below */
static void
char **server,
{
if (init_type != INIT_CREDS) {
}
if (handle->cache_name) {
}
}
if (*server) {
}
}
}
}
char *pass,
char **service_names,
char **db_args,
void **server_handle)
{
int i;
int code = 0;
if (! server_handle) {
return EINVAL;
}
return ENOMEM;
}
return ENOMEM;
}
handle->cache_name = 0;
handle->destroy_cache = 0;
client_name == NULL) {
return EINVAL;
}
/*
* Verify the version numbers before proceeding; we can't use
* CHECK_HANDLE because not all fields are set yet.
*/
/* Solaris Kerberos */
if (code != 0) {
return (code);
}
/*
* Acquire relevant profile entries. In version 2, merge values
* in params_in with values from profile, based on
* params_in->mask.
*
* In version 1, we've given a realm (which may be NULL) instead
* of params_in. So use that realm, make params_in contain an
* empty mask, and behave like version 2.
*/
#if 0 /* Since KDC config params can now be put in krb5.conf, these
could show up even when you're just using the remote kadmin
client. */
| KADM5_CONFIG_MAX_LIFE | \
return KADM5_BAD_CLIENT_PARAMS;
}
#endif
return(code);
}
return KADM5_MISSING_KRB5_CONF_PARAMS;
}
/*
* Acquire a service ticket for service_name@realm in the name of
* client_name, using password pass (which could be NULL), and
* create a ccache to store them in. If INIT_CREDS, use the
* ccache we were provided instead.
*/
/* Assumption: all service names refer to the same fundamental service */
strlen(KADM5_CHANGEPW_HOST_SERVICE)) == 0)
/*
* Client side multi-master support: loop through service names, stopping
* either if rpcsec not being done (set-change protocol has it's own logic
* for dealing with multiple admin_servers) or a rpcsec gss handle is
* successfully initialized with one of the admin servers specified listed
* in service_names.
*/
for (i = 0; service_names[i] != NULL; i++) {
goto error;
}
/*
* The 'service_name' is constructed by the caller
* but its done before the parameter which determines
* the kpasswd_protocol is found. The servers that
* a slightly different service principal than
* the normal SEAM kadmind so construct the correct
* name here and then forget it.
*/
if (newsvcname == NULL) {
goto error;
}
newsvcname = NULL;
goto error;
}
} else {
/* Solaris Kerberos */
(gss_name_t *)&name);
if (gssstat != GSS_S_COMPLETE) {
goto error;
}
}
/* XXX temporarily fix a bug in krb5_cc_get_type */
if (init_type == INIT_CREDS) {
handle->cache_name =
goto error;
}
} else {
#if 0
handle->cache_name =
goto error;
}
#endif
{
static int counter = 0;
+ (3 * sizeof(counter)));
}
&ccache)))
goto error;
goto error;
}
goto error;
/*
* Get a ticket, use the method specified in init_type.
*/
else
}
if (code)
goto error;
/*
* Solaris Kerberos:
* Save the original creds.server as krb5_get_init_creds*() always
* sets the realm of the server to the client realm.
*/
if (code)
goto error;
}
}
/* Improved error messages */
if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN) {
/* clean up for another go around */
saved_server = NULL;
continue;
}
if (code != 0) {
goto error;
}
/*
* Solaris Kerberos:
* If the server principal had an empty realm then store that in
* the cred cache and not the server realm as returned by
* krb5_get_init_creds_{keytab|password}(). This ensures that rpcsec_gss
* will find the credential in the cred cache even if a "fallback"
* method is being used to determine the realm.
*/
if (init_type != INIT_CREDS) {
}
/*
* If we got this far, save the creds in the cache.
*/
if (ccache) {
}
#ifdef ZEROPASSWD
#endif
service_names[i]);
/*
* Solaris Kerberos:
* If _kadm5_initialize_rpcsec_gss_handle() fails it will have
* called krb5_gss_release_cred(). If the credential cache is a
* MEMORY cred cache krb5_gss_release_cred() destroys the
* cred cache data. Make sure that the cred-cache is closed
* to prevent a double free in the "error" code.
*/
if (code != 0) {
/* clean up for another go around */
} else {
/* inited the rpcsec_gss handle, can stop looping now */
break;
}
} else {
/* if not initing the rpcsec_gss handle no reason to loop */
break;
}
} /* end for (i = 0; service_names[i] != NULL; i++) */
if (service_names[i] == NULL) {
/* wasn't able to setup a handle so bail */
goto error;
}
*server_handle = (void *) handle;
if (init_type != INIT_CREDS)
goto cleanup;
/*
* Note that it is illegal for this code to execute if "handle"
* has not been allocated and initialized. I.e., don't use "goto
* error" before the block of code at the top of the function
* that allocates and initializes "handle".
*/
if (handle->cache_name)
if (server)
/*
* cred's server and client pointers could have been overwritten
* by the krb5_get_init_* functions. If the addresses are different
* before and after the calls then we must free the memory that
* was allocated before the call.
*/
/*
* Dont clean up the handle if the code is OK (code==0)
* because it is returned to the caller in the 'server_handle'
* ptr.
*/
if (code) {
}
return code;
}
{
/* SUNW14resync:
* krb5_cc_resolve() will resolve a ccache with the same data that
* handle->my_cred points to. If the ccache is a MEMORY ccache then
* gss_release_cred() will free that data (it doesn't do this when ccache
* is a FILE ccache).
* if'ed out to avoid the double free.
*/
#if 0
}
#endif
if (handle->cache_name)
/*
* Since kadm5 doesn't use the default credentials we
* must clean this up manually.
*/
}
handle->magic_number = 0;
return code;
}
/* not supported on client */
{
return EINVAL;
}
/* not supported on client */
{
return EINVAL;
}
{
return KADM5_OK;
}
{
return 0;
}
{
return krb5_init_context(ctx);
}
/*
* Stub function for kadmin. It was created to eliminate the dependency on
* libkdb's ulog functions. The srv equivalent makes the actual calls.
*/
{
return (0);
}