00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "rsync.h"
00022
00023 extern char *password_file;
00024
00025
00026
00027
00028
00029 void base64_encode(char *buf, int len, char *out, int pad)
00030 {
00031 char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
00032 int bit_offset, byte_offset, idx, i;
00033 unsigned char *d = (unsigned char *)buf;
00034 int bytes = (len*8 + 5)/6;
00035
00036 for (i = 0; i < bytes; i++) {
00037 byte_offset = (i*6)/8;
00038 bit_offset = (i*6)%8;
00039 if (bit_offset < 3) {
00040 idx = (d[byte_offset] >> (2-bit_offset)) & 0x3F;
00041 } else {
00042 idx = (d[byte_offset] << (bit_offset-2)) & 0x3F;
00043 if (byte_offset+1 < len) {
00044 idx |= (d[byte_offset+1] >> (8-(bit_offset-2)));
00045 }
00046 }
00047 out[i] = b64[idx];
00048 }
00049
00050 while (pad && (i % 4))
00051 out[i++] = '=';
00052
00053 out[i] = '\0';
00054 }
00055
00056
00057 static void gen_challenge(char *addr, char *challenge)
00058 {
00059 char input[32];
00060 char md4_out[MD4_SUM_LENGTH];
00061 struct timeval tv;
00062
00063 memset(input, 0, sizeof input);
00064
00065 strlcpy((char *)input, addr, 17);
00066 sys_gettimeofday(&tv);
00067 SIVAL(input, 16, tv.tv_sec);
00068 SIVAL(input, 20, tv.tv_usec);
00069 SIVAL(input, 24, getpid());
00070
00071 sum_init(0);
00072 sum_update(input, sizeof input);
00073 sum_end(md4_out);
00074
00075 base64_encode(md4_out, MD4_SUM_LENGTH, challenge, 0);
00076 }
00077
00078
00079
00080
00081 static int get_secret(int module, char *user, char *secret, int len)
00082 {
00083 char *fname = lp_secrets_file(module);
00084 STRUCT_STAT st;
00085 int fd, ok = 1;
00086 char ch, *p;
00087
00088 if (!fname || !*fname)
00089 return 0;
00090
00091 if ((fd = open(fname, O_RDONLY)) < 0)
00092 return 0;
00093
00094 if (do_stat(fname, &st) == -1) {
00095 rsyserr(FLOG, errno, "stat(%s)", fname);
00096 ok = 0;
00097 } else if (lp_strict_modes(module)) {
00098 if ((st.st_mode & 06) != 0) {
00099 rprintf(FLOG, "secrets file must not be other-accessible (see strict modes option)\n");
00100 ok = 0;
00101 } else if (MY_UID() == 0 && st.st_uid != 0) {
00102 rprintf(FLOG, "secrets file must be owned by root when running as root (see strict modes)\n");
00103 ok = 0;
00104 }
00105 }
00106 if (!ok) {
00107 rprintf(FLOG, "continuing without secrets file\n");
00108 close(fd);
00109 return 0;
00110 }
00111
00112 if (*user == '#') {
00113
00114 close(fd);
00115 return 0;
00116 }
00117
00118
00119 p = user;
00120 while (1) {
00121 if (read(fd, &ch, 1) != 1) {
00122 close(fd);
00123 return 0;
00124 }
00125 if (ch == '\n')
00126 p = user;
00127 else if (p) {
00128 if (*p == ch)
00129 p++;
00130 else if (!*p && ch == ':')
00131 break;
00132 else
00133 p = NULL;
00134 }
00135 }
00136
00137
00138 p = secret;
00139 while (len > 0) {
00140 if (read(fd, p, 1) != 1 || *p == '\n')
00141 break;
00142 if (*p == '\r')
00143 continue;
00144 p++;
00145 len--;
00146 }
00147 *p = '\0';
00148 close(fd);
00149
00150 return 1;
00151 }
00152
00153 static char *getpassf(char *filename)
00154 {
00155 STRUCT_STAT st;
00156 char buffer[512], *p;
00157 int fd, n, ok = 1;
00158 char *envpw = getenv("RSYNC_PASSWORD");
00159
00160 if (!filename)
00161 return NULL;
00162
00163 if ((fd = open(filename,O_RDONLY)) < 0) {
00164 rsyserr(FERROR, errno, "could not open password file \"%s\"",
00165 filename);
00166 if (envpw)
00167 rprintf(FERROR, "falling back to RSYNC_PASSWORD environment variable.\n");
00168 return NULL;
00169 }
00170
00171 if (do_stat(filename, &st) == -1) {
00172 rsyserr(FERROR, errno, "stat(%s)", filename);
00173 ok = 0;
00174 } else if ((st.st_mode & 06) != 0) {
00175 rprintf(FERROR,"password file must not be other-accessible\n");
00176 ok = 0;
00177 } else if (MY_UID() == 0 && st.st_uid != 0) {
00178 rprintf(FERROR,"password file must be owned by root when running as root\n");
00179 ok = 0;
00180 }
00181 if (!ok) {
00182 rprintf(FERROR,"continuing without password file\n");
00183 if (envpw)
00184 rprintf(FERROR, "using RSYNC_PASSWORD environment variable.\n");
00185 close(fd);
00186 return NULL;
00187 }
00188
00189 if (envpw)
00190 rprintf(FERROR, "RSYNC_PASSWORD environment variable ignored\n");
00191
00192 n = read(fd, buffer, sizeof buffer - 1);
00193 close(fd);
00194 if (n > 0) {
00195 buffer[n] = '\0';
00196 if ((p = strtok(buffer, "\n\r")) != NULL)
00197 return strdup(p);
00198 }
00199
00200 return NULL;
00201 }
00202
00203
00204
00205 static void generate_hash(char *in, char *challenge, char *out)
00206 {
00207 char buf[MD4_SUM_LENGTH];
00208
00209 sum_init(0);
00210 sum_update(in, strlen(in));
00211 sum_update(challenge, strlen(challenge));
00212 sum_end(buf);
00213
00214 base64_encode(buf, MD4_SUM_LENGTH, out, 0);
00215 }
00216
00217
00218
00219
00220
00221
00222
00223 char *auth_server(int f_in, int f_out, int module, char *host, char *addr,
00224 char *leader)
00225 {
00226 char *users = lp_auth_users(module);
00227 char challenge[MD4_SUM_LENGTH*2];
00228 char line[BIGPATHBUFLEN];
00229 char secret[512];
00230 char pass2[MD4_SUM_LENGTH*2];
00231 char *tok, *pass;
00232
00233
00234 if (!users || !*users)
00235 return "";
00236
00237 gen_challenge(addr, challenge);
00238
00239 io_printf(f_out, "%s%s\n", leader, challenge);
00240
00241 if (!read_line(f_in, line, sizeof line - 1)
00242 || (pass = strchr(line, ' ')) == NULL) {
00243 rprintf(FLOG, "auth failed on module %s from %s (%s): "
00244 "invalid challenge response\n",
00245 lp_name(module), host, addr);
00246 return NULL;
00247 }
00248 *pass++ = '\0';
00249
00250 if (!(users = strdup(users)))
00251 out_of_memory("auth_server");
00252
00253 for (tok = strtok(users, " ,\t"); tok; tok = strtok(NULL, " ,\t")) {
00254 if (wildmatch(tok, line))
00255 break;
00256 }
00257 free(users);
00258
00259 if (!tok) {
00260 rprintf(FLOG, "auth failed on module %s from %s (%s): "
00261 "unauthorized user\n",
00262 lp_name(module), host, addr);
00263 return NULL;
00264 }
00265
00266 memset(secret, 0, sizeof secret);
00267 if (!get_secret(module, line, secret, sizeof secret - 1)) {
00268 memset(secret, 0, sizeof secret);
00269 rprintf(FLOG, "auth failed on module %s from %s (%s): "
00270 "missing secret for user \"%s\"\n",
00271 lp_name(module), host, addr, line);
00272 return NULL;
00273 }
00274
00275 generate_hash(secret, challenge, pass2);
00276 memset(secret, 0, sizeof secret);
00277
00278 if (strcmp(pass, pass2) != 0) {
00279 rprintf(FLOG, "auth failed on module %s from %s (%s): "
00280 "password mismatch\n",
00281 lp_name(module), host, addr);
00282 return NULL;
00283 }
00284
00285 return strdup(line);
00286 }
00287
00288
00289 void auth_client(int fd, char *user, char *challenge)
00290 {
00291 char *pass;
00292 char pass2[MD4_SUM_LENGTH*2];
00293
00294 if (!user || !*user)
00295 user = "nobody";
00296
00297 if (!(pass = getpassf(password_file))
00298 && !(pass = getenv("RSYNC_PASSWORD"))) {
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308 pass = getpass("Password: ");
00309 }
00310
00311 if (!pass)
00312 pass = "";
00313
00314 generate_hash(pass, challenge, pass2);
00315 io_printf(fd, "%s %s\n", user, pass2);
00316 }