From sinn@debian.fmi.uni-sofia.bg  Fri Jun 29 14:49:12 2007
Return-Path: <sinn@debian.fmi.uni-sofia.bg>
Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52])
	by hub.freebsd.org (Postfix) with ESMTP id D8BBB16A400;
	Fri, 29 Jun 2007 14:49:12 +0000 (UTC)
	(envelope-from sinn@debian.fmi.uni-sofia.bg)
Received: from smtp.fmi.uni-sofia.bg (smtp.fmi.uni-sofia.bg [62.44.101.3])
	by mx1.freebsd.org (Postfix) with ESMTP id B9CE413C44C;
	Fri, 29 Jun 2007 14:49:08 +0000 (UTC)
	(envelope-from sinn@debian.fmi.uni-sofia.bg)
Received: from debian.fmi.uni-sofia.bg ([62.44.101.36])
	by smtp.fmi.uni-sofia.bg (Kerio MailServer 6.4.0);
	Fri, 29 Jun 2007 16:47:48 +0300
Received: from debian.fmi.uni-sofia.bg (localhost [127.0.0.1])
	by debian.fmi.uni-sofia.bg (Postfix) with ESMTP id 0CBFA6DAC9;
	Fri, 29 Jun 2007 16:48:16 +0300 (EEST)
Received: by debian.fmi.uni-sofia.bg (Postfix, from userid 1316)
	id EA0CF2391C; Fri, 29 Jun 2007 16:48:15 +0300 (EEST)
Message-Id: <20070629134815.EA0CF2391C@debian.fmi.uni-sofia.bg>
Date: Fri, 29 Jun 2007 16:48:15 +0300 (EEST)
From: pesho.petrov@gmail.com
Reply-To: pesho.petrov@gmail.com
To: FreeBSD-gnats-submit@freebsd.org
Cc: mux@freebsd.org
Subject: [patch][csup] csup doesn't support authentication
X-Send-Pr-Version: 3.113
X-GNATS-Notify:

>Number:         114129
>Category:       bin
>Synopsis:       [patch] csup(1) doesn't support authentication
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    lulf
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Fri Jun 29 14:50:09 GMT 2007
>Closed-Date:    Tue Feb 02 06:03:16 UTC 2010
>Last-Modified:  Tue Feb 02 06:03:16 UTC 2010
>Originator:     Petar Zhivkov Petrov
>Release:        FreeBSD 6.2-STABLE i386
>Organization:
Home Inc.
>Environment:
System: FreeBSD mobi 6.2-STABLE FreeBSD 6.2-STABLE #4: Mon Jun 4 19:39:50 EEST 2007 root@mobi:/usr/obj/usr/src/sys/GENERIC i386

>Description:
Currently it is not possible to require the CVSup server to authenticate itself (the -a client command line option). It is also impossible for the client to authenticate itself to the server.

>How-To-Repeat:
	1. Setup a CVSup server which requires authentication.
	2. Try to checkout sources from the CVSup server.

>Fix:

--- csup-authentication.diff begins here ---
diff -ruN csup/Makefile csup_new/Makefile
--- csup/Makefile	Mon May 15 16:40:39 2006
+++ csup_new/Makefile	Wed Jun 27 14:03:05 2007
@@ -7,7 +7,7 @@
 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
 
@@ -40,5 +40,8 @@
 
 DPADD=	${LIBCRYPTO} ${LIBZ}
 LDADD=	-lcrypto -lz
+
+SCRIPTS=	cpasswd.sh
+MAN=		csup.1 cpasswd.1
 
 .include <bsd.prog.mk>
diff -ruN csup/TODO csup_new/TODO
--- csup/TODO	Mon May 15 16:40:39 2006
+++ csup_new/TODO	Tue Jun 12 17:57:14 2007
@@ -17,7 +17,6 @@
 
 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)
diff -ruN csup/auth.c csup_new/auth.c
--- csup/auth.c	Thu Jan  1 02:00:00 1970
+++ csup_new/auth.c	Wed Jun 27 14:08:56 2007
@@ -0,0 +1,330 @@
+/*-
+ * 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]);
+	}
+}
+
diff -ruN csup/auth.h csup_new/auth.h
--- csup/auth.h	Thu Jan  1 02:00:00 1970
+++ csup_new/auth.h	Tue Jun 12 17:57:14 2007
@@ -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_ */
+
diff -ruN csup/config.h csup_new/config.h
--- csup/config.h	Mon May 15 16:40:39 2006
+++ csup_new/config.h	Tue Jun 12 17:57:14 2007
@@ -108,6 +108,7 @@
 	struct chan *chan1;
 	struct stream *server;
 	fattr_support_t fasupport;
