Main Page   Alphabetical List   Data Structures   File List   Data Fields   Globals   Related Pages  

authenticate.c

Go to the documentation of this file.
00001 /* -*- c-file-style: "linux"; -*-
00002    
00003    Copyright (C) 1998-2000 by Andrew Tridgell 
00004    
00005    This program is free software; you can redistribute it and/or modify
00006    it under the terms of the GNU General Public License as published by
00007    the Free Software Foundation; either version 2 of the License, or
00008    (at your option) any later version.
00009    
00010    This program is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013    GNU General Public License for more details.
00014    
00015    You should have received a copy of the GNU General Public License
00016    along with this program; if not, write to the Free Software
00017    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00018 */
00019 
00020 /* support rsync authentication */
00021 #include "rsync.h"
00022 
00023 /***************************************************************************
00024 encode a buffer using base64 - simple and slow algorithm. null terminates
00025 the result.
00026   ***************************************************************************/
00027 static void base64_encode(char *buf, int len, char *out)
00028 {
00029         char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
00030         int bit_offset, byte_offset, idx, i;
00031         unsigned char *d = (unsigned char *)buf;
00032         int bytes = (len*8 + 5)/6;
00033 
00034         memset(out, 0, bytes+1);
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 
00051 /* create a 16 byte challenge buffer */
00052 static void gen_challenge(char *addr, char *challenge)
00053 {
00054         char input[32];
00055         struct timeval tv;
00056 
00057         memset(input, 0, sizeof(input));
00058 
00059         strlcpy((char *)input, addr, 17);
00060         sys_gettimeofday(&tv);
00061         SIVAL(input, 16, tv.tv_sec);
00062         SIVAL(input, 20, tv.tv_usec);
00063         SIVAL(input, 24, getpid());
00064 
00065         sum_init();
00066         sum_update(input, sizeof(input));
00067         sum_end(challenge);
00068 }
00069 
00070 
00071 /* return the secret for a user from the sercret file. maximum length
00072    is len. null terminate it */
00073 static int get_secret(int module, char *user, char *secret, int len)
00074 {
00075         char *fname = lp_secrets_file(module);
00076         int fd, found=0;
00077         char line[MAXPATHLEN];
00078         char *p, *pass=NULL;
00079         STRUCT_STAT st;
00080         int ok = 1;
00081         extern int am_root;
00082 
00083         if (!fname || !*fname) return 0;
00084 
00085         fd = open(fname,O_RDONLY);
00086         if (fd == -1) return 0;
00087 
00088         if (do_stat(fname, &st) == -1) {
00089                 rsyserr(FERROR, errno, "stat(%s)", fname);
00090                 ok = 0;
00091         } else if (lp_strict_modes(module)) {
00092                 if ((st.st_mode & 06) != 0) {
00093                         rprintf(FERROR,"secrets file must not be other-accessible (see strict modes option)\n");
00094                         ok = 0;
00095                 } else if (am_root && (st.st_uid != 0)) {
00096                         rprintf(FERROR,"secrets file must be owned by root when running as root (see strict modes)\n");
00097                         ok = 0;
00098                 }
00099         }
00100         if (!ok) {
00101                 rprintf(FERROR,"continuing without secrets file\n");
00102                 close(fd);
00103                 return 0;
00104         }
00105 
00106         while (!found) {
00107                 int i = 0;
00108                 memset(line, 0, sizeof line);
00109                 while ((size_t) i < (sizeof(line)-1)) {
00110                         if (read(fd, &line[i], 1) != 1) {
00111                                 memset(line, 0, sizeof(line));
00112                                 close(fd);
00113                                 return 0;
00114                         }
00115                         if (line[i] == '\r') continue;
00116                         if (line[i] == '\n') break;
00117                         i++;
00118                 }
00119                 line[i] = 0;
00120                 if (line[0] == '#') continue;
00121                 p = strchr(line,':');
00122                 if (!p) continue;
00123                 *p = 0;
00124                 if (strcmp(user, line)) continue;
00125                 pass = p+1;
00126                 found = 1;
00127         }
00128 
00129         close(fd);
00130         if (!found) return 0;
00131 
00132         strlcpy(secret, pass, len);
00133         return 1;
00134 }
00135 
00136 static char *getpassf(char *filename)
00137 {
00138         char buffer[100];
00139         int fd=0;
00140         STRUCT_STAT st;
00141         int ok = 1;
00142         extern int am_root;
00143         char *envpw=getenv("RSYNC_PASSWORD");
00144 
00145         if (!filename) return NULL;
00146 
00147         if ( (fd=open(filename,O_RDONLY)) == -1) {
00148                 rsyserr(FERROR, errno, "could not open password file \"%s\"",filename);
00149                 if (envpw) rprintf(FERROR,"falling back to RSYNC_PASSWORD environment variable.\n");    
00150                 return NULL;
00151         }
00152         
00153         if (do_stat(filename, &st) == -1) {
00154                 rsyserr(FERROR, errno, "stat(%s)", filename);
00155                 ok = 0;
00156         } else if ((st.st_mode & 06) != 0) {
00157                 rprintf(FERROR,"password file must not be other-accessible\n");
00158                 ok = 0;
00159         } else if (am_root && (st.st_uid != 0)) {
00160                 rprintf(FERROR,"password file must be owned by root when running as root\n");
00161                 ok = 0;
00162         }
00163         if (!ok) {
00164                 rprintf(FERROR,"continuing without password file\n");
00165                 if (envpw) rprintf(FERROR,"using RSYNC_PASSWORD environment variable.\n");
00166                 close(fd);
00167                 return NULL;
00168         }
00169 
00170         if (envpw) rprintf(FERROR,"RSYNC_PASSWORD environment variable ignored\n");
00171 
00172         buffer[sizeof(buffer)-1]='\0';
00173         if (read(fd,buffer,sizeof(buffer)-1) > 0)
00174         {
00175                 char *p = strtok(buffer,"\n\r");
00176                 close(fd);
00177                 if (p) p = strdup(p);
00178                 return p;
00179         }       
00180 
00181         return NULL;
00182 }
00183 
00184 /* generate a 16 byte hash from a password and challenge */
00185 static void generate_hash(char *in, char *challenge, char *out)
00186 {
00187         char buf[16];
00188 
00189         sum_init();
00190         sum_update(in, strlen(in));
00191         sum_update(challenge, strlen(challenge));
00192         sum_end(buf);
00193 
00194         base64_encode(buf, 16, out);
00195 }
00196 
00197 /* possible negotiate authentication with the client. Use "leader" to
00198    start off the auth if necessary 
00199 
00200    return NULL if authentication failed
00201 
00202    return "" if anonymous access
00203 
00204    otherwise return username
00205 */
00206 char *auth_server(int fd, int module, char *addr, char *leader)
00207 {
00208         char *users = lp_auth_users(module);
00209         char challenge[16];
00210         char b64_challenge[30];
00211         char line[MAXPATHLEN];
00212         static char user[100];
00213         char secret[100];
00214         char pass[30];
00215         char pass2[30];
00216         char *tok;
00217 
00218         /* if no auth list then allow anyone in! */
00219         if (!users || !*users) return "";
00220 
00221         gen_challenge(addr, challenge);
00222         
00223         base64_encode(challenge, 16, b64_challenge);
00224 
00225         io_printf(fd,"%s%s\n", leader, b64_challenge);
00226 
00227         if (!read_line(fd, line, sizeof(line)-1)) {
00228                 return NULL;
00229         }
00230 
00231         memset(user, 0, sizeof(user));
00232         memset(pass, 0, sizeof(pass));
00233 
00234         if (sscanf(line,"%99s %29s", user, pass) != 2) {
00235                 return NULL;
00236         }
00237         
00238         users = strdup(users);
00239         if (!users) return NULL;
00240 
00241         for (tok=strtok(users," ,\t"); tok; tok = strtok(NULL," ,\t")) {
00242                 if (fnmatch(tok, user, 0) == 0) break;
00243         }
00244         free(users);
00245 
00246         if (!tok) {
00247                 return NULL;
00248         }
00249         
00250         memset(secret, 0, sizeof(secret));
00251         if (!get_secret(module, user, secret, sizeof(secret)-1)) {
00252                 memset(secret, 0, sizeof(secret));
00253                 return NULL;
00254         }
00255 
00256         generate_hash(secret, b64_challenge, pass2);
00257         memset(secret, 0, sizeof(secret));
00258         
00259         if (strcmp(pass, pass2) == 0)
00260                 return user;
00261 
00262         return NULL;
00263 }
00264 
00265 
00266 void auth_client(int fd, char *user, char *challenge)
00267 {
00268         char *pass;
00269         char pass2[30];
00270         extern char *password_file;
00271 
00272         if (!user || !*user) return;
00273 
00274         if (!(pass=getpassf(password_file)) && !(pass=getenv("RSYNC_PASSWORD"))) {
00275                 /* XXX: cyeoh says that getpass is deprecated, because
00276                    it may return a truncated password on some systems,
00277                    and it is not in the LSB. */
00278                 pass = getpass("Password: ");
00279         }
00280 
00281         if (!pass || !*pass) {
00282                 pass = "";
00283         }
00284 
00285         generate_hash(pass, challenge, pass2);
00286         io_printf(fd, "%s %s\n", user, pass2);
00287 }
00288 
00289 

Generated on Tue Apr 16 12:37:36 2002 for rsync by doxygen1.2.15