2 Copyright (C) Andrew Tridgell 1998
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 /* support rsync authentication */
22 /***************************************************************************
23 encode a buffer using base64 - simple and slow algorithm. null terminates
25 ***************************************************************************/
26 static void base64_encode(char *buf, int len, char *out)
28 char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
29 int bit_offset, byte_offset, idx, i;
30 unsigned char *d = (unsigned char *)buf;
31 int bytes = (len*8 + 5)/6;
33 memset(out, 0, bytes+1);
35 for (i=0;i<bytes;i++) {
36 byte_offset = (i*6)/8;
39 idx = (d[byte_offset] >> (2-bit_offset)) & 0x3F;
41 idx = (d[byte_offset] << (bit_offset-2)) & 0x3F;
42 if (byte_offset+1 < len) {
43 idx |= (d[byte_offset+1] >> (8-(bit_offset-2)));
50 /* create a 16 byte challenge buffer */
51 static void gen_challenge(char *addr, char *challenge)
56 memset(input, 0, sizeof(input));
58 strlcpy((char *)input, addr, 17);
59 gettimeofday(&tv, NULL);
60 SIVAL(input, 16, tv.tv_sec);
61 SIVAL(input, 20, tv.tv_usec);
62 SIVAL(input, 24, getpid());
65 sum_update(input, sizeof(input));
70 /* return the secret for a user from the sercret file. maximum length
71 is len. null terminate it */
72 static int get_secret(int module, char *user, char *secret, int len)
74 char *fname = lp_secrets_file(module);
76 char line[MAXPATHLEN];
82 if (!fname || !*fname) return 0;
84 fd = open(fname,O_RDONLY);
85 if (fd == -1) return 0;
87 if (do_stat(fname, &st) == -1) {
88 rprintf(FERROR,"stat(%s) : %s\n", fname, strerror(errno));
90 } else if ((st.st_mode & 06) != 0) {
91 rprintf(FERROR,"secrets file must not be other-accessible\n");
93 } else if (am_root && (st.st_uid != 0)) {
94 rprintf(FERROR,"secrets file must be owned by root when running as root\n");
98 rprintf(FERROR,"continuing without secrets file\n");
105 memset(line, 0, sizeof(line));
106 while (i<(sizeof(line)-1)) {
107 if (read(fd, &line[i], 1) != 1) {
108 memset(line, 0, sizeof(line));
112 if (line[i] == '\r') continue;
113 if (line[i] == '\n') break;
117 if (line[0] == '#') continue;
118 p = strchr(line,':');
121 if (strcmp(user, line)) continue;
127 if (!found) return 0;
129 strlcpy(secret, pass, len);
133 /* generate a 16 byte hash from a password and challenge */
134 static void generate_hash(char *in, char *challenge, char *out)
139 sum_update(in, strlen(in));
140 sum_update(challenge, strlen(challenge));
143 base64_encode(buf, 16, out);
146 /* possible negotiate authentication with the client. Use "leader" to
147 start off the auth if necessary
149 return NULL if authentication failed
151 return "" if anonymous access
153 otherwise return username
155 char *auth_server(int fd, int module, char *addr, char *leader)
157 char *users = lp_auth_users(module);
159 char b64_challenge[30];
160 char line[MAXPATHLEN];
161 static char user[100];
167 /* if no auth list then allow anyone in! */
168 if (!users || !*users) return "";
170 gen_challenge(addr, challenge);
172 base64_encode(challenge, 16, b64_challenge);
174 io_printf(fd,"%s%s\n", leader, b64_challenge);
176 if (!read_line(fd, line, sizeof(line)-1)) {
180 memset(user, 0, sizeof(user));
181 memset(pass, 0, sizeof(pass));
183 if (sscanf(line,"%99s %29s", user, pass) != 2) {
187 users = strdup(users);
188 if (!users) return NULL;
190 for (tok=strtok(users," ,\t"); tok; tok = strtok(NULL," ,\t")) {
191 if (strcmp(tok, user) == 0) break;
199 memset(secret, 0, sizeof(secret));
200 if (!get_secret(module, user, secret, sizeof(secret)-1)) {
201 memset(secret, 0, sizeof(secret));
205 generate_hash(secret, b64_challenge, pass2);
206 memset(secret, 0, sizeof(secret));
208 if (strcmp(pass, pass2) == 0)
215 void auth_client(int fd, char *user, char *challenge)
220 if (!user || !*user) return;
222 if (!(pass=getenv("RSYNC_PASSWORD"))) {
223 pass = getpass("Password: ");
226 if (!pass || !*pass) {
230 generate_hash(pass, challenge, pass2);
232 io_printf(fd, "%s %s\n", user, pass2);