int tls_server_certificate_verify(int preverify_ok, X509_STORE_CTX *pX509CTX){
	// preverify_ok
	// 0 ==> Fail
	// 1 ==> Pass
	int verification_return = 0;

	//last certificate(depth = 0) is the one provided by the Server
	if((X509_STORE_CTX_get_error_depth(pX509CTX) == 0) && (preverify_ok == 1)){
		X509 *pX509Cert;
		HostnameValidationResult result;
		pX509Cert = X509_STORE_CTX_get_current_cert(pX509CTX);
		result = validate_hostname(pDestinationURL, pX509Cert);
		if(MatchFound == result){
			verification_return = 1;
		}
	}
	else{
		verification_return = preverify_ok;
	}

	return verification_return;
}
Esempio n. 2
0
/* See http://archives.seul.org/libevent/users/Jan-2013/msg00039.html */
static int cert_verify_callback(X509_STORE_CTX *x509_ctx, void *arg)
{
	char cert_str[256];
	const char *host = (const char *) arg;
	const char *res_str = "X509_verify_cert failed";
	HostnameValidationResult res = Error;

	/* This is the function that OpenSSL would call if we hadn't called
	 * SSL_CTX_set_cert_verify_callback().  Therefore, we are "wrapping"
	 * the default functionality, rather than replacing it. */
	int ok_so_far = 0;

	X509 *server_cert = NULL;

	if (ignore_cert) {
		return 1;
	}

	ok_so_far = X509_verify_cert(x509_ctx);

	server_cert = X509_STORE_CTX_get_current_cert(x509_ctx);

	if (ok_so_far) {
		res = validate_hostname(host, server_cert);

		switch (res) {
		case MatchFound:
			res_str = "MatchFound";
			break;
		case MatchNotFound:
			res_str = "MatchNotFound";
			break;
		case NoSANPresent:
			res_str = "NoSANPresent";
			break;
		case MalformedCertificate:
			res_str = "MalformedCertificate";
			break;
		case Error:
			res_str = "Error";
			break;
		default:
			res_str = "WTF!";
			break;
		}
	}

	X509_NAME_oneline(X509_get_subject_name (server_cert),
			  cert_str, sizeof (cert_str));

	if (res == MatchFound) {
		printf("https server '%s' has this certificate, "
		       "which looks good to me:\n%s\n",
		       host, cert_str);
		return 1;
	} else {
		printf("Got '%s' for hostname '%s' and certificate:\n%s\n",
		       res_str, host, cert_str);
		return 0;
	}
}
Esempio n. 3
0
static void
remote_send_cb(EV_P_ ev_io *w, int revents)
{
    remote_ctx_t *remote_send_ctx = (remote_ctx_t *)w;
    remote_t *remote              = remote_send_ctx->remote;
    server_t *server              = remote->server;

    ev_timer_stop(EV_A_ & remote_send_ctx->watcher);

    if (!remote_send_ctx->connected) {
        int r = 0;
        if (remote->addr == NULL) {
            struct sockaddr_storage addr;
            memset(&addr, 0, sizeof(struct sockaddr_storage));
            socklen_t len = sizeof addr;
            r = getpeername(remote->fd, (struct sockaddr *)&addr, &len);
        }
        if (r == 0) {
            remote_send_ctx->connected = 1;

            ev_io_stop(EV_A_ & remote_send_ctx->io);
            ev_io_stop(EV_A_ & server->recv_ctx->io);
            ev_io_start(EV_A_ & remote->recv_ctx->io);
            ev_timer_start(EV_A_ & remote->recv_ctx->watcher);

            // send destaddr
            buffer_t ss_addr_to_send;
            buffer_t *abuf = &ss_addr_to_send;
            balloc(abuf, BUF_SIZE);

            if (server->hostname_len > 0
                    && validate_hostname(server->hostname, server->hostname_len)) { // HTTP/SNI
                uint16_t port;
                if (AF_INET6 == server->destaddr.ss_family) { // IPv6
                    port = (((struct sockaddr_in6 *)&(server->destaddr))->sin6_port);
                } else {                             // IPv4
                    port = (((struct sockaddr_in *)&(server->destaddr))->sin_port);
                }

                abuf->data[abuf->len++] = 3;          // Type 3 is hostname
                abuf->data[abuf->len++] = server->hostname_len;
                memcpy(abuf->data + abuf->len, server->hostname, server->hostname_len);
                abuf->len += server->hostname_len;
                memcpy(abuf->data + abuf->len, &port, 2);
            } else if (AF_INET6 == server->destaddr.ss_family) { // IPv6
                abuf->data[abuf->len++] = 4;          // Type 4 is IPv6 address

                size_t in6_addr_len = sizeof(struct in6_addr);
                memcpy(abuf->data + abuf->len,
                       &(((struct sockaddr_in6 *)&(server->destaddr))->sin6_addr),
                       in6_addr_len);
                abuf->len += in6_addr_len;
                memcpy(abuf->data + abuf->len,
                       &(((struct sockaddr_in6 *)&(server->destaddr))->sin6_port),
                       2);
            } else {                             // IPv4
                abuf->data[abuf->len++] = 1; // Type 1 is IPv4 address

                size_t in_addr_len = sizeof(struct in_addr);
                memcpy(abuf->data + abuf->len,
                       &((struct sockaddr_in *)&(server->destaddr))->sin_addr, in_addr_len);
                abuf->len += in_addr_len;
                memcpy(abuf->data + abuf->len,
                       &((struct sockaddr_in *)&(server->destaddr))->sin_port, 2);
            }

            abuf->len += 2;

            int err = crypto->encrypt(abuf, server->e_ctx, BUF_SIZE);
            if (err) {
                LOGE("invalid password or cipher");
                bfree(abuf);
                close_and_free_remote(EV_A_ remote);
                close_and_free_server(EV_A_ server);
                return;
            }

            err = crypto->encrypt(remote->buf, server->e_ctx, BUF_SIZE);
            if (err) {
                LOGE("invalid password or cipher");
                bfree(abuf);
                close_and_free_remote(EV_A_ remote);
                close_and_free_server(EV_A_ server);
                return;
            }

            bprepend(remote->buf, abuf, BUF_SIZE);
            bfree(abuf);
        } else {
            ERROR("getpeername");
            // not connected
            close_and_free_remote(EV_A_ remote);
            close_and_free_server(EV_A_ server);
            return;
        }
    }

    if (remote->buf->len == 0) {
        // close and free
        close_and_free_remote(EV_A_ remote);
        close_and_free_server(EV_A_ server);
        return;
    } else {
        // has data to send
        ssize_t s;
        if (remote->addr != NULL) {
            s = sendto(remote->fd, remote->buf->data + remote->buf->idx,
                       remote->buf->len, MSG_FASTOPEN, remote->addr,
                       get_sockaddr_len(remote->addr));

            if (s == -1 && (errno == EOPNOTSUPP || errno == EPROTONOSUPPORT ||
                errno == ENOPROTOOPT)) {
                fast_open = 0;
                LOGE("fast open is not supported on this platform");
                close_and_free_remote(EV_A_ remote);
                close_and_free_server(EV_A_ server);
                return;
            }

            remote->addr = NULL;

            if (s == -1) {
                if (errno == CONNECT_IN_PROGRESS || errno == EAGAIN
                    || errno == EWOULDBLOCK) {
                    ev_io_start(EV_A_ & remote_send_ctx->io);
                    ev_timer_start(EV_A_ & remote_send_ctx->watcher);
                } else {
                    ERROR("connect");
                    close_and_free_remote(EV_A_ remote);
                    close_and_free_server(EV_A_ server);
                }
                return;
            }
        } else {
            s = send(remote->fd, remote->buf->data + remote->buf->idx,
                     remote->buf->len, 0);
        }

        if (s == -1) {
            if (errno != EAGAIN && errno != EWOULDBLOCK) {
                ERROR("send");
                // close and free
                close_and_free_remote(EV_A_ remote);
                close_and_free_server(EV_A_ server);
            }
            return;
        } else if (s < remote->buf->len) {
            // partly sent, move memory, wait for the next time to send
            remote->buf->len -= s;
            remote->buf->idx += s;
            ev_io_start(EV_A_ & remote_send_ctx->io);
            return;
        } else {
            // all sent out, wait for reading
            remote->buf->len = 0;
            remote->buf->idx = 0;
            ev_io_stop(EV_A_ & remote_send_ctx->io);
            ev_io_start(EV_A_ & server->recv_ctx->io);
        }
    }
}
Esempio n. 4
0
static void proceed_handshake(h2o_socket_t *sock, const char *err)
{
    h2o_iovec_t first_input = {NULL};
    int ret;

    sock->_cb.write = NULL;

    if (err != NULL) {
        goto Complete;
    }

    if (sock->ssl->handshake.server.async_resumption.state == ASYNC_RESUMPTION_STATE_RECORD) {
        if (sock->ssl->input.encrypted->size <= 1024) {
            /* retain a copy of input if performing async resumption */
            first_input = h2o_iovec_init(alloca(sock->ssl->input.encrypted->size), sock->ssl->input.encrypted->size);
            memcpy(first_input.base, sock->ssl->input.encrypted->bytes, first_input.len);
        } else {
            sock->ssl->handshake.server.async_resumption.state = ASYNC_RESUMPTION_STATE_COMPLETE;
        }
    }

Redo:
    if (SSL_is_server(sock->ssl->ssl)) {
        ret = SSL_accept(sock->ssl->ssl);
    } else {
        ret = SSL_connect(sock->ssl->ssl);
    }

    switch (sock->ssl->handshake.server.async_resumption.state) {
    case ASYNC_RESUMPTION_STATE_RECORD:
        /* async resumption has not been triggered; proceed the state to complete */
        sock->ssl->handshake.server.async_resumption.state = ASYNC_RESUMPTION_STATE_COMPLETE;
        break;
    case ASYNC_RESUMPTION_STATE_REQUEST_SENT: {
        /* sent async request, reset the ssl state, and wait for async response */
        assert(ret < 0);
        SSL_CTX *ssl_ctx = SSL_get_SSL_CTX(sock->ssl->ssl);
        SSL_free(sock->ssl->ssl);
        create_ssl(sock, ssl_ctx);
        clear_output_buffer(sock->ssl);
        h2o_buffer_consume(&sock->ssl->input.encrypted, sock->ssl->input.encrypted->size);
        h2o_buffer_reserve(&sock->ssl->input.encrypted, first_input.len);
        memcpy(sock->ssl->input.encrypted->bytes, first_input.base, first_input.len);
        sock->ssl->input.encrypted->size = first_input.len;
        h2o_socket_read_stop(sock);
        return;
    }
    default:
        break;
    }

    if (ret == 0 || (ret < 0 && SSL_get_error(sock->ssl->ssl, ret) != SSL_ERROR_WANT_READ)) {
        /* failed */
        long verify_result = SSL_get_verify_result(sock->ssl->ssl);
        if (verify_result != X509_V_OK) {
            err = X509_verify_cert_error_string(verify_result);
        } else {
            err = "ssl handshake failure";
        }
        goto Complete;
    }

    if (sock->ssl->output.bufs.size != 0) {
        h2o_socket_read_stop(sock);
        flush_pending_ssl(sock, ret == 1 ? on_handshake_complete : proceed_handshake);
    } else {
        if (ret == 1) {
            if (!SSL_is_server(sock->ssl->ssl)) {
                X509 *cert = SSL_get_peer_certificate(sock->ssl->ssl);
                if (cert != NULL) {
                    switch (validate_hostname(sock->ssl->handshake.client.server_name, cert)) {
                    case MatchFound:
                        /* ok */
                        break;
                    case MatchNotFound:
                        err = h2o_socket_error_ssl_cert_name_mismatch;
                        break;
                    default:
                        err = h2o_socket_error_ssl_cert_invalid;
                        break;
                    }
                    X509_free(cert);
                } else {
                    err = h2o_socket_error_ssl_no_cert;
                }
            }
            goto Complete;
        }
        if (sock->ssl->input.encrypted->size != 0)
            goto Redo;
        h2o_socket_read_start(sock, proceed_handshake);
    }
    return;

Complete:
    h2o_socket_read_stop(sock);
    on_handshake_complete(sock, err);
}
Esempio n. 5
0
int main(int argc, char *argv[]) {
	BIO *sbio;
	SSL_CTX *ssl_ctx;
	SSL *ssl;
	X509 *server_cert;

	// Initialize OpenSSL
	OpenSSL_add_all_algorithms();
	SSL_library_init();
	SSL_load_error_strings();

 	// Check OpenSSL PRNG
	if(RAND_status() != 1) {
		fprintf(stderr, "OpenSSL PRNG not seeded with enough data.");
		goto error_1;
	}

	ssl_ctx = SSL_CTX_new(TLSv1_client_method());
	
	// Enable certificate validation
	SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL);
	// Configure the CA trust store to be used
	if (SSL_CTX_load_verify_locations(ssl_ctx, TRUSTED_CA_PATHNAME, NULL) != 1) {
		fprintf(stderr, "Couldn't load certificate trust store.\n");
		goto error_2;
	}

	// Only support secure cipher suites
	if (SSL_CTX_set_cipher_list(ssl_ctx, SECURE_CIPHER_LIST) != 1)
		goto error_2;

	// Create the SSL connection
	sbio = BIO_new_ssl_connect(ssl_ctx);
	BIO_get_ssl(sbio, &ssl); 
	if(!ssl) {
	  fprintf(stderr, "Can't locate SSL pointer\n");
		goto error_3;
	}

	// Do the SSL handshake
	BIO_set_conn_hostname(sbio, TARGET_SERVER);
	if(SSL_do_handshake(ssl) <= 0) {
		// SSL Handshake failed
		long verify_err = SSL_get_verify_result(ssl);
		if (verify_err != X509_V_OK) { 
			// It failed because the certificate chain validation failed
			fprintf(stderr, "Certificate chain validation failed: %s\n", X509_verify_cert_error_string(verify_err));
		}
		else {
			// It failed for another reason
			ERR_print_errors_fp(stderr);
		}
		goto error_3;
	}

	// Recover the server's certificate
	server_cert =  SSL_get_peer_certificate(ssl);
	if (server_cert == NULL) {
		// The handshake was successful although the server did not provide a certificate
		// Most likely using an insecure anonymous cipher suite... get out!
		goto error_4;
	}

	// Validate the hostname
	if (validate_hostname(TARGET_HOST, server_cert) != MatchFound) {
		fprintf(stderr, "Hostname validation failed.\n");
		goto error_5;
	}

	// Hostname validation succeeded; we can start sending data
	send_http_get_and_print(sbio);


