Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/XRDP/xrdpapi/   (X11 Server Version 0.10.6.1©)  Datei vom 7.6.2026 mit Größe 12 kB image not shown  

Quelle  xrdp-ssh-agent.c

  Sprache: C
 

/**
 * xrdp: A Remote Desktop Protocol server.
 *
 * Copyright (C) Jay Sorg 2012-2013
 * Copyright (C) Laxmikant Rashinkar 2012-2013
 * Copyright (C) Ben Cohen 2017
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


/*
 * Portions are from OpenSSH, under the following license:
 *
 * Author: Tatu Ylonen <ylo@cs.hut.fi>
 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
 *                    All rights reserved
 * The authentication agent program.
 *
 * 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) 2000, 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.
 */


/*
 * xrdp-ssh-agent.c: program to forward ssh-agent protocol from xrdp session
 *
 * This performs the equivalent function of ssh-agent on a server you connect
 * to via ssh, but the ssh-agent protocol is over an RDP dynamic virtual
 * channel and not an SSH channel.
 *
 * This will print out variables to set in your environment (specifically,
 * $SSH_AUTH_SOCK) for ssh clients to find the agent's socket, then it will
 * run in the background.  This is suitable to run just as you would run the
 * normal ssh-agent, e.g. in your Xsession or /etc/xrdp/startwm.sh.
 *
 * Your RDP client needs to be running a compatible client-side plugin
 * that can see a local ssh-agent.
 *
 * usage (from within an xrdp session):
 *     xrdp-ssh-agent
 *
 * build instructions:
 *     gcc xrdp-ssh-agent.c -o xrdp-ssh-agent -L./.libs -lxrdpapi -Wall
 *
 * protocol specification:
 *     Forward data verbatim over RDP dynamic virtual channel named "sshagent"
 *     between a ssh client on the xrdp server and the real ssh-agent where
 *     the RDP client is running.  Each connection by a separate client to
 *     xrdp-ssh-agent gets a separate DVC invocation.
 */


#if defined(HAVE_CONFIG_H)
#include <config_ac.h>
#endif

#ifdef __WIN32__
#include <mstsapi.h>
#endif

#include "xrdpapi.h"
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/stat.h>
#include <linux/limits.h>
#include <fcntl.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <poll.h>

#define _PATH_DEVNULL  "/dev/null"

char socket_name[PATH_MAX];
char socket_dir[PATH_MAX];
static int sa_uds_fd = -1;
static int is_going = 1;


/* Make a template filename for mk[sd]temp() */
/* This is from mktemp_proto() in misc.c from openssh */
void
mktemp_proto(char *s, size_t len)
{
    const char *tmpdir;
    int r;

    if ((tmpdir = getenv("TMPDIR")) != NULL)
    {
        r = snprintf(s, len, "%s/ssh-XXXXXXXXXXXX", tmpdir);
        if (r > 0 && (size_t)r < len)
        {
            return;
        }
    }
    r = snprintf(s, len, "/tmp/ssh-XXXXXXXXXXXX");
    if (r < 0 || (size_t)r >= len)
    {
        fprintf(stderr, "%s: template string too short", __func__);
        exit(1);
    }
}


