int confWrite() { if (config_buffer) { char conffile[1024]; char tempfile[1024]; FILE *outf = NULL; if (!FORM_SERVAL_INSTANCE_PATH(conffile, "serval.conf")) return -1; if (!FORM_SERVAL_INSTANCE_PATH(tempfile, "serval.conf.temp")) return -1; if ((outf = fopen(tempfile, "w")) == NULL) return WHYF_perror("fopen(%s, \"w\")", tempfile); unsigned int i; for (i = 0; i != confc; ++i) fprintf(outf, "%s=%s\n", confvar[i], confvalue[i]); if (fclose(outf) == EOF) return WHYF_perror("fclose(%s)", tempfile); if (rename(tempfile, conffile)) { WHYF_perror("rename(%s, %s)", tempfile, conffile); unlink(tempfile); return -1; } } return 0; }
int overlay_mdp_recv(overlay_mdp_frame *mdp, int port, int *ttl) { char mdp_socket_name[101]; unsigned char recvaddrbuffer[1024]; struct sockaddr *recvaddr=(struct sockaddr *)recvaddrbuffer; unsigned int recvaddrlen=sizeof(recvaddrbuffer); struct sockaddr_un *recvaddr_un; if (!FORM_SERVAL_INSTANCE_PATH(mdp_socket_name, "mdp.socket")) return WHY("Could not find mdp socket"); mdp->packetTypeAndFlags=0; /* Check if reply available */ set_nonblock(mdp_client_socket); ssize_t len = recvwithttl(mdp_client_socket,(unsigned char *)mdp, sizeof(overlay_mdp_frame),ttl,recvaddr,&recvaddrlen); set_block(mdp_client_socket); recvaddr_un=(struct sockaddr_un *)recvaddr; /* Null terminate received address so that the stat() call below can succeed */ if (recvaddrlen<1024) recvaddrbuffer[recvaddrlen]=0; if (len>0) { /* Make sure recvaddr matches who we sent it to */ if (strncmp(mdp_socket_name, recvaddr_un->sun_path, sizeof(recvaddr_un->sun_path))) { /* Okay, reply was PROBABLY not from the server, but on OSX if the path has a symlink in it, it is resolved in the reply path, but might not be in the request path (mdp_socket_name), thus we need to stat() and compare inode numbers etc */ struct stat sb1,sb2; if (stat(mdp_socket_name,&sb1)) return WHY("stat(mdp_socket_name) failed, so could not verify that reply came from MDP server"); if (stat(recvaddr_un->sun_path,&sb2)) return WHY("stat(ra->sun_path) failed, so could not verify that reply came from MDP server"); if ((sb1.st_ino!=sb2.st_ino)||(sb1.st_dev!=sb2.st_dev)) return WHY("Reply did not come from server"); } // silently drop incoming packets for the wrong port number if (port>0 && port != mdp->in.dst.port){ WARNF("Ignoring packet for port %d",mdp->in.dst.port); return -1; } int expected_len = overlay_mdp_relevant_bytes(mdp); if (len < expected_len){ return WHYF("Expected packet length of %d, received only %lld bytes", expected_len, (long long) len); } /* Valid packet received */ return 0; } else /* no packet received */ return -1; }
int overlay_mdp_client_init() { if (mdp_client_socket==-1) { /* Open socket to MDP server (thus connection is always local) */ if (0) WHY("Use of abstract name space socket for Linux not implemented"); mdp_client_socket = socket(AF_UNIX, SOCK_DGRAM, 0); if (mdp_client_socket < 0) { WHY_perror("socket"); return WHY("Could not open socket to MDP server"); } /* We must bind to a temporary file name */ struct sockaddr_un name; unsigned int random_value; if (urandombytes((unsigned char *)&random_value,sizeof(int))) return WHY("urandombytes() failed"); name.sun_family = AF_UNIX; if (overlay_mdp_client_socket_path_len==-1) { char fmt[1024]; if (!FORM_SERVAL_INSTANCE_PATH(fmt, "mdp-client-%d-%08x.socket")) return WHY("Could not form MDP client socket name"); snprintf(overlay_mdp_client_socket_path,1024,fmt,getpid(),random_value); overlay_mdp_client_socket_path_len=strlen(overlay_mdp_client_socket_path)+1; if(config.debug.io) DEBUGF("MDP client socket name='%s'",overlay_mdp_client_socket_path); } if (overlay_mdp_client_socket_path_len > sizeof(name.sun_path) - 1) FATALF("MDP socket path too long (%d > %d)", overlay_mdp_client_socket_path_len, sizeof(name.sun_path) - 1); bcopy(overlay_mdp_client_socket_path,name.sun_path, overlay_mdp_client_socket_path_len); unlink(name.sun_path); int len = 1 + strlen(name.sun_path) + sizeof(name.sun_family) + 1; int r=bind(mdp_client_socket, (struct sockaddr *)&name, len); if (r) { WHY_perror("bind"); return WHY("Could not bind MDP client socket to file name"); } int send_buffer_size=128*1024; if (setsockopt(mdp_client_socket, SOL_SOCKET, SO_RCVBUF, &send_buffer_size, sizeof(send_buffer_size)) == -1) WARN_perror("setsockopt"); } return 0; }
int serval_sign(const char *sid, const size_t sid_len, const unsigned char *msg, const size_t msg_len, char *sig_buffer, const size_t sig_size, const char *keyringName, const size_t keyring_len) { keyring_identity *new_ident; char keyringFile[1024]; assert(msg_len); if (sid) assert(sid_len == 2*SID_SIZE); if (keyringName == NULL || keyring_len == 0) { FORM_SERVAL_INSTANCE_PATH(keyringFile, "serval.keyring"); // if no keyring specified, use default keyring } else { // otherwise, use specified keyring (NOTE: if keyring does not exist, it will be created) strncpy(keyringFile,keyringName,keyring_len); keyringFile[keyring_len] = '\0'; } keyring = keyring_open(keyringFile); keyring_enter_pin(keyring, KEYRING_PIN); // unlocks Serval keyring for using identities (also initializes global default identity my_subscriber) if (!sid) { //create new sid int c; for(c=0;c<keyring->context_count;c++) { // cycle through the keyring contexts until we find one with room for another identity new_ident = keyring_create_identity(keyring,keyring->contexts[c], KEYRING_PIN); // create new Serval identity if (new_ident) break; } if (!new_ident) { fprintf(stderr, "failed to create new SID\n"); return 1; } if (keyring_commit(keyring)) { // need to commit keyring or else new identity won't be saved (needs root permissions) fprintf(stderr, "Failed to save new SID into keyring...make sure you are running as root!\n"); return 1; } sid = alloca_tohex_sid(new_ident->subscriber->sid); // convert SID from binary to hex } else { if (!str_is_subscriber_id(sid)) { fprintf(stderr,"Invalid SID\n"); return 1; } } unsigned char packedSid[SID_SIZE]; stowSid(packedSid,0,sid); unsigned char *key=keyring_find_sas_private(keyring, packedSid, NULL); // get SAS key associated with our SID if (!key) return 1; unsigned char hash[crypto_hash_sha512_BYTES]; unsigned long long sig_length = SIGNATURE_BYTES; crypto_hash_sha512(hash, msg, msg_len); // create sha512 hash of message, which will then be signed unsigned char signed_msg[msg_len + sig_length]; memcpy(signed_msg,msg,msg_len); int ret = crypto_create_signature(key, hash, crypto_hash_sha512_BYTES, &signed_msg[msg_len], &sig_length); // create signature of message hash, append it to end of message if (!ret) { //success printf("%s\n", alloca_tohex(signed_msg + msg_len, sig_length)); printf("%s\n",sid); if (sig_size > 0) { if (sig_size >= 2*sig_length + 1) { strncpy(sig_buffer,alloca_tohex(signed_msg + msg_len,sig_length),2*sig_length); sig_buffer[2*sig_length] = '\0'; } else fprintf(stderr,"Insufficient signature buffer size\n"); } } keyring_free(keyring); return ret; }
int log_backtrace(int level, struct __sourceloc whence) { #ifndef NO_BACKTRACE _log_iterator it; _log_iterator_start(&it); _rotate_log_file(&it); char execpath[MAXPATHLEN]; if (get_self_executable_path(execpath, sizeof execpath) == -1) return WHY("cannot log backtrace: own executable path unknown"); char tempfile[MAXPATHLEN]; if (!FORM_SERVAL_INSTANCE_PATH(tempfile, "servalgdb.XXXXXX")) return -1; int tmpfd = mkstemp(tempfile); if (tmpfd == -1) return WHYF_perror("mkstemp(%s)", alloca_str_toprint(tempfile)); if (write_str(tmpfd, "backtrace\n") == -1) { close(tmpfd); unlink(tempfile); return -1; } if (close(tmpfd) == -1) { WHY_perror("close"); unlink(tempfile); return -1; } char pidstr[12]; snprintf(pidstr, sizeof pidstr, "%jd", (intmax_t)getpid()); int stdout_fds[2]; if (pipe(stdout_fds) == -1) return WHY_perror("pipe"); pid_t child_pid; switch (child_pid = fork()) { case -1: // error WHY_perror("fork"); close(stdout_fds[0]); close(stdout_fds[1]); return WHY("cannot log backtrace: fork failed"); case 0: // child if (dup2(stdout_fds[1], 1) == -1 || dup2(stdout_fds[1], 2) == -1) { perror("dup2"); _exit(-1); } close(0); if (open("/dev/null", O_RDONLY) != 0) { perror("open(\"/dev/null\")"); _exit(-2); } close(stdout_fds[0]); /* XXX: Need the cast on Solaris because it defins NULL as 0L and gcc doesn't * see it as a sentinal */ execlp("gdb", "gdb", "-n", "-batch", "-x", tempfile, execpath, pidstr, (void*)NULL); perror("execlp(\"gdb\")"); do { _exit(-3); } while (1); break; } // parent close(stdout_fds[1]); _log_iterator_printf_nl(&it, level, whence, "GDB BACKTRACE"); char buf[1024]; char *const bufe = buf + sizeof buf; char *linep = buf; char *readp = buf; ssize_t nr; while ((nr = read(stdout_fds[0], readp, bufe - readp)) > 0) { char *p = readp; readp = readp + nr; for (; p < readp; ++p) if (*p == '\n' || *p == '\0') { *p = '\0'; _log_iterator_printf_nl(&it, level, __NOWHERE__, "%s", linep); linep = p + 1; } if (readp >= bufe && linep == buf) { // Line does not fit into buffer. char t = bufe[-1]; bufe[-1] = '\0'; _log_iterator_printf_nl(&it, level, __NOWHERE__, "%s", buf); buf[0] = t; readp = buf + 1; } else if (readp + 120 >= bufe && linep != buf) { // Buffer low on space. if (linep < readp) memmove(buf, linep, readp - linep); readp -= linep - buf; linep = buf; } // Invariant: readp < bufe } if (nr == -1) WHY_perror("read"); if (readp > linep) { *readp = '\0'; _log_iterator_printf_nl(&it, level, __NOWHERE__, "%s", linep); } close(stdout_fds[0]); int status = 0; if (waitpid(child_pid, &status, 0) == -1) WHY_perror("waitpid"); strbuf b = strbuf_local(buf, sizeof buf); strbuf_append_exit_status(b, status); _log_iterator_printf_nl(&it, level, __NOWHERE__, "gdb %s", buf); unlink(tempfile); #endif return 0; }
static int _read_config() { char conffile[1024]; if (!FORM_SERVAL_INSTANCE_PATH(conffile, "serval.conf")) return -1; size_t size = 0; confc = 0; FILE *f = fopen(conffile, "r"); if (f == NULL) { if (errno != ENOENT) return WHYF_perror("fopen(%s)", conffile); } else { if (fseeko(f, (off_t) 0, SEEK_END) == -1) { WHYF_perror("fseeko(%s, 0, SEEK_END)", conffile); fclose(f); return -1; } off_t tell = ftello(f); if (tell == -1) { WHYF_perror("ftello(%s)", conffile); fclose(f); return -1; } size = tell; if (fseeko(f, (off_t) 0, SEEK_SET) == -1) { WHYF_perror("fseeko(%s, 0, SEEK_SET)", conffile); fclose(f); return -1; } if (grow_config_buffer(size) == NULL) { fclose(f); return -1; } if (fread(config_buffer, size, 1, f) != 1) { if (ferror(f)) WHYF_perror("fread(%s, %llu)", conffile, (unsigned long long) size); else WHYF("fread(%s, %llu) hit EOF", conffile, (unsigned long long) size); free(config_buffer); config_buffer = NULL; fclose(f); return -1; } if (fclose(f) == EOF) return WHYF_perror("fclose(%s)", conffile); } config_buffer_top = config_buffer_end = config_buffer + size; char *c = config_buffer; char *e = config_buffer_top; unsigned int linenum; char *problem = NULL; char *extra = ""; for (linenum = 1; !problem && c < e; ++linenum) { if (*c == '#') { // skip comment lines while (c < e && *c != '\n') ++c; } else if (*c == '\n') { // skip empty lines ++c; } else if (c < e - 1 && *c == '\r' && c[1] == '\n') { // skip empty lines c += 2; } else if (confc < MAX_CONFIG_VARS) { char *var = confvar[confc] = c; while (c < e && *c != '=' && *c != '\r' && *c != '\n') ++c; if (c < e && *c == '=') { *c++ = '\0'; if (is_configvarname(var)) { confvalue[confc] = c; while (c < e && *c != '\r' && *c != '\n') ++c; if (c < e && *c == '\n') { *c++ = '\0'; ++confc; } else if (c < e - 1 && *c == '\r' && c[1] == '\n') { *c++ = '\0'; *c++ = '\0'; ++confc; } else { problem = "missing end-of-line"; } } else { problem = "invalid variable name: "; extra = var; } } else { problem = "missing '='"; } } else { problem = "too many variables"; } } if (problem) return WHYF("Error in %s at line %u: %s%s", conffile, linenum, problem, extra); return 0; }
int overlay_mdp_send(overlay_mdp_frame *mdp,int flags,int timeout_ms) { int len=4; if (mdp_client_socket==-1) if (overlay_mdp_client_init() != 0) return -1; /* Minimise frame length to save work and prevent accidental disclosure of memory contents. */ len=overlay_mdp_relevant_bytes(mdp); if (len<0) return WHY("MDP frame invalid (could not compute length)"); /* Construct name of socket to send to. */ struct sockaddr_un name; name.sun_family = AF_UNIX; if (!FORM_SERVAL_INSTANCE_PATH(name.sun_path, "mdp.socket")) return -1; set_nonblock(mdp_client_socket); int result=sendto(mdp_client_socket, mdp, len, 0, (struct sockaddr *)&name, sizeof(struct sockaddr_un)); set_block(mdp_client_socket); if (result<0) { mdp->packetTypeAndFlags=MDP_ERROR; mdp->error.error=1; snprintf(mdp->error.message,128,"Error sending frame to MDP server."); return WHY_perror("sendto(f)"); } else { if (!(flags&MDP_AWAITREPLY)) { return 0; } } int port=0; if ((mdp->packetTypeAndFlags&MDP_TYPE_MASK) == MDP_TX) port = mdp->out.src.port; time_ms_t started = gettime_ms(); while(timeout_ms>=0 && overlay_mdp_client_poll(timeout_ms)>0){ int ttl=-1; if (!overlay_mdp_recv(mdp, port, &ttl)) { /* If all is well, examine result and return error code provided */ if ((mdp->packetTypeAndFlags&MDP_TYPE_MASK)==MDP_ERROR) return mdp->error.error; else /* Something other than an error has been returned */ return 0; } // work out how much longer we can wait for a valid response time_ms_t now = gettime_ms(); timeout_ms -= (now - started); } /* Timeout */ mdp->packetTypeAndFlags=MDP_ERROR; mdp->error.error=1; snprintf(mdp->error.message,128,"Timeout waiting for reply to MDP packet (packet was successfully sent)."); return -1; /* WHY("Timeout waiting for server response"); */ }