error_5:
	X509_free(server_cert);

error_4:
	BIO_ssl_shutdown(sbio);

error_3:
	BIO_free_all(sbio);

error_2:
	SSL_CTX_free(ssl_ctx);

error_1: // OpenSSL cleanup
    EVP_cleanup();
    ERR_free_strings();

	return 0;
}
Esempio n. 6
0
static lcb_error_t setup_bootstrap_hosts(lcb_t ret, const char *host)
{
    const char *ptr = host;
    lcb_size_t num = 0;
    int ii;

    while ((ptr = strchr(ptr, ';')) != NULL) {
        ++ptr;
        ++num;
    }

    /* Let's allocate the buffer space and copy the pointers
     * (the +2 and not +1 is because of the way we count the number of
     * bootstrap hosts (num == 0 means that we've got a single host etc)
     */
    if ((ret->backup_nodes = calloc(num + 2, sizeof(char *))) == NULL) {
        return LCB_CLIENT_ENOMEM;
    }

    ret->should_free_backup_nodes = 1;

    ptr = host;
    ii = 0;
    do {
        char nm[NI_MAXHOST + NI_MAXSERV + 2];
        const char *start = ptr;
        lcb_error_t error;

        ptr = strchr(ptr, ';');
        ret->backup_nodes[ii] = NULL;
        if (ptr == NULL) {
            /* this is the last part */
            error = validate_hostname(start, &ret->backup_nodes[ii]);
            ptr = NULL;
        } else {
            /* copy everything up to ';' */
            unsigned long size = (unsigned long)ptr - (unsigned long)start;
            /* skip the entry if it's too long */
            if (size < sizeof(nm)) {
                memcpy(nm, start, (lcb_size_t)(ptr - start));
                *(nm + size) = '\0';
            }
            ++ptr;
            error = validate_hostname(nm, &ret->backup_nodes[ii]);
        }
        if (error != LCB_SUCCESS) {
            while (ii > 0) {
                free(ret->backup_nodes[ii--]);
            }
            return error;
        }

        ++ii;
    } while (ptr != NULL);

    if (ret->randomize_bootstrap_nodes) {
        ii = 1;
        while (ret->backup_nodes[ii] != NULL) {
            lcb_size_t nidx = (lcb_size_t)(gethrtime() >> 10) % ii;
            char *other = ret->backup_nodes[nidx];
            ret->backup_nodes[nidx] = ret->backup_nodes[ii];
            ret->backup_nodes[ii] = other;
            ++ii;
        }
    }
Esempio n. 7
0
gfarm_error_t
add_line(char *line, int lineno)
{
	gfarm_error_t e;
	long port, ncpu, flags;
	int len, nhostaliases;
	char *s, *hostname, *architecture;
	char *hostaliases[MAX_HOSTALIASES + 1];

	/* parse architecture */
	line += strspn(line, space); /* skip space */
	len = strcspn(line, space);
	if (len == 0 || line[len] == '\0')
		return (invalid_input(lineno));
	line[len] = '\0';
	architecture = line;
	line += len + 1;
	s = validate_architecture(architecture);
	if (s != NULL) {
		fprintf(stderr,
		    "line %d: invalid character '%c' in architecture \"%s\"\n",
		    lineno, *s, architecture);
		return (GFARM_ERR_INVALID_ARGUMENT);
	}

	e = parse_string_long(&line, lineno, "ncpu", &ncpu);
	if (e != GFARM_ERR_NO_ERROR)
		return (e);

	/* parse hostname */
	line += strspn(line, space); /* skip space */
	len = strcspn(line, space);
	if (len == 0)
		return (invalid_input(lineno));
	hostname = line;
	if (line[len] == '\0') {
		line += len;
	} else {
		line[len] = '\0';
		line += len + 1;
	}
	s = validate_hostname(hostname);
	if (s != NULL) {
		fprintf(stderr,
		    "line %d: invalid character '%c' in hostname \"%s\"\n",
		    lineno, *s, hostname);
		return (GFARM_ERR_INVALID_ARGUMENT);
	}

	e = parse_string_long(&line, lineno, "port", &port);
	if (e != GFARM_ERR_NO_ERROR)
		return (e);

	e = parse_string_long(&line, lineno, "flags", &flags);
	if (e != GFARM_ERR_NO_ERROR)
		return (e);

	/* parse hostaliases */
	for (nhostaliases = 0;; nhostaliases++) {
		line += strspn(line, space); /* skip space */
		if (*line == '\0')
			break;
		len = strcspn(line, space);
		/* assert(len > 0); */
		if (nhostaliases >= MAX_HOSTALIASES) {
			fprintf(stderr, "line %d: "
			    "number of hostaliases exceeds %d\n",
			    lineno, nhostaliases);
			return (GFARM_ERR_INVALID_ARGUMENT);
		}
		hostaliases[nhostaliases] = line;
		if (line[len] == '\0') {
			line += len;
		} else {
			line[len] = '\0';
			line += len + 1;
		}
		s = validate_hostname(hostaliases[nhostaliases]);
		if (s != NULL) {
			fprintf(stderr, "line %d: "
			    "invalid character '%c' in hostalias \"%s\"\n",
			    lineno, *s, hostaliases[nhostaliases]);
			return (GFARM_ERR_INVALID_ARGUMENT);
		}
	}
	hostaliases[nhostaliases] = NULL;

	e = add_host(hostname, port, hostaliases, architecture, ncpu, flags);
	if (e != GFARM_ERR_NO_ERROR)
		fprintf(stderr, "line %d: %s\n",
		    lineno, gfarm_error_string(e));
	return (e);
}
Esempio n. 8
0
int
main(int argc, char **argv)
{
	int argc_save = argc;
	char **argv_save = argv;
	gfarm_error_t e, e_save = GFARM_ERR_NO_ERROR;
	char opt_operation = '\0'; /* default operation */
	int opt_concurrency = DEFAULT_CONCURRENCY;
	int opt_alter_aliases = 0;
	char *opt_architecture = NULL;
	char *opt_domainname = NULL;
	long opt_ncpu = 0;
	int opt_port = 0, opt_flags = -1;
	int opt_plain_order = 0; /* i.e. do not sort */
	int opt_sort_by_loadavg = 0;
	int i, c, opt_use_metadb = 1;
	char *s;

	if (argc > 0)
		program_name = basename(argv[0]);
	while ((c = getopt(argc, argv, "AD:HLMPUa:cdf:ij:lmn:p:ruv?")) != -1) {
		switch (c) {
		case 'A':
			opt_alter_aliases = 1;
			break;
		case 'L':
			opt_sort_by_loadavg = 1;
			break;
		case 'M':
		case 'H':
		case 'R':
		case 'c':
		case 'd':
		case 'l':
		case 'm':
			if (opt_operation != '\0' && opt_operation != c)
				inconsistent_option(opt_operation, c);
			opt_operation = c;
			break;
		case 'a':
			opt_architecture = optarg;
			s = validate_architecture(opt_architecture);
			if (s != NULL) {
				fprintf(stderr, "%s: "
				    "invalid character '%c' in \"-a %s\"\n",
				    program_name, *s, opt_architecture);
				exit(1);
			}
			break;
		case 'D':
			opt_domainname = optarg;
			s = validate_hostname(opt_domainname);
			if (s != NULL) {
				fprintf(stderr, "%s: "
				    "invalid character '%c' in \"-a %s\"\n",
				    program_name, *s, opt_domainname);
				exit(1);
			}
			break;
		case 'i':
			opt_resolv_addr = resolv_addr_without_address_use;
			break;
		case 'j':
			opt_concurrency = parse_opt_long(optarg,
			    c, "<concurrency>");
			if (opt_concurrency <= 0) {
				fprintf(stderr, "%s: invalid value: -%c %d\n",
				    program_name, c, opt_concurrency);
				usage();
			}
			break;
		case 'f':
			opt_flags = parse_opt_long(optarg, c, "<flags>");
			break;
		case 'n':
			opt_ncpu = parse_opt_long(optarg, c, "<ncpu>");
			break;
		case 'p':
			opt_port = parse_opt_long(optarg, c, "<port>");
			break;
		case 'r':
			output_sort_reverse = 1;
			break;
		case 'U':
			opt_udp_only = 1;
			break;
		case 'u':
			opt_plain_order = 1;
			break;
		case 'v':
			opt_verbose = 1;
			break;
		case '?':
			usage();
		}
	}
	argc -= optind;
	argv += optind;

	switch (opt_operation) {
	case OP_CREATE_ENTRY:
		if (opt_architecture == NULL) {
			fprintf(stderr, "%s: missing -a <architecture>\n",
			    program_name);
			usage();
		}
		if (opt_ncpu == 0)
			opt_ncpu = 1;
		if (opt_flags == -1)
			opt_flags = 0;
		/* opt_alter_aliases is meaningless, but allowed */
		break;
	case OP_REGISTER_DB:
	case OP_DELETE_ENTRY:
		if (opt_architecture != NULL)
			invalid_option('a');
		if (opt_domainname != NULL)
			invalid_option('D');
		/* fall through */
	case OP_NODENAME:
	case OP_LIST_GFSD_INFO:
	case OP_LIST_LONG:
	case OP_DUMP_METADB:
		if (opt_ncpu != 0)
			invalid_option('n');
		if (opt_alter_aliases)
			invalid_option('A');
		break;
	case OP_MODIFY_ENTRY:
		if (opt_domainname != NULL)
			invalid_option('D');
		break;
	default:
		;
	}

	for (i = 0; i < argc; i++) {
		s = validate_hostname(argv[i]);
		if (s != NULL) {
			fprintf(stderr, "%s: "
			    "invalid character '%c' in hostname \"%s\"\n",
			    program_name, *s, argv[i]);
			exit(1);
		}
	}

	e = gfarm_initialize(&argc_save, &argv_save);
	if (opt_operation == OP_LIST_GFSD_INFO && argc > 0 &&
	    opt_resolv_addr == resolv_addr_without_address_use) {
		/*
		 * An implicit feature to access gfsd directly
		 * without having working gfmd.
		 * e.g. gfhost -Hi <hostname>
		 *
		 * XXX	should describe this in the manual?
		 *	or use explicit and different option?
		 */
		opt_use_metadb = 0;
		opt_resolv_addr = resolv_addr_without_metadb;
	} else if (e != GFARM_ERR_NO_ERROR) {
		fprintf(stderr, "%s: %s\n", program_name,
		    gfarm_error_string(e));
		exit(1);
	}

	switch (opt_operation) {
	case OP_CREATE_ENTRY:
		if (argc > 0) {
			if (opt_port == 0) {
				fprintf(stderr, "%s: option -p <port> is "
				    "mandatory with -c\n", program_name);
				usage();
			}
			e_save = add_host(argv[0], opt_port, &argv[1],
			    opt_architecture, opt_ncpu, opt_flags);
			if (e_save != GFARM_ERR_NO_ERROR)
				fprintf(stderr, "%s: %s: %s\n", program_name,
				    argv[0], gfarm_error_string(e_save));
		}
		break;
	case OP_MODIFY_ENTRY:
		if (argc > 0) {
			e_save = gfarm_modify_host(argv[0], opt_port, &argv[1],
			    opt_architecture, opt_ncpu, opt_flags,
			    !opt_alter_aliases);
			if (e_save != GFARM_ERR_NO_ERROR)
				fprintf(stderr, "%s: %s: %s\n", program_name,
				    argv[0], gfarm_error_string(e_save));
		}
		break;
	case OP_DELETE_ENTRY:
		for (i = 0; i < argc; i++) {
			e = gfm_client_host_info_remove(gfarm_metadb_server,
			    argv[i]);
			if (e != GFARM_ERR_NO_ERROR) {
				fprintf(stderr, "%s: %s\n", argv[i],
				    gfarm_error_string(e));
				if (e_save == GFARM_ERR_NO_ERROR)
					e_save = e;
			}
		}
		break;
	case OP_REGISTER_DB:
		if (argc > 0) {
			fprintf(stderr, "%s: too many argument: %s\n",
			    program_name, argv[0]);
			exit(1);
		}
		e_save = register_db();
		break;
	case OP_LIST_GFSD_INFO:
		e = paraccess_list(opt_concurrency, opt_udp_only,
		    opt_architecture, opt_domainname, opt_port,
		    opt_plain_order, opt_sort_by_loadavg,
		    opt_use_metadb, argc, argv,
		    request_gfsd_info, callback_gfsd_info);
		break;
	case OP_NODENAME:
		e = paraccess_list(opt_concurrency, opt_udp_only,
		    opt_architecture, opt_domainname, opt_port,
		    opt_plain_order, opt_sort_by_loadavg,
		    opt_use_metadb, argc, argv,
		    request_nodename, callback_nodename);
		break;
	case OP_LIST_LONG:
		e = paraccess_list(opt_concurrency, opt_udp_only,
		    opt_architecture, opt_domainname, opt_port,
		    opt_plain_order, opt_sort_by_loadavg,
		    opt_use_metadb, argc, argv,
		    request_long_format, callback_long_format);
		break;
	case OP_DUMP_METADB:
		if (argc == 0) {
			e_save = list_all(opt_architecture, opt_domainname,
				print_host_info, NULL);
		} else {
			e_save = list(argc, argv, print_host_info, NULL);
		}
		break;
	}
	e = gfarm_terminate();
	if (e != GFARM_ERR_NO_ERROR) {
		fprintf(stderr, "%s: %s\n", program_name,
		    gfarm_error_string(e));
		exit(1);
	}
	exit(e_save == GFARM_ERR_NO_ERROR ? 0 : 1);
}