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, 16);
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];
79 if (!fname || !*fname) return 0;
81 fd = open(fname,O_RDONLY);
82 if (fd == -1) return 0;
86 memset(line, 0, sizeof(line));
87 while (i<(sizeof(line)-1)) {
88 if (read(fd, &line[i], 1) != 1) {
89 memset(line, 0, sizeof(line));
93 if (line[i] == '\r') continue;
94 if (line[i] == '\n') break;
98 if (line[0] == '#') continue;
102 if (strcmp(user, line)) continue;
108 if (!found) return 0;
110 strlcpy(secret, pass, len);
114 /* generate a 16 byte hash from a password and challenge */
115 void generate_hash(char *in, char *challenge, char *out)
120 sum_update(in, strlen(in));
121 sum_update(challenge, strlen(challenge));
124 base64_encode(buf, 16, out);
127 /* possible negotiate authentication with the client. Use "leader" to
128 start off the auth if necessary
130 return NULL if authentication failed
132 return "" if anonymous access
134 otherwise return username
136 char *auth_server(int fd, int module, char *addr, char *leader)
138 char *users = lp_auth_users(module);
140 char b64_challenge[30];
141 char line[MAXPATHLEN];
142 static char user[100];
148 /* if no auth list then allow anyone in! */
149 if (!users || !*users) return "";
151 gen_challenge(addr, challenge);
153 base64_encode(challenge, 16, b64_challenge);
155 io_printf(fd,"%s%s\n", leader, b64_challenge);
157 if (!read_line(fd, line, sizeof(line)-1)) {
161 memset(user, 0, sizeof(user));
162 memset(pass, 0, sizeof(pass));
164 if (sscanf(line,"%99s %29s", user, pass) != 2) {
168 users = strdup(users);
169 if (!users) return NULL;
171 for (tok=strtok(users," ,\t"); tok; tok = strtok(NULL," ,\t")) {
172 if (strcmp(tok, user) == 0) break;
180 memset(secret, 0, sizeof(secret));
181 if (!get_secret(module, user, secret, sizeof(secret)-1)) {
182 memset(secret, 0, sizeof(secret));
186 generate_hash(secret, b64_challenge, pass2);
187 memset(secret, 0, sizeof(secret));
189 if (strcmp(pass, pass2) == 0)
196 void auth_client(int fd, char *user, char *challenge)
201 if (!user || !*user) return;
203 if (!(pass=getenv("RSYNC_PASSWORD"))) {
204 pass = getpass("Password: ");
207 if (!pass || !*pass) {
211 generate_hash(pass, challenge, pass2);
213 io_printf(fd, "%s %s\n", user, pass2);