/* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved * * As far as I am concerned, the code I have written for this software * can be used freely for any purpose. Any derived versions of this * software must be clearly marked as such, and if the derived work is * incompatible with the protocol description in the RFC file, it must be * called by a name other than "ssh" or "Secure Shell". * * * Copyright (c) 2001 Markus Friedl. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "includes.h" RCSID("$OpenBSD: channel-auth.c,v 1.1 2001/05/30 12:55:07 markus Exp $"); #include "ssh1.h" #include "packet.h" #include "xmalloc.h" #include "log.h" #include "channel.h" #include "key.h" #include "authfd.h" #include "uidswap.h" /* Name and directory of socket for authentication agent forwarding. */ static char *auth_sock_name = NULL; static char *auth_sock_dir = NULL; /* Sends a message to the server to request authentication fd forwarding. */ void auth_request_forwarding() { packet_start(SSH_CMSG_AGENT_REQUEST_FORWARDING); packet_send(); packet_write_wait(); } /* * Returns the name of the forwarded authentication socket. Returns NULL if * there is no forwarded authentication socket. The returned value points to * a static buffer. */ char * auth_get_socket_name() { return auth_sock_name; } /* removes the agent forwarding socket */ void cleanup_socket(void) { unlink(auth_sock_name); rmdir(auth_sock_dir); } /* * This is called to process SSH_CMSG_AGENT_REQUEST_FORWARDING on the server. * This starts forwarding authentication requests. */ int auth_input_request_forwarding(struct passwd * pw) { Channel *nc; int sock; struct sockaddr_un sunaddr; if (auth_get_socket_name() != NULL) { error("authentication forwarding requested twice."); return 0; } /* Temporarily drop privileged uid for mkdir/bind. */ temporarily_use_uid(pw); /* Allocate a buffer for the socket name, and format the name. */ auth_sock_name = xmalloc(MAXPATHLEN); auth_sock_dir = xmalloc(MAXPATHLEN); strlcpy(auth_sock_dir, "/tmp/ssh-XXXXXXXX", MAXPATHLEN); /* Create private directory for socket */ if (mkdtemp(auth_sock_dir) == NULL) { packet_send_debug("Agent forwarding disabled: " "mkdtemp() failed: %.100s", strerror(errno)); restore_uid(); xfree(auth_sock_name); xfree(auth_sock_dir); auth_sock_name = NULL; auth_sock_dir = NULL; return 0; } snprintf(auth_sock_name, MAXPATHLEN, "%s/agent.%d", auth_sock_dir, (int) getpid()); if (atexit(cleanup_socket) < 0) { int saved = errno; cleanup_socket(); packet_disconnect("socket: %.100s", strerror(saved)); } /* Create the socket. */ sock = socket(AF_UNIX, SOCK_STREAM, 0); if (sock < 0) packet_disconnect("socket: %.100s", strerror(errno)); /* Bind it to the name. */ memset(&sunaddr, 0, sizeof(sunaddr)); sunaddr.sun_family = AF_UNIX; strncpy(sunaddr.sun_path, auth_sock_name, sizeof(sunaddr.sun_path)); if (bind(sock, (struct sockaddr *) & sunaddr, sizeof(sunaddr)) < 0) packet_disconnect("bind: %.100s", strerror(errno)); /* Restore the privileged uid. */ restore_uid(); /* Start listening on the socket. */ if (listen(sock, 5) < 0) packet_disconnect("listen: %.100s", strerror(errno)); /* Allocate a channel for the authentication agent socket. */ nc = channel_new("auth socket", SSH_CHANNEL_AUTH_SOCKET, sock, sock, -1, CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, 0, xstrdup("auth socket"), 1); if (nc == NULL) { error("auth_input_request_forwarding: channel_new failed"); close(sock); return 0; } strlcpy(nc->path, auth_sock_name, sizeof(nc->path)); return 1; } /* This is called to process an SSH_SMSG_AGENT_OPEN message. */ void auth_input_open_request(int type, int plen, void *ctxt) { Channel *c = NULL; int remote_id, sock; char *name; packet_integrity_check(plen, 4, type); /* Read the remote channel number from the message. */ remote_id = packet_get_int(); /* * Get a connection to the local authentication agent (this may again * get forwarded). */ sock = ssh_get_authentication_socket(); /* * If we could not connect the agent, send an error message back to * the server. This should never happen unless the agent dies, * because authentication forwarding is only enabled if we have an * agent. */ if (sock >= 0) { name = xstrdup("authentication agent connection"); c = channel_new("", SSH_CHANNEL_OPEN, sock, sock, -1, 0, 0, 0, name, 1); if (c == NULL) { error("auth_input_open_request: channel_new failed"); xfree(name); close(sock); } else { c->remote_id = remote_id; } } if (c == NULL) { packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); packet_put_int(remote_id); } else { /* Send a confirmation to the remote host. */ debug("Forwarding authentication connection."); packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION); packet_put_int(remote_id); packet_put_int(c->self); } packet_send(); }