+	int reqauth;
 };
 
 struct config	*config_init(const char *, struct coll *, int);
diff -ruN csup/cpasswd.1 csup_new/cpasswd.1
--- csup/cpasswd.1	Thu Jan  1 02:00:00 1970
+++ csup_new/cpasswd.1	Wed Jun 27 13:37:37 2007
@@ -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.
diff -ruN csup/cpasswd.sh csup_new/cpasswd.sh
--- csup/cpasswd.sh	Thu Jan  1 02:00:00 1970
+++ csup_new/cpasswd.sh	Wed Jun 27 14:05:43 2007
@@ -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 ""
+
diff -ruN csup/csup.1 csup_new/csup.1
--- csup/csup.1	Mon May 15 16:40:39 2006
+++ csup_new/csup.1	Wed Jun 27 14:11:38 2007
@@ -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 @@
 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
@@ -795,6 +801,102 @@
 .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
@@ -867,6 +969,7 @@
 List files.
 .El
 .Sh SEE ALSO
+.Xr cpasswd 1 ,
 .Xr cvs 1 ,
 .Xr rcsintro 1 ,
 .Xr ssh 1 .
diff -ruN csup/main.c csup_new/main.c
--- csup/main.c	Mon May 15 16:40:39 2006
+++ csup_new/main.c	Tue Jun 12 17:59:57 2007
@@ -60,6 +60,8 @@
 	    "(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 @@
 	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 @@
 	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 @@
 		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 @@
 		config->laddrlen = laddrlen;
 	}
 	config->deletelim = deletelim;
+	config->reqauth = reqauth;
 	lprintf(2, "Connecting to %s\n", config->host);
 
 	i = 0;
diff -ruN csup/proto.c csup_new/proto.c
--- csup/proto.c	Mon May 15 16:40:40 2006
+++ csup_new/proto.c	Tue Jun 12 17:57:14 2007
@@ -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 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 @@
 	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.
  */
@@ -605,7 +555,7 @@
 	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)
--- csup-authentication.diff ends here ---

--- csup-usr.bin-Makefile.diff begins here ---
diff -ruN usr.bin/csup/Makefile usr.bin_new/csup/Makefile
--- usr.bin/csup/Makefile	Mon May 15 16:47:39 2006
+++ usr.bin_new/csup/Makefile	Fri Jun 29 12:30:52 2007
@@ -4,6 +4,7 @@
 
 PROG=	csup
 SRCS=	attrstack.c \
+	auth.c \
 	config.c \
 	detailer.c \
 	diff.c \
@@ -32,5 +33,8 @@
 
 DPADD=	${LIBCRYPTO} ${LIBZ} ${LIBPTHREAD}
 LDADD=	-lcrypto -lz -lpthread
+
+MAN=csup.1 cpasswd.1
+SCRIPTS=cpasswd.sh
 
 .include <bsd.prog.mk>
--- csup-usr.bin-Makefile.diff ends here ---



>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: freebsd-bugs->mux 
Responsible-Changed-By: linimon 
Responsible-Changed-When: Fri Jun 29 15:58:31 UTC 2007 
Responsible-Changed-Why:  
Over to maintainer. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=114129 
Responsible-Changed-From-To: mux->lulf 
Responsible-Changed-By: gavin 
Responsible-Changed-When: Fri Jan 1 22:35:16 UTC 2010 
Responsible-Changed-Why:  
As discussed, pass this over to lulf, who is interested in getting this patch 
into the tree 

http://www.freebsd.org/cgi/query-pr.cgi?pr=114129 

