doc updates
[rsync/rsync.git] / authenticate.c
CommitLineData
31593dd6
AT
1/*
2 Copyright (C) Andrew Tridgell 1998
3
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.
8
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.
13
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.
17*/
18
19/* support rsync authentication */
20#include "rsync.h"
21
bcb7e502
AT
22/***************************************************************************
23encode a buffer using base64 - simple and slow algorithm. null terminates
24the result.
25 ***************************************************************************/
26static void base64_encode(char *buf, int len, char *out)
27{
28 char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
29 int bit_offset, byte_offset, idx, i;
30 unsigned char *d = (unsigned char *)buf;
bcb7e502
AT
31 int bytes = (len*8 + 5)/6;
32
33 memset(out, 0, bytes+1);
34
35 for (i=0;i<bytes;i++) {
36 byte_offset = (i*6)/8;
37 bit_offset = (i*6)%8;
38 if (bit_offset < 3) {
39 idx = (d[byte_offset] >> (2-bit_offset)) & 0x3F;
40 } else {
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)));
44 }
45 }
46 out[i] = b64[idx];
47 }
48}
49
50/* create a 16 byte challenge buffer */
51static void gen_challenge(char *addr, char *challenge)
52{
53 char input[32];
54 struct timeval tv;
55
56 memset(input, 0, sizeof(input));
57
e42c9458 58 strlcpy((char *)input, addr, 16);
bcb7e502
AT
59 gettimeofday(&tv, NULL);
60 SIVAL(input, 16, tv.tv_sec);
61 SIVAL(input, 20, tv.tv_usec);
62 SIVAL(input, 24, getpid());
63
64 sum_init();
65 sum_update(input, sizeof(input));
66 sum_end(challenge);
67}
68
69
70/* return the secret for a user from the sercret file. maximum length
71 is len. null terminate it */
72static int get_secret(int module, char *user, char *secret, int len)
73{
74 char *fname = lp_secrets_file(module);
75 int fd, found=0;
e42c9458
AT
76 char line[MAXPATHLEN];
77 char *p, *pass=NULL;
bcb7e502
AT
78
79 if (!fname || !*fname) return 0;
80
81 fd = open(fname,O_RDONLY);
82 if (fd == -1) return 0;
83
84 while (!found) {
85 int i = 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));
90 close(fd);
91 return 0;
92 }
93 if (line[i] == '\r') continue;
94 if (line[i] == '\n') break;
95 i++;
96 }
97 line[i] = 0;
98 if (line[0] == '#') continue;
99 p = strchr(line,':');
100 if (!p) continue;
101 *p = 0;
102 if (strcmp(user, line)) continue;
103 pass = p+1;
104 found = 1;
105 }
106
107 close(fd);
108 if (!found) return 0;
109
1a016bfd 110 strlcpy(secret, pass, len);
bcb7e502
AT
111 return 1;
112}
113
114/* generate a 16 byte hash from a password and challenge */
115void generate_hash(char *in, char *challenge, char *out)
116{
117 char buf[16];
118
119 sum_init();
120 sum_update(in, strlen(in));
121 sum_update(challenge, strlen(challenge));
122 sum_end(buf);
123
124 base64_encode(buf, 16, out);
125}
126
127/* possible negotiate authentication with the client. Use "leader" to
d0d56395
AT
128 start off the auth if necessary
129
130 return NULL if authentication failed
131
132 return "" if anonymous access
133
134 otherwise return username
135*/
136char *auth_server(int fd, int module, char *addr, char *leader)
bcb7e502
AT
137{
138 char *users = lp_auth_users(module);
139 char challenge[16];
140 char b64_challenge[30];
e42c9458 141 char line[MAXPATHLEN];
d0d56395 142 static char user[100];
bcb7e502
AT
143 char secret[100];
144 char pass[30];
145 char pass2[30];
c8e78d87 146 char *tok;
bcb7e502
AT
147
148 /* if no auth list then allow anyone in! */
d0d56395 149 if (!users || !*users) return "";
bcb7e502
AT
150
151 gen_challenge(addr, challenge);
152
153 base64_encode(challenge, 16, b64_challenge);
154
155 io_printf(fd,"%s%s\n", leader, b64_challenge);
156
157 if (!read_line(fd, line, sizeof(line)-1)) {
d0d56395 158 return NULL;
bcb7e502
AT
159 }
160
161 memset(user, 0, sizeof(user));
162 memset(pass, 0, sizeof(pass));
163
164 if (sscanf(line,"%99s %29s", user, pass) != 2) {
d0d56395 165 return NULL;
bcb7e502
AT
166 }
167
c8e78d87 168 users = strdup(users);
d0d56395 169 if (!users) return NULL;
c8e78d87
AT
170
171 for (tok=strtok(users," ,\t"); tok; tok = strtok(NULL," ,\t")) {
172 if (strcmp(tok, user) == 0) break;
173 }
174 free(users);
175
176 if (!tok) {
d0d56395 177 return NULL;
c8e78d87
AT
178 }
179
bcb7e502
AT
180 memset(secret, 0, sizeof(secret));
181 if (!get_secret(module, user, secret, sizeof(secret)-1)) {
182 memset(secret, 0, sizeof(secret));
d0d56395 183 return NULL;
bcb7e502
AT
184 }
185
186 generate_hash(secret, b64_challenge, pass2);
187 memset(secret, 0, sizeof(secret));
188
d0d56395
AT
189 if (strcmp(pass, pass2) == 0)
190 return user;
191
192 return NULL;
bcb7e502
AT
193}
194
195
196void auth_client(int fd, char *user, char *challenge)
197{
198 char *pass;
199 char pass2[30];
200
201 if (!user || !*user) return;
202
203 if (!(pass=getenv("RSYNC_PASSWORD"))) {
204 pass = getpass("Password: ");
205 }
206
207 if (!pass || !*pass) {
208 pass = "";
209 }
210
211 generate_hash(pass, challenge, pass2);
212
213 io_printf(fd, "%s %s\n", user, pass2);
214}
215