コード例 #1
0
ファイル: auth_distcc.c プロジェクト: DengZuoheng/distcc
/*
 * Perform any requested security.  Message replay and out of sequence
 * detection are given in addition to mutual authentication.
 *
 * @param to_net_sd.	Socket to write to.
 *
 * @param from_net_sd.	Socket to read from.
 *
 * Returns 0 on success, otherwise error.
 */
int dcc_gssapi_perform_requested_security(int to_net_sd,
					  int from_net_sd) {
    int ret;
    OM_uint32 req_flags, ret_flags;

    req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG;

    if ((ret = dcc_gssapi_establish_secure_context(to_net_sd,
						  from_net_sd,
						  req_flags,
						  &ret_flags)) != 0) {
	return ret;
    }

    if ((ret = dcc_gssapi_compare_flags(req_flags, ret_flags)) != 0) {
	dcc_gssapi_delete_ctx(&distcc_ctx_handle);
	return ret;
    }

    if ((ret = dcc_gssapi_recv_notification(from_net_sd)) != 0) {
        dcc_gssapi_delete_ctx(&distcc_ctx_handle);
        return ret;
    }

    rs_log_info("Authentication complete - happy compiling!");

    return 0;
}
コード例 #2
0
ファイル: fix_debug_info.c プロジェクト: DengZuoheng/distcc
/*
 * Edit the ELF file residing at @p path, changing all occurrences of
 * the path @p server_path to @p client_path in the debugging info.
 *
 * We're a bit sloppy about that; rather than properly parsing
 * the DWARF debug info, finding the DW_AT_comp_dir (compilation working
 * directory) field and the DW_AT_name (source file name) field,
 * we just do a search-and-replace in the ".debug_info" and ".debug_str"
 * sections.  But this is good enough.
 *
 * Returns 0 on success (whether or not the ".debug_info" and ".debug_str"
 * sections were found or updated).
 * Returns 1 on serious error that should cause distcc to fail.
 */
int dcc_fix_debug_info(const char *path, const char *client_path,
                              const char *server_path)
{
#ifndef HAVE_ELF_H
  rs_trace("no <elf.h>, so can't change %s to %s in debug info for %s",
           server_path, client_path, path);
  return 0;
#else
  /*
   * We can only safely replace a string with another of exactly
   * the same length.  (Replacing a string with a shorter string
   * results in errors from gdb.)
   * So we append trailing slashes on the client side path.
   */
  size_t client_path_len = strlen(client_path);
  size_t server_path_len = strlen(server_path);
  assert(client_path_len <= server_path_len);
  char *client_path_plus_slashes = malloc(server_path_len + 1);
  if (!client_path_plus_slashes) {
    rs_log_crit("failed to allocate memory");
    return 1;
  }
  strcpy(client_path_plus_slashes, client_path);
  while (client_path_len < server_path_len) {
    client_path_plus_slashes[client_path_len++] = '/';
  }
  client_path_plus_slashes[client_path_len] = '\0';
  rs_log_info("client_path_plus_slashes = %s", client_path_plus_slashes);
  return update_debug_info(path, server_path, client_path_plus_slashes);
#endif
}
コード例 #3
0
ファイル: fix_debug_info.c プロジェクト: DengZuoheng/distcc
/*
 * Update the ELF file residing at @p path, replacing all occurrences
 * of @p search with @p replace in the section named @p desired_section_name.
 * The replacement string must be the same length or shorter than
 * the search string.
 */
static void update_section(const char *path,
                           const void *base,
                           off_t size,
                           const char *desired_section_name,
                           const char *search,
                           const char *replace) {
  const void *desired_section = NULL;
  int desired_section_size = 0;

  if (FindElfSection(base, size, desired_section_name,
                     &desired_section, &desired_section_size)
      && desired_section_size > 0) {
    /* The local variable below works around a bug in some versions
     * of gcc (4.2.1?), which issues an erroneous warning if
     * 'desired_section_rw' is replaced with '(void *) desired_section'
     * in the call below, causing compile errors with -Werror.
     */
    void *desired_section_rw = (void *) desired_section;
    int count = replace_string(desired_section_rw, desired_section_size,
                               search, replace);
    if (count == 0) {
      rs_trace("\"%s\" section of file %s has no occurrences of \"%s\"",
               desired_section_name, path, search);
    } else {
      rs_log_info("updated \"%s\" section of file \"%s\": "
                  "replaced %d occurrences of \"%s\" with \"%s\"",
                  desired_section_name, path, count, search, replace);
      if (count > 1) {
        rs_log_warning("only expected to replace one occurrence!");
      }
    }
  } else {
    rs_trace("file %s has no \"%s\" section", path, desired_section_name);
  }
}
コード例 #4
0
ファイル: prefork.c プロジェクト: toh-ableton/toolwhip
/**
 * Fork a child to repeatedly accept and handle incoming connections.
 *
 * To protect against leaks, we quit after 50 requests and let the parent
 * recreate us.
 **/
static int dcc_preforked_child(int listen_fd)
{
    int ireq;
    const int child_lifetime = 50;

    for (ireq = 0; ireq < child_lifetime; ireq++) {
        int acc_fd;
        struct dcc_sockaddr_storage cli_addr;
        socklen_t cli_len;

        cli_len = sizeof cli_addr;

        do {
            acc_fd = accept(listen_fd, (struct sockaddr *) &cli_addr,
                            &cli_len);
        } while (acc_fd == -1 && errno == EINTR);

        if (acc_fd == -1) {
            rs_log_error("accept failed: %s", strerror(errno));
            dcc_exit(EXIT_CONNECT_FAILED);
        }

        dcc_service_job(acc_fd, acc_fd,
                        (struct sockaddr *) &cli_addr, cli_len);

        dcc_close(acc_fd);
    }

    rs_log_info("worn out");

    return 0;
}
コード例 #5
0
ファイル: dparent.c プロジェクト: RobbenBasten/distcc
/**
 * Main loop for no-fork mode.
 *
 * Much slower and may leak.  Should only be used when you want to run gdb on
 * distccd.
 **/
static void dcc_nofork_parent(int listen_fd)
{
    while (1) {
        int acc_fd;
        struct dcc_sockaddr_storage cli_addr;
        socklen_t cli_len;

        rs_log_info("waiting to accept connection");

        cli_len = sizeof cli_addr;
        acc_fd = accept(listen_fd,
                        (struct sockaddr *) &cli_addr, &cli_len);
        if (acc_fd == -1 && errno == EINTR) {
            ;
        }  else if (acc_fd == -1) {
            rs_log_error("accept failed: %s", strerror(errno));

#ifdef HAVE_GSSAPI
            if (dcc_auth_enabled) {
                dcc_gssapi_release_credentials();

                if (opt_blacklist_enabled || opt_whitelist_enabled) {
                    dcc_gssapi_free_list();
	            }
            }
#endif
            dcc_exit(EXIT_CONNECT_FAILED);
        } else {
            dcc_service_job(acc_fd, acc_fd, (struct sockaddr *) &cli_addr, cli_len);
            dcc_close(acc_fd);
        }
    }
}
コード例 #6
0
ファイル: auth_distcc.c プロジェクト: DengZuoheng/distcc
/*
 * Attempt handshake exchange with the server to indicate client's
 * desire to authentciate.
 *
 * @param to_net_sd.	Socket to write to.
 *
 * @param from_net_sd.	Socket to read from.
 *
 * Returns 0 on success, otherwise error.
 */
