Network Block Device @PACKAGE_VERSION@

nbdsrv.c

Go to the documentation of this file.
00001 #include "config.h"
00002 #include "nbd-debug.h"
00003 
00004 #include <nbdsrv.h>
00005 
00006 #include <assert.h>
00007 #include <ctype.h>
00008 #include <netdb.h>
00009 #include <stdlib.h>
00010 #include <stdio.h>
00011 #include <string.h>
00012 #include <syslog.h>
00013 #include <unistd.h>
00014 
00015 #include <sys/stat.h>
00016 #include <sys/types.h>
00017 #include <sys/socket.h>
00018 
00019 #define LINELEN 256       /**< Size of static buffer used to read the
00020                                authorization file (yuck) */
00021 
00022 #include <cliserv.h>
00023 
00024 bool address_matches(const char* mask, const void* addr, int af, GError** err) {
00025         struct addrinfo *res, *aitmp, hints;
00026         char *masksep;
00027         char privmask[strlen(mask)+1];
00028         int masklen;
00029         int addrlen = af == AF_INET ? 4 : 16;
00030 
00031         assert(af == AF_INET || af == AF_INET6);
00032 
00033         strcpy(privmask, mask);
00034 
00035         memset(&hints, 0, sizeof(hints));
00036         hints.ai_family = AF_UNSPEC;
00037         hints.ai_flags = AI_NUMERICHOST;
00038 
00039         if((masksep = strchr(privmask, '/'))) {
00040                 *masksep = '\0';
00041                 masklen = strtol(++masksep, NULL, 10);
00042         } else {
00043                 masklen = addrlen * 8;
00044         }
00045 
00046         int e;
00047         if((e = getaddrinfo(privmask, NULL, &hints, &res))) {
00048                 g_set_error(err, NBDS_ERR, NBDS_ERR_GAI, "could not parse netmask line: %s", gai_strerror(e));
00049                 return false;
00050         }
00051         aitmp = res;
00052         while(res) {
00053                 const uint8_t* byte_s = addr;
00054                 uint8_t* byte_t;
00055                 uint8_t mask = 0;
00056                 int len_left = masklen;
00057                 if(res->ai_family != af) {
00058                         goto next;
00059                 }
00060                 switch(af) {
00061                         case AF_INET:
00062                                 byte_t = (uint8_t*)(&(((struct sockaddr_in*)(res->ai_addr))->sin_addr));
00063                                 break;
00064                         case AF_INET6:
00065                                 byte_t = (uint8_t*)(&(((struct sockaddr_in6*)(res->ai_addr))->sin6_addr));
00066                                 break;
00067                 }
00068                 while(len_left >= 8) {
00069                         if(*byte_s != *byte_t) {
00070                                 goto next;
00071                         }
00072                         byte_s++; byte_t++;
00073                         len_left -= 8;
00074                 }
00075                 if(len_left) {
00076                         mask = getmaskbyte(len_left);
00077                         if((*byte_s & mask) != (*byte_t & mask)) {
00078                                 goto  next;
00079                         }
00080                 }
00081                 freeaddrinfo(aitmp);
00082                 return true;
00083         next:
00084                 res = res->ai_next;
00085         }
00086         freeaddrinfo(aitmp);
00087         return false;
00088 }
00089 
00090 uint8_t getmaskbyte(int masklen) {
00091         if(masklen >= 8) {
00092                 return 0xFF;
00093         }
00094         uint8_t retval = 0;
00095         for(int i = 7; i + masklen > 7; i--) {
00096                 retval |= 1 << i;
00097         }
00098 
00099         return retval;
00100 }
00101 
00102 int authorized_client(CLIENT *opts) {
00103         FILE *f ;
00104         char line[LINELEN]; 
00105         char *tmp;
00106         struct in_addr addr;
00107         struct in_addr client;
00108         struct in_addr cltemp;
00109         int len;
00110 
00111         if ((f=fopen(opts->server->authname,"r"))==NULL) {
00112                 msg(LOG_INFO, "Can't open authorization file %s (%s).",
00113                     opts->server->authname, strerror(errno));
00114                 return 1 ; 
00115         }
00116   
00117         while (fgets(line,LINELEN,f)!=NULL) {
00118                 char* pos;
00119                 /* Drop comments */
00120                 if((pos = strchr(line, '#'))) {
00121                         *pos = '\0';
00122                 }
00123                 /* Skip whitespace */
00124                 pos = line;
00125                 while((*pos) && isspace(*pos)) {
00126                         pos++;
00127                 }
00128                 /* Skip content-free lines */
00129                 if(!(*pos)) {
00130                         continue;
00131                 }
00132                 struct sockaddr* sa = (struct sockaddr*)&opts->clientaddr;
00133                 if(address_matches(line, sa->sa_data, sa->sa_family, NULL)) {
00134                         fclose(f);
00135                         return 1;
00136                 }
00137         }
00138         fclose(f);
00139         return 0;
00140 }
00141 
00142 /**
00143  * duplicate server
00144  * @param s the old server we want to duplicate
00145  * @return new duplicated server
00146  **/
00147 SERVER* dup_serve(const SERVER *const s) {
00148         SERVER *serve = NULL;
00149 
00150         serve=g_new0(SERVER, 1);
00151         if(serve == NULL)
00152                 return NULL;
00153 
00154         if(s->exportname)
00155                 serve->exportname = g_strdup(s->exportname);
00156 
00157         serve->expected_size = s->expected_size;
00158 
00159         if(s->listenaddr)
00160                 serve->listenaddr = g_strdup(s->listenaddr);
00161 
00162         serve->port = s->port;
00163 
00164         if(s->authname)
00165                 serve->authname = strdup(s->authname);
00166 
00167         serve->flags = s->flags;
00168         serve->socket = s->socket;
00169         serve->socket_family = s->socket_family;
00170         serve->virtstyle = s->virtstyle;
00171         serve->cidrlen = s->cidrlen;
00172 
00173         if(s->prerun)
00174                 serve->prerun = g_strdup(s->prerun);
00175 
00176         if(s->postrun)
00177                 serve->postrun = g_strdup(s->postrun);
00178 
00179         if(s->transactionlog)
00180                 serve->transactionlog = g_strdup(s->transactionlog);
00181         
00182         if(s->servename)
00183                 serve->servename = g_strdup(s->servename);
00184 
00185         serve->max_connections = s->max_connections;
00186 
00187         return serve;
00188 }
00189 
00190 int append_serve(const SERVER *const s, GArray *const a) {
00191         SERVER *ns = NULL;
00192         struct addrinfo hints;
00193         struct addrinfo *ai = NULL;
00194         struct addrinfo *rp = NULL;
00195         char   host[NI_MAXHOST];
00196         gchar  *port = NULL;
00197         int e;
00198         int ret;
00199 
00200         assert(s != NULL);
00201         if(a == NULL) {
00202                 return -1;
00203         }
00204 
00205         port = g_strdup_printf("%d", s->port);
00206 
00207         memset(&hints,'\0',sizeof(hints));
00208         hints.ai_family = AF_UNSPEC;
00209         hints.ai_socktype = SOCK_STREAM;
00210         hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE;
00211         hints.ai_protocol = IPPROTO_TCP;
00212 
00213         e = getaddrinfo(s->listenaddr, port, &hints, &ai);
00214 
00215         if (port)
00216                 g_free(port);
00217 
00218         if(e == 0) {
00219                 for (rp = ai; rp != NULL; rp = rp->ai_next) {
00220                         e = getnameinfo(rp->ai_addr, rp->ai_addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST);
00221 
00222                         if (e != 0) { // error
00223                                 fprintf(stderr, "getnameinfo: %s\n", gai_strerror(e));
00224                                 continue;
00225                         }
00226 
00227                         // duplicate server and set listenaddr to resolved IP address
00228                         ns = dup_serve (s);
00229                         if (ns) {
00230                                 ns->listenaddr = g_strdup(host);
00231                                 ns->socket_family = rp->ai_family;
00232                                 g_array_append_val(a, *ns);
00233                                 free(ns);
00234                                 ns = NULL;
00235                         }
00236                 }
00237 
00238                 ret = 0;
00239         } else {
00240                 fprintf(stderr, "getaddrinfo failed on listen host/address: %s (%s)\n", s->listenaddr ? s->listenaddr : "any", gai_strerror(e));
00241                 ret = -1;
00242         }
00243 
00244         if (ai)
00245                 freeaddrinfo(ai);
00246 
00247         return ret;
00248 }
00249 
00250 uint64_t size_autodetect(int fhandle) {
00251         off_t es;
00252         u64 bytes __attribute__((unused));
00253         struct stat stat_buf;
00254         int error;
00255 
00256 #ifdef HAVE_SYS_MOUNT_H
00257 #ifdef HAVE_SYS_IOCTL_H
00258 #ifdef BLKGETSIZE64
00259         DEBUG("looking for export size with ioctl BLKGETSIZE64\n");
00260         if (!ioctl(fhandle, BLKGETSIZE64, &bytes) && bytes) {
00261                 return bytes;
00262         }
00263 #endif /* BLKGETSIZE64 */
00264 #endif /* HAVE_SYS_IOCTL_H */
00265 #endif /* HAVE_SYS_MOUNT_H */
00266 
00267         DEBUG("looking for fhandle size with fstat\n");
00268         stat_buf.st_size = 0;
00269         error = fstat(fhandle, &stat_buf);
00270         if (!error) {
00271                 /* always believe stat if a regular file as it might really
00272                  * be zero length */
00273                 if (S_ISREG(stat_buf.st_mode) || (stat_buf.st_size > 0))
00274                         return (uint64_t)stat_buf.st_size;
00275         } else {
00276                 DEBUG("fstat failed: %s", strerror(errno));
00277         }
00278 
00279         DEBUG("looking for fhandle size with lseek SEEK_END\n");
00280         es = lseek(fhandle, (off_t)0, SEEK_END);
00281         if (es > ((off_t)0)) {
00282                 return (uint64_t)es;
00283         } else {
00284                 DEBUG("lseek failed: %d", errno==EBADF?1:(errno==ESPIPE?2:(errno==EINVAL?3:4)));
00285         }
00286 
00287         DEBUG("Could not find size of exported block device: %s", strerror(errno));
00288         return UINT64_MAX;
00289 }
00290