added finddead target, removed dead code and made some functions
[rsync/rsync.git] / authenticate.c
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 /***************************************************************************
23 encode a buffer using base64 - simple and slow algorithm. null terminates
24 the result.
25   ***************************************************************************/
26 static 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 */
51 static 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 */
72 static 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 */
115 static void 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 */
136 char *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
196 void 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