From: Maxime Henrion <mux@FreeBSD.org>
To: bug-followup@FreeBSD.org, pesho.petrov@gmail.com
Cc:  
Subject: Re: bin/114129: [patch] csup(1) doesn't support authentication
Date: Sat, 2 Jan 2010 00:12:47 +0100

 That sounds good, lulf@ should be able to deal with this patch.
 
 Sorry for being out of touch for so long (damn, 3 years already!).
 
 For what it's worth, the patch looks fine from afar; it even includes
 a cpasswd shell script similar to CVSup's cvpasswd, and a manual page
 update. I have not tested it in anyway though. One minor nit: the two
 lines added to the Makefile are not correctly indented.

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: bin/114129: commit references a PR
Date: Tue,  2 Feb 2010 05:57:58 +0000 (UTC)

 Author: lulf
 Date: Tue Feb  2 05:57:42 2010
 New Revision: 203368
 URL: http://svn.freebsd.org/changeset/base/203368
 
 Log:
   - 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
 
 Added:
   head/contrib/csup/auth.c   (contents, props changed)
   head/contrib/csup/auth.h   (contents, props changed)
   head/contrib/csup/cpasswd.1
   head/contrib/csup/cpasswd.sh   (contents, props changed)
 Modified:
   head/contrib/csup/Makefile
   head/contrib/csup/TODO
   head/contrib/csup/config.h
   head/contrib/csup/csup.1
   head/contrib/csup/main.c
   head/contrib/csup/proto.c
   head/usr.bin/csup/Makefile
 
 Modified: head/contrib/csup/Makefile
 ==============================================================================
 --- head/contrib/csup/Makefile	Tue Feb  2 01:20:33 2010	(r203367)
 +++ head/contrib/csup/Makefile	Tue Feb  2 05:57:42 2010	(r203368)
 @@ -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>
 
 Modified: head/contrib/csup/TODO
 ==============================================================================
 --- head/contrib/csup/TODO	Tue Feb  2 01:20:33 2010	(r203367)
 +++ head/contrib/csup/TODO	Tue Feb  2 05:57:42 2010	(r203368)
 @@ -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)
 
 Added: head/contrib/csup/auth.c
 ==============================================================================
 --- /dev/null	00:00:00 1970	(empty, because file is newly added)
 +++ head/contrib/csup/auth.c	Tue Feb  2 05:57:42 2010	(r203368)
 @@ -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]);
 +	}
 +}
 +
 
 Added: head/contrib/csup/auth.h
 ==============================================================================
 --- /dev/null	00:00:00 1970	(empty, because file is newly added)
 +++ head/contrib/csup/auth.h	Tue Feb  2 05:57:42 2010	(r203368)
 @@ -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_ */
 +
 
 Modified: head/contrib/csup/config.h
 ==============================================================================
 --- head/contrib/csup/config.h	Tue Feb  2 01:20:33 2010	(r203367)
 +++ head/contrib/csup/config.h	Tue Feb  2 05:57:42 2010	(r203368)
 @@ -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);
 
 Added: head/contrib/csup/cpasswd.1
 ==============================================================================
 --- /dev/null	00:00:00 1970	(empty, because file is newly added)
 +++ head/contrib/csup/cpasswd.1	Tue Feb  2 05:57:42 2010	(r203368)
 @@ -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.
 
 Added: head/contrib/csup/cpasswd.sh
 ==============================================================================
 --- /dev/null	00:00:00 1970	(empty, because file is newly added)
 +++ head/contrib/csup/cpasswd.sh	Tue Feb  2 05:57:42 2010	(r203368)
 @@ -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 ""
 +
 
 Modified: head/contrib/csup/csup.1
 ==============================================================================
 --- head/contrib/csup/csup.1	Tue Feb  2 01:20:33 2010	(r203367)
 +++ head/contrib/csup/csup.1	Tue Feb  2 05:57:42 2010	(r203368)
 @@ -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 .
 
 Modified: head/contrib/csup/main.c
 ==============================================================================
 --- head/contrib/csup/main.c	Tue Feb  2 01:20:33 2010	(r203367)
 +++ head/contrib/csup/main.c	Tue Feb  2 05:57:42 2010	(r203368)
 @@ -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;
 
 Modified: head/contrib/csup/proto.c
 ==============================================================================
 --- head/contrib/csup/proto.c	Tue Feb  2 01:20:33 2010	(r203367)
 +++ head/contrib/csup/proto.c	Tue Feb  2 05:57:42 2010	(r203368)
 @@ -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 @@ bad:
  	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)
 
 Modified: head/usr.bin/csup/Makefile
 ==============================================================================
 --- head/usr.bin/csup/Makefile	Tue Feb  2 01:20:33 2010	(r203367)
 +++ head/usr.bin/csup/Makefile	Tue Feb  2 05:57:42 2010	(r203368)
 @@ -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>
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
State-Changed-From-To: open->closed 
State-Changed-By: lulf 
State-Changed-When: Tue Feb 2 06:02:45 UTC 2010 
State-Changed-Why:  
- Patch submitted with a few modifications. Thanks! 

http://www.freebsd.org/cgi/query-pr.cgi?pr=114129 
>Unformatted:
