doc updates
[rsync/rsync.git] / authenticate.c
... / ...
CommitLineData
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
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;
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
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());
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;
76 char line[MAXPATHLEN];
77 char *p, *pass=NULL;
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
110 strlcpy(secret, pass, len);
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
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)
137{
138 char *users = lp_auth_users(module);
139 char challenge[16];
140 char b64_challenge[30];
141 char line[MAXPATHLEN];
142 static char user[100];
143 char secret[100];
144 char pass[30];
145 char pass2[30];
146 char *tok;
147
148 /* if no auth list then allow anyone in! */
149 if (!users || !*users) return "";
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)) {
158 return NULL;
159 }
160
161 memset(user, 0, sizeof(user));
162 memset(pass, 0, sizeof(pass));
163
164 if (sscanf(line,"%99s %29s", user, pass) != 2) {
165 return NULL;
166 }
167
168 users = strdup(users);
169 if (!users) return NULL;
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) {
177 return NULL;
178 }
179
180 memset(secret, 0, sizeof(secret));
181 if (!get_secret(module, user, secret, sizeof(secret)-1)) {
182 memset(secret, 0, sizeof(secret));
183 return NULL;
184 }
185
186 generate_hash(secret, b64_challenge, pass2);
187 memset(secret, 0, sizeof(secret));
188
189 if (strcmp(pass, pass2) == 0)
190 return user;
191
192 return NULL;
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