static int dcc_gssapi_send_handshake(int to_net_sd, int from_net_sd) {
    char auth = HANDSHAKE;
    fd_set sockets;
    int ret;
    struct timeval timeout;

    rs_log_info("Sending handshake.");

    if ((ret = dcc_writex(to_net_sd, &auth, sizeof(auth))) != 0) {
	return ret;
    }

    rs_log_info("Sent %c.", auth);

    FD_ZERO(&sockets);
    FD_SET(from_net_sd, &sockets);
    timeout.tv_sec = 1;
    timeout.tv_usec = 0;

    ret = select(from_net_sd + 1, &sockets, NULL, NULL, &timeout);

    if (ret < 0) {
        rs_log_error("select failed: %s.", strerror(errno));
        return EXIT_IO_ERROR;
    }

    if (ret == 0) {
        rs_log_error("Timeout - does this server require authentication?");
        return EXIT_TIMEOUT;
    }

    rs_log_info("Receiving handshake.");

    if ((ret = dcc_readx(from_net_sd, &auth, sizeof(auth))) != 0) {
        return ret;
    }

    rs_log_info("Received %c.", auth);

    if (auth != HANDSHAKE) {
        rs_log_crit("No server handshake.");
        return EXIT_GSSAPI_FAILED;
    }

    return 0;
}
コード例 #7
0
ファイル: daemon.c プロジェクト: lifelongchaser/toolwhip
static int dcc_should_be_inetd(void)
{
    /* Work out if we ought to serve stdin or be a standalone daemon */
    if (opt_inetd_mode)
        return 1;
    else if (opt_daemon_mode)
        return 0;
    else if (is_a_socket(STDIN_FILENO)) {
        rs_log_info("stdin is socket; assuming --inetd mode");
        return 1;
    } else if (isatty(STDIN_FILENO)) {
        rs_log_info("stdin is a tty; assuming --daemon mode");
        return 0;
    } else {
        rs_log_info("stdin is neither a tty nor a socket; assuming --daemon mode");
        return 0;
    }
}
コード例 #8
0
ファイル: daemon.c プロジェクト: lifelongchaser/toolwhip
int dcc_log_daemon_started(const char *role)
{
    rs_log_info("%s started (%s %s, built %s %s)",
                role,
                PACKAGE_VERSION,
                GNU_HOST,
                __DATE__, __TIME__);

    return 0;
}
コード例 #9
0
ファイル: sendfile.c プロジェクト: aosm/distcc
/*
 * Transmit the body of a file using sendfile().
 *
 * Linux at the moment requires the input be page-based -- ie a disk file, and
 * only on particular filesystems.  If the sendfile() call fails in a way that
 * makes us think that regular IO might work, then we try that instead.  For
 * example, the /tmp filesystem may not support sendfile().
 */
int
dcc_pump_sendfile(int ofd, int ifd, size_t size)
{
    ssize_t sent;
    off_t offset = 0;
    int ret;

    while (size) {
        /* Handle possibility of partial transmission, e.g. if
         * sendfile() is interrupted by a signal.  size is decremented
         * as we go. */

        sent = sys_sendfile(ofd, ifd, &offset, size);
        if (sent == -1) {
            if ((errno == ENOSYS || errno == EINVAL) && offset == 0) {
                /* The offset==0 tests is because we may be part way through
                 * the file.  We can't just naively go back to read/write
                 * because sendfile() does not update the file pointer: we
                 * would need to lseek() first.  That case is not handled at
                 * the moment because it's unlikely that sendfile() would
                 * suddenly be unsupported while we're using it.  A failure
                 * halfway through probably indicates a genuine error.*/

                rs_log_info("decided to use read/write rather than sendfile");
                return dcc_pump_readwrite(ofd, ifd, size);
            } else if (errno == EAGAIN) {
                /* Sleep until we're able to write out more data. */
                if ((ret = dcc_select_for_write(ofd, dcc_io_timeout)) != 0)
                    return ret;
                rs_trace("select() returned, continuing to write");
            } else if (errno == EINTR) {
                rs_trace("sendfile() interrupted, continuing");
            } else {
                rs_log_error("sendfile failed: %s", strerror(errno));
                return EXIT_IO_ERROR;
            }
        } else if (sent == 0) {
            rs_log_error("sendfile returned 0? can't cope");
            return EXIT_IO_ERROR;
        } else if (sent != (ssize_t) size) {
            /* offset is automatically updated by sendfile. */
            size -= sent;
            rs_log_notice("sendfile: partial transmission of %ld bytes; retrying %ld @%ld",
                          (long) sent, (long) size, (long) offset);
        } else {
            /* normal case, everything was sent. */
            break;
        }
    }
    return 0;
}
コード例 #10
0
ファイル: rs_dump_listen.c プロジェクト: haiger/MySQL-Syncer
static void rs_free_accept_thread(void *data)
{
    rs_master_info_t    *mi;

    mi = (rs_master_info_t *) data;

    /* NOTICE : if reload signal, must skip send SIGQUIT */
    if(mi != NULL) {
        rs_log_info("free accept thread");
        // kill(rs_pid, SIGQUIT);
        rs_close(mi->svr_fd);
        mi->svr_fd = -1;
    }
}
コード例 #11
0
ファイル: dparent.c プロジェクト: RobbenBasten/distcc
static void dcc_log_child_exited(pid_t kid,
                                 int status)
{
    if (WIFSIGNALED(status)) {
        int sig = WTERMSIG(status);
        int severity = sig == SIGTERM ? RS_LOG_INFO : RS_LOG_ERR;

        rs_log(severity, "child %d: signal %d (%s)", (int) kid, sig,
               WCOREDUMP(status) ? "core dumped" : "no core");
    } else if (WIFEXITED(status)) {
        rs_log_info("child %d exited: exit status %d",
                    (int) kid, WEXITSTATUS(status));
    }
}
コード例 #12
0
ファイル: auth_distcc.c プロジェクト: DengZuoheng/distcc
/*
 * Receive notification from an authenticating server as to
 * whether the client has successfully gained access or not.
 *
 * @param sd.	Socket to read from.
 *
 * Returns 0 on success, otherwise error.
 */
