static void server_send_login (struct irc_network *s) { struct irc_login_details *login_details = s->callbacks->get_login_details(s); g_assert(s); s->connection.state = NETWORK_CONNECTION_STATE_LOGIN_SENT; network_log(LOG_TRACE, s, "Sending login details"); s->external_state = network_state_init(login_details->nick, login_details->username, get_my_hostname()); network_state_set_log_fn(s->external_state, state_log_helper, s); if (s->callbacks->state_set) s->callbacks->state_set(s); g_assert(s->linestack != NULL); if (login_details->password != NULL) { network_send_args(s, "PASS", login_details->password, NULL); } g_assert(login_details->nick != NULL && strlen(login_details->nick) > 0); network_send_args(s, "NICK", login_details->nick, NULL); g_assert(login_details->username != NULL && strlen(login_details->username) > 0); g_assert(login_details->mode != NULL && strlen(login_details->mode) > 0); g_assert(login_details->unused != NULL && strlen(login_details->unused) > 0); g_assert(login_details->realname != NULL && strlen(login_details->realname) > 0); network_send_args(s, "USER", login_details->username, login_details->mode, login_details->unused, login_details->realname, NULL); free_login_details(login_details); }
gchar *get_server_name(void) { gchar *server_name; server_name = g_strdup(g_getenv("PIONEERS_SERVER_NAME")); if (!server_name) server_name = g_strdup(g_getenv("GNOCATAN_SERVER_NAME")); if (!server_name) server_name = get_my_hostname(); return server_name; }
static void plain_handle_auth_finish(struct daemon_backend *backend, gboolean accepted) { struct daemon_client *dc = (struct daemon_client *)backend->userdata; if (!accepted) { transport_send_response(dc->client_transport, NULL, get_my_hostname(), "*", ERR_PASSWDMISMATCH, "Password invalid", NULL); daemon_client_kill(dc); } else { daemon_client_forward_credentials(dc); } }
static gboolean handle_client_line(struct pending_client *pc, const struct irc_line *l) { struct daemon_client *cd = pc->private_data; if (l == NULL || l->args[0] == NULL) { return TRUE; } if (!base_strcmp(l->args[0], "PASS")) { cd->login_details->password = g_strdup(l->args[1]); } else if (!base_strcmp(l->args[0], "CONNECT")) { cd->servername = g_strdup(l->args[1]); cd->servicename = g_strdup(l->args[2]); } else if (!base_strcmp(l->args[0], "USER") && l->argc > 4) { cd->login_details->username = g_strdup(l->args[1]); cd->login_details->mode = g_strdup(l->args[2]); cd->login_details->unused = g_strdup(l->args[3]); cd->login_details->realname = g_strdup(l->args[4]); } else if (!base_strcmp(l->args[0], "NICK")) { cd->login_details->nick = g_strdup(l->args[1]); } else if (!base_strcmp(l->args[0], "QUIT")) { return FALSE; } else { irc_sendf(pc->connection, pc->listener->iconv, NULL, ":%s %d %s :You are not registered. Did you specify a password?", get_my_hostname(), ERR_NOTREGISTERED, "*"); g_io_channel_flush(pc->connection, NULL); } if (cd->login_details->username != NULL && cd->login_details->password != NULL && cd->login_details->nick != NULL) { if (!daemon_client_connect_backend(cd, pc, cd->login_details->username)) return FALSE; cd->description = g_io_channel_ip_get_description(pc->connection); listener_log(LOG_INFO, pc->listener, "Accepted new client %s for user %s", cd->description, cd->user->username); cd->client_transport = irc_transport_new_iochannel(pc->connection); daemon_backend_authenticate(cd->backend, cd->login_details->password, plain_handle_auth_finish); irc_transport_set_callbacks(cd->client_transport, &daemon_client_callbacks, cd); return FALSE; } return TRUE; }
/** * iterate through the 'login_servers' configuration variable, contacting * each one and setting my copy of peer's key on it * @param name of the client key to push * @return the number of login servers we failed to set the key on * (thus 0 is success) */ int pushkey (const char *peer, const security_context * context, const char *crt) { pool *p = NULL; char **lservers = libpbc_config_getlist (p, "login_servers"); const char *hostname; char *lservername, *ptr, *lhostname; int x; int res; int fail = 0; if (!lservers) { /* only me here */ return (0); } hostname = get_my_hostname (p, context); if (!hostname) { pbc_log_activity (p, PBC_LOG_ERROR, "get_my_hostname() failed? %m"); perror ("get_my_hostname"); exit (1); } x = 0; for (x = 0; lservers[x] != NULL; x++) { /* login_servers (should? might?) contain a URI */ /* break out the hostname and see if that is us */ lhostname = lservername = strdup (lservers[x]); if (!strncmp (lhostname, "https://", 8)) lhostname += 8; ptr = strchr (lhostname, '/'); if (ptr) { *ptr = '\0'; } ptr = strchr (lhostname, ':'); if (ptr) { *ptr = '\0'; } if (!strcasecmp (hostname, lhostname)) { /* don't push the key to myself */ free (lservername); continue; } free (lservername); pbc_log_activity (p, PBC_LOG_AUDIT, "setting %s's %s on %s", peer, crt ? "pubkey" : "key", lservers[x]); res = fork (); if (res < 0) { pbc_log_activity (p, PBC_LOG_ERROR, "fork(): %m"); perror ("fork"); exit (1); } if (res == 0) { const char *keyclient = KEYCLIENT; const char *cmd[20]; int n = 0; close(0); close(1); close(2); cmd[n++] = keyclient; cmd[n++] = "-q"; if (crt) { cmd[n++] = "-U"; /* upload a cert */ cmd[n++] = crt; } else cmd[n++] = "-u"; /* upload a key */ cmd[n++] = "-H"; cmd[n++] = peer; cmd[n++] = "-L"; cmd[n++] = lservers[x]; cmd[n++] = "-k"; cmd[n++] = keyfile; cmd[n++] = "-c"; cmd[n++] = certfile; if (cafile != NULL) { cmd[n++] = "-C"; cmd[n++] = cafile; } if (cadir != NULL) { cmd[n++] = "-D"; cmd[n++] = cadir; } if (NULL != configfile) { cmd[n++] = "-f"; cmd[n++] = configfile; } cmd[n] = NULL; res = execv (keyclient, (char **const) cmd); pbc_log_activity (p, PBC_LOG_ERROR, "execv(): %m"); for (n = 0; cmd[n] != NULL; n++) { pbc_log_activity (p, PBC_LOG_ERROR, "%d %s", n, cmd[n]); } exit (2); } /* parent */ wait (&res); pbc_log_activity (p, PBC_LOG_AUDIT, "setting %s's key on %s: %s", peer, lservers[x], WEXITSTATUS (res) == 0 ? "done" : "error"); if (WEXITSTATUS (res) != 0) { fail++; } } free (lservers); return fail; }
static void create_services(AvahiClient * c, Game * game) { gchar *hostname; gchar *servicename; AvahiStringList *sl; int ret; g_assert(c != NULL); /* If this is the first time we're called, let's create a new entry group */ if (!group) { if (! (group = avahi_entry_group_new(c, entry_group_callback, NULL))) { log_message(MSG_ERROR, _("Avahi error: %s, %s\n"), "avahi_entry_group_new() failed", avahi_strerror(avahi_client_errno(c))); avahi_glib_poll_free(glib_poll); return; } } sl = avahi_string_list_new(NULL, NULL); sl = avahi_string_list_add_printf(sl, "version=%s", PROTOCOL_VERSION); sl = avahi_string_list_add_printf(sl, "title=%s", game->params->title); /* Add the service for IPP */ hostname = game->hostname ? g_strdup(game->hostname) : get_my_hostname(); servicename = g_strdup_printf("%s [%s]", hostname, game->server_port); g_free(hostname); ret = avahi_entry_group_add_service_strlst(group, AVAHI_IF_UNSPEC, AVAHI_NETWORK_PROTOCOL, 0, servicename, AVAHI_ANNOUNCE_NAME, NULL, NULL, atoi(game->server_port), sl); g_free(servicename); if (ret < 0) { gchar *msg = g_strdup_printf("Failed to add '%s' service", AVAHI_ANNOUNCE_NAME); log_message(MSG_ERROR, _("Avahi error: %s, %s\n"), msg, avahi_strerror(ret)); g_free(msg); avahi_string_list_free(sl); avahi_glib_poll_free(glib_poll); return; } /* Tell the server to register the service */ if ((ret = avahi_entry_group_commit(group)) < 0) { log_message(MSG_ERROR, _("Avahi error: %s, %s\n"), "Failed to commit entry_group", avahi_strerror(ret)); avahi_string_list_free(sl); avahi_glib_poll_free(glib_poll); return; } avahi_string_list_free(sl); return; }
int cmd_invite(int argc, char *argv[]) { if(argc < 2) { fprintf(stderr, "Not enough arguments!\n"); return 1; } // Check validity of the new node's name if(!check_id(argv[1])) { fprintf(stderr, "Invalid name for node.\n"); return 1; } char *myname = get_my_name(true); if(!myname) return 1; // Ensure no host configuration file with that name exists char filename[PATH_MAX]; snprintf(filename, sizeof filename, "%s" SLASH "hosts" SLASH "%s", confbase, argv[1]); if(!access(filename, F_OK)) { fprintf(stderr, "A host config file for %s already exists!\n", argv[1]); return 1; } // If a daemon is running, ensure no other nodes know about this name bool found = false; if(connect_tincd(false)) { sendline(fd, "%d %d", CONTROL, REQ_DUMP_NODES); while(recvline(fd, line, sizeof line)) { char node[4096]; int code, req; if(sscanf(line, "%d %d %s", &code, &req, node) != 3) break; if(!strcmp(node, argv[1])) found = true; } if(found) { fprintf(stderr, "A node with name %s is already known!\n", argv[1]); return 1; } } snprintf(filename, sizeof filename, "%s" SLASH "invitations", confbase); if(mkdir(filename, 0700) && errno != EEXIST) { fprintf(stderr, "Could not create directory %s: %s\n", filename, strerror(errno)); return 1; } // Count the number of valid invitations, clean up old ones DIR *dir = opendir(filename); if(!dir) { fprintf(stderr, "Could not read directory %s: %s\n", filename, strerror(errno)); return 1; } errno = 0; int count = 0; struct dirent *ent; time_t deadline = time(NULL) - 604800; // 1 week in the past while((ent = readdir(dir))) { if(strlen(ent->d_name) != 24) continue; char invname[PATH_MAX]; struct stat st; snprintf(invname, sizeof invname, "%s" SLASH "%s", filename, ent->d_name); if(!stat(invname, &st)) { if(deadline < st.st_mtime) count++; else unlink(invname); } else { fprintf(stderr, "Could not stat %s: %s\n", invname, strerror(errno)); errno = 0; } } closedir(dir); if(errno) { fprintf(stderr, "Error while reading directory %s: %s\n", filename, strerror(errno)); return 1; } ecdsa_t *key; snprintf(filename, sizeof filename, "%s" SLASH "invitations" SLASH "ed25519_key.priv", confbase); // Remove the key if there are no outstanding invitations. if(!count) unlink(filename); // Create a new key if necessary. FILE *f = fopen(filename, "r"); if(!f) { if(errno != ENOENT) { fprintf(stderr, "Could not read %s: %s\n", filename, strerror(errno)); return 1; } key = ecdsa_generate(); if(!key) return 1; f = fopen(filename, "w"); if(!f) { fprintf(stderr, "Could not write %s: %s\n", filename, strerror(errno)); return 1; } chmod(filename, 0600); if(!ecdsa_write_pem_private_key(key, f)) { fprintf(stderr, "Could not write ECDSA private key\n"); fclose(f); return 1; } fclose(f); if(connect_tincd(false)) sendline(fd, "%d %d", CONTROL, REQ_RELOAD); } else { key = ecdsa_read_pem_private_key(f); fclose(f); if(!key) fprintf(stderr, "Could not read private key from %s\n", filename); } if(!key) return 1; // Create a hash of the key. char hash[64]; char *fingerprint = ecdsa_get_base64_public_key(key); sha512(fingerprint, strlen(fingerprint), hash); b64encode_urlsafe(hash, hash, 18); // Create a random cookie for this invitation. char cookie[25]; randomize(cookie, 18); // Create a filename that doesn't reveal the cookie itself char buf[18 + strlen(fingerprint)]; char cookiehash[64]; memcpy(buf, cookie, 18); memcpy(buf + 18, fingerprint, sizeof buf - 18); sha512(buf, sizeof buf, cookiehash); b64encode_urlsafe(cookiehash, cookiehash, 18); b64encode_urlsafe(cookie, cookie, 18); // Create a file containing the details of the invitation. snprintf(filename, sizeof filename, "%s" SLASH "invitations" SLASH "%s", confbase, cookiehash); int ifd = open(filename, O_RDWR | O_CREAT | O_EXCL, 0600); if(!ifd) { fprintf(stderr, "Could not create invitation file %s: %s\n", filename, strerror(errno)); return 1; } f = fdopen(ifd, "w"); if(!f) abort(); // Get the local address char *address = get_my_hostname(); // Fill in the details. fprintf(f, "Name = %s\n", argv[1]); if(netname) fprintf(f, "NetName = %s\n", netname); fprintf(f, "ConnectTo = %s\n", myname); // Copy Broadcast and Mode FILE *tc = fopen(tinc_conf, "r"); if(tc) { char buf[1024]; while(fgets(buf, sizeof buf, tc)) { if((!strncasecmp(buf, "Mode", 4) && strchr(" \t=", buf[4])) || (!strncasecmp(buf, "Broadcast", 9) && strchr(" \t=", buf[9]))) { fputs(buf, f); // Make sure there is a newline character. if(!strchr(buf, '\n')) fputc('\n', f); } } fclose(tc); } fprintf(f, "#---------------------------------------------------------------#\n"); fprintf(f, "Name = %s\n", myname); char filename2[PATH_MAX]; snprintf(filename2, sizeof filename2, "%s" SLASH "hosts" SLASH "%s", confbase, myname); fcopy(f, filename2); fclose(f); // Create an URL from the local address, key hash and cookie char *url; xasprintf(&url, "%s/%s%s", address, hash, cookie); // Call the inviation-created script char *envp[6] = {}; xasprintf(&envp[0], "NAME=%s", myname); xasprintf(&envp[1], "NETNAME=%s", netname); xasprintf(&envp[2], "NODE=%s", argv[1]); xasprintf(&envp[3], "INVITATION_FILE=%s", filename); xasprintf(&envp[4], "INVITATION_URL=%s", url); execute_script("invitation-created", envp); for(int i = 0; i < 6 && envp[i]; i++) free(envp[i]); puts(url); free(url); free(address); return 0; }