o Repair conflicts in configure.ac.
INSTALL_SSH_PRNG_CMDS=@INSTALL_SSH_PRNG_CMDS@
INSTALL_SSH_RAND_HELPER=@INSTALL_SSH_RAND_HELPER@
+INSTALL_GSISSH=@INSTALL_GSISSH@
@NO_SFTP@SFTP_PROGS=sftp-server$(EXEEXT) sftp$(EXEEXT)
ln -s ssh$(EXEEXT) $(DESTDIR)$(bindir)/slogin
-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/slogin.1
ln -s ssh.1 $(DESTDIR)$(mandir)/$(mansubdir)1/slogin.1
- -rm -f $(DESTDIR)$(bindir)/gsissh
- ln -s ssh$(EXEEXT) $(DESTDIR)$(bindir)/gsissh
- -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/gsissh.1
- ln -s ssh.1 $(DESTDIR)$(mandir)/$(mansubdir)1/gsissh.1
- -rm -f $(DESTDIR)$(bindir)/gsiscp
- ln -s scp$(EXEEXT) $(DESTDIR)$(bindir)/gsiscp
- -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/gsiscp.1
- ln -s scp.1 $(DESTDIR)$(mandir)/$(mansubdir)1/gsiscp.1
+ if [ ! -z "$(INSTALL_GSISSH)" ]; then \
+ rm -f $(DESTDIR)$(bindir)/gsissh; \
+ ln -s ssh$(EXEEXT) $(DESTDIR)$(bindir)/gsissh; \
+ rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/gsissh.1; \
+ ln -s ssh.1 $(DESTDIR)$(mandir)/$(mansubdir)1/gsissh.1; \
+ rm -f $(DESTDIR)$(bindir)/gsiscp; \
+ ln -s scp$(EXEEXT) $(DESTDIR)$(bindir)/gsiscp; \
+ rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/gsiscp.1; \
+ ln -s scp.1 $(DESTDIR)$(mandir)/$(mansubdir)1/gsiscp.1; \
+ fi
if [ ! -d $(DESTDIR)$(sysconfdir) ]; then \
$(srcdir)/mkinstalldirs $(DESTDIR)$(sysconfdir); \
fi
uninstall:
-rm -f $(DESTDIR)$(bindir)/slogin
- -rm -f $(DESTDIR)$(bindir)/gsiscp
- -rm -f $(DESTDIR)$(bindir)/gsissh
+ if [ ! -z "$(INSTALL_GSISSH)" ]; then \
+ rm -f $(DESTDIR)$(bindir)/gsiscp; \
+ rm -f $(DESTDIR)$(bindir)/gsissh; \
+ fi
-rm -f $(DESTDIR)$(bindir)/ssh$(EXEEXT)
-rm -f $(DESTDIR)$(bindir)/scp$(EXEEXT)
-rm -f $(DESTDIR)$(bindir)/ssh-add$(EXEEXT)
-rm -f $(DESTDIR)$(RAND_HELPER)$(EXEEXT)
-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1
-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/scp.1
- -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/gsissh.1
- -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/gsiscp.1
+ if [ ! -z "$(INSTALL_GSISSH)" ]; then \
+ rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/gsissh.1; \
+ rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/gsiscp.1; \
+ fi
-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-add.1
-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-agent.1
-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-keygen.1
/* Define if compiler implements __func__ */
#undef HAVE___func__
+/* Define this if you're building with GSSAPI MechGlue */
+#undef MECHGLUE
+
/* Define this is you want GSSAPI support in the version 2 protocol */
#undef GSSAPI
authmsg,
method,
authctxt->valid ? "" : "illegal user ",
- authctxt->user,
+ (authctxt->user[0]) ? authctxt->user : "<implicit>",
get_remote_ipaddr(),
get_remote_port(),
info);
"Unknown packet type %d", type);
}
+#ifdef GSI
int
gsi_gridmap(char *subject_name, char **mapped_name)
{
return(globus_gss_assist_gridmap(subject_name, mapped_name) == 0);
}
+#endif
/*
* SSH1 GSSAPI clients may send us a user name of the form:
Gssctxt *gssctxt;
gss_buffer_desc send_tok,recv_tok;
OM_uint32 maj_status, min_status;
+ int len;
if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
fatal("No authentication or GSSAPI context");
gssctxt=authctxt->methoddata;
- recv_tok.value=packet_get_string(&recv_tok.length);
+ recv_tok.value=packet_get_string(&len);
+ recv_tok.length=len; /* int vs. size_t */
maj_status=PRIVSEP(ssh_gssapi_accept_ctx(gssctxt, &recv_tok,
&send_tok, NULL));
if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
fatal("No authentication or GSSAPI context");
+ if ((strcmp(authctxt->user, "") == 0) && (authctxt->pw == NULL)) {
+ char *lname = NULL;
+ PRIVSEP(ssh_gssapi_localname(&lname));
+ if (lname && lname[0] != '\0') {
+ xfree(authctxt->user);
+ authctxt->user = lname;
+ debug("set username to %s from gssapi context", lname);
+ authctxt->pw = PRIVSEP(getpwnamallow(authctxt->user));
+ } else {
+ debug("failed to set username from gssapi context");
+ }
+ }
+ if (authctxt->pw) {
+#ifdef USE_PAM
+ PRIVSEP(start_pam(authctxt->pw->pw_name));
+#endif
+ } else {
+ authctxt->valid = 0;
+ authenticated = 0;
+ goto finish;
+ }
+
gssctxt=authctxt->methoddata;
/* ssh1 needs to exchange the hash of the keys */
authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user));
+finish:
authctxt->postponed = 0;
dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
#include "dispatch.h"
#include "pathnames.h"
#include "monitor_wrap.h"
-#include "misc.h"
#ifdef GSSAPI
#include "ssh-gss.h"
#ifdef GSSAPI
if (strcmp(user, "") == 0) {
- char *lname = NULL;
- debug("gssapi received empty username");
- PRIVSEP(ssh_gssapi_localname(&lname));
- if (lname && lname[0] != '\0') {
- xfree(user);
- user = lname;
- debug("gssapi successfully set username to %s", user);
- } else if (authctxt->valid) {
- debug("failed to set username from gssapi context");
- goto finish;
+ debug("received empty username for %s", method);
+ if (strcmp(method, "external-keyx") == 0) {
+ char *lname = NULL;
+ PRIVSEP(ssh_gssapi_localname(&lname));
+ if (lname && lname[0] != '\0') {
+ xfree(user);
+ user = lname;
+ debug("set username to %s from gssapi context", user);
+ } else if (authctxt->valid) {
+ debug("failed to set username from gssapi context");
+ }
}
}
#endif
- debug("userauth-request for user %s service %s method %s", user, service, method);
+ debug("userauth-request for user %s service %s method %s",
+ (user && user[0]) ? user : "<implicit>", service, method);
debug("attempt %d failures %d", authctxt->attempt, authctxt->failures);
if ((style = strchr(user, ':')) != NULL)
*style++ = 0;
+ authctxt->attempt++;
if (!authctxt->user ||
strcmp(user, authctxt->user) != 0) {
/* setup auth context */
xfree(authctxt->style);
authctxt->style = NULL;
}
+#ifdef GSSAPI
+ /* We'll verify the username after we set it from the
+ GSSAPI context. */
+ if ((strcmp(user, "") == 0) &&
+ ((strcmp(method, "gssapi") == 0) ||
+ (strcmp(method, "external-keyx") == 0))) {
+ authctxt->pw = NULL;
+ authctxt->valid = 1;
+ } else {
+#endif
authctxt->pw = PRIVSEP(getpwnamallow(user));
if (authctxt->pw && strcmp(service, "ssh-connection")==0) {
authctxt->valid = 1;
PRIVSEP(start_pam("NOUSER"));
#endif
}
+#ifdef GSSAPI
+ }
+#endif
setproctitle("%s%s", authctxt->pw ? user : "unknown",
use_privsep ? " [net]" : "");
authctxt->user = xstrdup(user);
authctxt->service = xstrdup(service);
authctxt->style = style ? xstrdup(style) : NULL;
- if (use_privsep)
+ if (use_privsep && (authctxt->attempt == 1))
mm_inform_authserv(service, style);
}
/* reset state */
debug2("input_userauth_request: try method %s", method);
authenticated = m->userauth(authctxt);
}
-finish:
+
userauth_finish(authctxt, authenticated, method);
xfree(service);
{
return get_port(1);
}
+
+/* If *host is a name for the loopback interface, try to change
+ it to local hostname (not necessarily fully-qualified). */
+void
+resolve_localhost(char **host)
+{
+ struct hostent *hostinfo;
+
+ hostinfo = gethostbyname(*host);
+ if (hostinfo &&
+ hostinfo->h_addrtype == AF_INET) {
+ struct in_addr addr;
+ addr = *(struct in_addr *)(hostinfo->h_addr);
+ if (ntohl(addr.s_addr) == INADDR_LOOPBACK) {
+ char buf[MAXHOSTNAMELEN];
+ if (gethostname(buf, sizeof(buf)) == 0) {
+ xfree(*host);
+ *host = xstrdup(buf);
+ }
+ }
+ }
+}
+
+/* A (hopefully) portable way to make a fully-qualified hostname for
+ GSSAPI authentication without relying on a potentially remote,
+ untrusted resolver.
+ Note: getdomainname() is not portable.
+*/
+void
+make_fqhn(char **host)
+{
+ char *domainname = NULL, *fqhn = NULL, myhn[MAXHOSTNAMELEN];
+ struct hostent *hent = NULL;
+ int i;
+
+ if (strchr(*host, '.')) {
+ return; /* already fully qualified */
+ }
+
+ /* Otherwise, figure out our local domainname without using
+ getdomainname(). */
+ if (gethostname(myhn, sizeof(myhn)) < 0) {
+ debug("gethostname() failed, can't convert %s to fqhn", *host);
+ return;
+ }
+ if ((domainname = strchr(myhn, '.')) == NULL) {
+
+ /* Resolving our local hostname should be secure
+ (unlike resolving a remote hostname). */
+ if ((hent = gethostbyname(myhn)) != NULL) {
+ if ((domainname = strchr(hent->h_name, '.')) == NULL) {
+ for (i=0;
+ hent->h_aliases[i] &&
+ (domainname =
+ strchr(hent->h_aliases[i], '.')) == NULL;
+ i++);
+ }
+ }
+ }
+
+ if (domainname) {
+ domainname++;
+ fqhn = xmalloc(strlen(*host)+strlen(domainname)+1);
+ sprintf(fqhn, "%s.%s", *host, domainname);
+ xfree(*host);
+ *host = fqhn;
+ return;
+ }
+
+ debug("unable to determine fully-qualified local hostname");
+ return;
+}
int get_remote_port(void);
int get_local_port(void);
+
+void resolve_localhost(char **host);
+void make_fqhn(char **host);
]
)
+# Check whether the user wants GSSAPI mechglue support
+AC_ARG_WITH(mechglue,
+ [ --with-mechglue=PATH Build with GSSAPI mechglue library],
+ [
+ AC_MSG_CHECKING(for mechglue library)
+
+ if test -e ${withval}/libgssapi.a ; then
+ mechglue_lib=${withval}/libgssapi.a
+ elif test -e ${withval}/lib/libgssapi.a ; then
+ mechglue_lib=${withval}/lib/libgssapi.a
+ else
+ AC_MSG_ERROR("Can't find libgssapi in ${withval}");
+ fi
+ LIBS="$LIBS ${mechglue_lib}"
+ AC_MSG_RESULT(${mechglue_lib})
+
+# if test -e ${withval}/gssapi.h ; then
+# CPPFLAGS="$CPPFLAGS -I${withval}"
+# elif test -e ${withval}/include/gssapi.h ; then
+# CPPFLAGS="$CPPFLAGS -I${withval}/include"
+# else
+# AC_MSG_ERROR("Can't find gssapi.h in ${withval}");
+# fi
+
+ AC_CHECK_LIB(dl, dlopen, , )
+ if test $ac_cv_lib_dl_dlopen = yes; then
+ LDFLAGS="$LDFLAGS -ldl -Wl,-Bsymbolic"
+ fi
+
+ AC_DEFINE(GSSAPI)
+ AC_DEFINE(MECHGLUE)
+ GSSAPI="mechglue"
+
+ ]
+)
+
+
# Check whether the user wants GSI (Globus) support
gsi_path="no"
AC_ARG_WITH(gsi,
if test "x$gsi_path" != "xno" ; then
# Globus GSSAPI configuration
- AC_DEFINE(GSSAPI)
AC_DEFINE(GSI)
+ if test "$GSSAPI" -a "$GSSAPI" != "mechglue"; then
+ AC_MSG_ERROR([Previously configured GSSAPI library conflicts with Globus/GSI.])
+ fi
+ if test -z "$GSSAPI"; then
+ AC_DEFINE(GSSAPI)
+ GSSAPI="GSI"
+ fi
+
# Find GLOBUS/GSI installation Directory
AC_MSG_CHECKING(for Globus/GSI installation directory)
fi
AC_MSG_RESULT($globus_flavor_type)
- GSI_LIBS="${gsi_path}/lib/libglobus_gss_assist_${globus_flavor_type}.a ${gsi_path}/lib/libglobus_gssapi_gsi_${globus_flavor_type}.a"
- GSI_CFLAGS="-I${GLOBUS_FLAVOR_TYPE_INCL_DIR}"
+ if test "$GSSAPI" = "mechglue"; then
+ GSI_LIBS="${gsi_path}/lib/libglobus_gss_assist_${globus_flavor_type}.a"
+ else
+ GSI_LIBS="${gsi_path}/lib/libglobus_gss_assist_${globus_flavor_type}.a ${gsi_path}/lib/libglobus_gssapi_gsi_${globus_flavor_type}.a"
+ fi
+ GSI_CPPFLAGS="-I${GLOBUS_FLAVOR_TYPE_INCL_DIR}"
fi
LIBS="$LIBS $GSI_LIBS"
LDFLAGS="$LDFLAGS $GSI_LDFLAGS"
- CFLAGS="$CFLAGS $GSI_CFLAGS"
-# End Globus/GSI section
+ CPPFLAGS="$CPPFLAGS $GSI_CPPFLAGS"
+ INSTALL_GSISSH="yes"
+else
+ INSTALL_GSISSH=""
fi
+AC_SUBST(INSTALL_GSISSH)
+# End Globus/GSI section
# Check whether user wants S/Key support
SKEY_MSG="no"
fi
AC_CHECK_LIB(resolv, dn_expand, , )
+ # If we're using some other GSSAPI
+ if test "$GSSAPI" -a "$GSSAPI" != "mechglue"; then
+ AC_MSG_ERROR([$GSSAPI GSSAPI library conflicts with Kerberos support. Use mechglue instead.])
+ fi
AC_CHECK_LIB(gssapi,gss_init_sec_context,
[ AC_DEFINE(GSSAPI)
K5LIBS="-lgssapi $K5LIBS" ],
$K5LIBS)
],
$K5LIBS)
-
+
AC_CHECK_HEADER(gssapi.h, ,
[ unset ac_cv_header_gssapi_h
CPPFLAGS="$CPPFLAGS -I${KRB5ROOT}/include/gssapi"
]
)
+ AC_CHECK_LIB(gssapi, gss_krb5_copy_ccache, /bin/true,
+ [ K5LIBS="-lgssapi_krb5 $K5LIBS"
+ AC_CHECK_LIB(gssapi_krb5, gss_krb5_copy_ccache, /bin/true,
+ AC_MSG_WARN([Cannot find gss_krb5_copy_ccache -- build may fail]),
+ $K5LIBS)
+ ],
+ $K5LIBS)
+
oldCPP="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS -I${KRB5ROOT}/include/gssapi"
AC_CHECK_HEADER(gssapi_krb5.h, ,
[ CPPFLAGS="$oldCPP" ])
+ if test -z "$GSSAPI"; then
+ GSSAPI="KRB5";
+ fi
+
KRB5=yes
fi
]
#include "log.h"
#include "compat.h"
#include "monitor_wrap.h"
+#include "canohost.h"
#include <netdb.h>
Buffer buf;
int i = 0;
int present;
+ int mech_count=0;
char * mechs;
Gssctxt * ctx = NULL;
&supported_mechs[i].oid,
host)))) {
/* Append gss_group1_sha1_x to our list */
+ if (++mech_count > 1) {
+ buffer_append(&buf, ",", 1);
+ }
buffer_append(&buf, gssprefix,
strlen(gssprefix));
buffer_append(&buf,
supported_mechs[i].enc_name,
strlen(supported_mechs[i].enc_name));
- }
- }
+ debug("GSSAPI mechanism %s (%s%s) supported",
+ supported_mechs[i].name, gssprefix,
+ supported_mechs[i].enc_name);
+ } else {
+ debug("no credentials for GSSAPI mechanism %s",
+ supported_mechs[i].name);
+ }
+ } else {
+ debug("GSSAPI mechanism %s not supported",
+ supported_mechs[i].name);
+ }
} while (supported_mechs[++i].name != NULL);
buffer_put_char(&buf,'\0');
enum ssh_gss_id ssh_gssapi_get_ctype(Gssctxt *ctxt) {
enum ssh_gss_id i=0;
- while(supported_mechs[i].name!=NULL &&
- supported_mechs[i].oid.length != ctxt->oid->length &&
- (memcmp(supported_mechs[i].oid.elements,
- ctxt->oid->elements,ctxt->oid->length) !=0)) {
+ while(supported_mechs[i].name!=NULL) {
+ if (supported_mechs[i].oid.length == ctxt->oid->length &&
+ (memcmp(supported_mechs[i].oid.elements,
+ ctxt->oid->elements,ctxt->oid->length) == 0))
+ return i;
i++;
}
- return(i);
+ return(GSS_LAST_ENTRY);
}
/* Set the GSS context's OID to the oid indicated by the given key exchange
if (ctx) ssh_gssapi_set_oid(ctx,&supported_mechs[i].oid);
+ debug("using GSSAPI mechanism %s (%s%s)", supported_mechs[i].name,
+ gssprefix, supported_mechs[i].enc_name);
+
return &supported_mechs[i].oid;
}
ssh_gssapi_error_ex(OM_uint32 major_status,OM_uint32 minor_status,
int send_packet) {
OM_uint32 lmaj, lmin;
- gss_buffer_desc msg;
+ gss_buffer_desc msg = {0,NULL};
OM_uint32 ctx;
ctx = 0;
if ((*ctx)==NULL)
return;
+#if !defined(MECHGLUE) /* mechglue has some memory management issues */
if ((*ctx)->context != GSS_C_NO_CONTEXT)
gss_delete_sec_context(&ms,&(*ctx)->context,GSS_C_NO_BUFFER);
if ((*ctx)->name != GSS_C_NO_NAME)
gss_release_name(&ms,&(*ctx)->client);
if ((*ctx)->client_creds != GSS_C_NO_CREDENTIAL)
gss_release_cred(&ms,&(*ctx)->client_creds);
+#endif
xfree(*ctx);
*ctx=NULL;
/* Create a service name for the given host */
OM_uint32
ssh_gssapi_import_name(Gssctxt *ctx, const char *host) {
- gss_buffer_desc gssbuf;
+ gss_buffer_desc gssbuf = {0,NULL};
OM_uint32 maj_status, min_status;
- struct hostent *hostinfo = NULL;
char *xhost;
/* Make a copy of the host name, in case it was returned by a
* previous call to gethostbyname(). */
xhost = xstrdup(host);
- /* Make sure we have the FQDN. Some GSSAPI implementations don't do
+ /* If xhost is the loopback interface, switch it to our
+ true local hostname. */
+ resolve_localhost(&xhost);
+
+ /* Make sure we have the FQHN. Some GSSAPI implementations don't do
* this for us themselves */
-
- hostinfo = gethostbyname(xhost);
-
- if ((hostinfo == NULL) || (hostinfo->h_name == NULL)) {
- debug("Unable to get FQDN for \"%s\"", xhost);
- } else {
- xfree(xhost);
- xhost = xstrdup(hostinfo->h_name);
- }
-
+ make_fqhn(&xhost);
+
gssbuf.length = sizeof("host@")+strlen(xhost);
gssbuf.value = xmalloc(gssbuf.length);
OM_uint32
ssh_gssapi_client_ctx(Gssctxt **ctx,gss_OID oid, char *host) {
- gss_buffer_desc token;
+ gss_buffer_desc token = {0,NULL};
OM_uint32 major,minor;
if (*ctx) ssh_gssapi_delete_ctx(ctx);
{
krb5_principal princ;
+ if (ssh_gssapi_krb5_init() == 0)
+ return 0;
+
if (krb5_parse_name(krb_context, gssapi_client_name.value, &princ)) {
return(0);
}
* populated.
*/
-void
-ssh_gssapi_krb5_storecreds() {
+OM_uint32
+ssh_gssapi_krb5_storecreds(gss_buffer_t export_buffer) {
krb5_ccache ccache;
krb5_error_code problem;
krb5_principal princ;
static char name[40];
int tmpfd;
OM_uint32 maj_status,min_status;
+ gss_cred_id_t krb5_cred_handle;
if (gssapi_client_creds==NULL) {
debug("No credentials stored");
- return;
+ return GSS_S_NO_CRED;
}
if (ssh_gssapi_krb5_init() == 0)
- return;
+ return GSS_S_FAILURE;
if (options.gss_use_session_ccache) {
snprintf(ccname,sizeof(ccname),"/tmp/krb5cc_%d_XXXXXX",geteuid());
if ((tmpfd = mkstemp(ccname))==-1) {
log("mkstemp(): %.100s", strerror(errno));
- return;
+ return GSS_S_FAILURE;
}
if (fchmod(tmpfd, S_IRUSR | S_IWUSR) == -1) {
log("fchmod(): %.100s", strerror(errno));
close(tmpfd);
- return;
+ return GSS_S_FAILURE;
}
} else {
snprintf(ccname,sizeof(ccname),"/tmp/krb5cc_%d",geteuid());
tmpfd = open(ccname, O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR);
if (tmpfd == -1) {
log("open(): %.100s", strerror(errno));
- return;
+ return GSS_S_FAILURE;
}
}
if ((problem = krb5_cc_resolve(krb_context, name, &ccache))) {
log("krb5_cc_default(): %.100s",
krb5_get_err_text(krb_context,problem));
- return;
+ return GSS_S_FAILURE;
}
if ((problem = krb5_parse_name(krb_context, gssapi_client_name.value,
log("krb5_parse_name(): %.100s",
krb5_get_err_text(krb_context,problem));
krb5_cc_destroy(krb_context,ccache);
- return;
+ return GSS_S_FAILURE;
}
if ((problem = krb5_cc_initialize(krb_context, ccache, princ))) {
krb5_get_err_text(krb_context,problem));
krb5_free_principal(krb_context,princ);
krb5_cc_destroy(krb_context,ccache);
- return;
+ return GSS_S_FAILURE;
}
krb5_free_principal(krb_context,princ);
- #ifdef HEIMDAL
- if ((problem = krb5_cc_copy_cache(krb_context,
- gssapi_client_creds->ccache,
- ccache))) {
- log("krb5_cc_copy_cache(): %.100s",
- krb5_get_err_text(krb_context,problem));
- krb5_cc_destroy(krb_context,ccache);
- return;
- }
- #else
+#ifdef MECHGLUE
+ krb5_cred_handle =
+ __gss_get_mechanism_cred(gssapi_client_creds,
+ &(supported_mechs[GSS_KERBEROS].oid));
+#else
+ krb5_cred_handle = gssapi_client_creds;
+#endif
+
if ((maj_status = gss_krb5_copy_ccache(&min_status,
- gssapi_client_creds,
+ krb5_cred_handle,
ccache))) {
log("gss_krb5_copy_ccache() failed");
ssh_gssapi_error(maj_status,min_status);
krb5_cc_destroy(krb_context,ccache);
- return;
+ return GSS_S_FAILURE;
}
- #endif
krb5_cc_close(krb_context,ccache);
+ export_buffer->length = strlen("KRB5CCNAME")+strlen(name)+1;
+ export_buffer->value = xmalloc(export_buffer->length+1);
+ sprintf(export_buffer->value, "%s=%s", "KRB5CCNAME", name);
-#ifdef USE_PAM
- do_pam_putenv("KRB5CCNAME",name);
-#endif
-
- gssapi_cred_store.filename=strdup(ccname);
- gssapi_cred_store.envvar="KRB5CCNAME";
- gssapi_cred_store.envval=strdup(name);
-
- return;
+ return GSS_S_COMPLETE;
}
#endif /* KRB5 */
*
* Make sure that this is called _after_ we've setuid to the user.
*/
-void
-ssh_gssapi_gsi_storecreds()
+OM_uint32
+ssh_gssapi_gsi_storecreds(gss_buffer_t export_buffer)
{
OM_uint32 major_status;
OM_uint32 minor_status;
-
-
+
if (gssapi_client_creds != NULL)
{
char *creds_env = NULL;
{
*value = '\0';
value++;
-#ifdef USE_PAM
- do_pam_putenv("X509_USER_PROXY",value);
-#endif
- gssapi_cred_store.filename=NULL;
- gssapi_cred_store.envvar="X509_USER_PROXY";
- gssapi_cred_store.envval=strdup(value);
-
- return;
+ export_buffer->length=
+ strlen("X509_USER_PROXY")+strlen(value)+1;
+ export_buffer->value =
+ xmalloc(export_buffer->length+1);
+ sprintf(export_buffer->value, "%s=%s",
+ "X509_USER_PROXY", value);
+
+ return GSS_S_COMPLETE;
}
else
{
log("Failed to export delegated credentials (error %ld)",
major_status);
}
- }
+ }
+ return 0;
}
#endif /* GSI */
void
ssh_gssapi_cleanup_creds(void *ignored)
{
+ /* OM_uint32 min_stat; */
+
if (gssapi_cred_store.filename!=NULL) {
/* Unlink probably isn't sufficient */
- debug("removing gssapi cred file\"%s\"",gssapi_cred_store.filename);
+ debug("removing gssapi cred file \"%s\"",gssapi_cred_store.filename);
unlink(gssapi_cred_store.filename);
}
+ /* DK ??
+ if (gssapi_client_creds != GSS_C_NO_CREDENTIAL)
+ gss_release_cred(&min_stat, &gssapi_client_creds);
+ */
}
-void
-ssh_gssapi_storecreds()
+OM_uint32
+ssh_gssapi_export_cred(OM_uint32 * minor_status,
+ const gss_cred_id_t cred_handle,
+ const gss_OID desired_mech,
+ OM_uint32 option_req,
+ gss_buffer_t export_buffer)
{
+ OM_uint32 maj_stat = GSS_S_FAILURE;
+
+ if (option_req != 1) return GSS_S_UNAVAILABLE;
+ if (desired_mech != NULL) return GSS_S_BAD_MECH;
+
switch (gssapi_client_type) {
#ifdef KRB5
case GSS_KERBEROS:
- ssh_gssapi_krb5_storecreds();
+ maj_stat = ssh_gssapi_krb5_storecreds(export_buffer);
break;
#endif
#ifdef GSI
case GSS_GSI:
- ssh_gssapi_gsi_storecreds();
+ maj_stat = ssh_gssapi_gsi_storecreds(export_buffer);
break;
#endif /* GSI */
case GSS_LAST_ENTRY:
log("ssh_gssapi_do_child: Unknown mechanism");
}
-
+
+ if (GSS_ERROR(maj_stat)) {
+ *minor_status = GSS_S_FAILURE;
+ }
+ return maj_stat;
+}
+
+void
+ssh_gssapi_storecreds()
+{
+ OM_uint32 maj_stat, min_stat;
+ gss_buffer_desc export_cred = GSS_C_EMPTY_BUFFER;
+ char *p;
+
+ if (gssapi_client_creds == GSS_C_NO_CREDENTIAL)
+ return;
+
+#ifdef HAVE_GSSAPI_EXT
+ maj_stat = gss_export_cred(&min_stat, gssapi_client_creds,
+ GSS_C_NO_OID, 1, &export_cred);
+ if (GSS_ERROR(maj_stat) && maj_stat != GSS_S_UNAVAILABLE) {
+ ssh_gssapi_error(maj_stat, min_stat);
+ return;
+ }
+#endif
+
+ /* If gss_export_cred() is not available, use old methods */
+ if (export_cred.length == 0) {
+ ssh_gssapi_export_cred(&min_stat, gssapi_client_creds,
+ GSS_C_NO_OID, 1, &export_cred);
+ if (GSS_ERROR(maj_stat)) {
+ ssh_gssapi_error(maj_stat, min_stat);
+ }
+ }
+
+ p = strchr((char *) export_cred.value, '=');
+ if (p == NULL) {
+ log("Failed to parse exported credentials string '%.100s'",
+ (char *)export_cred.value);
+ gss_release_buffer(&min_stat, &export_cred);
+ return;
+ }
+ *p++ = '\0';
+ gssapi_cred_store.envvar = strdup((char *)export_cred.value);
+ gssapi_cred_store.envval = strdup(p);
+#ifdef USE_PAM
+ do_pam_putenv(gssapi_cred_store.envvar, gssapi_cred_store.envval);
+#endif
+ if (strncmp(p, "FILE:", 5) == 0) {
+ p += 5;
+ }
+ if (access(p, R_OK) == 0) {
+ gssapi_cred_store.filename = strdup(p);
+ }
+ gss_release_buffer(&min_stat, &export_cred);
+
if (options.gss_cleanup_creds) {
fatal_add_cleanup(ssh_gssapi_cleanup_creds, NULL);
}
-
}
/* This allows GSSAPI methods to do things to the childs environment based
debug("Received GSSAPI_CONTINUE");
if (maj_status == GSS_S_COMPLETE)
fatal("GSSAPI Continue received from server when complete");
- recv_tok.value=packet_get_string(&recv_tok.length);
+ recv_tok.value=packet_get_string(&slen);
+ recv_tok.length=slen; /* int vs. size_t */
break;
case SSH2_MSG_KEXGSS_COMPLETE:
debug("Received GSSAPI_COMPLETE");
packet_get_bignum2(dh_server_pub);
- msg_tok.value=
- packet_get_string(&msg_tok.length);
+ msg_tok.value=packet_get_string(&slen);
+ msg_tok.length=slen; /* int vs. size_t */
/* Is there a token included? */
if (packet_get_char()) {
recv_tok.value=
- packet_get_string(&recv_tok.length);
+ packet_get_string(&slen);
+ recv_tok.length=slen; /* int/size_t */
/* If we're already complete - protocol error */
if (maj_status == GSS_S_COMPLETE)
packet_disconnect("Protocol error: received token when complete");
memset(kbuf, 0, klen);
xfree(kbuf);
+ slen=0;
hash = kex_gssapi_hash(
kex->client_version_string,
kex->server_version_string,
BIGNUM *dh_client_pub = NULL;
int type =0;
gss_OID oid;
+ u_int slen;
/* Initialise GSSAPI */
if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt,oid))))
packet_disconnect("Unable to acquire credentials for the server");
-
+
do {
debug("Wait SSH2_MSG_GSSAPI_INIT");
type = packet_read();
case SSH2_MSG_KEXGSS_INIT:
if (dh_client_pub!=NULL)
packet_disconnect("Received KEXGSS_INIT after initialising");
- recv_tok.value=packet_get_string(&recv_tok.length);
+ recv_tok.value=packet_get_string(&slen);
+ recv_tok.length=slen; /* int vs. size_t */
dh_client_pub = BN_new();
case SSH2_MSG_KEXGSS_CONTINUE:
if (dh_client_pub == NULL)
packet_disconnect("Received KEXGSS_CONTINUE without initialising");
- recv_tok.value=packet_get_string(&recv_tok.length);
+ recv_tok.value=packet_get_string(&slen);
+ recv_tok.length=slen; /* int vs. size_t */
break;
default:
packet_disconnect("Protocol error: didn't expect packet type %d",
mm_answer_gss_setup_ctx(int socket, Buffer *m) {
gss_OID_desc oid;
OM_uint32 major;
+ int len;
- oid.elements=buffer_get_string(m,&oid.length);
+ oid.elements=buffer_get_string(m,&len);
+ oid.length=len;
major=ssh_gssapi_server_ctx(&gsscontext,&oid);
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
-RCSID("$OpenBSD: msg.c,v 1.3 2002/06/24 15:49:22 itojun Exp $");
+RCSID("$OpenBSD: msg.c,v 1.2 2002/06/19 00:27:55 deraadt Exp $");
#include "buffer.h"
#include "getput.h"
u_char buf[5];
u_int mlen = buffer_len(m);
- debug3("msg_send: type %u", (unsigned int)type & 0xff);
+ debug3("msg_send: type %d", type);
PUT_32BIT(buf, mlen + 1);
buf[4] = type; /* 1st byte of payload is mesg-type */
if (res != sizeof(buf)) {
if (res == 0)
return -1;
- fatal("msg_recv: read: header %ld", (long)res);
+ fatal("msg_recv: read: header %d", res);
}
msg_len = GET_32BIT(buf);
if (msg_len > 256 * 1024)
#include "config.h"
+#define get_progname bsd_get_progname
char *get_progname(char *argv0);
#ifndef HAVE_SETSID
<Source_Dependencies Type="compile">
<Dependency Name="globus_openssl">
<Version>
- <Version_Range Upper_Major="1000" Lower_Major="0" Upper_Minor="1000" Lower_Minor="8" />
+ <Version_Range Lower_Major="0" Lower_Minor="8" Upper_Major="0" Upper_Minor="40" />
</Version>
</Dependency>
<Dependency Name="globus_gssapi_gsi">
<Source_Dependencies Type="pgm_link">
<Dependency Name="globus_openssl">
<Version>
- <Version_Range Upper_Major="1000" Lower_Major="0" Upper_Minor="1000" Lower_Minor="8" />
+ <Version_Range Lower_Major="0" Lower_Minor="8" Upper_Major="0" Upper_Minor="40" />
</Version>
</Dependency>
<Dependency Name="globus_gss_assist">
<Source_Setup_Dependency PkgType="pgm">
<Setup_Dependency Name="trusted_ca_setup">
<Version>
- <Version_Range Upper_Major="1000" Lower_Major="2" Upper_Minor="1000" Lower_Minor="0" />
+ <Simple_Version Major="2"></Simple_Version>
</Version>
</Setup_Dependency>
<Setup_Dependency Name="gsi_openssh_setup">
char *host_key_alias; /* hostname alias for .ssh/known_hosts */
char *proxy_command; /* Proxy command for connecting the host. */
char *user; /* User to log in as. */
- int implicit;
+ int implicit; /* Login user was not specified.
+ Server may choose based on authctxt. */
int escape_char; /* Escape character; -2 = none */
char *system_hostfile;/* Path for /etc/ssh/ssh_known_hosts. */
#endif
#if defined(KRB5)
#ifdef HEIMDAL
-#include <krb.h>
#else
/* Bodge - but then, so is using the kerberos IV KEYFILE to get a Kerberos V
* keytab */
#include <gssapi.h>
+#ifndef MECHGLUE
#ifdef KRB5
#ifndef HEIMDAL
#include <gssapi_generic.h>
#endif /* GSS_C_NT_... */
#endif /* !HEIMDAL */
#endif /* KRB5 */
+#endif /* !MECHGLUE */
/* draft-ietf-secsh-gsskeyex-03 */
#define SSH2_MSG_KEXGSS_INIT 30
#ifdef GSI
int gsi_gridmap(char *subject_name, char **mapped_name);
+#ifdef _HAVE_GSI_EXTENDED_GSSAPI
+#define HAVE_GSSAPI_EXT
+#endif
+#endif
+
+#ifdef MECHGLUE
+gss_cred_id_t __gss_get_mechanism_cred
+ (gss_cred_id_t, /* union_cred */
+ gss_OID /* mech_type */
+ );
+#ifndef _HAVE_GSI_EXTENDED_GSSAPI
+#define HAVE_GSSAPI_EXT
+OM_uint32 gss_export_cred
+ (OM_uint32 *, /* minor_status */
+ const gss_cred_id_t,/* cred_handle */
+ const gss_OID, /* desired mech */
+ OM_uint32, /* option req */
+ gss_buffer_t); /* output buffer */
+#endif
#endif
#endif /* GSSAPI */
return NULL;
}
- maj_stat = gss_export_name(&min_stat,
- pname,
- tmpnamed);
+ maj_stat = gss_display_name(&min_stat,
+ pname,
+ tmpnamed,
+ NULL);
if (maj_stat != GSS_S_COMPLETE) {
- return NULL;
+ return NULL;
}
- debug("gss_export_name finsished");
+ debug("gss_display_name finsished");
retname = (char *)malloc(tmpname.length + 1);
if (!retname) {
return NULL;
OM_uint32 ret_flags;
int type;
char *gssapi_auth_type = NULL;
- struct hostent *hostinfo;
+ char *xhost;
+ unsigned int slen;
+ /* Make a copy of the host name, in case it was returned by a
+ * previous call to gethostbyname(). */
+ xhost = xstrdup(host);
- /*
- * host is not guarenteed to be a FQDN, so we need to make sure it is.
- */
- hostinfo = gethostbyname(host);
+ /* If xhost is the loopback interface, switch it to our
+ true local hostname. */
+ resolve_localhost(&xhost);
- if ((hostinfo == NULL) || (hostinfo->h_name == NULL)) {
- debug("GSSAPI authentication: Unable to get FQDN for \"%s\"", host);
- goto cleanup;
- }
+ /* Make sure we have the FQHN. Some GSSAPI implementations don't do
+ * this for us themselves */
+ make_fqhn(&xhost);
/*
* Default flags
debug("Attempting %s authentication", gssapi_auth_type);
- service_name = (char *) malloc(strlen("host") +
- strlen(hostinfo->h_name) +
- 2 /* 1 for '@', 1 for NUL */);
-
- if (service_name == NULL) {
- debug("malloc() failed");
- goto cleanup;
- }
+ service_name = (char *) xmalloc(strlen("host") +
+ strlen(xhost) +
+ 2 /* 1 for '@', 1 for NUL */);
+ sprintf(service_name, "host@%s", xhost);
- sprintf(service_name, "host@%s", hostinfo->h_name);
+ xfree(xhost);
+ xhost = NULL;
name_type = GSS_C_NT_HOSTBASED_SERVICE;
#endif /* GSSAPI */
- debug("req_flags = %lu", req_flags);
+ debug("req_flags = %u", (unsigned int)req_flags);
name_tok.value = service_name;
name_tok.length = strlen(service_name) + 1;
}
/* Read the mechanism the server returned */
- mech_oid.elements = packet_get_string((unsigned int *) &(mech_oid.length));
+ mech_oid.elements = packet_get_string(&slen);
+ mech_oid.length = slen; /* safe typecast */
packet_get_all();
/*
/* Does not return */
}
- recv_tok.value = packet_get_string((unsigned int *) &recv_tok.length);
+ recv_tok.value = packet_get_string(&slen);
+ recv_tok.length=slen; /* safe typecast */
packet_get_all();
token_ptr = &recv_tok;
}
gss_qop_t qop_state;
- wrapped_buf.value = packet_get_string(&(wrapped_buf.length));
+ wrapped_buf.value = packet_get_string(&slen);
+ wrapped_buf.length=slen; /* safe typecast */
packet_get_all();
maj_stat = gss_unwrap(&min_stat,
if (unwrapped_buf.length != sizeof(ssh_key_digest)) {
packet_disconnect("Verification of SSHD keys through GSSAPI-secured channel failed: "
"Size of key hashes do not match (%d != %d)!",
- unwrapped_buf.length, sizeof(ssh_key_digest));
+ (int)unwrapped_buf.length,
+ (int)sizeof(ssh_key_digest));
}
if (memcmp(ssh_key_digest, unwrapped_buf.value, sizeof(ssh_key_digest)) != 0) {
authctxt->methoddata=(void *)gssctxt;
packet_start(SSH2_MSG_USERAUTH_REQUEST);
+#ifdef GSI
if(options.implicit && !(datafellows & SSH_BUG_GSS_EMPTYUSER)) {
packet_put_cstring("");
} else {
+#endif
packet_put_cstring(authctxt->server_user);
+#ifdef GSI
}
+#endif
packet_put_cstring(authctxt->service);
packet_put_cstring(authctxt->method->name);
Gssctxt *gssctxt;
gss_buffer_desc send_tok,recv_tok;
OM_uint32 status;
+ u_int slen;
if (authctxt == NULL)
fatal("input_gssapi_response: no authentication context");
gssctxt = authctxt->methoddata;
- recv_tok.value=packet_get_string(&recv_tok.length);
+ recv_tok.value=packet_get_string(&slen);
+ recv_tok.length=slen; /* safe typecast */
status=ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds,
&recv_tok, &send_tok, NULL);
debug2("userauth_external");
packet_start(SSH2_MSG_USERAUTH_REQUEST);
+#ifdef GSI
if(options.implicit && !(datafellows & SSH_BUG_GSS_EMPTYUSER)) {
packet_put_cstring("");
} else {
+#endif
packet_put_cstring(authctxt->server_user);
+#ifdef GSI
}
+#endif
packet_put_cstring(authctxt->service);
packet_put_cstring(authctxt->method->name);
packet_send();
session for storing delegated credentials.
The default is
.Dq yes .
+.It Cm GssapiCleanupCreds
+Specifies whether the credentials cache should be removed at the end
+of the session.
+The default is
+.Dq yes .
.It Cm HostKey
Specifies a file containing a private host key
used by SSH.