#######################################################################
# OpenVAS Network Vulnerability Test
#
# rsync modules list
#
# LSS-NVT-2009-003
#
# Developed by LSS Security Team <http://security.lss.hr>
#
# Copyright (C) 2009 LSS <http://www.lss.hr>
#
# This program is free software: you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation, either version 2 of
# the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public
# License along with this program. If not, see
# <http://www.gnu.org/licenses/>.
#######################################################################

if (description) {

    script_id(102003);
    script_version("$Revision: 8018 $");
    script_tag(name:"risk_factor", value:"None");

    script_name("rsync modules list");

    desc = "
This script lists all modules available from particular rsync daemon.

It's based on csprotocol.txt from the rsync source tree.
";
    script_description(desc);

    script_summary("Lists all available rsync modules");

    script_category(ACT_GATHER_INFO);
    script_family("Service detection");

    script_copyright("Copyright (C) 2009 LSS");

    exit(0);
}


function rsync_connect() {
    sock = open_sock_tcp(port);
    if (! sock)
        return NULL;

    banner = recv_line(socket : sock, length : 8096);
    send(socket : sock, data : banner);

    # skip MOTD

    for (i = 0; i < motd_lines; ++i)
        recv_line(socket : sock, length : 8096);

    return sock;
}

function get_module_list() {
    sock = rsync_connect();
    if (! sock)
        return NULL;

    num = 0;
    send(socket : sock, data : '#list\r\n');
    while (1) {
        line = recv_line(socket : sock, length : 8096, timeout : 1);
        if (! line || strstr(line, '@RSYNCD'))
            break;

        ret[num++] = line;
    }

    return ret;
}

function authentication_required(module) {
    sock = rsync_connect();
    if (! sock)
        return 'unknown';

    send(socket : sock, data : string(module + '\r\n'));
    line = recv_line(socket : sock, length : 8096);

    if (strstr(line, '@RSYNCD: OK'))
        return 'no';
    else if (strstr(line, '@RSYNCD: AUTHREQD'))
        return 'yes';
    else
        return 'unknown';
}

#------------------------------------------------------------------------------

port = get_kb_item("Services/rsync");

if (! port)
    port = 873; # default

if (! get_port_state(port))
  exit (0);

# Read the banner and motd. Send dummy data to force rsyncd to close
# the connection.

sock = open_sock_tcp(port);
if (! sock)
    exit(0);

send(socket : sock, data : '@RSYNCD: DUMMY\r\n');

banner = recv_line(socket : sock, length : 8096);
while (1) {
    buf = recv_line(socket : sock, length : 8096);
    if (! buf || strstr(buf, '@ERROR'))
        break;

    motd_lines++;
}

set_kb_item(name : "rsync/" + port + "/banner", value : chomp(banner));

# Extract all modules and prepare a report

modules = get_module_list();
if (! modules)
    exit(0);

report = 'Available rsync modules: \n\n';

foreach line (modules) {
    chomp(line);

    ar = split(line, sep : '\t', keep : 0);

    module = chomp(ar[0]);
    dsc    = chomp(ar[1]);
    auth   = authentication_required(module : module);

    report += '  ' + module + '\t(' + dsc + '; authentication: ' + auth + ')\n';
}

security_note(data : report);