/* This uses parts of main() in ssh-agent.c from openssh */
static void
setup_ssh_agent(struct sockaddr_un *addr)
{
    int rc;

    /* Create private directory for agent socket */
    mktemp_proto(socket_dir, sizeof(socket_dir));
    if (mkdtemp(socket_dir) == NULL)
    {
        perror("mkdtemp: private socket dir");
        exit(1);
    }
    snprintf(socket_name, sizeof socket_name, "%s/agent.%ld", socket_dir,
             (long)getpid());

    /* Create unix domain socket */
    unlink(socket_name);

    sa_uds_fd = socket(AF_UNIX, SOCK_STREAM, 0);
    if (sa_uds_fd == -1)
    {
        fprintf(stderr, "sshagent: socket creation failed");
        exit(2);
    }

    memset(addr, 0sizeof(struct sockaddr_un));
    addr->sun_family = AF_UNIX;
    strncpy(addr->sun_path, socket_name, sizeof(addr->sun_path));
    addr->sun_path[sizeof(addr->sun_path) - 1] = 0;

    /* Create with privileges rw------- so other users can't access the UDS */
    mode_t umask_sav = umask(0177);
    rc = bind(sa_uds_fd, (struct sockaddr *)addr, sizeof(struct sockaddr_un));
    if (rc != 0)
    {
        fprintf(stderr, "sshagent: bind failed");
        close(sa_uds_fd);
        unlink(socket_name);
        exit(3);
    }
    umask(umask_sav);

    rc = listen(sa_uds_fd, /* backlog = */ 5);
    if (rc != 0)
    {
        fprintf(stderr, "listen failed\n");
        close(sa_uds_fd);
        unlink(socket_name);
        exit(1);
    }

    /* Now fork: the child becomes the ssh-agent daemon and the parent prints
     * out the pid and socket name. */

    pid_t pid = fork();
    if (pid == -1)
    {
        perror("fork");
        exit(1);
    }
    else if (pid != 0)
    {
        /* Parent */
        close(sa_uds_fd);
        printf("SSH_AUTH_SOCK=%s; export SSH_AUTH_SOCK;\n", socket_name);
        printf("SSH_AGENT_PID=%d; export SSH_AGENT_PID;\n", pid);
        printf("echo Agent pid %d;\n", pid);
        exit(0);
    }

    /* Child */

    if (setsid() == -1)
    {
        fprintf(stderr, "setsid failed");
        exit(1);
    }

    (void)chdir("/");
    int devnullfd;
    if ((devnullfd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1)
    {
        /* XXX might close listen socket */
        (void)dup2(devnullfd, STDIN_FILENO);
        (void)dup2(devnullfd, STDOUT_FILENO);
        (void)dup2(devnullfd, STDERR_FILENO);
        if (devnullfd > 2)
        {
            close(devnullfd);
        }
    }

    /* deny core dumps, since memory contains unencrypted private keys */
    struct rlimit rlim;
    rlim.rlim_cur = rlim.rlim_max = 0;
    if (setrlimit(RLIMIT_CORE, &rlim) < 0)
    {
        fprintf(stderr, "setrlimit RLIMIT_CORE: %s", strerror(errno));
        exit(1);
    }
}


static void
handle_connection(int client_fd)
{
    int     rdp_fd = -1;
    int     rc;
    void *channel = WTSVirtualChannelOpenEx(WTS_CURRENT_SESSION,
                                            "SSHAGENT",
                                            WTS_CHANNEL_OPTION_DYNAMIC_PRI_MED);
    if (channel == NULL)
    {
        fprintf(stderr, "WTSVirtualChannelOpenEx() failed\n");
    }

    unsigned int retlen;
    int *retdata;
    rc = WTSVirtualChannelQuery(channel,
                                WTSVirtualFileHandle,
                                (void **)&retdata,
                                &retlen);
    if (!rc)
    {
        fprintf(stderr, "WTSVirtualChannelQuery() failed\n");
    }
    if (retlen != sizeof(rdp_fd))
    {
        fprintf(stderr, "WTSVirtualChannelQuery() returned wrong length %u\n",
                retlen);
    }
    rdp_fd = *retdata;

    int client_going = 1;
    while (client_going)
    {
        struct pollfd pollfd[2];
        enum
        {
            RDP_FD = 0,
            CLIENT_FD
        };

        /* Wait for data from RDP or the client */
        pollfd[RDP_FD].fd = rdp_fd;
        pollfd[RDP_FD].events = POLLIN;
        pollfd[RDP_FD].revents = 0;
        pollfd[CLIENT_FD].fd = client_fd;
        pollfd[CLIENT_FD].events = POLLIN;
        pollfd[CLIENT_FD].revents = 0;

        poll(pollfd, 2, -1);

        if ((pollfd[RDP_FD].revents & (POLLIN | POLLHUP)) != 0)
        {
            /* Read from RDP and write to the client */
            char buffer[4096];
            unsigned int bytes_to_write;
            rc = WTSVirtualChannelRead(channel,
                                       /* TimeOut = */ 5000,
                                       buffer,
                                       sizeof(buffer),
                                       &bytes_to_write);
            if (rc == 1)
            {
                char *pos = buffer;
                errno = 0;
                while (bytes_to_write > 0)
                {
                    int bytes_written = send(client_fd, pos, bytes_to_write, 0);

                    if (bytes_written > 0)
                    {
                        bytes_to_write -= bytes_written;
                        pos += bytes_written;
                    }
                    else if (bytes_written == 0)
                    {
                        fprintf(stderr, "send() returned 0!\n");
                    }
                    else if (errno != EINTR)
                    {
                        /* Error */
                        fprintf(stderr, "Error %d on recv\n", errno);
                        client_going = 0;
                    }
                }
            }
            else
            {
                /* Error */
                fprintf(stderr, "WTSVirtualChannelRead() failed: %d\n", errno);
                client_going = 0;
            }
        }

        if ((pollfd[CLIENT_FD].revents & (POLLIN | POLLHUP)) != 0)
        {
            /* Read from the client and write to RDP */
            char buffer[4096];
            ssize_t bytes_to_write = recv(client_fd, buffer, sizeof(buffer), 0);
            if (bytes_to_write > 0)
            {
                char *pos = buffer;
                while (bytes_to_write > 0)
                {
                    unsigned int bytes_written;
                    int rc = WTSVirtualChannelWrite(channel,
                                                    pos,
                                                    bytes_to_write,
                                                    &bytes_written);
                    if (rc == 0)
                    {
                        fprintf(stderr, "WTSVirtualChannelWrite() failed: %d\n",
                                errno);
                        client_going = 0;
                    }
                    else
                    {
                        bytes_to_write -= bytes_written;
                        pos += bytes_written;
                    }
                }
            }
            else if (bytes_to_write == 0)
            {
                /* Client has closed connection */
                client_going = 0;
            }
            else
            {
                /* Error */
                fprintf(stderr, "Error %d on recv\n", errno);
                client_going = 0;
            }
        }
    }
    WTSVirtualChannelClose(channel);
}


int
main(int argc, char **argv)
{
    /* Setup the Unix domain socket and daemon process */
    struct sockaddr_un addr;
    setup_ssh_agent(&addr);

    /* Wait for a client to connect to the socket */
    while (is_going)
    {
        struct pollfd pollfd;

        pollfd.fd = sa_uds_fd;
        pollfd.events = POLLIN;
        pollfd.revents = 0;

        poll(pollfd, 1, -1);

        /* If something connected then get it...
         * (You can test this using "socat - UNIX-CONNECT:<udspath>".) */

        if ((pollfd.revents & (POLLIN | POLLHUP)) != 0)

        {
            socklen_t addrsize = sizeof(addr);
            int client_fd = accept(sa_uds_fd,
                                   (struct sockaddr *)&addr,
                                   &addrsize);
            handle_connection(client_fd);
            close(client_fd);
        }
    }

    close(sa_uds_fd);
    unlink(socket_name);

    return 0;
}

Messung V0.5 in Prozent
C=93 H=94 G=93

¤ Dauer der Verarbeitung: 0.2 Sekunden  (vorverarbeitet am  2026-07-10) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.