version 1.1.1.2, 2013/10/14 07:51:14
|
version 1.1.1.4, 2021/03/17 00:32:36
|
Line 2
|
Line 2
|
* Support rsync daemon authentication. |
* Support rsync daemon authentication. |
* |
* |
* Copyright (C) 1998-2000 Andrew Tridgell |
* 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 |
* 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 |
* it under the terms of the GNU General Public License as published by |
Line 20
|
Line 20
|
|
|
#include "rsync.h" |
#include "rsync.h" |
#include "itypes.h" |
#include "itypes.h" |
|
#include "ifuncs.h" |
|
|
extern int read_only; |
extern int read_only; |
extern char *password_file; |
extern char *password_file; |
Line 71 static void gen_challenge(const char *addr, char *chal
|
Line 72 static void gen_challenge(const char *addr, char *chal
|
SIVAL(input, 20, tv.tv_usec); |
SIVAL(input, 20, tv.tv_usec); |
SIVAL(input, 24, getpid()); |
SIVAL(input, 24, getpid()); |
|
|
sum_init(0); | sum_init(-1, 0); |
sum_update(input, sizeof input); |
sum_update(input, sizeof input); |
len = sum_end(digest); |
len = sum_end(digest); |
|
|
Line 85 static void generate_hash(const char *in, const char *
|
Line 86 static void generate_hash(const char *in, const char *
|
char buf[MAX_DIGEST_LEN]; |
char buf[MAX_DIGEST_LEN]; |
int len; |
int len; |
|
|
sum_init(0); | sum_init(-1, 0); |
sum_update(in, strlen(in)); |
sum_update(in, strlen(in)); |
sum_update(challenge, strlen(challenge)); |
sum_update(challenge, strlen(challenge)); |
len = sum_end(buf); |
len = sum_end(buf); |
Line 102 static const char *check_secret(int module, const char
|
Line 103 static const char *check_secret(int module, const char
|
char pass2[MAX_DIGEST_LEN*2]; |
char pass2[MAX_DIGEST_LEN*2]; |
const char *fname = lp_secrets_file(module); |
const char *fname = lp_secrets_file(module); |
STRUCT_STAT st; |
STRUCT_STAT st; |
int fd, ok = 1; | int ok = 1; |
int user_len = strlen(user); |
int user_len = strlen(user); |
int group_len = group ? strlen(group) : 0; |
int group_len = group ? strlen(group) : 0; |
char *err; |
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"; |
return "no secrets file"; |
|
|
if (do_fstat(fd, &st) == -1) { | if (do_fstat(fileno(fh), &st) == -1) { |
rsyserr(FLOG, errno, "fstat(%s)", fname); |
rsyserr(FLOG, errno, "fstat(%s)", fname); |
ok = 0; |
ok = 0; |
} else if (lp_strict_modes(module)) { |
} else if (lp_strict_modes(module)) { |
if ((st.st_mode & 06) != 0) { |
if ((st.st_mode & 06) != 0) { |
rprintf(FLOG, "secrets file must not be other-accessible (see strict modes option)\n"); |
rprintf(FLOG, "secrets file must not be other-accessible (see strict modes option)\n"); |
ok = 0; |
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"); |
rprintf(FLOG, "secrets file must be owned by root when running as root (see strict modes)\n"); |
ok = 0; |
ok = 0; |
} |
} |
} |
} |
if (!ok) { |
if (!ok) { |
close(fd); | fclose(fh); |
return "ignoring secrets file"; |
return "ignoring secrets file"; |
} |
} |
|
|
if (*user == '#') { |
if (*user == '#') { |
/* Reject attempt to match a comment. */ |
/* Reject attempt to match a comment. */ |
close(fd); | fclose(fh); |
return "invalid username"; |
return "invalid username"; |
} |
} |
|
|
/* Try to find a line that starts with the user (or @group) name and a ':'. */ |
/* Try to find a line that starts with the user (or @group) name and a ':'. */ |
err = "secret not found"; |
err = "secret not found"; |
while ((user || group) && read_line_old(fd, line, sizeof line, 1)) { | while ((user || group) && fgets(line, sizeof line, fh) != NULL) { |
const char **ptr, *s; | const char **ptr, *s = strtok(line, "\n\r"); |
int len; |
int len; |
if (*line == '@') { | if (!s) |
| continue; |
| if (*s == '@') { |
ptr = &group; |
ptr = &group; |
len = group_len; |
len = group_len; |
s = line+1; | s++; |
} else { |
} else { |
ptr = &user; |
ptr = &user; |
len = user_len; |
len = user_len; |
s = line; |
|
} |
} |
if (!*ptr || strncmp(s, *ptr, len) != 0 || s[len] != ':') |
if (!*ptr || strncmp(s, *ptr, len) != 0 || s[len] != ':') |
continue; |
continue; |
Line 158 static const char *check_secret(int module, const char
|
Line 161 static const char *check_secret(int module, const char
|
*ptr = NULL; /* Don't look for name again. */ |
*ptr = NULL; /* Don't look for name again. */ |
} |
} |
|
|
close(fd); | fclose(fh); |
|
|
memset(line, 0, sizeof line); | force_memzero(line, sizeof line); |
memset(pass2, 0, sizeof pass2); | force_memzero(pass2, sizeof pass2); |
|
|
return err; |
return err; |
} |
} |
Line 193 static const char *getpassf(const char *filename)
|
Line 196 static const char *getpassf(const char *filename)
|
rprintf(FERROR, "ERROR: password file must not be other-accessible\n"); |
rprintf(FERROR, "ERROR: password file must not be other-accessible\n"); |
exit_cleanup(RERR_SYNTAX); |
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"); |
rprintf(FERROR, "ERROR: password file must be owned by root when running as root\n"); |
exit_cleanup(RERR_SYNTAX); |
exit_cleanup(RERR_SYNTAX); |
} |
} |
Line 224 char *auth_server(int f_in, int f_out, int module, con
|
Line 227 char *auth_server(int f_in, int f_out, int module, con
|
char *users = lp_auth_users(module); |
char *users = lp_auth_users(module); |
char challenge[MAX_DIGEST_LEN*2]; |
char challenge[MAX_DIGEST_LEN*2]; |
char line[BIGPATHBUFLEN]; |
char line[BIGPATHBUFLEN]; |
char **auth_uid_groups = NULL; | const char **auth_uid_groups = NULL; |
int auth_uid_groups_cnt = -1; |
int auth_uid_groups_cnt = -1; |
const char *err = NULL; |
const char *err = NULL; |
int group_match = -1; |
int group_match = -1; |
Line 248 char *auth_server(int f_in, int f_out, int module, con
|
Line 251 char *auth_server(int f_in, int f_out, int module, con
|
} |
} |
*pass++ = '\0'; |
*pass++ = '\0'; |
|
|
if (!(users = strdup(users))) | users = strdup(users); |
out_of_memory("auth_server"); | |
|
|
for (tok = strtok(users, " ,\t"); tok; tok = strtok(NULL, " ,\t")) { |
for (tok = strtok(users, " ,\t"); tok; tok = strtok(NULL, " ,\t")) { |
char *opts; |
char *opts; |
Line 277 char *auth_server(int f_in, int f_out, int module, con
|
Line 279 char *auth_server(int f_in, int f_out, int module, con
|
/* See if authorizing user is a real user, and if so, see |
/* See if authorizing user is a real user, and if so, see |
* if it is in a group that matches tok+1 wildmat. */ |
* if it is in a group that matches tok+1 wildmat. */ |
if (auth_uid_groups_cnt < 0) { |
if (auth_uid_groups_cnt < 0) { |
gid_t gid_list[64]; | item_list gid_list = EMPTY_ITEM_LIST; |
uid_t auth_uid; |
uid_t auth_uid; |
auth_uid_groups_cnt = sizeof gid_list / sizeof (gid_t); |
|
if (!user_to_uid(line, &auth_uid, False) |
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; |
auth_uid_groups_cnt = 0; |
else { |
else { |
if ((auth_uid_groups = new_array(char *, auth_uid_groups_cnt)) == NULL) | gid_t *gid_array = gid_list.items; |
out_of_memory("auth_server"); | 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++) |
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++) { |
for (j = 0; j < auth_uid_groups_cnt; j++) { |
Line 311 char *auth_server(int f_in, int f_out, int module, con
|
Line 313 char *auth_server(int f_in, int f_out, int module, con
|
else if (opt_ch == 'd') |
else if (opt_ch == 'd') |
err = "denied by rule"; |
err = "denied by rule"; |
else { |
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); |
err = check_secret(module, line, group, challenge, pass); |
} |
} |
|
|
memset(challenge, 0, sizeof challenge); | force_memzero(challenge, sizeof challenge); |
memset(pass, 0, strlen(pass)); | force_memzero(pass, strlen(pass)); |
|
|
if (auth_uid_groups) { |
if (auth_uid_groups) { |
int j; |
int j; |
for (j = 0; j < auth_uid_groups_cnt; j++) { |
for (j = 0; j < auth_uid_groups_cnt; j++) { |
if (auth_uid_groups[j]) |
if (auth_uid_groups[j]) |
free(auth_uid_groups[j]); | free((char*)auth_uid_groups[j]); |
} |
} |
free(auth_uid_groups); |
free(auth_uid_groups); |
} |
} |
Line 354 void auth_client(int fd, const char *user, const char
|
Line 356 void auth_client(int fd, const char *user, const char
|
/* XXX: cyeoh says that getpass is deprecated, because |
/* XXX: cyeoh says that getpass is deprecated, because |
* it may return a truncated password on some systems, |
* it may return a truncated password on some systems, |
* and it is not in the LSB. |
* and it is not in the LSB. |
* | * |
* Andrew Klein says that getpassphrase() is present | * Andrew Klein says that getpassphrase() is present |
* on Solaris and reads up to 256 characters. | * on Solaris and reads up to 256 characters. |
* | * |
* OpenBSD has a readpassphrase() that might be more suitable. | * OpenBSD has a readpassphrase() that might be more suitable. |
*/ | */ |
pass = getpass("Password: "); |
pass = getpass("Password: "); |
} |
} |
|
|