static int dcc_gssapi_recv_notification(int sd) {
    char notification;
    fd_set sockets;
    int ret;
    struct timeval timeout;

    FD_ZERO(&sockets);
    FD_SET(sd, &sockets);
    timeout.tv_sec = 1;
    timeout.tv_usec = 0;

    ret = select(sd + 1, &sockets, NULL, NULL, &timeout);

    if (ret < 0) {
        rs_log_error("select failed: %s.", strerror(errno));
        return EXIT_IO_ERROR;
    }

    if (ret == 0) {
        rs_log_error("Timeout - error receiving notification.");
        return EXIT_TIMEOUT;
    }

    if ((ret = dcc_readx(sd, &notification, sizeof(notification))) != 0) {
        rs_log_crit("Failed to receive notification.");
        return ret;
    }

    if (notification != ACCESS) {
	    rs_log_crit("Access denied by server.");
        rs_log_info("Your principal may be blacklisted or may not be whitelisted.");
	    return EXIT_ACCESS_DENIED;
    }

    rs_log_info("Access granted by server.");
    return 0;
}
コード例 #13
0
ファイル: zeroconf.c プロジェクト: PascalGohl/distcc
/* Write host data to host file */
static int write_hosts(struct daemon_data *d) {
    struct host *h;
    int r = 0;
    assert(d);

    rs_log_info("writing zeroconf data.\n");

    if (generic_lock(d->fd, 1, 1, 1) < 0) {
        rs_log_crit("lock failed: %s\n", strerror(errno));
        return -1;
    }

    if (lseek(d->fd, 0, SEEK_SET) < 0) {
        rs_log_crit("lseek() failed: %s\n", strerror(errno));
        return -1;
    }

    if (ftruncate(d->fd, 0) < 0) {
        rs_log_crit("ftruncate() failed: %s\n", strerror(errno));
        return -1;
    }

    remove_duplicate_services(d);

    for (h = d->hosts; h; h = h->next) {
        char t[256], a[AVAHI_ADDRESS_STR_MAX];

        if (h->resolver)
            /* Not yet fully resolved */
            continue;
	if (h->address.proto == AVAHI_PROTO_INET6)
	    snprintf(t, sizeof(t), "[%s]:%u/%i\n", avahi_address_snprint(a, sizeof(a), &h->address), h->port, d->n_slots * h->n_cpus);
	else
	    snprintf(t, sizeof(t), "%s:%u/%i\n", avahi_address_snprint(a, sizeof(a), &h->address), h->port, d->n_slots * h->n_cpus);

        if (dcc_writex(d->fd, t, strlen(t)) != 0) {
            rs_log_crit("write() failed: %s\n", strerror(errno));
            goto finish;
        }
    }

    r = 0;

finish:

    generic_lock(d->fd, 1, 0, 1);
    return r;

};
コード例 #14
0
ファイル: daemon.c プロジェクト: lifelongchaser/toolwhip
static int dcc_setup_daemon_path(void)
{
    int ret;
    const char *path;

    if ((path = getenv("DISTCCD_PATH")) != NULL) {
        if ((ret = dcc_set_path(path)))
            return ret;

        return 0;
    } else {
        path = getenv("PATH");
        rs_log_info("daemon's PATH is %s", path ? path : "(NULL)");
        return 0;
    }
}
コード例 #15
0
static void dcc_xci_zeroconf_reply(const DNSServiceRef zeroconf,
                                   const DNSServiceFlags flags,
                                   const DNSServiceErrorType error,
                                   const char *name,
                                   const char *reg_type,
                                   const char *domain,
                                   void *user_data) {
    context *ctx = user_data;

    /* Avoid unused parameter warnings. */
    (void)zeroconf;
    (void)flags;

    if (error != kDNSServiceErr_NoError) {
        rs_log_error("received error %d", error);
        ctx->thread_live = 0;
        pthread_exit(NULL);
    } else {
        rs_log_info("registered as \"%s.%s%s\"", name, reg_type, domain);
    }
}
コード例 #16
0
/* Called when publishing of service data completes */
static void publish_reply(AvahiEntryGroup *UNUSED(g), AvahiEntryGroupState state, void *userdata) {
    struct context *ctx = userdata;

    switch (state) {

        case AVAHI_ENTRY_GROUP_COLLISION: {
            char *n;

            /* Pick a new name for our service */

            n = avahi_alternative_service_name(ctx->name);
            assert(n);

            avahi_free(ctx->name);
            ctx->name = n;

            register_stuff(ctx);
            break;
        }

        case AVAHI_ENTRY_GROUP_FAILURE:
            rs_log_crit("Failed to register service: %s", avahi_strerror(avahi_client_errno(ctx->client)));
            avahi_threaded_poll_quit(ctx->threaded_poll);
            break;

        case AVAHI_ENTRY_GROUP_ESTABLISHED:
            rs_log_info("registered as \"%s.%s.%s\"",
                        avahi_client_get_host_name(ctx->client),
                        ctx->service_type,
                        avahi_client_get_domain_name(ctx->client));
            break;

        case AVAHI_ENTRY_GROUP_UNCOMMITED:
        case AVAHI_ENTRY_GROUP_REGISTERING:
            ;
    }
}
コード例 #17
0
ファイル: util.c プロジェクト: lifelongchaser/toolwhip
/* Given a string @p s, this function returns a new string with all
 * occurrences of @p find replaced with the contents of @p replace.
 * If any arguments are missing, or any error occurs, returns NULL.
 */
char *dcc_replace_substring(const char *s,
                            const char *find, const char *replace) {
    int s_left;
    int buf_pos = 0, buf_size = 0;
    char *buf = NULL, *new_buf;
    const char *next;
    int replace_len, find_len;
    int len_change;

    if (!s || !find || !replace) {
        rs_log_error("got NULL arguments");
        goto out_error;
    }
  
    find_len = strlen(find);
    replace_len = strlen(replace);

    if (!find_len) {
        rs_log_error("Asked to replace an empty string");
        goto out_error;
    }
    
    /* This is the number of chars we'll need to add each time we do
     * a replacement.  If replace is shorter then find, we'll catch it
     * with a final realloc when done. */
    len_change = replace_len - find_len;
    if (len_change < 0)
        len_change = 0;

    s_left = strlen(s);
    buf_size = s_left + 1;
    buf = malloc(buf_size * sizeof(char));
    if (!buf) {
        rs_log_error("malloc(%ld) failed: %s",
                     (long)buf_size * sizeof(char), strerror(errno));
        goto out_error;
    }

    /* Loop on matches */
    while ((next = strstr(s, find))) {
        if (len_change) {
            buf_size += len_change;
            new_buf = realloc(buf, buf_size * sizeof(char));
            if (!new_buf) {
                rs_log_error("realloc(%ld) failed: %s",
                             (long)buf_size * sizeof(char), strerror(errno));
                goto out_error;
            }
            buf = new_buf;
        }
        strncpy(buf + buf_pos, s, next - s);
        buf_pos += (next - s);
        s_left -= (next - s);
        strcpy(buf + buf_pos, replace);
        buf_pos += replace_len;
        s_left -= find_len;

        s = next + find_len;
    }
    
    /* Copy over what was left after the last replacement. */
    if (s_left) {
        strcpy(buf + buf_pos, s);
        buf_pos += s_left;
    }

    /* Terminate it. */
    buf[buf_pos++] = '\0';
    
    /* If we shrunk the string, do a final realloc to downsize it
     * to be the right length.  But, we don't fail if this doesn't
     * work because the string will still be ok, just using more
     * memory then needed. */
    if (buf_pos < buf_size) {
        buf_size = buf_pos;
        new_buf = realloc(buf, buf_size * sizeof(char));
        if (new_buf) {
            buf = new_buf;
        } else {
            rs_log_info("realloc(%ld) failed: %s",
                        (long)buf_size * sizeof(char), strerror(errno));
        }
    }

    return buf;

  out_error:

    if (buf)
        free(buf);
    return NULL;
}
コード例 #18
0
ファイル: exec.c プロジェクト: katakk/distcc
/**
 * Blocking wait for a child to exit.  This is used when waiting for
 * cpp, gcc, etc.
 *
 * This is not used by the daemon-parent; it has its own
 * implementation in dcc_reap_kids().  They could be unified, but the
 * parent only waits when it thinks a child has exited; the child
 * waits all the time.
 **/
