- Add support for CVSup authentication mechanisms to csup.

- Include a cpasswd script performing the same mechanisms as the cvpasswd
  utility from CVSup.

PR:		bin/114129
Submitted by:	Petar Zhivkov Petrov <pesho.petrov -at- gmail.com>
MFC after:	1 month
This commit is contained in:
Ulf Lilleengen 2010-02-02 05:57:42 +00:00
parent 7b59c0c5f5
commit 1282a5e283
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=203368
11 changed files with 749 additions and 57 deletions

View File

@ -7,7 +7,7 @@ MANDIR?= ${PREFIX}/man/man
UNAME!= /usr/bin/uname -s
PROG= csup
SRCS= attrstack.c config.c detailer.c diff.c fattr.c fixups.c fnmatch.c \
SRCS= attrstack.c auth.c config.c detailer.c diff.c fattr.c fixups.c fnmatch.c \
globtree.c idcache.c keyword.c lister.c main.c misc.c mux.c parse.y \
pathcomp.c proto.c status.c stream.c threads.c token.l updater.c \
rcsfile.c rcsparse.c lex.rcs.c rsyncfile.c
@ -42,4 +42,7 @@ parse.h: y.tab.h
DPADD= ${LIBCRYPTO} ${LIBZ}
LDADD= -lcrypto -lz
SCRIPTS= cpasswd.sh
MAN= csup.1 cpasswd.1
.include <bsd.prog.mk>

View File

@ -17,7 +17,6 @@ BUGS:
MISSING FEATURES:
- Add support for authentication.
- Add support for shell commands sent by the server.
- Add missing support for various CVSup options : -D, -a (requires
authentication support), -e and -E (requires shell commands support)

331
contrib/csup/auth.c Normal file
View File

