📄 gclient.c
字号:
/* * * Copyright 2000-2001 Sistina Software, Inc. * Portions Copyright 2001 The OpenGFS Project * * This is free software released under the GNU General Public License. * There is no warranty for this software. See the file COPYING for * details. * * See the file AUTHORS for a list of contributors. * *//* * This is a user level interface for setting up and configuring the * gnbd client devices. *//* * AUDIT: <Alan> * Audited for security flaws * - Fixed multiple buffer overflows [LOCAL, TRUSTED NETWORK] * - Fixed network DNS assumption insecurity [NETWORK] * TODO * - We need an authentication mechanism. Right now gclient will do * arbitarily dumb things and it really needs to. */#define HELPER_PROGRAM#include <unistd.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <fcntl.h>#include <sys/ioctl.h>#include <netdb.h>#include <errno.h>#include <dirent.h>#include <ctype.h>#include "gnbd.h"int message_flag = 1;#define printm(fmt, args...)\{\ if(message_flag != 0) \ fprintf(stderr, "gclient: " fmt, ##args); \}typedef struct devlist_s { char name[300]; struct devlist_s *next;} devlist_t;int match(char *name, devlist_t * ptr){ while (ptr != NULL) { if (strcmp(name, ptr->name) == 0) return 0; ptr = ptr->next; } return -1;}devlist_t *getnext(devlist_t * ptr){ if (ptr == NULL) return NULL; return (ptr->next);}devlist_t *add(char *name, devlist_t * head){ devlist_t *ptr; devlist_t *tmp = (devlist_t *) malloc(sizeof(devlist_t)); snprintf(tmp->name, 300, "%s", name); tmp->next = NULL; if (head == NULL) return tmp; ptr = head; while (ptr->next != NULL) ptr = ptr->next; ptr->next = tmp; return head;}devlist_t *clear(devlist_t * ptr){ devlist_t *tmp; while (ptr != NULL) { tmp = ptr; ptr = ptr->next; free(tmp); } return NULL;}int do_device_remove(int comm_fd, int minor_nr){ gnbd_device_t dev; errno = 0; dev.name = NULL; dev.length = 0; dev.action = GNBD_DEV_REMOVE; dev.minor_nr = minor_nr; if (ioctl(comm_fd, GNBD_DEVICE, &dev) < 0) return -1; return 0;}int do_disconnect(int comm_fd, char *dev_name){ struct stat st; gnbd_action_t act; char path[300]; errno = 0; memset(&act, 0, sizeof(gnbd_action_t)); snprintf(path, 300, "/dev/gnbd/%s", dev_name); if (stat(path, &st) < 0) return -1; act.device = minor(st.st_rdev); act.action = GNBD_ACT_Disconnect; if (ioctl(comm_fd, GNBD_ACTION, &act) < 0) return -1; return 0;}int do_connect(int comm_fd, uint16_t minor_nr){ gnbd_action_t act; errno = 0; memset(&act, 0, sizeof(gnbd_action_t)); act.device = minor_nr; act.action = GNBD_ACT_Connect; if (ioctl(comm_fd, GNBD_ACTION, &act) < 0) return -1; return 0;}int do_setipport(int comm_fd, uint16_t minor_nr, uint16_t port, struct in_addr ipaddr){ gnbd_action_t act; errno = 0; memset(&act, 0, sizeof(gnbd_action_t)); act.device = minor_nr; act.port = htons(port); act.ip = (uint32_t) ipaddr.s_addr; act.action = GNBD_ACT_SetIPPort; if (ioctl(comm_fd, GNBD_ACTION, &act) < 0) { perror("ioctl failed"); return -1; } return 0;}int get_proc_data(char *buf, int len){ int n; int bytes = 0; int proc_fd; proc_fd = open("/proc/gnbd", O_RDONLY); if (proc_fd < 0) { fprintf(stderr, "could not open /proc/gnbd: %s\n", strerror(errno)); return -1; } while ((n = read(proc_fd, buf + bytes, len - bytes)) != 0) { if (n < 0 && errno != EINTR) { fprintf(stderr, "list request failed: %s\n", strerror(errno)); close(proc_fd); return -1; } bytes += n; } if (bytes < len) buf[bytes] = 0; else buf[len - 1] = 0; close(proc_fd); return bytes;}int proc_match(char *name){ char buf[4096]; char *nameptr, *bufptr; int bytes; bytes = get_proc_data(buf, 4096); if (bytes < 0) return -1; bufptr = buf; while ((nameptr = strchr(bufptr, '/')) != NULL) { nameptr++; bufptr = strchr(nameptr, '/'); if (bufptr == NULL) { perror("/proc/gnbd formatted incorrectly\n"); return -1; } *bufptr++ = 0; if (strcmp(name, nameptr) == 0) return 1; } return 0;}int do_device_create(int comm_fd, char *dev_name){ int err; gnbd_device_t dev; errno = 0; err = proc_match(dev_name); if (err < 0) { fprintf(stderr, "errored trying proc_match\n"); return -1; } if (err == 1) { errno = EEXIST; return -1; } dev.name = dev_name; dev.length = strlen(dev_name) + 1; dev.action = GNBD_DEV_CREATE; if (ioctl(comm_fd, GNBD_DEVICE, &dev) < 0) { fprintf(stderr, "errored in ioctl\n"); return -1; } return dev.minor_nr;}int connect_to_server(char *hostname, uint16_t port, struct in_addr *ip_addr){ int sock_fd; struct sockaddr_in server; struct hostent *hp; sock_fd = socket(AF_INET, SOCK_STREAM, 0); if (sock_fd < 0) { fprintf(stderr, "error creating socket: %s\n", strerror(errno)); return -1; } server.sin_family = AF_INET; hp = gethostbyname(hostname); if (hp == NULL) { fprintf(stderr, "cannot resolve host ip from name %s: %s", hostname, strerror(errno)); return -1; } if (memcpy(&(server.sin_addr.s_addr), hp->h_addr, hp->h_length) == NULL) { fprintf(stderr, "cannot copy host address: %s\n", strerror(errno)); return -1; } if (ip_addr != NULL) ip_addr->s_addr = server.sin_addr.s_addr; server.sin_port = htons(port); if (connect(sock_fd, (struct sockaddr *) &server, sizeof(server)) < 0) { close(sock_fd); fprintf(stderr, "error connecting to server: %s\n", strerror(errno)); return -1; } return sock_fd;}int stomith(char *hostname){ uint32_t stomithip; int bytes; struct hostent *hp; int sock_fd; devlist_t *listptr, *iplist = NULL; char buf[4096]; char *ipaddr, *bufptr; hp = gethostbyname(hostname); if (hp == NULL) { fprintf(stderr, "cannot resolve stomith host ip from name %s: %s\n", hostname, strerror(errno)); return 1; } if (memcpy(&stomithip, hp->h_addr, hp->h_length) == NULL) { fprintf(stderr, "cannot copy host address: %s\n", strerror(errno)); return 1; } bufptr = (char *) &stomithip; /* fprintf(stderr, "the stomith ip is %d.%d.%d.%d\n", (int)*bufptr, (int)*(bufptr+1), (int)*(bufptr+2), (int)*(bufptr+3)); */ bytes = get_proc_data(buf, 4096); if (bytes < 0) return 1; bufptr = buf; while ((ipaddr = strstr(bufptr, "IP :")) != NULL) { ipaddr += 5; if ((bufptr = strchr(ipaddr, '\n')) == NULL) { fprintf(stderr, "malformed /proc/gnbd entry\n"); goto fail; } *bufptr++ = 0; if (match(ipaddr, iplist) < 0) iplist = add(ipaddr, iplist); } listptr = iplist; while (listptr != NULL) { sock_fd = connect_to_server(listptr->name, (unsigned int) 14243, NULL); if (sock_fd < 0) { fprintf(stderr, "cannot connect to the server: %s\n", strerror(errno)); goto fail; } write(sock_fd, "stom", 5); write(sock_fd, (char *) &stomithip, 4); read(sock_fd, buf, 5); write(sock_fd, "bye", 4); close(sock_fd); if (strcmp(buf, "fail") == 0) { fprintf(stderr, "server is closing, cannot stomith\n"); goto fail; } listptr = getnext(listptr); } fprintf(stderr, "%s stomithed\n", hostname); iplist = clear(iplist); return 0; fail: iplist = clear(iplist); return 1;}int getserver(char *hostname){ int n; int total; int sock_fd; char buf[300]; char *port; sock_fd = connect_to_server(hostname, (unsigned int) 14243, NULL); if (sock_fd < 0) return -1; write(sock_fd, "port", 5); printf("GNBD's on host: %s\n", hostname); while (1) { total = 0; do { n = read(sock_fd, buf+total, 300-total); if (n < 0) { close(sock_fd); fprintf(stderr, "error reading from the server: %s\n", strerror(errno)); return -1; } total += n; } while (buf[total - 1] != 0 && total!=300); if(total==300) { fprintf(stderr, "error reading from server: reply too long.\n"); return -1; } if (strncmp(buf, "bye", 3) == 0) break; if ((port = strchr(buf, '/')) == NULL) { fprintf(stderr, "malformed server message: %s\n", buf); close(sock_fd); return -1; } *port++ = 0; printf("Port: %5s Name: %s\n", port, buf); if (write(sock_fd, "next", 5) != 5) { fprintf(stderr, "error writing to the server: %s\n", strerror(errno)); close(sock_fd); return -1; } } write(sock_fd, "quit", 5); close(sock_fd); return 0;}int validate_devs(int comm_fd){ DIR *dp; int major_nr; uint16_t minor_nr; char buf[4096]; int bytes; char *name; char *minor; char *bufptr; char path[300]; devlist_t *save_list = NULL; devlist_t *del_list = NULL; devlist_t *list_ptr = NULL; struct dirent *entry; bytes = get_proc_data(buf, 4096); if (bytes < 0) return -1; name = strchr(buf, ':'); name = name + 2; bufptr = strchr(name, '\n'); *bufptr = 0; major_nr = (int) strtoul(name, &bufptr, 0); if (major_nr == 0 || bufptr == name) { perror("couldn't find the major number for gnbd"); return -1; } bufptr++; while ((name = strchr(bufptr, '/')) != NULL) { name++; bufptr = strchr(name, '/'); *bufptr++ = 0; minor = strchr(bufptr, ':'); minor = minor + 2; minor_nr = (uint16_t) strtoul(minor, &bufptr, 0); if (minor_nr == 0 || bufptr == minor) { fprintf(stderr, "couldn't find the minor number for %s: %s\n", name, strerror(errno)); return -1; } bufptr++; if (do_connect(comm_fd, minor_nr) < 0) { if (do_device_remove(comm_fd, (int) minor_nr) < 0) { fprintf(stderr, "couldn't remove bad device '%s': %s\n", name, strerror(errno)); return -1; } printm("invalid GNBD '%s' removed\n", name); } else { save_list = add(name, save_list); } } dp = opendir("/dev/gnbd/"); if (dp == NULL) { perror("error opening directory /dev/gnbd"); clear(save_list); return -1; } errno = 0; while ((entry = readdir(dp)) != NULL) { if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) continue; if (match(entry->d_name, save_list) < 0) del_list = add(entry->d_name, del_list); } clear(save_list); if (closedir(dp) < 0) { perror("error closeing directory /dev/gnbd"); save_list = clear(save_list); del_list = clear(del_list); return -1; } list_ptr = del_list; while (list_ptr != NULL) { snprintf(path, 300, "/dev/gnbd/%s", list_ptr->name); if (remove(strcat(path, list_ptr->name)) < 0) { fprintf(stderr, "error removing %s: %s\n", path, strerror(errno)); del_list = clear(save_list); del_list = clear(del_list); return -1; } printm("removed file %s\n", path); list_ptr = getnext(list_ptr); } del_list = clear(del_list); return major_nr;}int list(void){ int i; int bytes; char *bufptr; char buf[4096]; bytes = get_proc_data(buf, 4096); if (bytes < 0) return -1; for (i = 0; i < bytes; i++) if (buf[i] == '/') buf[i] = ' '; bufptr = strchr(buf, '\n'); if (bufptr == NULL || bufptr >= &buf[bytes]) { perror("incorrectly formatted /proc/gnbd file?!?\n"); return -1; } printf("GNBD's currently registered%s", bufptr); return 0;}int get_major_nr(void){ char buf[31]; int bytes; char *major; char *tail;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -