* Support rsync daemon authentication.
*
* Copyright (C) 1998-2000 Andrew Tridgell
- * Copyright (C) 2002-2013 Wayne Davison
+ * Copyright (C) 2002-2020 Wayne Davison
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
#include "rsync.h"
#include "itypes.h"
+#include "ifuncs.h"
extern int read_only;
extern char *password_file;
+extern struct name_num_obj valid_auth_checksums;
/***************************************************************************
encode a buffer using base64 - simple and slow algorithm. null terminates
SIVAL(input, 20, tv.tv_usec);
SIVAL(input, 24, getpid());
- sum_init(0);
+ len = sum_init(valid_auth_checksums.negotiated_nni, 0);
sum_update(input, sizeof input);
- len = sum_end(digest);
+ sum_end(digest);
base64_encode(digest, len, challenge, 0);
}
char buf[MAX_DIGEST_LEN];
int len;
- sum_init(0);
+ len = sum_init(valid_auth_checksums.negotiated_nni, 0);
sum_update(in, strlen(in));
sum_update(challenge, strlen(challenge));
- len = sum_end(buf);
+ sum_end(buf);
base64_encode(buf, len, out, 0);
}
char pass2[MAX_DIGEST_LEN*2];
const char *fname = lp_secrets_file(module);
STRUCT_STAT st;
- int fd, ok = 1;
+ int ok = 1;
int user_len = strlen(user);
int group_len = group ? strlen(group) : 0;
char *err;
+ FILE *fh;
- if (!fname || !*fname || (fd = open(fname, O_RDONLY)) < 0)
+ if (!fname || !*fname || (fh = fopen(fname, "r")) == NULL)
return "no secrets file";
- if (do_fstat(fd, &st) == -1) {
+ if (do_fstat(fileno(fh), &st) == -1) {
rsyserr(FLOG, errno, "fstat(%s)", fname);
ok = 0;
} else if (lp_strict_modes(module)) {
if ((st.st_mode & 06) != 0) {
rprintf(FLOG, "secrets file must not be other-accessible (see strict modes option)\n");
ok = 0;
- } else if (MY_UID() == 0 && st.st_uid != 0) {
+ } else if (MY_UID() == ROOT_UID && st.st_uid != ROOT_UID) {
rprintf(FLOG, "secrets file must be owned by root when running as root (see strict modes)\n");
ok = 0;
}
}
if (!ok) {
- close(fd);
+ fclose(fh);
return "ignoring secrets file";
}
if (*user == '#') {
/* Reject attempt to match a comment. */
- close(fd);
+ fclose(fh);
return "invalid username";
}
/* Try to find a line that starts with the user (or @group) name and a ':'. */
err = "secret not found";
- while ((user || group) && read_line_old(fd, line, sizeof line, 1)) {
- const char **ptr, *s;
+ while ((user || group) && fgets(line, sizeof line, fh) != NULL) {
+ const char **ptr, *s = strtok(line, "\n\r");
int len;
- if (*line == '@') {
+ if (!s)
+ continue;
+ if (*s == '@') {
ptr = &group;
len = group_len;
- s = line+1;
+ s++;
} else {
ptr = &user;
len = user_len;
- s = line;
}
if (!*ptr || strncmp(s, *ptr, len) != 0 || s[len] != ':')
continue;
*ptr = NULL; /* Don't look for name again. */
}
- close(fd);
+ fclose(fh);
- memset(line, 0, sizeof line);
- memset(pass2, 0, sizeof pass2);
+ force_memzero(line, sizeof line);
+ force_memzero(pass2, sizeof pass2);
return err;
}
rprintf(FERROR, "ERROR: password file must not be other-accessible\n");
exit_cleanup(RERR_SYNTAX);
}
- if (MY_UID() == 0 && st.st_uid != 0) {
+ if (MY_UID() == ROOT_UID && st.st_uid != ROOT_UID) {
rprintf(FERROR, "ERROR: password file must be owned by root when running as root\n");
exit_cleanup(RERR_SYNTAX);
}
char *users = lp_auth_users(module);
char challenge[MAX_DIGEST_LEN*2];
char line[BIGPATHBUFLEN];
- char **auth_uid_groups = NULL;
+ const char **auth_uid_groups = NULL;
int auth_uid_groups_cnt = -1;
const char *err = NULL;
int group_match = -1;
if (!users || !*users)
return "";
+ negotiate_daemon_auth(f_out, 0);
gen_challenge(addr, challenge);
io_printf(f_out, "%s%s\n", leader, challenge);
}
*pass++ = '\0';
- if (!(users = strdup(users)))
- out_of_memory("auth_server");
+ users = strdup(users);
for (tok = strtok(users, " ,\t"); tok; tok = strtok(NULL, " ,\t")) {
char *opts;
/* See if authorizing user is a real user, and if so, see
* if it is in a group that matches tok+1 wildmat. */
if (auth_uid_groups_cnt < 0) {
- gid_t gid_list[64];
+ item_list gid_list = EMPTY_ITEM_LIST;
uid_t auth_uid;
- auth_uid_groups_cnt = sizeof gid_list / sizeof (gid_t);
if (!user_to_uid(line, &auth_uid, False)
- || getallgroups(auth_uid, gid_list, &auth_uid_groups_cnt) != NULL)
+ || getallgroups(auth_uid, &gid_list) != NULL)
auth_uid_groups_cnt = 0;
else {
- if ((auth_uid_groups = new_array(char *, auth_uid_groups_cnt)) == NULL)
- out_of_memory("auth_server");
+ gid_t *gid_array = gid_list.items;
+ auth_uid_groups_cnt = gid_list.count;
+ auth_uid_groups = new_array(const char *, auth_uid_groups_cnt);
for (j = 0; j < auth_uid_groups_cnt; j++)
- auth_uid_groups[j] = gid_to_group(gid_list[j]);
+ auth_uid_groups[j] = gid_to_group(gid_array[j]);
}
}
for (j = 0; j < auth_uid_groups_cnt; j++) {
else if (opt_ch == 'd')
err = "denied by rule";
else {
- char *group = group_match >= 0 ? auth_uid_groups[group_match] : NULL;
+ const char *group = group_match >= 0 ? auth_uid_groups[group_match] : NULL;
err = check_secret(module, line, group, challenge, pass);
}
- memset(challenge, 0, sizeof challenge);
- memset(pass, 0, strlen(pass));
+ force_memzero(challenge, sizeof challenge);
+ force_memzero(pass, strlen(pass));
if (auth_uid_groups) {
int j;
for (j = 0; j < auth_uid_groups_cnt; j++) {
if (auth_uid_groups[j])
- free(auth_uid_groups[j]);
+ free((char*)auth_uid_groups[j]);
}
free(auth_uid_groups);
}
if (!user || !*user)
user = "nobody";
+ negotiate_daemon_auth(-1, 1);
if (!(pass = getpassf(password_file))
&& !(pass = getenv("RSYNC_PASSWORD"))) {
/* XXX: cyeoh says that getpass is deprecated, because
* it may return a truncated password on some systems,
* and it is not in the LSB.
- *
- * Andrew Klein says that getpassphrase() is present
- * on Solaris and reads up to 256 characters.
- *
- * OpenBSD has a readpassphrase() that might be more suitable.
- */
+ *
+ * Andrew Klein says that getpassphrase() is present
+ * on Solaris and reads up to 256 characters.
+ *
+ * OpenBSD has a readpassphrase() that might be more suitable.
+ */
pass = getpass("Password: ");
}