int dcc_collect_child(const char *what, pid_t pid,
                      int *wait_status, int in_fd)
{
    struct rusage ru;
    pid_t ret_pid;

    int ret;
    int wait_timeout_sec;
    fd_set fds,readfds;

    wait_timeout_sec = dcc_job_lifetime;

    FD_ZERO(&readfds);
    if (in_fd != timeout_null_fd){
        FD_SET(in_fd,&readfds);
    }


    while (!dcc_job_lifetime || wait_timeout_sec-- >= 0) {

        /* If we're called with a socket, break out of the loop if the socket
         * disconnects. To do that, we need to block in select, not in
         * sys_wait4.  (Only waitpid uses WNOHANG to mean don't block ever,
         * so I've modified sys_wait4 above to preferentially call waitpid.)
         */
        int flags = (in_fd == timeout_null_fd) ? 0 : WNOHANG;
        ret_pid = sys_wait4(pid, wait_status, flags, &ru);

        if (ret_pid == -1) {
            if (errno == EINTR) {
                rs_trace("wait4 was interrupted; retrying");
            } else {
                rs_log_error("sys_wait4(pid=%d) borked: %s", (int) pid,
                             strerror(errno));
                return EXIT_DISTCC_FAILED;
            }
        } else if (ret_pid != 0) {
            /* This is not the main user-visible message; that comes from
             * critique_status(). */
            rs_trace("%s child %ld terminated with status %#x",
                     what, (long) ret_pid, *wait_status);
            rs_log_info("%s times: user %lld.%06lds, system %lld.%06lds, "
                        "%ld minflt, %ld majflt",
                        what,
                        ru.ru_utime.tv_sec, (long) ru.ru_utime.tv_usec,
                        ru.ru_stime.tv_sec, (long) ru.ru_stime.tv_usec,
                        ru.ru_minflt, ru.ru_majflt);

            return 0;
        }

        /* check timeout */
        if (in_fd != timeout_null_fd) {
            struct timeval timeout;

            /* If client disconnects, the socket will become readable,
             * and a read should return -1 and set errno to EPIPE.
             */
            fds = readfds;
            timeout.tv_sec = 1;
            timeout.tv_usec = 0;
            ret = select(in_fd+1,&fds,NULL,NULL,&timeout);
            if (ret == 1) {
                char buf;
                int nread = read(in_fd, &buf, 1);
                if ((nread == -1) && (errno == EWOULDBLOCK)) {
                    /* spurious wakeup, ignore */
                    ;
                } else if (nread == 0) {
                    rs_log_error("Client fd disconnected, killing job");
                    /* If killpg fails, it might means the child process is not
                     * in a new group, so, just kill the child process */
                    if (killpg(pid,SIGTERM)!=0)
                        kill(pid, SIGTERM);
                    return EXIT_IO_ERROR;
                } else if (nread == 1) {
                    rs_log_error("Bug!  Read from fd succeeded when checking "
                                 "whether client disconnected!");
                } else {
                    rs_log_error("Bug!  nread %d, errno %d checking whether "
                                 "client disconnected!", nread, errno);
                }
            }
        } else {
            poll(NULL, 0, 1000);
        }
    }
    /* If timeout, also kill the child process */
    if (killpg(pid, SIGTERM) != 0)
        kill(pid, SIGTERM);
    rs_log_error("Compilation takes too long, timeout.");

    return EXIT_TIMEOUT;
}
コード例 #19
0
ファイル: dparent.c プロジェクト: RobbenBasten/distcc
/**
 * Be a standalone server, with responsibility for sockets and forking
 * children.  Puts the daemon in the background and detaches from the
 * controlling tty.
 **/
int dcc_standalone_server(void)
{
    int listen_fd;
    int n_cpus;
    int ret;
#ifdef HAVE_AVAHI
    void *avahi = NULL;
#endif

    if ((ret = dcc_socket_listen(arg_port, &listen_fd, opt_listen_addr)) != 0)
        return ret;

    dcc_defer_accept(listen_fd);

    set_cloexec_flag(listen_fd, 1);

    if (dcc_ncpus(&n_cpus) == 0)
        rs_log_info("%d CPU%s online on this server", n_cpus, n_cpus == 1 ? "" : "s");

    /* By default, allow one job per CPU, plus two for the pot.  The extra
     * ones are started to allow for a bit of extra concurrency so that the
     * machine is not idle waiting for disk or network IO. */
    if (arg_max_jobs)
        dcc_max_kids = arg_max_jobs;
    else
        dcc_max_kids = 2 + n_cpus;

    rs_log_info("allowing up to %d active jobs", dcc_max_kids);

    if (!opt_no_detach) {
        /* Don't go into the background until we're listening and
         * ready.  This is useful for testing -- when the daemon
         * detaches, we know we can go ahead and try to connect.  */
        dcc_detach();
    } else {
        /* Still create a new process group, even if not detached */
        rs_trace("not detaching");
        if ((ret = dcc_new_pgrp()) != 0)
            return ret;
        dcc_save_pid(getpid());
    }

    /* Don't catch signals until we've detached or created a process group. */
    dcc_daemon_catch_signals();

#ifdef HAVE_AVAHI
    /* Zeroconf registration */
    if (opt_zeroconf) {
        if (!(avahi = dcc_zeroconf_register((uint16_t) arg_port, n_cpus, dcc_max_kids)))
            return EXIT_CONNECT_FAILED;
    }
#endif

    /* This is called in the master daemon, whether that is detached or
     * not.  */
    dcc_master_pid = getpid();

    if (opt_no_fork) {
        dcc_log_daemon_started("non-forking daemon");
        dcc_nofork_parent(listen_fd);
        ret = 0;
    } else {
        dcc_log_daemon_started("preforking daemon");
        ret = dcc_preforking_parent(listen_fd);
    }

#ifdef HAVE_AVAHI
    /* Remove zeroconf registration */
    if (opt_zeroconf) {
        if (dcc_zeroconf_unregister(avahi) != 0)
            return EXIT_CONNECT_FAILED;
    }
#endif

    return ret;
}
コード例 #20
0
ファイル: arg.c プロジェクト: lifelongchaser/toolwhip
/**
 * Parse arguments, extract ones we care about, and also work out
 * whether it will be possible to distribute this invocation remotely.
 *
 * This is a little hard because the cc argument rules are pretty complex, but
 * the function still ought to be simpler than it already is.
 *
 * This code is called on both the client and the server, though they use the
 * results differently.
 *
 * This function makes a copy of the arguments, modified to ensure that
 * the arguments include '-o <filename>'.  This is returned in *ret_newargv.
 * The copy is dynamically allocated and the caller is responsible for
 * deallocating it.
 *
 * If @p forced_cpp_ext is non NULL, it is filled it with the extension that
 * is forced by a -x language directive.  The caller should not free this
 * value.
 *
 * @returns 0 if it's ok to distribute this compilation, or an error code.
 **/