@ -0,0 +1,331 @@
/*-
* Copyright (c) 2003-2007, Petar Zhivkov Petrov <pesho.petrov@gmail.com>
* 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
*
* $FreeBSD$
*/
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <ctype.h>
#include <openssl/md5.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "auth.h"
#include "config.h"
#include "misc.h"
#include "proto.h"
#include "stream.h"
#define MD5_BYTES 16
/* This should be at least 2 * MD5_BYTES + 6 (length of "$md5$" + 1) */
#define MD5_CHARS_MAX (2*(MD5_BYTES)+6)
struct srvrecord {
char server[MAXHOSTNAMELEN];
char client[256];
char password[256];
};
static int auth_domd5auth(struct config *);
static int auth_lookuprecord(char *, struct srvrecord *);
static int auth_parsetoken(char **, char *, int);
static void auth_makesecret(struct srvrecord *, char *);
static void auth_makeresponse(char *, char *, char *);
static void auth_readablesum(unsigned char *, char *);
static void auth_makechallenge(struct config *, char *);
static int auth_checkresponse(char *, char *, char *);
int auth_login(struct config *config)
{
struct stream *s;
char hostbuf[MAXHOSTNAMELEN];
char *login, *host;
int error;
s = config->server;
error = gethostname(hostbuf, sizeof(hostbuf));
hostbuf[sizeof(hostbuf) - 1] = '\0';
if (error)
host = NULL;
else
host = hostbuf;
login = getlogin();
proto_printf(s, "USER %s %s\n", login != NULL ? login : "?",
host != NULL ? host : "?");
stream_flush(s);
error = auth_domd5auth(config);
return (error);
}
static int
auth_domd5auth(struct config *config)
{
struct stream *s;
char *line, *cmd, *challenge, *realm, *client, *srvresponse, *msg;
char shrdsecret[MD5_CHARS_MAX], response[MD5_CHARS_MAX];
char clichallenge[MD5_CHARS_MAX];
struct srvrecord auth;
int error;
lprintf(2, "MD5 authentication started\n");
s = config->server;
line = stream_getln(s, NULL);
cmd = proto_get_ascii(&line);
realm = proto_get_ascii(&line);
challenge = proto_get_ascii(&line);
if (challenge == NULL ||
line != NULL ||
(strcmp(cmd, "AUTHMD5") != 0)) {
lprintf(-1, "Invalid server reply to USER\n");
return (STATUS_FAILURE);
}
client = NULL;
response[0] = clichallenge[0] = '.';
response[1] = clichallenge[1] = 0;
if (config->reqauth || (strcmp(challenge, ".") != 0)) {
if (strcmp(realm, ".") == 0) {
lprintf(-1, "Authentication required, but not enabled on server\n");
return (STATUS_FAILURE);
}
error = auth_lookuprecord(realm, &auth);
if (error != STATUS_SUCCESS)
return (error);
client = auth.client;
auth_makesecret(&auth, shrdsecret);
}
if (strcmp(challenge, ".") != 0)
auth_makeresponse(challenge, shrdsecret, response);
if (config->reqauth)
auth_makechallenge(config, clichallenge);
proto_printf(s, "AUTHMD5 %s %s %s\n",
client == NULL ? "." : client, response, clichallenge);
stream_flush(s);
line = stream_getln(s, NULL);
cmd = proto_get_ascii(&line);
if (cmd == NULL || line == NULL)
goto bad;
if (strcmp(cmd, "OK") == 0) {
srvresponse = proto_get_ascii(&line);
if (srvresponse == NULL)
goto bad;
if (config->reqauth &&
!auth_checkresponse(srvresponse, clichallenge, shrdsecret)) {
lprintf(-1, "Server failed to authenticate itself to client\n");
return (STATUS_FAILURE);
}
lprintf(2, "MD5 authentication successfull\n");
return (STATUS_SUCCESS);
}
if (strcmp(cmd, "!") == 0) {
msg = proto_get_rest(&line);
if (msg == NULL)
goto bad;
lprintf(-1, "Server error: %s\n", msg);
return (STATUS_FAILURE);
}
bad:
lprintf(-1, "Invalid server reply to AUTHMD5\n");
return (STATUS_FAILURE);
}
static int
auth_lookuprecord(char *server, struct srvrecord *auth)
{
char *home, *line, authfile[FILENAME_MAX];
struct stream *s;
int linenum = 0, error;
home = getenv("HOME");
if (home == NULL) {
lprintf(-1, "Environment variable \"HOME\" is not set\n");
return (STATUS_FAILURE);
}
snprintf(authfile, sizeof(authfile), "%s/%s", home, AUTHFILE);
s = stream_open_file(authfile, O_RDONLY);
if (s == NULL) {
lprintf(-1, "Could not open file %s\n", authfile);
return (STATUS_FAILURE);
}
while ((line = stream_getln(s, NULL)) != NULL) {
linenum++;
if (line[0] == '#' || line[0] == '\0')
continue;
error = auth_parsetoken(&line, auth->server,
sizeof(auth->server));
if (error != STATUS_SUCCESS) {
lprintf(-1, "%s:%d Missng client name\n", authfile, linenum);
goto close;
}
/* Skip the rest of this line, it isn't what we are looking for. */
if (strcmp(auth->server, server) != 0)
continue;
error = auth_parsetoken(&line, auth->client,
sizeof(auth->client));
if (error != STATUS_SUCCESS) {
lprintf(-1, "%s:%d Missng password\n", authfile, linenum);
goto close;
}
error = auth_parsetoken(&line, auth->password,
sizeof(auth->password));
if (error != STATUS_SUCCESS) {
lprintf(-1, "%s:%d Missng comment\n", authfile, linenum);
goto close;
}
stream_close(s);
lprintf(2, "Found authentication record for server \"%s\"\n",
server);
return (STATUS_SUCCESS);
}
lprintf(-1, "Unknown server \"%s\". Fix your %s\n", server , authfile);
memset(auth->password, 0, sizeof(auth->password));
close:
stream_close(s);
return (STATUS_FAILURE);
}
static int
auth_parsetoken(char **line, char *buf, int len)
{
char *colon;
colon = strchr(*line, ':');
if (colon == NULL)
return (STATUS_FAILURE);
*colon = 0;
buf[len - 1] = 0;
strncpy(buf, *line, len - 1);
*line = colon + 1;
return (STATUS_SUCCESS);
}
static void
auth_makesecret(struct srvrecord *auth, char *secret)
{
char *s, ch;
const char *md5salt = "$md5$";
unsigned char md5sum[MD5_BYTES];
MD5_CTX md5;
MD5_Init(&md5);
for (s = auth->client; *s != 0; ++s) {
ch = tolower(*s);
MD5_Update(&md5, &ch, 1);
}
MD5_Update(&md5, ":", 1);
for (s = auth->server; *s != 0; ++s) {
ch = tolower(*s);
MD5_Update(&md5, &ch, 1);
}
MD5_Update(&md5, ":", 1);
MD5_Update(&md5, auth->password, strlen(auth->password));
MD5_Final(md5sum, &md5);
memset(secret, 0, sizeof(secret));
strcpy(secret, md5salt);
auth_readablesum(md5sum, secret + strlen(md5salt));
}
static void
auth_makeresponse(char *challenge, char *sharedsecret, char *response)
{
MD5_CTX md5;
unsigned char md5sum[MD5_BYTES];
MD5_Init(&md5);
MD5_Update(&md5, sharedsecret, strlen(sharedsecret));
MD5_Update(&md5, ":", 1);
MD5_Update(&md5, challenge, strlen(challenge));
MD5_Final(md5sum, &md5);
auth_readablesum(md5sum, response);
}
/*
* Generates a challenge string which is an MD5 sum
* of a fairly random string. The purpose is to decrease
* the possibility of generating the same challenge
* string (even by different clients) more then once
* for the same server.
*/
static void
auth_makechallenge(struct config *config, char *challenge)
{
MD5_CTX md5;
unsigned char md5sum[MD5_BYTES];
char buf[128];
struct timeval tv;
struct sockaddr_in laddr;
pid_t pid, ppid;
int error, addrlen;
gettimeofday(&tv, NULL);
pid = getpid();
ppid = getppid();
srand(tv.tv_usec ^ tv.tv_sec ^ pid);
addrlen = sizeof(laddr);
error = getsockname(config->socket, (struct sockaddr *)&laddr, &addrlen);
if (error < 0) {
memset(&laddr, 0, sizeof(laddr));
}
gettimeofday(&tv, NULL);
MD5_Init(&md5);
snprintf(buf, sizeof(buf), "%s:%ld:%ld:%ld:%d:%d",
inet_ntoa(laddr.sin_addr), tv.tv_sec, tv.tv_usec, random(), pid, ppid);
MD5_Update(&md5, buf, strlen(buf));
MD5_Final(md5sum, &md5);
auth_readablesum(md5sum, challenge);
}
static int
auth_checkresponse(char *response, char *challenge, char *secret)
{
char correctresponse[MD5_CHARS_MAX];
auth_makeresponse(challenge, secret, correctresponse);
return (strcmp(response, correctresponse) == 0);
}
static void
auth_readablesum(unsigned char *md5sum, char *readable)
{
unsigned int i;
char *s = readable;
for (i = 0; i < MD5_BYTES; ++i, s+=2) {
sprintf(s, "%.2x", md5sum[i]);
}
}

