made the "max connections" and "lock file" local rather than global
[rsync/rsync.git] / authenticate.c
index 4f4aac2..ba83a89 100644 (file)
@@ -28,7 +28,6 @@ static void base64_encode(char *buf, int len, char *out)
        char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
        int bit_offset, byte_offset, idx, i;
        unsigned char *d = (unsigned char *)buf;
-       char *p;
        int bytes = (len*8 + 5)/6;
 
        memset(out, 0, bytes+1);
@@ -56,7 +55,7 @@ static void gen_challenge(char *addr, char *challenge)
 
        memset(input, 0, sizeof(input));
 
-       strncpy((char *)input, addr, 16);
+       strlcpy((char *)input, addr, 17);
        gettimeofday(&tv, NULL);
        SIVAL(input, 16, tv.tv_sec);
        SIVAL(input, 20, tv.tv_usec);
@@ -74,14 +73,33 @@ static int get_secret(int module, char *user, char *secret, int len)
 {
        char *fname = lp_secrets_file(module);
        int fd, found=0;
-       char line[1024];
-       char *p, *pass;
+       char line[MAXPATHLEN];
+       char *p, *pass=NULL;
+       STRUCT_STAT st;
+       int ok = 1;
+       extern int am_root;
 
        if (!fname || !*fname) return 0;
 
        fd = open(fname,O_RDONLY);
        if (fd == -1) return 0;
 
+       if (do_stat(fname, &st) == -1) {
+               rprintf(FERROR,"stat(%s) : %s\n", fname, strerror(errno));
+               ok = 0;
+       } else if ((st.st_mode & 06) != 0) {
+               rprintf(FERROR,"secrets file must not be other-accessible\n");
+               ok = 0;
+       } else if (am_root && (st.st_uid != 0)) {
+               rprintf(FERROR,"secrets file must be owned by root when running as root\n");
+               ok = 0;
+       }
+       if (!ok) {
+               rprintf(FERROR,"continuing without secrets file\n");
+               close(fd);
+               return 0;
+       }
+
        while (!found) {
                int i = 0;
                memset(line, 0, sizeof(line));
@@ -108,17 +126,12 @@ static int get_secret(int module, char *user, char *secret, int len)
        close(fd);
        if (!found) return 0;
 
-       if (strlen(pass) > len-1) {
-               memset(line, 0, sizeof(line));
-               return 0;
-       }
-
-       strcpy(secret, pass);
+       strlcpy(secret, pass, len);
        return 1;
 }
 
 /* generate a 16 byte hash from a password and challenge */
-void generate_hash(char *in, char *challenge, char *out)
+static void generate_hash(char *in, char *challenge, char *out)
 {
        char buf[16];
 
@@ -131,20 +144,28 @@ void generate_hash(char *in, char *challenge, char *out)
 }
 
 /* possible negotiate authentication with the client. Use "leader" to
-   start off the auth if necessary */
-int auth_server(int fd, int module, char *addr, char *leader)
+   start off the auth if necessary 
+
+   return NULL if authentication failed
+
+   return "" if anonymous access
+
+   otherwise return username
+*/
+char *auth_server(int fd, int module, char *addr, char *leader)
 {
        char *users = lp_auth_users(module);
        char challenge[16];
        char b64_challenge[30];
-       char line[1024];
-       char user[100];
+       char line[MAXPATHLEN];
+       static char user[100];
        char secret[100];
        char pass[30];
        char pass2[30];
+       char *tok;
 
        /* if no auth list then allow anyone in! */
-       if (!users || !*users) return 1;
+       if (!users || !*users) return "";
 
        gen_challenge(addr, challenge);
        
@@ -153,26 +174,41 @@ int auth_server(int fd, int module, char *addr, char *leader)
        io_printf(fd,"%s%s\n", leader, b64_challenge);
 
        if (!read_line(fd, line, sizeof(line)-1)) {
-               return 0;
+               return NULL;
        }
 
        memset(user, 0, sizeof(user));
        memset(pass, 0, sizeof(pass));
 
        if (sscanf(line,"%99s %29s", user, pass) != 2) {
-               return 0;
+               return NULL;
+       }
+
+       users = strdup(users);
+       if (!users) return NULL;
+
+       for (tok=strtok(users," ,\t"); tok; tok = strtok(NULL," ,\t")) {
+               if (strcmp(tok, user) == 0) break;
        }
+       free(users);
 
+       if (!tok) {
+               return NULL;
+       }
+       
        memset(secret, 0, sizeof(secret));
        if (!get_secret(module, user, secret, sizeof(secret)-1)) {
                memset(secret, 0, sizeof(secret));
-               return 0;
+               return NULL;
        }
 
        generate_hash(secret, b64_challenge, pass2);
        memset(secret, 0, sizeof(secret));
        
-       return (strcmp(pass, pass2) == 0);
+       if (strcmp(pass, pass2) == 0)
+               return user;
+
+       return NULL;
 }