int dcc_scan_args(char *argv[], char **input_file, char **output_file,
                  char ***ret_newargv, const char **forced_cpp_ext)
{
    int seen_opt_c = 0, seen_opt_s = 0;
    int i;
    char *a, *optx_lang;
    const char *optx_ext = NULL;
    int ret;

     /* allow for -o foo.o */
    if ((ret = dcc_copy_argv(argv, ret_newargv, 2)) != 0)
        return ret;
    argv = *ret_newargv;

    /* FIXME: new copy of argv is leaked */

    dcc_trace_argv("scanning arguments", argv);

#ifdef XCODE_INTEGRATION
    /* Xcode invokes the distcc client as "distcc --host-info HOST" to gather
     * info about HOST.  When the request is transmitted to the distccd server,
     * it will see only "--host-info" and no other arguments in argv. */
    if (argv[0] && !strcmp(argv[0], "--host-info")) {
        return 0;
    }
#endif /* XCODE_INTEGRATION */

    /* Things like "distcc -c hello.c" with an implied compiler are
     * handled earlier on by inserting a compiler name.  At this
     * point, argv[0] should always be a compiler name. */
    if (argv[0] && argv[0][0] == '-') {
        rs_log_error("unrecognized distcc option: %s", argv[0]);
        exit(EXIT_BAD_ARGUMENTS);
    }

    *input_file = *output_file = NULL;

    for (i = 0; (a = argv[i]); i++) {
        if (a[0] == '-') {
            if (!strcmp(a, "-E")) {
                rs_trace("-E call for cpp must be local");
                return EXIT_DISTCC_FAILED;
            } else if (!strcmp(a, "-MD") || !strcmp(a, "-MMD")) {
                /* These two generate dependencies as a side effect.  They
                 * should work with the way we call cpp. */
            } else if (!strcmp(a, "-MG") || !strcmp(a, "-MP")) {
                /* These just modify the behaviour of other -M* options and do
                 * nothing by themselves. */
            } else if (!strcmp(a, "-MF") || !strcmp(a, "-MT") ||
                       !strcmp(a, "-MQ")) {
                /* As above but with extra argument. */
                i++;
            } else if (!strncmp(a, "-MF", 3) || !strncmp(a, "-MT", 3) ||
                       !strncmp(a, "-MQ", 3)) {
                /* As above, without extra argument. */
            } else if (a[1] == 'M') {
                /* -M(anything else) causes the preprocessor to
                    produce a list of make-style dependencies on
                    header files, either to stdout or to a local file.
                    It implies -E, so only the preprocessor is run,
                    not the compiler.  There would be no point trying
                    to distribute it even if we could. */
                rs_trace("%s implies -E (maybe) and must be local", a);
                return EXIT_DISTCC_FAILED;
            } else if (!strcmp(a, "-march=native")) {
                rs_trace("-march=native generates code for local machine; "
                         "must be local");
                return EXIT_DISTCC_FAILED;
            } else if (!strcmp(a, "-mtune=native")) {
                rs_trace("-mtune=native optimizes for local machine; "
                         "must be local");
                return EXIT_DISTCC_FAILED;
            } else if (str_startswith("-Wa,", a)) {
                /* Look for assembler options that would produce output
                 * files and must be local.
                 *
                 * Writing listings to stdout could be supported but it might
                 * be hard to parse reliably. */
                if (strstr(a, ",-a") || strstr(a, "--MD")) {
                    rs_trace("%s must be local", a);
                    return EXIT_DISTCC_FAILED;
                }
            } else if (str_startswith("-specs=", a)) {
                rs_trace("%s must be local", a);
                return EXIT_DISTCC_FAILED;
            } else if (!strcmp(a, "-S")) {
                seen_opt_s = 1;
            } else if (!strcmp(a, "-fprofile-arcs")
                       || !strcmp(a, "-ftest-coverage")) {
                rs_log_info("compiler will emit profile info; must be local");
                return EXIT_DISTCC_FAILED;
            } else if (!strcmp(a, "-frepo")) {
                rs_log_info("compiler will emit .rpo files; must be local");
                return EXIT_DISTCC_FAILED;
            } else if (!strcmp("-x", a)) {
              optx_lang = argv[++i];
              if (!optx_lang || !strlen(optx_lang)) {
                rs_log_info("-x requires an argument; running locally");
                return EXIT_DISTCC_FAILED;
              }
              if (*input_file) {
                rs_log_info("-x must precede source file; running locally");
                return EXIT_DISTCC_FAILED;
              }
              if (optx_ext) {
                rs_log_info("at most one -x supported; running locally");
                return EXIT_DISTCC_FAILED;
              }
              optx_ext = dcc_optx_ext_lookup(optx_lang);
              if (!optx_ext) {
                rs_log_info("unsupported -x language; running locally");
                return EXIT_DISTCC_FAILED;
              }
            } else if (str_startswith("-x", a)) {
                /* Handling -xlanguage is possible, but it makes some of the
                 * command rewriting (over in remote.c) much harder, so it
                 * isn't supported at this time. */
                rs_log_info("-xlanguage unsupported, use -x language instead; "
                            "running locally");
                return EXIT_DISTCC_FAILED;
            } else if (str_startswith("-dr", a)) {
                rs_log_info("gcc's debug option %s may write extra files; "
                            "running locally", a);
                return EXIT_DISTCC_FAILED;
            } else if (!strcmp(a, "-c")) {
                seen_opt_c = 1;
            } else if (!strcmp(a, "-o")) {
                /* Whatever follows must be the output */
                a = argv[++i];
                goto GOT_OUTPUT;
            } else if (str_startswith("-o", a)) {
                a += 2;         /* skip "-o" */
                goto GOT_OUTPUT;
            }
        } else {
            if (dcc_is_source(a)) {
                rs_trace("found input file \"%s\"", a);
                if (*input_file) {
                    rs_log_info("do we have two inputs?  i give up");
                    return EXIT_DISTCC_FAILED;
                }
                *input_file = a;
            } else if (str_endswith(".o", a)) {
              GOT_OUTPUT:
                rs_trace("found object/output file \"%s\"", a);
                if (*output_file) {
                    rs_log_info("called for link?  i give up");
                    return EXIT_DISTCC_FAILED;
                }
                *output_file = a;
            }
        }
    }

    /* TODO: ccache has the heuristic of ignoring arguments that are not
     * extant files when looking for the input file; that's possibly
     * worthwile.  Of course we can't do that on the server. */

    if (!seen_opt_c && !seen_opt_s) {
        rs_log_info("compiler apparently called not for compile");
        return EXIT_DISTCC_FAILED;
    }

    if (!*input_file) {
        rs_log_info("no visible input file");
        return EXIT_DISTCC_FAILED;
    }

    if (dcc_source_needs_local(*input_file))
        return EXIT_DISTCC_FAILED;

    if (!*output_file) {
        /* This is a commandline like "gcc -c hello.c".  They want
         * hello.o, but they don't say so.  For example, the Ethereal
         * makefile does this.
         *
         * Note: this doesn't handle a.out, the other implied
         * filename, but that doesn't matter because it would already
         * be excluded by not having -c or -S.
         */
        char *ofile;

        /* -S takes precedence over -c, because it means "stop after
         * preprocessing" rather than "stop after compilation." */
        if (seen_opt_s) {
            if (dcc_output_from_source(*input_file, ".s", &ofile))
                return EXIT_DISTCC_FAILED;
        } else if (seen_opt_c) {
            if (dcc_output_from_source(*input_file, ".o", &ofile))
                return EXIT_DISTCC_FAILED;
        } else {
            rs_log_crit("this can't be happening(%d)!", __LINE__);
            return EXIT_DISTCC_FAILED;
        }
        rs_log_info("no visible output file, going to add \"-o %s\" at end",
                      ofile);
        dcc_argv_append(argv, strdup("-o"));
        dcc_argv_append(argv, ofile);
        *output_file = ofile;
    }

    dcc_note_compiled(*input_file, *output_file);

    if (strcmp(*output_file, "-") == 0) {
        /* Different compilers may treat "-o -" as either "write to
         * stdout", or "write to a file called '-'".  We can't know,
         * so we just always run it locally.  Hopefully this is a
         * pretty rare case. */
        rs_log_info("output to stdout?  running locally");
        return EXIT_DISTCC_FAILED;
    }

    if (forced_cpp_ext)
        *forced_cpp_ext = optx_ext;

    return 0;
}
コード例 #21
0
ファイル: zeroconf.c プロジェクト: PascalGohl/distcc
/* Get the host list from zeroconf */
int dcc_zeroconf_add_hosts(struct dcc_hostdef **ret_list, int *ret_nhosts, int n_slots, struct dcc_hostdef **ret_prev) {
    char host_file[PATH_MAX], lock_file[PATH_MAX], *s = NULL;
    int lock_fd = -1, host_fd = -1;
    int fork_daemon = 0;
    int r = -1;
    char *dir;
    struct stat st;

    if (get_zeroconf_dir(&dir) != 0) {
        rs_log_crit("failed to get zeroconf dir.\n");
        goto finish;
    }

    snprintf(lock_file, sizeof(lock_file), "%s/lock", dir);
    snprintf(host_file, sizeof(host_file), "%s/hosts", dir);

    /* Open lock file */
    if ((lock_fd = open(lock_file, O_RDWR|O_CREAT, 0666)) < 0) {
        rs_log_crit("open('%s') failed: %s\n", lock_file, strerror(errno));
        goto finish;
    }

    /* Try to lock the lock file */
    if (generic_lock(lock_fd, 1, 1, 0) >= 0) {
        /* The lock succeeded => there's no daemon running yet! */
        fork_daemon = 1;
        generic_lock(lock_fd, 1, 0, 0);
    }

    close(lock_fd);

    /* Shall we fork a new daemon? */
    if (fork_daemon) {
        pid_t pid;

        rs_log_info("Spawning zeroconf daemon.\n");

        if ((pid = fork()) == -1) {
            rs_log_crit("fork() failed: %s\n", strerror(errno));
            goto finish;
        } else if (pid == 0) {
            int fd;
            /* Child */

            /* Close file descriptors and replace them by /dev/null */
            close(0);
            close(1);
            close(2);
            fd = open("/dev/null", O_RDWR);
            assert(fd == 0);
            fd = dup(0);
            assert(fd == 1);
            fd = dup(0);
            assert(fd == 2);

#ifdef HAVE_SETSID
            setsid();
#endif

            chdir("/");
            rs_add_logger(rs_logger_syslog, RS_LOG_DEBUG, NULL, 0);
            _exit(daemon_proc(host_file, lock_file, n_slots));
        }

        /* Parent */

        /* Wait some time for initial host gathering */
        usleep(1000000);         /* 1000 ms */
    }

    /* Open host list read-only */
    if ((host_fd = open(host_file, O_RDONLY)) < 0) {
        rs_log_crit("open('%s') failed: %s\n", host_file, strerror(errno));
        goto finish;
    }

    /* A read lock */
    if (generic_lock(host_fd, 0, 1, 1) < 0) {
        rs_log_crit("lock failed: %s\n", strerror(errno));
        goto finish;
    }

    /* Get file size */
    if (fstat(host_fd, &st) < 0) {
        rs_log_crit("stat() failed: %s\n", strerror(errno));
        goto finish;
    }

    if (st.st_size >= MAX_FILE_SIZE) {
        rs_log_crit("file too large.\n");
        goto finish;
    }

    /* read file data */
    s = malloc((size_t) st.st_size+1);
    assert(s);

    if (dcc_readx(host_fd, s, (size_t) st.st_size) != 0) {
        rs_log_crit("failed to read from file.\n");
        goto finish;
    }
    s[st.st_size] = 0;

    /* Parse host data */
    if (dcc_parse_hosts(s, host_file, ret_list, ret_nhosts, ret_prev) != 0) {
        rs_log_crit("failed to parse host file.\n");
        goto finish;
    }

    r = 0;

finish:
    if (host_fd >= 0) {
        generic_lock(host_fd, 0, 0, 1);
        close(host_fd);
    }

    free(s);

    return r;
}
コード例 #22
0
ファイル: zeroconf.c プロジェクト: PascalGohl/distcc
/* The main function of the background daemon */
static int daemon_proc(const char *host_file, const char *lock_file, int n_slots) {
    int ret = 1;
    int lock_fd = -1;
    struct daemon_data d;
    time_t clip_time;
    int error;
    char machine[64], version[64], stype[128];

    rs_add_logger(rs_logger_syslog, RS_LOG_DEBUG, NULL, 0);

    /* Prepare daemon data structure */
    d.fd = -1;
    d.hosts = NULL;
    d.n_slots = n_slots;
    d.simple_poll = NULL;
    d.browser = NULL;
    d.client = NULL;
    clip_time = time(NULL);

    rs_log_info("Zeroconf daemon running.\n");

    /* Open daemon lock file and lock it */
    if ((lock_fd = open(lock_file, O_RDWR|O_CREAT, 0666)) < 0) {
        rs_log_crit("open('%s') failed: %s\n", lock_file, strerror(errno));
        goto finish;
    }

    if (generic_lock(lock_fd, 1, 1, 0) < 0) {
        /* lock failed, there's probably already another daemon running */
        goto finish;
    }

    /* Open host file */
    if ((d.fd = open(host_file, O_RDWR|O_CREAT, 0666)) < 0) {
        rs_log_crit("open('%s') failed: %s\n", host_file, strerror(errno));
        goto finish;
    }

    /* Clear host file */
    write_hosts(&d);

    if (!(d.simple_poll = avahi_simple_poll_new())) {
        rs_log_crit("Failed to create simple poll object.\n");
        goto finish;
    }

    if (!(d.client = avahi_client_new(
                  avahi_simple_poll_get(d.simple_poll),
                  0,
                  client_callback,
                  &d,
                  &error))) {
        rs_log_crit("Failed to create Avahi client object: %s\n", avahi_strerror(error));
        goto finish;
    }

    if (dcc_get_gcc_version(version, sizeof(version)) &&
        dcc_get_gcc_machine(machine, sizeof(machine))) {

        dcc_make_dnssd_subtype(stype, sizeof(stype), version, machine);
    } else {
        rs_log_warning("Warning, failed to get CC version and machine type.\n");

        strncpy(stype, DCC_DNS_SERVICE_TYPE, sizeof(stype));
        stype[sizeof(stype)-1] = 0;
    }

    rs_log_info("Browsing for '%s'.\n", stype);

    if (!(d.browser = avahi_service_browser_new(
                  d.client,
                  AVAHI_IF_UNSPEC,
                  AVAHI_PROTO_UNSPEC,
                  stype,
                  NULL,
                  0,
                  browse_reply,
                  &d))) {
        rs_log_crit("Failed to create service browser object: %s\n", avahi_strerror(avahi_client_errno(d.client)));
        goto finish;
    }

    /* Check whether the host file has been used recently */
    while (fd_last_used(d.fd, clip_time) <= MAX_IDLE_TIME) {

        /* Iterate the main loop for 5s */
        if (avahi_simple_poll_iterate(d.simple_poll, 5000) != 0) {
            rs_log_crit("Event loop exited abnormaly.\n");
            goto finish;
        }
    }

    /* Wer are idle */
    rs_log_info("Zeroconf daemon unused.\n");

    ret = 0;

finish:

    /* Cleanup */
    if (lock_fd >= 0) {
        generic_lock(lock_fd, 1, 0, 0);
        close(lock_fd);
    }

    if (d.fd >= 0)
        close(d.fd);

    while (d.hosts) {
        struct host *h = d.hosts;
        d.hosts = d.hosts->next;
        free_host(h);
    }

    if (d.client)
        avahi_client_free(d.client);

    if (d.simple_poll)
        avahi_simple_poll_free(d.simple_poll);

    rs_log_info("zeroconf daemon ended.\n");

    return ret;
}
コード例 #23
0
ファイル: zeroconf.c プロジェクト: PascalGohl/distcc
/* Called whenever a new service is found or removed */
static void browse_reply(
        AvahiServiceBrowser *UNUSED(b),
        AvahiIfIndex interface,
        AvahiProtocol protocol,
        AvahiBrowserEvent event,
        const char *name,
        const char *type,
        const char *domain,
        AvahiLookupResultFlags UNUSED(flags),
        void *userdata) {

    struct daemon_data *d = userdata;
    assert(d);

    switch (event) {
        case AVAHI_BROWSER_NEW: {
            struct host *h;

            h = malloc(sizeof(struct host));
            assert(h);

            rs_log_info("new service: %s\n", name);

            if (!(h->resolver = avahi_service_resolver_new(d->client,
                                                           interface,
                                                           protocol,
                                                           name,
                                                           type,
                                                           domain,
                                                           AVAHI_PROTO_UNSPEC,
                                                           0,
                                                           resolve_reply,
                                                           h))) {
                rs_log_warning("Failed to create service resolver for '%s': %s\n", name,
                               avahi_strerror(avahi_client_errno(d->client)));

                free(h);

            } else {

                /* Fill in missing data */
                h->service = strdup(name);
                assert(h->service);
                h->domain = strdup(domain);
                assert(h->domain);
                h->daemon_data = d;
                h->interface = interface;
                h->protocol = protocol;
                h->next = d->hosts;
                h->n_cpus = 1;
                d->hosts = h;
            }

            break;
        }

        case AVAHI_BROWSER_REMOVE:

            rs_log_info("Removed service: %s\n", name);

            remove_service(d, interface, protocol, name, domain);
            write_hosts(d);
            break;

        case AVAHI_BROWSER_FAILURE:
            rs_log_crit("Service Browser failure '%s': %s\n", name,
                        avahi_strerror(avahi_client_errno(d->client)));

            avahi_simple_poll_quit(d->simple_poll);
            break;

        case AVAHI_BROWSER_CACHE_EXHAUSTED:
        case AVAHI_BROWSER_ALL_FOR_NOW:
            ;

    }
}
コード例 #24
0
ファイル: auth_distcc.c プロジェクト: DengZuoheng/distcc
/*
 * Establish a secure context using the GSS-API.  A handshake is attempted in
 * order to detect a non-authenticating server.  The server IP address is obtained
 * from the socket and is used to perform an fqdn lookup in case a DNS alias is
 * used as a host spec, this ensures we authenticate against the correct server.
 * We attempt to extract the server principal name, a service, from the
 * environment, if it is not specified we use "host/" as a default.
 *
 * @pram to_net_sd.	Socket to write to.
 *
 * @pram from_net_sd.	Socket to read from.
 *
 * @param req_flags.	A representation of the security services to
 *			be requested.
 *
 * @param ret_flags.    A representation of the security services
 *			provided/supported by the underlying mechanism
 *			to be returned to the invoking function.
 *
 * Returns 0 on success, otherwise error.
 */