38
contrib/csup/auth.h Normal file
View File

@ -0,0 +1,38 @@
/*-
* Copyright (c) 2003-2007, Petar Zhivkov Petrov <pesho.petrov@gmail.com>
* 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
*
* $FreeBSD$
*/
#ifndef _AUTH_H_
#define _AUTH_H_
#define AUTHFILE ".csup/auth" /* user home relative */
struct config;
int auth_login(struct config *);
#endif /* !_AUTH_H_ */

View File

@ -108,6 +108,7 @@ struct config {
struct chan *chan1;
struct stream *server;
fattr_support_t fasupport;
int reqauth;
};
struct config *config_init(const char *, struct coll *, int);

120
contrib/csup/cpasswd.1 Normal file
View File

@ -0,0 +1,120 @@
.\" Copyright 1999-2003 John D. Polstra.
.\" 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.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgment:
.\" This product includes software developed by John D. Polstra.
.\" 4. The name of the author may not be used to endorse or promote products
.\" derived from this software without specific prior written permission.
.\"
.\" 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.
.\"
.\" $Id: cvpasswd.1,v 1.4 2003/03/04 18:24:42 jdp Exp $
.\" $FreeBSD $
.\"
.Dd June 27, 2007
.Os FreeBSD
.Dt CPASSWD 1
.Sh NAME
.Nm cpasswd
.Nd scramble passwords for csup authentication
.Sh SYNOPSIS
.Nm
.Ar clientName
.Ar serverName
.Sh DESCRIPTION
The
.Nm
utility creates scrambled passwords for the
.Nm CVSup
server's authentication database. It is invoked with a client name
and a server name.
.Ar ClientName
is the name the client uses to gain access to the
server. By convention, e-mail addresses are used for all client
names, e.g.,
.Ql BillyJoe@FreeBSD.ORG .
Client names are case-insensitive.
.Pp
.Ar ServerName
is the name of the
.Nm CVSup
server which the client wishes to access. By convention,
it is the canonical fully-qualified domain name of the server, e.g.,
.Ql CVSup.FreeBSD.ORG .
This must agree with the server's own idea of its name. The name is
case-insensitive.
.Pp
To set up authentication for a given server, one must perform the
following steps:
.Bl -enum
.It
Obtain the official
.Ar serverName
from the administrator of the server or from some other source.
.It
Choose an appropriate
.Ar clientName .
It should be in the form of a valid e-mail address, to make it easy
for the server administrator to contact the user if necessary.
.It
Choose an arbitrary secret
.Ar password .
.It
Run
.Nm cpasswd ,
and type in the
.Ar password
when prompted for it. The utility will print out a line to send
to the server administrator, and instruct you how to modify your
.Li $ Ns Ev HOME Ns Pa /.csup/auth
file. You should use a secure channel to send the line to the
server administrator.
.El
.Pp
Since
.Li $ Ns Ev HOME Ns Pa /.csup/auth
contains passwords, you should ensure that it is not readable by
anyone except yourself.
.Sh FILES
.Bl -tag -width $HOME/.csup/authxx -compact
.It Li $ Ns Ev HOME Ns Pa /.csup/auth
Authentication password file.
.El
.Sh SEE ALSO
.Xr csup 1 ,
.Xr cvsup 1 ,
.Xr cvsupd 8 .
.Pp
.Bd -literal
http://www.cvsup.org/
.Ed
.Sh AUTHORS
.An -nosplit
.An Petar Zhivkov Petrov Aq pesho.petrov@gmail.com
is the author of
.Nm ,
the rewrite of
.Nm cvpasswd .
.An John Polstra Aq jdp@polstra.com
is the author of
.Nm CVSup .
.Sh LEGALITIES
CVSup is a registered trademark of John D. Polstra.

