Index: Makefile =================================================================== RCS file: /home/ncvs/projects/csup/Makefile,v retrieving revision 1.45 diff -u -r1.45 Makefile --- Makefile 7 Mar 2006 19:10:25 -0000 1.45 +++ Makefile 7 Jul 2006 20:14:21 -0000 @@ -7,9 +7,9 @@ UNAME!= /usr/bin/uname -s PROG= csup -SRCS= attrstack.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 +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 CFLAGS+= -I. -I${.CURDIR} -g -pthread -DHAVE_FFLAGS -DNDEBUG WARNS?= 6 Index: config.c =================================================================== RCS file: /home/ncvs/projects/csup/config.c,v retrieving revision 1.55 diff -u -r1.55 config.c --- config.c 7 Mar 2006 11:14:50 -0000 1.55 +++ config.c 7 Jul 2006 20:14:21 -0000 @@ -62,7 +62,8 @@ * file and some command line parameters. */ struct config * -config_init(const char *file, struct coll *override, int overridemask) +config_init(const char *file, struct coll *override, int overridemask, + int aflag) { struct config *config; struct coll *coll; @@ -143,6 +144,8 @@ coll_free(cur_coll); coll_free(defaults); config->host = STAILQ_FIRST(&config->colls)->co_host; + /* Set authentication flag */ + config->auth = aflag; return (config); bad: coll_free(cur_coll); Index: config.h =================================================================== RCS file: /home/ncvs/projects/csup/config.h,v retrieving revision 1.38 diff -u -r1.38 config.h --- config.h 7 Mar 2006 12:02:13 -0000 1.38 +++ config.h 7 Jul 2006 20:14:21 -0000 @@ -102,6 +102,8 @@ char *host; struct sockaddr *laddr; socklen_t laddrlen; + in_addr_t addr; + int auth; int deletelim; int socket; struct chan *chan0; @@ -110,7 +112,7 @@ fattr_support_t fasupport; }; -struct config *config_init(const char *, struct coll *, int); +struct config *config_init(const char *, struct coll *, int, int); int config_checkcolls(struct config *); void config_free(struct config *); Index: main.c =================================================================== RCS file: /home/ncvs/projects/csup/main.c,v retrieving revision 1.39 diff -u -r1.39 main.c --- main.c 7 Mar 2006 12:02:13 -0000 1.39 +++ main.c 7 Jul 2006 20:14:21 -0000 @@ -62,6 +62,8 @@ lprintf(-1, USAGE_OPTFMT, "-6", "Force usage of IPv6 addresses"); lprintf(-1, USAGE_OPTFMT, "-A addr", "Bind local socket to a specific address"); + lprintf(-1, USAGE_OPTFMT, "-a", + "Require server to authenticate itself to us"); lprintf(-1, USAGE_OPTFMT, "-b base", "Override supfile's \"base\" directory"); lprintf(-1, USAGE_OPTFMT, "-c collDir", @@ -107,9 +109,10 @@ struct stream *lock; char *argv0, *file, *lockfile; int family, error, lockfd, lflag, overridemask; - int c, i, deletelim, port, retries, status; + int aflag, c, i, deletelim, port, retries, status; time_t nexttry; + aflag = 0; error = 0; family = PF_UNSPEC; deletelim = -1; @@ -126,7 +129,7 @@ overridemask = 0; while ((c = getopt(argc, argv, - "146A:b:c:d:gh:i:kl:L:p:P:r:svzZ")) != -1) { + "146A:ab:c:d:gh:i:kl:L:p:P:r:svzZ")) != -1) { switch (c) { case '1': retries = 0; @@ -149,6 +152,9 @@ memcpy(laddr, res->ai_addr, laddrlen); freeaddrinfo(res); break; + case 'a': + aflag = 1; + break; case 'b': if (override->co_base != NULL) free(override->co_base); @@ -288,7 +294,7 @@ file = argv[0]; lprintf(2, "Parsing supfile \"%s\"\n", file); - config = config_init(file, override, overridemask); + config = config_init(file, override, overridemask, aflag); coll_free(override); if (config == NULL) return (1); Index: proto.c =================================================================== RCS file: /home/ncvs/projects/csup/proto.c,v retrieving revision 1.92 diff -u -r1.92 proto.c --- proto.c 18 May 2006 15:29:43 -0000 1.92 +++ proto.c 7 Jul 2006 20:14:21 -0000 @@ -32,6 +32,8 @@ #include #include +#include + #include #include #include @@ -45,6 +47,7 @@ #include #include +#include "auth.h" #include "config.h" #include "detailer.h" #include "fattr.h" @@ -121,6 +124,7 @@ /* Enough to hold sizeof("cvsup") or any port number. */ char servname[8]; struct addrinfo *res, *ai, hints; + struct sockaddr_in *s_addr; int error, opt, s; s = -1; @@ -171,6 +175,9 @@ strerror(errno)); continue; } + s_addr = (struct sockaddr_in *)ai->ai_addr; + config->addr = s_addr->sin_addr.s_addr; + lprintf(1, "Connected to %s\n", addrbuf); freeaddrinfo(res); config->socket = s; @@ -254,9 +261,18 @@ { struct stream *s; char hostbuf[MAXHOSTNAMELEN]; - char *line, *login, *host, *cmd, *realm, *challenge, *msg; + char *line, *login, *host, *cmd, *realm, *challenge, *msg, *s_response, + *s_secret, *c_response, *c_challenge; + struct auth *a; + struct auth_record *ar; int error; + ar = NULL; + s_secret = NULL; + s_response = NULL; + c_response = NULL; + c_challenge = NULL; + a = auth_read_records(); s = config->server; error = gethostname(hostbuf, sizeof(hostbuf)); hostbuf[sizeof(hostbuf) - 1] = '\0'; @@ -274,28 +290,61 @@ 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); + if (config->auth || strcmp(challenge, ".") != 0) { + if (strcmp(realm, ".") == 0) { + lprintf(-1, "Authentication required but not enabled " + "on server\n"); + goto bad; + } + if ((ar = auth_lookup(a, config->host)) == NULL) { + lprintf(-1, "Unable to find record in ~" AUTHF "\n"); + goto bad; + } + s_secret = auth_makesecret(ar); + if (strcmp(challenge, ".") != 0) + c_response = auth_genresponse(challenge, s_secret); + if (config->auth) + c_challenge = auth_genchallenge(config->addr, "."); + auth_respond(s, ar, c_response, c_challenge); + } else { + proto_printf(s, "AUTHMD5 . . .\n"); + stream_flush(s); } - proto_printf(s, "AUTHMD5 . . .\n"); - stream_flush(s); + auth_free_records(a); line = stream_getln(s, NULL); cmd = proto_get_ascii(&line); if (cmd == NULL || line == NULL) goto bad; - if (strcmp(cmd, "OK") == 0) + if (strcmp(cmd, "OK") == 0) { + s_response = proto_get_ascii(&line); + if (config->auth && auth_checkresponse(s_response, c_challenge, + s_secret) == 0) { + lprintf(-1, "Invalid server reply to AUTHMD5\n"); + goto bad; + } + if (s_secret) + free(s_secret); + if (c_response) + free(c_response); + if (c_challenge) + free(c_challenge); 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); + goto bad; } bad: - lprintf(-1, "Invalid server reply to AUTHMD5\n"); + auth_free_records(a); + if (s_secret) + free(s_secret); + if (c_response) + free(c_response); + if (c_challenge) + free(c_challenge); return (STATUS_FAILURE); }