static int dcc_gssapi_establish_secure_context(int to_net_sd,
					       int from_net_sd,
					       OM_uint32 req_flags,
					       OM_uint32 *ret_flags) {
    char *ext_princ_name = NULL;
    char *full_name = NULL;
    char *princ_env_val = NULL;
    gss_buffer_desc input_tok = GSS_C_EMPTY_BUFFER;
    gss_buffer_desc name_buffer = GSS_C_EMPTY_BUFFER;
    gss_buffer_desc output_tok = GSS_C_EMPTY_BUFFER;
    gss_name_t int_serv_name;
    gss_OID name_type;
    int ret;
    OM_uint32 major_status, minor_status, return_status;
    socklen_t addr_len;
    struct hostent *hp;
    struct sockaddr_in addr;

    addr_len = sizeof(addr);

    if ((ret = getpeername(to_net_sd, &addr, &addr_len)) != 0) {
        rs_log_error("Failed to look up peer address using socket \"%d\": %s.",
                     to_net_sd,
                     hstrerror(h_errno));
        return EXIT_CONNECT_FAILED;
    }

    rs_log_info("Successfully looked up IP address %s using socket %d.",
                                                inet_ntoa(addr.sin_addr),
                                                to_net_sd);

    if ((hp = gethostbyaddr((char *) &addr.sin_addr,
                            sizeof(addr.sin_addr),
                            AF_INET)) == NULL) {
        rs_log_error("Failed to look up host by address \"%s\": %s.",
                     inet_ntoa(addr.sin_addr),
                     hstrerror(h_errno));
        return EXIT_CONNECT_FAILED;
    }

    rs_log_info("Successfully looked up host %s using IP address %s.",
                                                hp->h_name,
                                                inet_ntoa(addr.sin_addr));

    if ((full_name = malloc(strlen(hp->h_name) + 1)) == NULL) {
        rs_log_error("malloc failed : %ld bytes: out of memory.",
                                        (long) (strlen(hp->h_name) + 1));
        return EXIT_OUT_OF_MEMORY;
    }

    strcpy(full_name, hp->h_name);

    if ((princ_env_val = getenv("DISTCC_PRINCIPAL"))) {
        if (asprintf(&ext_princ_name, "%s@%s", princ_env_val, full_name) < 0) {
            rs_log_error("Failed to allocate memory for asprintf.");
            return EXIT_OUT_OF_MEMORY;
        }

        name_type = GSS_C_NT_HOSTBASED_SERVICE;
    } else {
        if (asprintf(&ext_princ_name, "host/%s", full_name) < 0) {
            rs_log_error("Failed to allocate memory for asprintf.");
            return EXIT_OUT_OF_MEMORY;
        }

        name_type = GSS_C_NT_USER_NAME;
    }

    free(full_name);
    name_buffer.value = ext_princ_name;
    name_buffer.length = strlen(ext_princ_name);

    if ((major_status = gss_import_name(&minor_status,
				       &name_buffer,
				       name_type,
				       &int_serv_name)) != GSS_S_COMPLETE) {
	rs_log_error("Failed to import service name to internal GSS-API format.");
        return EXIT_GSSAPI_FAILED;
    }

    input_tok.value = NULL;
    input_tok.length = 0;
    output_tok.value = NULL;
    output_tok.length = 0;

    if ((ret = dcc_gssapi_send_handshake(to_net_sd, from_net_sd)) != 0) {
        return ret;
    }

    do
    {
        major_status = gss_init_sec_context(&minor_status,
					    GSS_C_NO_CREDENTIAL,
					    &distcc_ctx_handle,
					    int_serv_name,
					    GSS_C_NO_OID,
					    req_flags,
					    0,
					    GSS_C_NO_CHANNEL_BINDINGS,
					    &input_tok,
					    NULL,
					    &output_tok,
					    ret_flags,
					    NULL);

	if (GSS_ERROR(major_status)) {
	    rs_log_crit("Failed to initiate a secure context.");
	    dcc_gssapi_status_to_log(major_status, GSS_C_GSS_CODE);
	    dcc_gssapi_status_to_log(minor_status, GSS_C_MECH_CODE);
	    return EXIT_GSSAPI_FAILED;
	}

	if (output_tok.length > 0) {
	    if ((ret = send_token(to_net_sd, &output_tok)) != 0) {
		dcc_gssapi_cleanup(&input_tok, &output_tok, &int_serv_name);
		return ret;
	    } else {
		if ((return_status = gss_release_buffer(&minor_status,
						 &output_tok)) != GSS_S_COMPLETE) {
		    rs_log_error("Failed to release buffer.");
		}
	    }
	}

	if (input_tok.length > 0) {
	    if ((return_status = gss_release_buffer(&minor_status,
						   &input_tok)) != GSS_S_COMPLETE) {
		rs_log_error("Failed to release buffer.");
	    }
	}

	if (major_status == GSS_S_CONTINUE_NEEDED) {
	    if ((ret = recv_token(from_net_sd, &input_tok)) != 0) {
		dcc_gssapi_cleanup(&input_tok, &output_tok, &int_serv_name);
		return ret;
	    }
	}

    } while (major_status != GSS_S_COMPLETE);

    rs_log_info("Successfully authenticated %s.", ext_princ_name);
    dcc_gssapi_cleanup(&input_tok, &output_tok, &int_serv_name);

    if ((major_status = gss_release_buffer(&minor_status,
					  &name_buffer)) != GSS_S_COMPLETE) {
	rs_log_error("Failed to release buffer.");
    }

    return 0;
}
コード例 #25
0
ファイル: rs_dump_listen.c プロジェクト: haiger/MySQL-Syncer
/*
 *  Description
 *      Create listen fd for registering slaves.
 *      
 *  
 *  Return Value
 *      On success, RS_OK is returned. On error, RS_ERR is returned
 *
 */
