made the "max connections" and "lock file" local rather than global
[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
37f9805d 58 strlcpy((char *)input, addr, 17);
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;
d1be2312
DD
78 STRUCT_STAT st;
79 int ok = 1;
80 extern int am_root;
bcb7e502
AT
81
82 if (!fname || !*fname) return 0;
83
84 fd = open(fname,O_RDONLY);
85 if (fd == -1) return 0;
86
d1be2312
DD
87 if (do_stat(fname, &st) == -1) {
88 rprintf(FERROR,"stat(%s) : %s\n", fname, strerror(errno));
89 ok = 0;
90 } else if ((st.st_mode & 06) != 0) {
91 rprintf(FERROR,"secrets file must not be other-accessible\n");
92 ok = 0;
93 } else if (am_root && (st.st_uid != 0)) {
94 rprintf(FERROR,"secrets file must be owned by root when running as root\n");
95 ok = 0;
96 }
97 if (!ok) {
98 rprintf(FERROR,"continuing without secrets file\n");
99 close(fd);
100 return 0;
101 }
102
bcb7e502
AT
103 while (!found) {
104 int i = 0;
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));
109 close(fd);
110 return 0;
111 }
112 if (line[i] == '\r') continue;
113 if (line[i] == '\n') break;
114 i++;
115 }
116 line[i] = 0;
117 if (line[0] == '#') continue;
118 p = strchr(line,':');
119 if (!p) continue;
120 *p = 0;
121 if (strcmp(user, line)) continue;
122 pass = p+1;
123 found = 1;
124 }
125
126 close(fd);
127 if (!found) return 0;
128
1a016bfd 129 strlcpy(secret, pass, len);
bcb7e502
AT
130 return 1;
131}
132
133/* generate a 16 byte hash from a password and challenge */
6e4fb64e 134static void generate_hash(char *in, char *challenge, char *out)
bcb7e502
AT
135{
136 char buf[16];
137
138 sum_init();
139 sum_update(in, strlen(in));
140 sum_update(challenge, strlen(challenge));
141 sum_end(buf);
142
143 base64_encode(buf, 16, out);
144}
145
146/* possible negotiate authentication with the client. Use "leader" to
d0d56395
AT
147 start off the auth if necessary
148
149 return NULL if authentication failed
150
151 return "" if anonymous access
152
153 otherwise return username
154*/
155char *auth_server(int fd, int module, char *addr, char *leader)
bcb7e502
AT
156{
157 char *users = lp_auth_users(module);
158 char challenge[16];
159 char b64_challenge[30];
e42c9458 160 char line[MAXPATHLEN];
d0d56395 161 static char user[100];
bcb7e502
AT
162 char secret[100];
163 char pass[30];
164 char pass2[30];
c8e78d87 165 char *tok;
bcb7e502
AT
166
167 /* if no auth list then allow anyone in! */
d0d56395 168 if (!users || !*users) return "";
bcb7e502
AT
169
170 gen_challenge(addr, challenge);
171
172 base64_encode(challenge, 16, b64_challenge);
173
174 io_printf(fd,"%s%s\n", leader, b64_challenge);
175
176 if (!read_line(fd, line, sizeof(line)-1)) {
d0d56395 177 return NULL;
bcb7e502
AT
178 }
179
180 memset(user, 0, sizeof(user));
181 memset(pass, 0, sizeof(pass));
182
183 if (sscanf(line,"%99s %29s", user, pass) != 2) {
d0d56395 184 return NULL;
bcb7e502
AT
185 }
186
c8e78d87 187 users = strdup(users);
d0d56395 188 if (!users) return NULL;
c8e78d87
AT
189
190 for (tok=strtok(users," ,\t"); tok; tok = strtok(NULL," ,\t")) {
191 if (strcmp(tok, user) == 0) break;
192 }
193 free(users);
194
195 if (!tok) {
d0d56395 196 return NULL;
c8e78d87
AT
197 }
198
bcb7e502
AT
199 memset(secret, 0, sizeof(secret));
200 if (!get_secret(module, user, secret, sizeof(secret)-1)) {
201 memset(secret, 0, sizeof(secret));
d0d56395 202 return NULL;
bcb7e502
AT
203 }
204
205 generate_hash(secret, b64_challenge, pass2);
206 memset(secret, 0, sizeof(secret));
207
d0d56395
AT
208 if (strcmp(pass, pass2) == 0)
209 return user;
210
211 return NULL;
bcb7e502
AT
212}
213
214
215void auth_client(int fd, char *user, char *challenge)
216{
217 char *pass;
218 char pass2[30];
219
220 if (!user || !*user) return;
221
222 if (!(pass=getenv("RSYNC_PASSWORD"))) {
223 pass = getpass("Password: ");
224 }
225
226 if (!pass || !*pass) {
227 pass = "";
228 }
229
230 generate_hash(pass, challenge, pass2);
231
232 io_printf(fd, "%s %s\n", user, pass2);
233}
234