135
contrib/csup/cpasswd.sh Executable file
View File

@ -0,0 +1,135 @@
#! /bin/sh
#
# Copyright 2007. Petar Zhivkov Petrov
# pesho.petrov@gmail.com
#
# $FreeBSD$
usage() {
echo "Usage: $0 clientName serverName"
echo " $0 -v"
}
countChars() {
_count="`echo "$1" | sed -e "s/[^$2]//g" | tr -d "\n" | wc -c`"
return 0
}
readPassword() {
while [ true ]; do
stty -echo
read -p "$1" _password
stty echo
echo ""
countChars "$_password" ":"
if [ $_count != 0 ]; then
echo "Sorry, password must not contain \":\" characters"
echo ""
else
break
fi
done
return 0
}
makeSecret() {
local clientLower="`echo "$1" | tr "[:upper:]" "[:lower:]"`"
local serverLower="`echo "$2" | tr "[:upper:]" "[:lower:]"`"
local secret="`md5 -qs "$clientLower:$serverLower:$3"`"
_secret="\$md5\$$secret"
}
if [ $# -eq 1 -a "X$1" = "X-v" ]; then
echo "Csup authentication key generator"
usage
exit
elif [ $# -ne 2 ]; then
usage
exit
fi
clientName=$1
serverName=$2
#
# Client name must contain exactly one '@' and at least one '.'.
# It must not contain a ':'.
#
countChars "$clientName" "@"
aCount=$_count
countChars "$clientName" "."
dotCount=$_count
if [ $aCount -ne 1 -o $dotCount -eq 0 ]; then
echo "Client name must have the form of an e-mail address,"
echo "e.g., \"user@domain.com\""
exit
fi
countChars "$clientName" ":"
colonCount=$_count
if [ $colonCount -gt 0 ]; then
echo "Client name must not contain \":\" characters"
exit
fi
#
# Server name must not contain '@' and must have at least one '.'.
# It also must not contain a ':'.
#
countChars "$serverName" "@"
aCount=$_count
countChars "$serverName" "."
dotCount=$_count
if [ $aCount != 0 -o $dotCount = 0 ]; then
echo "Server name must be a fully-qualified domain name."
echo "e.g., \"host.domain.com\""
exit
fi
countChars "$serverName" ":"
colonCount=$_count
if [ $colonCount -gt 0 ]; then
echo "Server name must not contain \":\" characters"
exit
fi
#
# Ask for password and generate secret.
#
while [ true ]; do
readPassword "Enter password: "
makeSecret "$clientName" "$serverName" "$_password"
secret=$_secret
readPassword "Enter same password again: "
makeSecret "$clientName" "$serverName" "$_password"
secret2=$_secret
if [ "X$secret" = "X$secret2" ]; then
break
else
echo "Passwords did not match. Try again."
echo ""
fi
done
echo ""
echo "Send this line to the server administrator at $serverName:"
echo "-------------------------------------------------------------------------------"
echo "$clientName:$secret::"
echo "-------------------------------------------------------------------------------"
echo "Be sure to send it using a secure channel!"
echo ""
echo "Add this line to your file \"$HOME/.csup/auth\", replacing \"XXX\""
echo "with the password you typed in:"
echo "-------------------------------------------------------------------------------"
echo "$serverName:$clientName:XXX:"
echo "-------------------------------------------------------------------------------"
echo "Make sure the file is readable and writable only by you!"
echo ""

View File

@ -32,7 +32,7 @@
.Nd network distribution package for CVS repositories
.Sh SYNOPSIS
.Nm
.Op Fl 146ksvzZ
.Op Fl 146aksvzZ
.Op Fl A Ar addr
.Op Fl b Ar base
.Op Fl c Ar collDir
@ -106,6 +106,12 @@ to use IPv4 addresses only.
Forces
.Nm
to use IPv6 addresses only.
.It Fl a
Requires the server to authenticate itself (prove its identity) to
the client. If authentication of the server fails, the update is
canceled. See
.Sx AUTHENTICATION ,
below.
.It Fl A Ar addr
Specifies a local address to bind to when connecting to the server.
The local address might be a hostname or a numeric host address string
@ -793,6 +799,102 @@ as well:
.It
.Pa /bar/stool/src-all/refuse.cvs:RELENG_3
.El
.Sh AUTHENTICATION
.Nm
implements an optional authentication mechanism which can be used by the
client and server to verify each other's identities.
Public CVSup servers normally do not enable authentication.
.Nm
users may ignore this section unless they have been informed
that authentication is required by the administrator of their server.
.Pp
The authentication subsystem uses a
challenge-response protocol which is immune to packet sniffing and
replay attacks. No passwords are sent over the network in either
direction. Both the client and the server can independently verify
the identities of each other.
.Pp
The file
.Li $ Ns Ev HOME Ns Pa /.csup/auth
holds the information used for authentication. This file contains a
record for each server that the client is allowed to access. Each
record occupies one line in the file. Lines beginning with
.Ql #
are ignored, as are lines containing only white space. White space is
significant everywhere else in the file. Fields are separated by
.Ql \&:
characters.
.Pp
Each record of the file has the following form:
.Bd -literal -offset indent
.Sm off
.Xo Ar serverName No : Ar clientName No :
.Ar password No : Ar comment
.Xc
.Sm on
.Ed
.Pp
All fields must be present even if some of them are empty.
.Ar ServerName
is the name of the server to which the record applies. By convention,
it is the canonical fully-qualified domain name of the server, e.g.,
.Ql CVSup177.FreeBSD.ORG .
This must agree with the server's own idea of its name. The name is
case-insensitive.
.Pp
.Ar ClientName
is the name the client uses to gain access to the server. By
convention, e-mail addresses are used for all client names, e.g.,
.Ql BillyJoe@FreeBSD.ORG .
Client names are case-insensitive.
.Pp
.Ar Password
is a secret string of characters that the client uses to prove its
identity. It may not contain any
.Ql \&:
or newline characters.
.Pp
.Ar Comment
may contain any additional information to identify the record. It
is not interpreted by the program.
.Pp
To set up authentication for a given server, one must perform the
following steps:
.Bl -enum
.It
Obtain the official
.Ar serverName
from the administrator of the server or from some other source.
.It
Choose an appropriate
.Ar clientName .
It should be in the form of a valid e-mail address, to make it easy
for the server administrator to contact the user if necessary.
.It
Choose an arbitrary secret
.Ar password .
.It
Run the
.Nm cpasswd
utility, and type in the
.Ar password
when prompted for it. The utility will print out a line to send
to the server administrator, and instruct you how to modify your
.Li $ Ns Ev HOME Ns Pa /.csup/auth
file. You should use a secure channel to send the line to the
server administrator.
.El
.Pp
Since
.Li $ Ns Ev HOME Ns Pa /.csup/auth
contains passwords, you should ensure that it is not readable by
anyone except yourself.
.Pp
Authentication works independently in both directions. The server
administrator controls whether you must prove your identity.
You control whether to check the server's identity, by means of the
.Fl a
command line option.
.Sh csup AND FIREWALLS
In its default mode,
.Nm
@ -865,6 +967,7 @@ subdirectory.
List files.
.El
.Sh SEE ALSO
.Xr cpasswd 1 ,
.Xr cvs 1 ,
.Xr rcsintro 1 ,
.Xr ssh 1 .

View File

@ -60,6 +60,8 @@ usage(char *argv0)
"(same as \"-r 0\")");
lprintf(-1, USAGE_OPTFMT, "-4", "Force usage of IPv4 addresses");
lprintf(-1, USAGE_OPTFMT, "-6", "Force usage of IPv6 addresses");
lprintf(-1, USAGE_OPTFMT, "-a",
"Require server to authenticate itself to us");
lprintf(-1, USAGE_OPTFMT, "-A addr",
"Bind local socket to a specific address");
lprintf(-1, USAGE_OPTFMT, "-b base",
@ -107,7 +109,7 @@ main(int argc, char *argv[])
struct stream *lock;
char *argv0, *file, *lockfile;
int family, error, lockfd, lflag, overridemask;
int c, i, deletelim, port, retries, status;
int c, i, deletelim, port, retries, status, reqauth;
time_t nexttry;
error = 0;
@ -124,9 +126,10 @@ main(int argc, char *argv[])
lockfile = NULL;
override = coll_new(NULL);
overridemask = 0;
reqauth = 0;
while ((c = getopt(argc, argv,
"146A:b:c:d:gh:i:kl:L:p:P:r:svzZ")) != -1) {
"146aA:b:c:d:gh:i:kl:L:p:P:r:svzZ")) != -1) {
switch (c) {
case '1':
retries = 0;
@ -137,6 +140,10 @@ main(int argc, char *argv[])
case '6':
family = AF_INET6;
break;
case 'a':
/* Require server authentication */
reqauth = 1;
break;
case 'A':
error = getaddrinfo(optarg, NULL, NULL, &res);
if (error) {
@ -303,6 +310,7 @@ main(int argc, char *argv[])
config->laddrlen = laddrlen;
}
config->deletelim = deletelim;
config->reqauth = reqauth;
lprintf(2, "Connecting to %s\n", config->host);
i = 0;

View File

@ -45,6 +45,7 @@
#include <string.h>
#include <unistd.h>
#include "auth.h"
#include "config.h"
#include "detailer.h"
#include "fattr.h"
@ -74,7 +75,6 @@ static void killer_stop(struct killer *);
static int proto_waitconnect(int);
static int proto_greet(struct config *);
static int proto_negproto(struct config *);
static int proto_login(struct config *);
static int proto_fileattr(struct config *);
static int proto_xchgcoll(struct config *);
static struct mux *proto_mux(struct config *);
@ -251,56 +251,6 @@ proto_negproto(struct config *config)
return (STATUS_FAILURE);
}
static int
proto_login(struct config *config)
{
struct stream *s;
char hostbuf[MAXHOSTNAMELEN];
char *line, *login, *host, *cmd, *realm, *challenge, *msg;
int error;
s = config->server;
error = gethostname(hostbuf, sizeof(hostbuf));
hostbuf[sizeof(hostbuf) - 1] = '\0';
if (error)
host = NULL;
else
host = hostbuf;
login = getlogin();
proto_printf(s, "USER %s %s\n", login != NULL ? login : "?",
host != NULL ? host : "?");
stream_flush(s);
line = stream_getln(s, NULL);
cmd = proto_get_ascii(&line);
realm = proto_get_ascii(&line);
challenge = proto_get_ascii(&line);
if (challenge == NULL || line != NULL)
goto bad;
if (strcmp(realm, ".") != 0 || strcmp(challenge, ".") != 0) {
lprintf(-1, "Authentication required by the server and not "
"supported by client\n");
return (STATUS_FAILURE);
}
proto_printf(s, "AUTHMD5 . . .\n");
stream_flush(s);
line = stream_getln(s, NULL);
cmd = proto_get_ascii(&line);
if (cmd == NULL || line == NULL)
goto bad;
if (strcmp(cmd, "OK") == 0)
return (STATUS_SUCCESS);
if (strcmp(cmd, "!") == 0) {
msg = proto_get_rest(&line);
if (msg == NULL)
goto bad;
lprintf(-1, "Server error: %s\n", msg);
return (STATUS_FAILURE);
}
bad:
lprintf(-1, "Invalid server reply to AUTHMD5\n");
return (STATUS_FAILURE);
}
/*
* File attribute support negotiation.
*/
@ -601,7 +551,7 @@ proto_run(struct config *config)
if (status == STATUS_SUCCESS)
status = proto_negproto(config);
if (status == STATUS_SUCCESS)
status = proto_login(config);
status = auth_login(config);
if (status == STATUS_SUCCESS)
status = proto_fileattr(config);
if (status == STATUS_SUCCESS)

View File

@ -4,6 +4,7 @@
PROG= csup
SRCS= attrstack.c \
auth.c \
config.c \
detailer.c \
diff.c \
@ -37,4 +38,7 @@ WARNS?= 1
DPADD= ${LIBCRYPTO} ${LIBZ} ${LIBPTHREAD}
LDADD= -lcrypto -lz -lpthread
SCRIPTS= cpasswd.sh
MAN= csup.1 cpasswd.1
.include <bsd.prog.mk>