int rs_dump_listen(rs_master_info_t *mi) 
{
    int     err, tries, reuseaddr;
    struct  sockaddr_in svr_addr;

    /* init var */
    reuseaddr = 1;
    rs_memzero(&svr_addr, sizeof(svr_addr));

    svr_addr.sin_family = AF_INET;

    if(mi->listen_port <= 0) {
        rs_log_err(0, "listen_port is invalid");
        goto free;
    }
 
    svr_addr.sin_port = htons(mi->listen_port);

    if(mi->listen_addr == NULL) {
        rs_log_err(0, "listen_addr must not be null");
        goto free;
    }

    if (inet_pton(AF_INET, mi->listen_addr, &(svr_addr.sin_addr)) != 1) {
        rs_log_err(rs_errno, "inet_pton() failed, %s", mi->listen_addr);
        goto free;
    }

    for(tries = RS_RETRY_BIND_TIMES; tries; tries--) {

        mi->svr_fd = socket(AF_INET, SOCK_STREAM, 0);

        if(mi->svr_fd == -1) {
            rs_log_err(rs_errno, "socket() failed");
            goto free;
        }

        if(setsockopt(mi->svr_fd, SOL_SOCKET, SO_REUSEADDR, 
                    (const void *) &reuseaddr, sizeof(int)) == -1)
        {
            rs_log_err(rs_errno, "setsockopt(SO_REUSEADDR) failed, %s", 
                    mi->listen_addr);
            goto free;
        }

        if(bind(mi->svr_fd, (const struct sockaddr *) &svr_addr, 
                    sizeof(svr_addr)) == -1) 
        {
            err = errno;

            rs_close(mi->svr_fd);
            mi->svr_fd = -1;

            if(err != EADDRINUSE) {
                rs_log_err(err, "bind() failed, %s", mi->listen_addr);
                goto free;
            }

            rs_log_info(0, "try again to bind() after %ums"
                    , RS_RETRY_BIND_SLEEP_MSC);

            usleep(RS_RETRY_BIND_SLEEP_MSC * 1000);

            continue;
        }

        if(listen(mi->svr_fd, RS_BACKLOG) == -1) {
            rs_log_err(rs_errno, "listen() failed, %s", mi->listen_addr);
            goto free;
        }

        break;
    }

    if(!tries) {
        goto free;
    }

    return RS_OK;

free : 
    return RS_ERR;
}