|
Network Block Device @PACKAGE_VERSION@
|
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
1.7.3