Mercurial > dropbear
diff svr-agentfwd.c @ 4:fe6bca95afa7
Makefile.in contains updated files required
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Tue, 01 Jun 2004 02:46:09 +0000 |
parents | |
children | bc6477a6c393 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/svr-agentfwd.c Tue Jun 01 02:46:09 2004 +0000 @@ -0,0 +1,247 @@ +/* + * Dropbear - a SSH2 server + * + * Copyright (c) 2002,2003 Matt Johnston + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ + +/* This file (agentfwd.c) handles authentication agent forwarding, for OpenSSH + * style agents. */ + +#include "includes.h" + +#ifndef DISABLE_AGENTFWD + +#include "agentfwd.h" +#include "session.h" +#include "ssh.h" +#include "dbutil.h" +#include "chansession.h" +#include "channel.h" +#include "packet.h" +#include "buffer.h" +#include "random.h" + +#define AGENTDIRPREFIX "/tmp/dropbear-" + +static int send_msg_channel_open_agent(int fd); +static int bindagent(struct ChanSess * chansess); + +/* Handles client requests to start agent forwarding, sets up listening socket. + * Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */ +int agentreq(struct ChanSess * chansess) { + + if (chansess->agentfd != -1) { + return DROPBEAR_FAILURE; + } + + /* create listening socket */ + chansess->agentfd = socket(PF_UNIX, SOCK_STREAM, 0); + if (chansess->agentfd < 0) { + goto fail; + } + + /* create the unix socket dir and file */ + if (bindagent(chansess) == DROPBEAR_FAILURE) { + return DROPBEAR_FAILURE; + } + + /* listen */ + if (listen(chansess->agentfd, 20) < 0) { + goto fail; + } + + /* set non-blocking */ + if (fcntl(chansess->agentfd, F_SETFL, O_NONBLOCK) < 0) { + goto fail; + } + + /* channel.c's channel fd code will handle the socket now */ + + /* set the maxfd so that select() loop will notice it */ + ses.maxfd = MAX(ses.maxfd, chansess->agentfd); + + return DROPBEAR_SUCCESS; + +fail: + /* cleanup */ + agentcleanup(chansess); + + return DROPBEAR_FAILURE; +} + +/* accepts a connection on the forwarded socket and opens a new channel for it + * back to the client */ +/* returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */ +int agentaccept(struct ChanSess * chansess) { + + int fd; + + fd = accept(chansess->agentfd, NULL, NULL); + if (fd < 0) { + return DROPBEAR_FAILURE; + } + + return send_msg_channel_open_agent(fd); + +} + +/* set up the environment variable pointing to the socket. This is called + * just before command/shell execution, after dropping priveleges */ +void agentset(struct ChanSess * chansess) { + + char *path = NULL; + int len; + + if (chansess->agentfd == -1) { + return; + } + + /* 2 for "/" and "\0" */ + len = strlen(chansess->agentdir) + strlen(chansess->agentfile) + 2; + + path = m_malloc(len); + snprintf(path, len, "%s/%s", chansess->agentdir, chansess->agentfile); + addnewvar("SSH_AUTH_SOCK", path); + m_free(path); +} + +/* close the socket, remove the socket-file */ +void agentcleanup(struct ChanSess * chansess) { + + char *path = NULL; + uid_t uid; + gid_t gid; + int len; + + if (chansess->agentfd == -1) { + return; + } + + close(chansess->agentfd); + + /* Remove the dir as the user. That way they can't cause problems except + * for themselves */ + uid = getuid(); + gid = getgid(); + if ((setegid(ses.authstate.pw->pw_gid)) < 0 || + (seteuid(ses.authstate.pw->pw_uid)) < 0) { + dropbear_exit("failed to set euid"); + } + + /* 2 for "/" and "\0" */ + len = strlen(chansess->agentdir) + strlen(chansess->agentfile) + 2; + + path = m_malloc(len); + snprintf(path, len, "%s/%s", chansess->agentdir, chansess->agentfile); + unlink(path); + m_free(path); + + rmdir(chansess->agentdir); + + if ((seteuid(uid)) < 0 || + (setegid(gid)) < 0) { + dropbear_exit("failed to revert euid"); + } + + m_free(chansess->agentfile); + m_free(chansess->agentdir); + +} + +/* helper for accepting an agent request */ +static int send_msg_channel_open_agent(int fd) { + + if (send_msg_channel_open_init(fd, CHANNEL_ID_AGENT, + "[email protected]") == DROPBEAR_SUCCESS) { + encrypt_packet(); + return DROPBEAR_SUCCESS; + } else { + return DROPBEAR_FAILURE; + } +} + +/* helper for creating the agent socket-file + returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */ +static int bindagent(struct ChanSess * chansess) { + + struct sockaddr_un addr; + unsigned int prefix; + char path[sizeof(addr.sun_path)], sockfile[sizeof(addr.sun_path)]; + mode_t mode; + int i; + uid_t uid; + gid_t gid; + int ret = DROPBEAR_FAILURE; + + /* drop to user privs to make the dir/file */ + uid = getuid(); + gid = getgid(); + if ((setegid(ses.authstate.pw->pw_gid)) < 0 || + (seteuid(ses.authstate.pw->pw_uid)) < 0) { + dropbear_exit("failed to set euid"); + } + + memset((void*)&addr, 0x0, sizeof(addr)); + addr.sun_family = AF_UNIX; + + mode = S_IRWXU; + + for (i = 0; i < 20; i++) { + genrandom((unsigned char*)&prefix, sizeof(prefix)); + /* we want 32 bits (8 hex digits) - "/tmp/dropbear-f19c62c0" */ + snprintf(path, sizeof(path), AGENTDIRPREFIX "%.8x", prefix); + + if (mkdir(path, mode) == 0) { + goto bindsocket; + } + if (errno != EEXIST) { + break; + } + } + /* couldn't make a dir */ + goto out; + +bindsocket: + /* Format is "/tmp/dropbear-0246dead/auth-d00f7654-23". + * The "23" is the file desc, the random data is to avoid collisions + * between subsequent user processes reusing socket fds (odds are now + * 1/(2^64) */ + genrandom((unsigned char*)&prefix, sizeof(prefix)); + snprintf(sockfile, sizeof(sockfile), "auth-%.8x-%d", prefix, + chansess->agentfd); + snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s", path, sockfile); + + if (bind(chansess->agentfd, (struct sockaddr*)&addr, sizeof(addr)) == 0) { + chansess->agentdir = strdup(path); + chansess->agentfile = strdup(sockfile); + ret = DROPBEAR_SUCCESS; + } + + +out: + if ((seteuid(uid)) < 0 || + (setegid(gid)) < 0) { + dropbear_exit("failed to revert euid"); + } + return ret; +} + +#endif