void parse_cmdline(int argc, char *argv[]) { int s, i; int failed = 0; while ((s = getopt(argc, argv, "c:fn:r:e:o:l:s:?h")) != -1) { switch (s) { case 'c': cfgfile = hstrdup(optarg); break; case 'f': fork_a_daemon = 1; break; case 'n': logname = hstrdup(optarg); break; case 'r': log_dir = hstrdup(optarg); break; case 'e': i = pick_loglevel(optarg, log_levelnames); if (i > -1) log_level = i; else { fprintf(stderr, "Log level unknown: \"%s\"\n", optarg); failed = 1; } break; case 'o': i = pick_loglevel(optarg, log_destnames); if (i > -1) log_dest = i; else { fprintf(stderr, "Log destination unknown: \"%s\"\n", optarg); failed = 1; } break; case 'l': sound_in_file = hstrdup(optarg); break; case 's': sound_out_file = hstrdup(optarg); break; case '?': case 'h': fprintf(stderr, "%s\n", VERSTR); failed = 1; } } if ((log_dest == L_FILE) && (!log_dir)) { fprintf(stderr, "Log destination set to 'file' but no log directory specified!\n"); failed = 1; } if (failed) { fprintf(stderr," %s",HELPS); exit(failed); } }
int do_uplink(struct uplink_config_t **lq, int argc, char **argv) { struct uplink_config_t *l; int uplink_proto = 0; if (argc < 3) return -1; if (strcasecmp(argv[2], "json") == 0) { uplink_proto = UPLINK_JSON; } else { hlog(LOG_ERR, "Uplink: Unsupported uplink protocol '%s'\n", argv[2]); return -2; } l = hmalloc(sizeof(*l)); l->proto = uplink_proto; l->name = hstrdup(argv[1]); l->url = hstrdup(argv[3]); /* put in the list */ l->next = *lq; if (l->next) l->next->prevp = &l->next; *lq = l; return 0; }
time_t parse_interval(char *origs) { time_t t = 0; int i; char *s, *np, *p, c; np = p = s = hstrdup(origs); while (*p) { if (!isdigit((int)*p)) { c = tolower(*p); *p = '\0'; i = atoi(np); if (c == 's') t += i; else if (c == 'm') t += 60 * i; else if (c == 'h') t += 60 * 60 * i; else if (c == 'd') t += 24 * 60 * 60 * i; np = p + 1; } p++; } if (*np) t += atoi(np); hfree(s); return t; }
struct cdata_t *cdata_alloc(const char *name) { int e; struct cdata_t *cd; cd = hmalloc(sizeof(*cd)); memset(cd, 0, sizeof(*cd)); pthread_mutex_init(&cd->mt, NULL); cd->name = hstrdup(name); cd->last_index = -1; // no data inserted yet cd->is_gauge = 0; if ((e = pthread_mutex_lock(&counterdata_mt))) { hlog(LOG_CRIT, "cdata_allocate: failed to lock counterdata_mt: %s", strerror(e)); exit(1); } cd->next = counterdata; if (counterdata) counterdata->prevp = &cd->next; counterdata = cd; cd->prevp = &counterdata; if ((e = pthread_mutex_unlock(&counterdata_mt))) { hlog(LOG_CRIT, "cdata_allocate: could not unlock counterdata_mt: %s", strerror(e)); exit(1); } //hlog(LOG_DEBUG, "cdata: allocated: %s", cd->name); return cd; }
/* * classify by file name extensions */ HContents uriclass(HConnect *hc, char *name) { HContents conts; Suffix *s; HContent *type, *enc; char *buf, *p; type = nil; enc = nil; if((p = strrchr(name, '/')) != nil) name = p + 1; buf = hstrdup(hc, name); while((p = strrchr(buf, '.')) != nil){ for(s = suffixes; s; s = s->next){ if(strcmp(p, s->suffix) == 0){ if(s->generic != nil && type == nil) type = hmkcontent(hc, s->generic, s->specific, nil); if(s->encoding != nil && enc == nil) enc = hmkcontent(hc, s->encoding, nil, nil); } } *p = 0; } conts.type = type; conts.encoding = enc; return conts; }
static char* getword(HConnect *c) { char *buf; int ch, n; while((ch = getc(c)) == ' ' || ch == '\t' || ch == '\r') ; if(ch == '\n') return nil; n = 0; buf = halloc(c, 1); for(;;){ switch(ch){ case ' ': case '\t': case '\r': case '\n': buf[n] = '\0'; return hstrdup(c, buf); } if(n < HMaxWord-1){ buf = bingrow(&c->bin, buf, n, n + 1, 0); if(buf == nil) return nil; buf[n++] = ch; } ch = getc(c); } }
static Strings parseuri(HConnect *c, char *uri) { Strings ss; char *urihost, *p; urihost = nil; if(uri[0] != '/') { if(cistrncmp(uri, "http://", 7) != 0) { ss.s1 = nil; ss.s2 = nil; return ss; } uri += 5; /* skip http: */ } /* * anything starting with // is a host name or number * hostnames consists of letters, digits, - and . * for now, just ignore any port given */ if(uri[0] == '/' && uri[1] == '/') { urihost = uri + 2; p = strchr(urihost, '/'); if(p == nil) uri = hstrdup(c, "/"); else { uri = hstrdup(c, p); *p = '\0'; } p = strchr(urihost, ':'); if(p != nil) *p = '\0'; } if(uri[0] != '/' || uri[1] == '/') { ss.s1 = nil; ss.s2 = nil; return ss; } ss.s1 = uri; ss.s2 = hlower(urihost); return ss; }
int do_string(char **dest, int argc, char **argv) { if (argc < 2) return -1; if (*dest) hfree(*dest); *dest = hstrdup(argv[1]); return 0; }
/* * to circumscribe the accessible files we have to eliminate ..'s * and resolve all names from the root. */ static char* abspath(HConnect *cc, char *origpath, char *curdir) { char *p, *sp, *path, *work, *rpath; int len, n, c; if(curdir == nil) curdir = "/"; if(origpath == nil) origpath = ""; work = hstrdup(cc, origpath); path = work; /* * remove any really special characters */ for(sp = "`;|"; *sp; sp++){ p = strchr(path, *sp); if(p) *p = 0; } len = strlen(curdir) + strlen(path) + 2 + UTFmax; if(len < 10) len = 10; rpath = halloc(cc, len); if(*path == '/') rpath[0] = 0; else strcpy(rpath, curdir); n = strlen(rpath); while(path){ p = strchr(path, '/'); if(p) *p++ = 0; if(strcmp(path, "..") == 0){ while(n > 1){ n--; c = rpath[n]; rpath[n] = 0; if(c == '/') break; } }else if(strcmp(path, ".") == 0){ ; }else if(n == 1) n += snprint(rpath+n, len-n, "%s", path); else n += snprint(rpath+n, len-n, "/%s", path); path = p; } if(strncmp(rpath, "/bin/", 5) == 0) strcpy(rpath, "/"); return rpath; }
void login_set_app_name(struct client_t *c, const char *app_name, const char *app_ver) { #ifndef FIXED_IOBUFS c->app_name = hstrdup(app_name); #else strncpy(c->app_name, app_name, sizeof(c->app_name)); c->app_name[sizeof(c->app_name)-1] = 0; #endif sanitize_ascii_string(c->app_name); #ifndef FIXED_IOBUFS c->app_version = hstrdup(app_ver); #else strncpy(c->app_version, app_ver, sizeof(c->app_version)); c->app_version[sizeof(c->app_version)-1] = 0; #endif sanitize_ascii_string(c->app_version); }
void hintprint(HConnect *hc, Hio *hout, char *uri, int thresh, int havej) { int i, j, pr, prefix, fd, siz, havei, newhint = 0, n; char *query, *sf, etag[32], *wurl; Dir *dir; Hint *h, *haveh; query = hstrdup(hc, uri); urlcanon(query); j = urllookup(hashstr(query)); if(j < 0) return; query = strrchr(uri,'/'); if(!query) return; /* can't happen */ prefix = query-uri+1; /* = strlen(dirname)+1 */ h = hints[j]; for(i=0; i<nhint[j]; i++){ if(havej > 0 && havej < URLmax){ /* exclude hints client has */ haveh = hints[havej]; for(havei=0; havei<nhint[havej]; havei++) if( haveh[havei].url == h[i].url) goto continuei; } sf = urlname[h[i].url]; pr = h[i].prob; if(pr<thresh) break; n = strlen(webroot) + strlen(sf) + 1; wurl = halloc(hc, n); strcpy(wurl, webroot); strcat(wurl, sf); fd = open(wurl, OREAD); if(fd<0) continue; dir = dirfstat(fd); if(dir == nil){ close(fd); continue; } close(fd); snprint(etag, sizeof(etag), "\"%lluxv%lx\"", dir->qid.path, dir->qid.vers); siz = (int)( log((double)dir->length) * RECIPLOG2 + 0.9999); free(dir); if(strncmp(uri,sf,prefix)==0 && strchr(sf+prefix,'/')==0 && sf[prefix]!=0) sf = sf+prefix; hprint(hout, "Fresh: %d,%s,%d,%s\r\n", pr, etag, siz, sf); newhint++; continuei: ; } if(newhint) hprint(hout, "Fresh: have/%d\r\n", j); }
static void listener_copy_filters(struct listen_t *l, struct listen_config_t *lc) { int i; char filter_s[FILTER_S_SIZE] = ""; int filter_s_l = 0; for (i = 0; i < (sizeof(l->filters)/sizeof(l->filters[0])); ++i) { if (l->filters[i]) { hfree(l->filters[i]); l->filters[i] = NULL; } if (i < (sizeof(lc->filters)/sizeof(lc->filters[0]))) { if (!lc->filters[i]) continue; l->filters[i] = hstrdup(lc->filters[i]); int len = strlen(l->filters[i]); if (filter_s_l + len + 2 < FILTER_S_SIZE) { if (filter_s_l) filter_s[filter_s_l++] = ' '; memcpy(filter_s + filter_s_l, l->filters[i], len); filter_s_l += len; filter_s[filter_s_l] = 0; } } } if (l->filter_s) { hfree(l->filter_s); l->filter_s = NULL; } if (filter_s_l == 0) return; sanitize_ascii_string(filter_s); l->filter_s = hstrdup(filter_s); }
struct status_error_t *status_error_find(const char *err) { struct status_error_t *e; for (e = status_errs; (e); e = e->next) { if (strcmp(e->err, err) == 0) return e; } e = hmalloc(sizeof(*e)); e->err = hstrdup(err); e->next = status_errs; e->set = -1; status_errs = e; return e; }
int open_log(char *name, int reopen) { if (!reopen) rwl_wrlock(&log_file_lock); if (log_name) hfree(log_name); if (!(log_name = hstrdup(name))) { fprintf(stderr, "aprsc logger: out of memory!\n"); exit(1); } if (log_basename) hfree(log_basename); log_basename = hmalloc(strlen(log_name) + 5); sprintf(log_basename, "%s.log", log_name); if (log_dest == L_SYSLOG) openlog(name, LOG_NDELAY|LOG_PID, log_facility); if (log_dest == L_FILE) { if (log_fname) hfree(log_fname); log_fname = hmalloc(strlen(log_dir) + strlen(log_basename) + 2); sprintf(log_fname, "%s/%s", log_dir, log_basename); log_file = open(log_fname, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR|S_IRGRP); if (log_file < 0) { fprintf(stderr, "aprsc logger: Could not open %s: %s\n", log_fname, strerror(errno)); exit(1); } } rwl_wrunlock(&log_file_lock); if (log_dest == L_FILE) hlog(LOG_DEBUG, "Log file %s %sopened on fd %d", log_fname, (reopen) ? "re" : "", log_file); return 0; }
int close_log(int reopen) { hlog(LOG_DEBUG, "close_log"); char *s = NULL; if (log_name) s = hstrdup(log_name); rwl_wrlock(&log_file_lock); if (log_name) { hfree(log_name); log_name = NULL; } if (log_dest == L_SYSLOG) { closelog(); } else if (log_dest == L_FILE) { if (log_file >= 0) { if (close(log_file)) fprintf(stderr, "aprsc logger: Could not close log file %s: %s\n", log_fname, strerror(errno)); log_file = -1; } if (log_fname) { hfree(log_fname); log_fname = NULL; } } if (reopen && s) open_log(s, 1); if (!reopen) rwl_wrunlock(&log_file_lock); if (s) hfree(s); return 0; }
int accesslog_open(char *logd, int reopen) { if (!reopen) rwl_wrlock(&accesslog_lock); if (accesslog_fname) hfree(accesslog_fname); if (accesslog_dir) hfree(accesslog_dir); accesslog_dir = hstrdup(logd); accesslog_fname = hmalloc(strlen(accesslog_dir) + strlen(accesslog_basename) + 2); sprintf(accesslog_fname, "%s/%s", accesslog_dir, accesslog_basename); accesslog_file = open(accesslog_fname, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR|S_IRGRP); if (accesslog_file < 0) hlog(LOG_CRIT, "Could not open %s: %s", accesslog_fname, strerror(errno)); rwl_wrunlock(&accesslog_lock); return accesslog_file; }
char *status_json_string(int no_cache, int periodical) { char *out = NULL; int pe; /* if we have a very recent status JSON available, return it instead. */ if (!no_cache) { if ((pe = pthread_mutex_lock(&status_json_mt))) { hlog(LOG_ERR, "status_json_string(): could not lock status_json_mt: %s", strerror(pe)); return NULL; } if (status_json_cached && (status_json_cache_t == tick || status_json_cache_t == tick - 1)) { out = hstrdup(status_json_cached); if ((pe = pthread_mutex_unlock(&status_json_mt))) { hlog(LOG_ERR, "status_json_string(): could not unlock status_json_mt: %s", strerror(pe)); hfree(out); return NULL; } return out; } if ((pe = pthread_mutex_unlock(&status_json_mt))) { hlog(LOG_ERR, "status_json_string(): could not unlock status_json_mt: %s", strerror(pe)); return NULL; } } /* Ok, go and build the JSON tree */ cJSON *root = cJSON_CreateObject(); if (http_status_options) cJSON_AddStringToObject(root, "status_options", http_status_options); status_check_motd(root); cJSON *server = cJSON_CreateObject(); cJSON_AddStringToObject(server, "server_id", serverid); cJSON_AddStringToObject(server, "admin", myadmin); cJSON_AddStringToObject(server, "email", myemail); cJSON_AddStringToObject(server, "software", PROGNAME); cJSON_AddStringToObject(server, "software_version", version_build); cJSON_AddStringToObject(server, "software_build_time", verstr_build_time); cJSON_AddStringToObject(server, "software_build_user", verstr_build_user); cJSON_AddStringToObject(server, "software_build_features", verstr_features); cJSON_AddNumberToObject(server, "uptime", tick - startup_tick); cJSON_AddNumberToObject(server, "tick_now", tick); cJSON_AddNumberToObject(server, "time_now", now); cJSON_AddNumberToObject(server, "time_started", startup_time); status_uname(server); cJSON_AddItemToObject(root, "server", server); cJSON *memory = cJSON_CreateObject(); #ifndef _FOR_VALGRIND_ struct cellstatus_t cellst; historydb_cell_stats(&cellst), cJSON_AddNumberToObject(memory, "historydb_cells_used", historydb_cellgauge); cJSON_AddNumberToObject(memory, "historydb_cells_free", cellst.freecount); cJSON_AddNumberToObject(memory, "historydb_used_bytes", historydb_cellgauge*cellst.cellsize_aligned); cJSON_AddNumberToObject(memory, "historydb_allocated_bytes", (long)cellst.blocks * (long)cellst.block_size); cJSON_AddNumberToObject(memory, "historydb_block_size", (long)cellst.block_size); cJSON_AddNumberToObject(memory, "historydb_blocks", (long)cellst.blocks); cJSON_AddNumberToObject(memory, "historydb_blocks_max", (long)cellst.blocks_max); cJSON_AddNumberToObject(memory, "historydb_cell_size", cellst.cellsize); cJSON_AddNumberToObject(memory, "historydb_cell_size_aligned", cellst.cellsize_aligned); cJSON_AddNumberToObject(memory, "historydb_cell_align", cellst.alignment); dupecheck_cell_stats(&cellst), cJSON_AddNumberToObject(memory, "dupecheck_cells_used", dupecheck_cellgauge); cJSON_AddNumberToObject(memory, "dupecheck_cells_free", cellst.freecount); cJSON_AddNumberToObject(memory, "dupecheck_used_bytes", dupecheck_cellgauge*cellst.cellsize_aligned); cJSON_AddNumberToObject(memory, "dupecheck_allocated_bytes", (long)cellst.blocks * (long)cellst.block_size); cJSON_AddNumberToObject(memory, "dupecheck_block_size", (long)cellst.block_size); cJSON_AddNumberToObject(memory, "dupecheck_blocks", (long)cellst.blocks); cJSON_AddNumberToObject(memory, "dupecheck_blocks_max", (long)cellst.blocks_max); cJSON_AddNumberToObject(memory, "dupecheck_cell_size", cellst.cellsize); cJSON_AddNumberToObject(memory, "dupecheck_cell_size_aligned", cellst.cellsize_aligned); cJSON_AddNumberToObject(memory, "dupecheck_cell_align", cellst.alignment); struct cellstatus_t cellst_filter, cellst_filter_wx, cellst_filter_entrycall; filter_cell_stats(&cellst_filter, &cellst_filter_entrycall, &cellst_filter_wx), cJSON_AddNumberToObject(memory, "filter_cells_used", filter_cellgauge); cJSON_AddNumberToObject(memory, "filter_cells_free", cellst_filter.freecount); cJSON_AddNumberToObject(memory, "filter_used_bytes", filter_cellgauge*cellst_filter.cellsize_aligned); cJSON_AddNumberToObject(memory, "filter_allocated_bytes", (long)cellst_filter.blocks * (long)cellst_filter.block_size); cJSON_AddNumberToObject(memory, "filter_block_size", (long)cellst_filter.block_size); cJSON_AddNumberToObject(memory, "filter_blocks", (long)cellst_filter.blocks); cJSON_AddNumberToObject(memory, "filter_blocks_max", (long)cellst_filter.blocks_max); cJSON_AddNumberToObject(memory, "filter_cell_size", cellst_filter.cellsize); cJSON_AddNumberToObject(memory, "filter_cell_size_aligned", cellst_filter.cellsize_aligned); cJSON_AddNumberToObject(memory, "filter_cell_align", cellst_filter.alignment); cJSON_AddNumberToObject(memory, "filter_wx_cells_used", filter_wx_cellgauge); cJSON_AddNumberToObject(memory, "filter_wx_cells_free", cellst_filter_wx.freecount); cJSON_AddNumberToObject(memory, "filter_wx_used_bytes", filter_wx_cellgauge*cellst_filter_wx.cellsize_aligned); cJSON_AddNumberToObject(memory, "filter_wx_allocated_bytes", (long)cellst_filter_wx.blocks * (long)cellst_filter_wx.block_size); cJSON_AddNumberToObject(memory, "filter_wx_block_size", (long)cellst_filter_wx.block_size); cJSON_AddNumberToObject(memory, "filter_wx_blocks", (long)cellst_filter_wx.blocks); cJSON_AddNumberToObject(memory, "filter_wx_blocks_max", (long)cellst_filter_wx.blocks_max); cJSON_AddNumberToObject(memory, "filter_wx_cell_size", cellst_filter_wx.cellsize); cJSON_AddNumberToObject(memory, "filter_wx_cell_size_aligned", cellst_filter_wx.cellsize_aligned); cJSON_AddNumberToObject(memory, "filter_wx_cell_align", cellst_filter_wx.alignment); cJSON_AddNumberToObject(memory, "filter_entrycall_cells_used", filter_entrycall_cellgauge); cJSON_AddNumberToObject(memory, "filter_entrycall_cells_free", cellst_filter_entrycall.freecount); cJSON_AddNumberToObject(memory, "filter_entrycall_used_bytes", filter_entrycall_cellgauge*cellst_filter_entrycall.cellsize_aligned); cJSON_AddNumberToObject(memory, "filter_entrycall_allocated_bytes", (long)cellst_filter_entrycall.blocks * (long)cellst_filter_entrycall.block_size); cJSON_AddNumberToObject(memory, "filter_entrycall_block_size", (long)cellst_filter_entrycall.block_size); cJSON_AddNumberToObject(memory, "filter_entrycall_blocks", (long)cellst_filter_entrycall.blocks); cJSON_AddNumberToObject(memory, "filter_entrycall_blocks_max", (long)cellst_filter_entrycall.blocks_max); cJSON_AddNumberToObject(memory, "filter_entrycall_cell_size", cellst_filter_entrycall.cellsize); cJSON_AddNumberToObject(memory, "filter_entrycall_cell_size_aligned", cellst_filter_entrycall.cellsize_aligned); cJSON_AddNumberToObject(memory, "filter_entrycall_cell_align", cellst_filter_entrycall.alignment); struct cellstatus_t cellst_pbuf_small, cellst_pbuf_medium, cellst_pbuf_large; incoming_cell_stats(&cellst_pbuf_small, &cellst_pbuf_medium, &cellst_pbuf_large); cJSON_AddNumberToObject(memory, "pbuf_small_cells_used", cellst_pbuf_small.cellcount - cellst_pbuf_small.freecount); cJSON_AddNumberToObject(memory, "pbuf_small_cells_free", cellst_pbuf_small.freecount); cJSON_AddNumberToObject(memory, "pbuf_small_cells_alloc", cellst_pbuf_small.cellcount); cJSON_AddNumberToObject(memory, "pbuf_small_used_bytes", (cellst_pbuf_small.cellcount - cellst_pbuf_small.freecount)*cellst_pbuf_small.cellsize_aligned); cJSON_AddNumberToObject(memory, "pbuf_small_allocated_bytes", (long)cellst_pbuf_small.blocks * (long)cellst_pbuf_small.block_size); cJSON_AddNumberToObject(memory, "pbuf_small_block_size", (long)cellst_pbuf_small.block_size); cJSON_AddNumberToObject(memory, "pbuf_small_blocks", (long)cellst_pbuf_small.blocks); cJSON_AddNumberToObject(memory, "pbuf_small_blocks_max", (long)cellst_pbuf_small.blocks_max); cJSON_AddNumberToObject(memory, "pbuf_small_cell_size", cellst_pbuf_small.cellsize); cJSON_AddNumberToObject(memory, "pbuf_small_cell_size_aligned", cellst_pbuf_small.cellsize_aligned); cJSON_AddNumberToObject(memory, "pbuf_small_cell_align", cellst_pbuf_small.alignment); cJSON_AddNumberToObject(memory, "pbuf_medium_cells_used", cellst_pbuf_medium.cellcount - cellst_pbuf_medium.freecount); cJSON_AddNumberToObject(memory, "pbuf_medium_cells_free", cellst_pbuf_medium.freecount); cJSON_AddNumberToObject(memory, "pbuf_medium_cells_alloc", cellst_pbuf_medium.cellcount); cJSON_AddNumberToObject(memory, "pbuf_medium_used_bytes", (cellst_pbuf_medium.cellcount - cellst_pbuf_medium.freecount)*cellst_pbuf_medium.cellsize_aligned); cJSON_AddNumberToObject(memory, "pbuf_medium_allocated_bytes", (long)cellst_pbuf_medium.blocks * (long)cellst_pbuf_medium.block_size); cJSON_AddNumberToObject(memory, "pbuf_medium_block_size", (long)cellst_pbuf_medium.block_size); cJSON_AddNumberToObject(memory, "pbuf_medium_blocks", (long)cellst_pbuf_medium.blocks); cJSON_AddNumberToObject(memory, "pbuf_medium_blocks_max", (long)cellst_pbuf_medium.blocks_max); cJSON_AddNumberToObject(memory, "pbuf_medium_cell_size", cellst_pbuf_medium.cellsize); cJSON_AddNumberToObject(memory, "pbuf_medium_cell_size_aligned", cellst_pbuf_medium.cellsize_aligned); cJSON_AddNumberToObject(memory, "pbuf_medium_cell_align", cellst_pbuf_medium.alignment); cJSON_AddNumberToObject(memory, "pbuf_large_cells_used", cellst_pbuf_large.cellcount - cellst_pbuf_large.freecount); cJSON_AddNumberToObject(memory, "pbuf_large_cells_free", cellst_pbuf_large.freecount); cJSON_AddNumberToObject(memory, "pbuf_large_cells_alloc", cellst_pbuf_large.cellcount); cJSON_AddNumberToObject(memory, "pbuf_large_used_bytes", (cellst_pbuf_large.cellcount - cellst_pbuf_large.freecount)*cellst_pbuf_large.cellsize_aligned); cJSON_AddNumberToObject(memory, "pbuf_large_allocated_bytes", (long)cellst_pbuf_large.blocks * (long)cellst_pbuf_large.block_size); cJSON_AddNumberToObject(memory, "pbuf_large_block_size", (long)cellst_pbuf_large.block_size); cJSON_AddNumberToObject(memory, "pbuf_large_blocks", (long)cellst_pbuf_large.blocks); cJSON_AddNumberToObject(memory, "pbuf_large_blocks_max", (long)cellst_pbuf_large.blocks_max); cJSON_AddNumberToObject(memory, "pbuf_large_cell_size", cellst_pbuf_large.cellsize); cJSON_AddNumberToObject(memory, "pbuf_large_cell_size_aligned", cellst_pbuf_large.cellsize_aligned); cJSON_AddNumberToObject(memory, "pbuf_large_cell_align", cellst_pbuf_large.alignment); struct cellstatus_t cellst_client_heard; client_heard_cell_stats(&cellst_client_heard); cJSON_AddNumberToObject(memory, "client_heard_cells_used", cellst_client_heard.cellcount - cellst_client_heard.freecount); cJSON_AddNumberToObject(memory, "client_heard_cells_free", cellst_client_heard.freecount); cJSON_AddNumberToObject(memory, "client_heard_cells_alloc", cellst_client_heard.cellcount); cJSON_AddNumberToObject(memory, "client_heard_used_bytes", (cellst_client_heard.cellcount - cellst_client_heard.freecount)*cellst_client_heard.cellsize_aligned); cJSON_AddNumberToObject(memory, "client_heard_allocated_bytes", (long)cellst_client_heard.blocks * (long)cellst_client_heard.block_size); cJSON_AddNumberToObject(memory, "client_heard_block_size", (long)cellst_client_heard.block_size); cJSON_AddNumberToObject(memory, "client_heard_blocks", (long)cellst_client_heard.blocks); cJSON_AddNumberToObject(memory, "client_heard_blocks_max", (long)cellst_client_heard.blocks_max); cJSON_AddNumberToObject(memory, "client_heard_cell_size", cellst_client_heard.cellsize); cJSON_AddNumberToObject(memory, "client_heard_cell_size_aligned", cellst_client_heard.cellsize_aligned); cJSON_AddNumberToObject(memory, "client_heard_cell_align", cellst_client_heard.alignment); #endif cJSON_AddItemToObject(root, "memory", memory); cJSON *historydb = cJSON_CreateObject(); cJSON_AddNumberToObject(historydb, "inserts", historydb_inserts); cJSON_AddNumberToObject(historydb, "lookups", historydb_lookups); cJSON_AddNumberToObject(historydb, "hashmatches", historydb_hashmatches); cJSON_AddNumberToObject(historydb, "keymatches", historydb_keymatches); cJSON_AddNumberToObject(historydb, "noposcount", historydb_noposcount); cJSON_AddNumberToObject(historydb, "cleaned", historydb_cleanup_cleaned); cJSON_AddItemToObject(root, "historydb", historydb); cJSON *dupecheck = cJSON_CreateObject(); cJSON_AddNumberToObject(dupecheck, "dupes_dropped", dupecheck_dupecount); cJSON_AddNumberToObject(dupecheck, "uniques_out", dupecheck_outcount); cJSON_AddItemToObject(root, "dupecheck", dupecheck); cJSON *dupe_vars = cJSON_CreateObject(); cJSON_AddNumberToObject(dupe_vars, "exact", dupecheck_dupetypes[0]); cJSON_AddNumberToObject(dupe_vars, "space_trim", dupecheck_dupetypes[DTYPE_SPACE_TRIM]); cJSON_AddNumberToObject(dupe_vars, "8bit_strip", dupecheck_dupetypes[DTYPE_STRIP_8BIT]); cJSON_AddNumberToObject(dupe_vars, "8bit_clear", dupecheck_dupetypes[DTYPE_CLEAR_8BIT]); cJSON_AddNumberToObject(dupe_vars, "8bit_spaced", dupecheck_dupetypes[DTYPE_SPACED_8BIT]); cJSON_AddNumberToObject(dupe_vars, "low_strip", dupecheck_dupetypes[DTYPE_LOWDATA_STRIP]); cJSON_AddNumberToObject(dupe_vars, "low_spaced", dupecheck_dupetypes[DTYPE_LOWDATA_SPACED]); cJSON_AddNumberToObject(dupe_vars, "del_strip", dupecheck_dupetypes[DTYPE_DEL_STRIP]); cJSON_AddNumberToObject(dupe_vars, "del_spaced", dupecheck_dupetypes[DTYPE_DEL_SPACED]); cJSON_AddItemToObject(dupecheck, "variations", dupe_vars); cJSON *json_totals = cJSON_CreateObject(); cJSON *json_listeners = cJSON_CreateArray(); accept_listener_status(json_listeners, json_totals); cJSON_AddItemToObject(root, "totals", json_totals); cJSON_AddItemToObject(root, "listeners", json_listeners); cJSON *json_clients = cJSON_CreateArray(); cJSON *json_uplinks = cJSON_CreateArray(); cJSON *json_peers = cJSON_CreateArray(); cJSON *json_workers = cJSON_CreateArray(); worker_client_list(json_workers, json_clients, json_uplinks, json_peers, json_totals, memory); cJSON_AddItemToObject(root, "workers", json_workers); cJSON_AddItemToObject(root, "uplinks", json_uplinks); cJSON_AddItemToObject(root, "peers", json_peers); cJSON_AddItemToObject(root, "clients", json_clients); /* if this is a periodical per-minute dump, collect historical data */ if (periodical) { cJSON *ct, *cv; struct cdata_list_t *cl; for (cl = cdata_list; (cl); cl = cl->next) { ct = cJSON_GetObjectItem(root, cl->tree); if (!ct) continue; cv = cJSON_GetObjectItem(ct, cl->name); /* cJSON's cv->valueint is just an integer, which will overflow * too quickly. So, let's take the more expensive valuedouble. */ if (cl->gauge) cdata_gauge_sample(cl->cd, (cv) ? cv->valuedouble : -1); else cdata_counter_sample(cl->cd, (cv) ? cv->valuedouble : -1); } } cJSON_AddNumberToObject(json_totals, "tcp_bytes_rx_rate", cdata_get_last_value("totals.tcp_bytes_rx") / CDATA_INTERVAL); cJSON_AddNumberToObject(json_totals, "tcp_bytes_tx_rate", cdata_get_last_value("totals.tcp_bytes_tx") / CDATA_INTERVAL); cJSON_AddNumberToObject(json_totals, "udp_bytes_rx_rate", cdata_get_last_value("totals.udp_bytes_rx") / CDATA_INTERVAL); cJSON_AddNumberToObject(json_totals, "udp_bytes_tx_rate", cdata_get_last_value("totals.udp_bytes_tx") / CDATA_INTERVAL); cJSON_AddNumberToObject(json_totals, "bytes_rx_rate", (cdata_get_last_value("totals.tcp_bytes_rx") + cdata_get_last_value("totals.udp_bytes_rx")) / CDATA_INTERVAL); cJSON_AddNumberToObject(json_totals, "bytes_tx_rate", (cdata_get_last_value("totals.tcp_bytes_tx") + cdata_get_last_value("totals.udp_bytes_tx")) / CDATA_INTERVAL); cJSON *json_rx_errs = cJSON_CreateStringArray(inerr_labels, INERR_BUCKETS); cJSON_AddItemToObject(root, "rx_errs", json_rx_errs); cJSON_AddItemToObject(root, "alarms", status_error_json()); /* the tree is built, print it out to a malloc'ed string */ out = cJSON_Print(root); cJSON_Delete(root); /* cache it */ if ((pe = pthread_mutex_lock(&status_json_mt))) { hlog(LOG_ERR, "status_json_string(): could not lock status_json_mt: %s", strerror(pe)); return NULL; } if (status_json_cached) hfree(status_json_cached); status_json_cached = hstrdup(out); status_json_cache_t = tick; if ((pe = pthread_mutex_unlock(&status_json_mt))) { hlog(LOG_ERR, "status_json_string(): could not unlock status_json_mt: %s", strerror(pe)); return NULL; } return out; }
static int accept_liveupgrade_single(cJSON *client, int *rxerr_map, int rxerr_map_len) { cJSON *fd, *listener_id, *username, *time_connect, *tick_connect; cJSON *state; cJSON *addr_loc; cJSON *udp_port; cJSON *app_name, *app_version; cJSON *verified; cJSON *obuf_q; cJSON *bytes_rx, *bytes_tx; cJSON *pkts_rx, *pkts_tx, *pkts_ign; cJSON *rx_errs; cJSON *filter; cJSON *ibuf, *obuf; cJSON *client_heard; cJSON *lat, *lng; unsigned addr_len; union sockaddr_u sa; char *argv[256]; int i, argc; const char *username_s = "unknown"; /* get username first, so we can log it later */ username = accept_liveupgrade_cJSON_get(client, "username", cJSON_String, username_s); if (username) username_s = username->valuestring; fd = accept_liveupgrade_cJSON_get(client, "fd", cJSON_Number, username_s); int fd_i = -1; if (fd) fd_i = fd->valueint; if (fd_i < 0) { hlog(LOG_INFO, "Live upgrade: Client '%s' has negative fd %d, ignoring (corepeer?)", username_s, fd_i); return -1; } listener_id = accept_liveupgrade_cJSON_get(client, "listener_id", cJSON_Number, username_s); state = accept_liveupgrade_cJSON_get(client, "state", cJSON_String, username_s); time_connect = accept_liveupgrade_cJSON_get(client, "t_connect", cJSON_Number, username_s); addr_loc = accept_liveupgrade_cJSON_get(client, "addr_loc", cJSON_String, username_s); app_name = accept_liveupgrade_cJSON_get(client, "app_name", cJSON_String, username_s); app_version = accept_liveupgrade_cJSON_get(client, "app_version", cJSON_String, username_s); verified = accept_liveupgrade_cJSON_get(client, "verified", cJSON_Number, username_s); obuf_q = accept_liveupgrade_cJSON_get(client, "obuf_q", cJSON_Number, username_s); bytes_rx = accept_liveupgrade_cJSON_get(client, "bytes_rx", cJSON_Number, username_s); bytes_tx = accept_liveupgrade_cJSON_get(client, "bytes_tx", cJSON_Number, username_s); pkts_rx = accept_liveupgrade_cJSON_get(client, "pkts_rx", cJSON_Number, username_s); pkts_tx = accept_liveupgrade_cJSON_get(client, "pkts_tx", cJSON_Number, username_s); pkts_ign = accept_liveupgrade_cJSON_get(client, "pkts_ign", cJSON_Number, username_s); rx_errs = accept_liveupgrade_cJSON_get(client, "rx_errs", cJSON_Array, username_s); filter = accept_liveupgrade_cJSON_get(client, "filter", cJSON_String, username_s); /* optional */ tick_connect = cJSON_GetObjectItem(client, "t_connect_tick"); udp_port = cJSON_GetObjectItem(client, "udp_port"); ibuf = cJSON_GetObjectItem(client, "ibuf"); obuf = cJSON_GetObjectItem(client, "obuf"); client_heard = cJSON_GetObjectItem(client, "client_heard"); lat = cJSON_GetObjectItem(client, "lat"); lng = cJSON_GetObjectItem(client, "lng"); if (!( (fd) && (listener_id) && (state) && (username) && (time_connect) && (addr_loc) && (app_name) && (app_version) && (verified) && (obuf_q) && (bytes_rx) && (bytes_tx) && (pkts_rx) && (pkts_tx) && (pkts_ign) && (rx_errs) && (filter) )) { hlog(LOG_ERR, "Live upgrade: Fields missing from client JSON, discarding client fd %d", fd_i); if (fd_i >= 0) close(fd_i); return -1; } hlog(LOG_DEBUG, "Old client on fd %d: %s", fd->valueint, username->valuestring); /* fetch peer address from the fd instead of parsing it from text */ addr_len = sizeof(sa); if (getpeername(fd->valueint, &sa.sa, &addr_len) != 0) { /* Sometimes clients disconnect during upgrade, especially on slow RPi servers... */ if (errno == ENOTCONN) hlog(LOG_INFO, "Live upgrade: Client %s on fd %d has disconnected during upgrade (%s)", username->valuestring, fd->valueint, strerror(errno)); else hlog(LOG_ERR, "Live upgrade: getpeername client fd %d failed: %s", fd->valueint, strerror(errno)); close(fd->valueint); return -1; } /* convert client address to string */ char *client_addr_s = strsockaddr( &sa.sa, addr_len ); /* find the right listener for this client, for configuration and accounting */ struct listen_t *l = liveupgrade_find_listener(listener_id->valueint); if (!l) { hlog(LOG_INFO, "Live upgrade: Listener has been removed for fd %d (%s - local %s): disconnecting %s", fd->valueint, client_addr_s, addr_loc->valuestring, username->valuestring); close(fd->valueint); hfree(client_addr_s); return -1; } struct client_t *c = accept_client_for_listener(l, fd->valueint, client_addr_s, &sa, addr_len); if (!c) { hlog(LOG_ERR, "Live upgrade - client_alloc returned NULL, too many clients. Denied client %s on fd %d from %s", username->valuestring, fd->valueint, client_addr_s); close(fd->valueint); hfree(client_addr_s); return -1; } hfree(client_addr_s); if (strcmp(state->valuestring, "connected") == 0) { c->state = CSTATE_CONNECTED; c->handler_line_in = &incoming_handler; strncpy(c->username, username->valuestring, sizeof(c->username)); c->username[sizeof(c->username)-1] = 0; c->username_len = strlen(c->username); } else if (strcmp(state->valuestring, "login") == 0) { c->state = CSTATE_LOGIN; c->handler_line_in = &login_handler; } else { hlog(LOG_ERR, "Live upgrade: Client %s is in invalid state '%s' (fd %d)", l->addr_s, state->valuestring, l->fd); goto err; } /* distribute keepalive intervals for the existing old clients * but send them rather sooner than later */ // coverity[dont_call] // squelch warning: not security sensitive use of random(): load distribution c->keepalive = tick + (random() % (keepalive_interval/2)); /* distribute cleanup intervals over the next 2 minutes */ // coverity[dont_call] // squelch warning: not security sensitive use of random(): load distribution c->cleanup = tick + (random() % 120); c->connect_time = time_connect->valueint; /* live upgrade / backward compatibility: upgrading from <= 1.8.2 requires the 'else' path' */ if (tick_connect && tick_connect->type == cJSON_Number) c->connect_tick = tick_connect->valueint; else /* convert to monotonic time */ c->connect_tick = tick - (now - c->connect_time); c->validated = verified->valueint; c->localaccount.rxbytes = bytes_rx->valuedouble; c->localaccount.txbytes = bytes_tx->valuedouble; c->localaccount.rxpackets = pkts_rx->valuedouble; c->localaccount.txpackets = pkts_tx->valuedouble; c->localaccount.rxdrops = pkts_ign->valuedouble; login_set_app_name(c, app_name->valuestring, app_version->valuestring); // handle client's filter setting if (c->flags & CLFLAGS_USERFILTEROK && (filter) && (filter->valuestring) && *(filter->valuestring)) { // archive a copy of the filters, for status display strncpy(c->filter_s, filter->valuestring, FILTER_S_SIZE); c->filter_s[FILTER_S_SIZE-1] = 0; sanitize_ascii_string(c->filter_s); char *f = hstrdup(filter->valuestring); argc = parse_args(argv, f); for (i = 0; i < argc; ++i) { filter_parse(c, argv[i], 1); } hfree(f); } // set up UDP downstream if necessary if (udp_port && udp_port->type == cJSON_Number && udp_port->valueint > 1024 && udp_port->valueint < 65536) { if (login_setup_udp_feed(c, udp_port->valueint) != 0) { hlog(LOG_DEBUG, "%s/%s: Requested UDP on client port with no UDP configured", c->addr_rem, c->username); } } // fill up ibuf if (ibuf && ibuf->type == cJSON_String && ibuf->valuestring) { int l = hex_decode(c->ibuf, c->ibuf_size, ibuf->valuestring); if (l < 0) { hlog(LOG_ERR, "Live upgrade: %s/%s: Failed to decode ibuf: %s", c->addr_rem, c->username, ibuf->valuestring); } else { c->ibuf_end = l; hlog(LOG_DEBUG, "Live upgrade: Decoded ibuf %d bytes: '%.*s'", l, l, c->ibuf); hlog(LOG_DEBUG, "Hex: %s", ibuf->valuestring); } } // fill up obuf if (obuf && obuf->type == cJSON_String && obuf->valuestring) { int l = hex_decode(c->obuf, c->obuf_size, obuf->valuestring); if (l < 0) { hlog(LOG_ERR, "Live upgrade: %s/%s: Failed to decode obuf: %s", c->addr_rem, c->username, obuf->valuestring); } else { c->obuf_start = 0; c->obuf_end = l; hlog(LOG_DEBUG, "Live upgrade: Decoded obuf %d bytes: '%.*s'", l, l, c->obuf); hlog(LOG_DEBUG, "Hex: %s", obuf->valuestring); } } /* load list of stations heard by this client, to immediately support * messaging */ if (client_heard && client_heard->type == cJSON_Array) client_heard_json_load(c, client_heard); /* load rxerrs counters, with error name string mapping to support * adding/reordering of error counters */ if (rx_errs && rx_errs->type == cJSON_Array && rxerr_map && rxerr_map_len > 0) accept_rx_err_load(c, rx_errs, rxerr_map, rxerr_map_len); /* set client lat/lon, if they're given */ if (lat && lng && lat->type == cJSON_Number && lng->type == cJSON_Number) { c->loc_known = 1; c->lat = lat->valuedouble; c->lng = lng->valuedouble; } hlog(LOG_DEBUG, "%s - Accepted live upgrade client on fd %d from %s", c->addr_loc, c->fd, c->addr_rem); /* set client socket options, return -1 on serious errors */ if (set_client_sockopt(c) != 0) goto err; /* Add the client to the client list. */ int old_fd = clientlist_add(c); if (c->validated && old_fd != -1) { /* TODO: If old connection is SSL validated, and this one is not, do not disconnect it. */ hlog(LOG_INFO, "fd %d: Disconnecting duplicate validated client with username '%s'", old_fd, c->username); shutdown(old_fd, SHUT_RDWR); } /* ok, found it... lock the new client queue and pass the client */ if (pass_client_to_worker(pick_next_worker(), c)) goto err; return 0; err: close(c->fd); inbound_connects_account(0, c->portaccount); /* something failed, remove this from accounts.. */ client_free(c); return -1; }
static int open_listener(struct listen_config_t *lc) { struct listen_t *l; int i; l = listener_alloc(); l->id = lc->id; l->hidden = lc->hidden; l->corepeer = lc->corepeer; l->client_flags = lc->client_flags; l->clients_max = lc->clients_max; l->portaccount = port_accounter_alloc(); /* Pick first of the AIs for this listen definition */ l->addr_s = strsockaddr( lc->ai->ai_addr, lc->ai->ai_addrlen ); l->name = hstrdup(lc->name); l->portnum = lc->portnum; l->ai_protocol = lc->ai->ai_protocol; l->listener_id = keyhash(l->addr_s, strlen(l->addr_s), 0); l->listener_id = keyhash(&lc->ai->ai_socktype, sizeof(lc->ai->ai_socktype), l->listener_id); l->listener_id = keyhash(&lc->ai->ai_protocol, sizeof(lc->ai->ai_protocol), l->listener_id); hlog(LOG_DEBUG, "Opening listener %d/%d '%s': %s", lc->id, l->listener_id, lc->name, l->addr_s); if (lc->ai->ai_socktype == SOCK_DGRAM && lc->ai->ai_protocol == IPPROTO_UDP) { /* UDP listenting is not quite same as TCP listening.. */ i = open_udp_listener(l, lc->ai); } else if (lc->ai->ai_socktype == SOCK_STREAM && lc->ai->ai_protocol == IPPROTO_TCP) { /* TCP listenting... */ i = open_tcp_listener(l, lc->ai, "TCP"); #ifdef USE_SCTP } else if (lc->ai->ai_socktype == SOCK_STREAM && lc->ai->ai_protocol == IPPROTO_SCTP) { i = open_tcp_listener(l, lc->ai, "SCTP"); if (i >= 0) i = sctp_set_listen_params(l); #endif } else { hlog(LOG_ERR, "Unsupported listener protocol for '%s'", l->name); listener_free(l); return -1; } if (i < 0) { hlog(LOG_DEBUG, "... failed"); listener_free(l); return -1; } hlog(LOG_DEBUG, "... ok, bound"); /* Set up an SSL context if necessary */ #ifdef USE_SSL if (lc->keyfile && lc->certfile) { l->ssl = ssl_alloc(); if (ssl_create(l->ssl, (void *)l)) { hlog(LOG_ERR, "Failed to create SSL context for '%s*': %s", lc->name, l->addr_s); listener_free(l); return -1; } if (ssl_certificate(l->ssl, lc->certfile, lc->keyfile)) { hlog(LOG_ERR, "Failed to load SSL key and certificates for '%s*': %s", lc->name, l->addr_s); listener_free(l); return -1; } /* optional client cert validation */ if (lc->cafile) { if (ssl_ca_certificate(l->ssl, lc->cafile, 2)) { hlog(LOG_ERR, "Failed to load trusted SSL CA certificates for '%s*': %s", lc->name, l->addr_s); listener_free(l); return -1; } } hlog(LOG_INFO, "SSL initialized for '%s': %s%s", lc->name, l->addr_s, (lc->cafile) ? " (client validation enabled)" : ""); } #endif /* Copy access lists */ if (lc->acl) l->acl = acl_dup(lc->acl); /* Copy filter definitions */ listener_copy_filters(l, lc); hlog(LOG_DEBUG, "... adding %s to listened sockets", l->addr_s); // put (first) in the list of listening sockets l->next = listen_list; l->prevp = &listen_list; if (listen_list) listen_list->prevp = &l->next; listen_list = l; return 0; }
int login_handler(struct worker_t *self, struct client_t *c, int l4proto, char *s, int len) { int argc; char *argv[256]; int i, rc; /* make it null-terminated for our string processing */ char *e = s + len; *e = 0; hlog(LOG_DEBUG, "%s: login string: '%s' (%d)", c->addr_rem, s, len); /* parse to arguments */ if ((argc = parse_args_noshell(argv, s)) == 0 || *argv[0] == '#') return 0; if (argc < 2) { hlog(LOG_WARNING, "%s: Invalid login string, too few arguments: '%s'", c->addr_rem, s); rc = client_printf(self, c, "# Invalid login string, too few arguments\r\n"); goto failed_login; } if (strcasecmp(argv[0], "user") != 0) { if (strcasecmp(argv[0], "GET") == 0) c->failed_cmds = 10; /* bail out right away for a HTTP client */ c->failed_cmds++; hlog(LOG_WARNING, "%s: Invalid login string, no 'user': '******'", c->addr_rem, s); rc = client_printf(self, c, "# Invalid login command\r\n"); goto failed_login; } char *username = argv[1]; /* limit username length */ if (strlen(username) > CALLSIGNLEN_MAX) { hlog(LOG_WARNING, "%s: Invalid login string, too long 'user' username: '******'", c->addr_rem, c->username); username[CALLSIGNLEN_MAX] = 0; rc = client_printf(self, c, "# Invalid username format\r\n"); goto failed_login; } #ifndef FIXED_IOBUFS c->username = hstrdup(username); #else strncpy(c->username, username, sizeof(c->username)); c->username[sizeof(c->username)-1] = 0; #endif c->username_len = strlen(c->username); /* check the username against a static list of disallowed usernames */ for (i = 0; (disallow_login_usernames[i]); i++) { if (strcasecmp(c->username, disallow_login_usernames[i]) == 0) { hlog(LOG_WARNING, "%s: Login by user '%s' not allowed", c->addr_rem, c->username); rc = client_printf(self, c, "# Login by user not allowed\r\n"); goto failed_login; } } /* make sure the callsign is OK on the APRS-IS */ if (check_invalid_q_callsign(c->username, c->username_len)) { hlog(LOG_WARNING, "%s: Invalid login string, invalid 'user': '******'", c->addr_rem, c->username); rc = client_printf(self, c, "# Invalid username format\r\n"); goto failed_login; } int given_passcode = -1; for (i = 2; i < argc; i++) { if (strcasecmp(argv[i], "pass") == 0) { if (++i >= argc) { hlog(LOG_WARNING, "%s/%s: No passcode after pass command", c->addr_rem, username); break; } given_passcode = atoi(argv[i]); if (given_passcode >= 0) if (given_passcode == aprs_passcode(c->username)) c->validated = 1; } else if (strcasecmp(argv[i], "vers") == 0) { /* Collect application name and version separately. * Some clients only give out application name but * no version. If those same applications do try to * use filter or udp, the filter/udp keyword will end * up as the version number. So good luck with that. */ if (i+1 >= argc) { hlog(LOG_INFO, "%s/%s: No application name after 'vers' in login", c->addr_rem, username); break; } login_set_app_name(c, argv[i+1], (i+2 < argc) ? argv[i+2] : ""); i += 2; } else if (strcasecmp(argv[i], "udp") == 0) { if (++i >= argc) { hlog(LOG_WARNING, "%s/%s: Missing UDP port number after UDP command", c->addr_rem, username); break; } int udp_port = atoi(argv[i]); if (udp_port < 1024 || udp_port > 65535) { hlog(LOG_WARNING, "%s/%s: UDP port number %s is out of range", c->addr_rem, username, argv[i]); break; } if (login_setup_udp_feed(c, udp_port) != 0) { /* Sorry, no UDP service for this port.. */ hlog(LOG_DEBUG, "%s/%s: Requested UDP on client port with no UDP configured", c->addr_rem, username); rc = client_printf(self, c, "# No UDP service available on this port\r\n"); if (rc < -2) return rc; // client got destroyed } } else if (strstr(argv[i], "filter")) { /* Follows javaaprssrvr's example - any command having 'filter' in the * end is OK. */ if (!(c->flags & CLFLAGS_USERFILTEROK)) { rc = client_printf(self, c, "# No user-specified filters on this port\r\n"); if (rc < -2) return rc; // client got destroyed break; } /* copy the null-separated filter arguments back to a space-separated * string, for the status page to show */ char *fp = c->filter_s; char *fe = c->filter_s + FILTER_S_SIZE; int f_non_first = 0; while (++i < argc) { int l = strlen(argv[i]); if (fp + l + 2 < fe) { if (f_non_first) { *fp++ = ' '; } memcpy(fp, argv[i], l); fp += l; *fp = 0; f_non_first = 1; } /* parse filters in argv[i] */ rc = filter_parse(c, argv[i], 1); if (rc) { rc = client_printf( self, c, "# Parse errors on filter spec: '%s'\r\n", argv[i]); if (rc < -2) return rc; // The client probably got destroyed! } } } } /* ok, login succeeded, switch handler */ c->handler = &incoming_handler; /* handler of all incoming APRS-IS data during a connection */ rc = client_printf( self, c, "# logresp %s %s, server %s\r\n", username, (c->validated) ? "verified" : "unverified", serverid ); if (rc < -2) return rc; // The client probably got destroyed! c->keepalive = now + keepalive_interval/2 + random() % keepalive_interval; c->state = CSTATE_CONNECTED; hlog(LOG_DEBUG, "%s: login '%s'%s%s%s%s%s%s%s%s", c->addr_rem, username, (c->validated) ? " pass_ok" : "", (!c->validated && given_passcode >= 0) ? " pass_invalid" : "", (given_passcode < 0) ? " pass_none" : "", (c->udp_port) ? " UDP" : "", (c->app_name) ? " app " : "", (c->app_name) ? c->app_name : "", (c->app_version) ? " ver " : "", (c->app_version) ? c->app_version : "" ); /* Add the client to the client list. * * If the client logged in with a valid passcode, check if there are * other validated clients logged in with the same username. * If one is found, it needs to be disconnected. * * The lookup is done while holding the write lock to the clientlist, * instead of a separate lookup call, so that two clients logging in * at exactly the same time won't make it. */ int old_fd = clientlist_add(c); if (c->validated && old_fd != -1) { hlog(LOG_INFO, "fd %d: Disconnecting duplicate validated client with username '%s'", old_fd, username); /* The other client may be on another thread, so cannot client_close() it. * There is a small potential race here, if the old client disconnected and * the fd was recycled for another client right after the clientlist check. */ shutdown(old_fd, SHUT_RDWR); } return 0; failed_login: /* if we already lost the client, just return */ if (rc < -2) return rc; c->failed_cmds++; if (c->failed_cmds >= 3) { client_close(self, c, CLIERR_LOGIN_RETRIES); return -3; } return rc; }
/* * parse the next request line * returns: * 1 ok * 0 eof * -1 error */ int hparsereq(HConnect *c, int timeout) { Strings ss; char *vs, *v, *search, *uri, *origuri, *extra; if(c->bin != nil){ hfail(c, HInternal); return -1; } /* * serve requests until a magic request. * later requests have to come quickly. * only works for http/1.1 or later. */ if(timeout) alarm(timeout); if(hgethead(c, 0) < 0) return -1; if(timeout) alarm(0); c->reqtime = time(nil); c->req.meth = getword(c); if(c->req.meth == nil){ hfail(c, HSyntax); return -1; } uri = getword(c); if(uri == nil || strlen(uri) == 0){ hfail(c, HSyntax); return -1; } v = getword(c); if(v == nil){ if(strcmp(c->req.meth, "GET") != 0){ hfail(c, HUnimp, c->req.meth); return -1; } c->req.vermaj = 0; c->req.vermin = 9; }else{ vs = v; if(strncmp(vs, "HTTP/", 5) != 0){ hfail(c, HUnkVers, vs); return -1; } vs += 5; c->req.vermaj = strtoul(vs, &vs, 10); if(*vs != '.' || c->req.vermaj != 1){ hfail(c, HUnkVers, vs); return -1; } vs++; c->req.vermin = strtoul(vs, &vs, 10); if(*vs != '\0'){ hfail(c, HUnkVers, vs); return -1; } extra = getword(c); if(extra != nil){ hfail(c, HSyntax); return -1; } } /* * the fragment is not supposed to be sent * strip it 'cause some clients send it */ origuri = uri; uri = strchr(origuri, '#'); if(uri != nil) *uri = 0; /* * http/1.1 requires the server to accept absolute * or relative uri's. convert to relative with an absolute path */ if(http11(c)){ ss = parseuri(c, origuri); uri = ss.s1; c->req.urihost = ss.s2; if(uri == nil){ hfail(c, HBadReq, uri); return -1; } origuri = uri; } /* * munge uri for search, protection, and magic */ ss = stripsearch(origuri); origuri = ss.s1; search = ss.s2; uri = hurlunesc(c, origuri); uri = abspath(c, uri, "/"); if(uri == nil || uri[0] == '\0'){ hfail(c, HNotFound, "no object specified"); return -1; } c->req.uri = uri; c->req.search = search; if(search) c->req.searchpairs = hparsequery(c, hstrdup(c, search)); return 1; }
static void peerip_clients_config(void) { struct client_t *c; struct peerip_config_t *pe; struct client_udp_t *udpclient; char *s; union sockaddr_u sa; /* large enough for also IPv6 address */ socklen_t addr_len = sizeof(sa); for (pe = peerip_config; (pe); pe = pe->next) { hlog(LOG_DEBUG, "Setting up UDP peer %s (%s)", pe->name, pe->host); udpclient = client_udp_find(udppeers, pe->af, pe->local_port); if (!udpclient) { hlog(LOG_ERR, "Failed to find UDP socket on port %d for peer %s (%s)", pe->local_port, pe->name, pe->host); continue; } c = client_alloc(); if (!c) { hlog(LOG_ERR, "peerip_clients_config: client_alloc returned NULL"); abort(); } c->fd = -1; // Right, this client will never have a socket of it's own. c->ai_protocol = IPPROTO_UDP; c->portnum = pe->local_port; // local port c->state = CSTATE_COREPEER; c->validated = VALIDATED_WEAK; c->flags = CLFLAGS_UPLINKPORT; c->handler_line_in = &incoming_handler; memcpy((void *)&c->udpaddr.sa, (void *)pe->ai->ai_addr, pe->ai->ai_addrlen); c->udpaddrlen = pe->ai->ai_addrlen; c->udp_port = pe->remote_port; // remote port c->addr = c->udpaddr; c->udpclient = udpclient; //c->portaccount = l->portaccount; c->keepalive = tick + keepalive_interval; c->last_read = tick; /* not simulated time */ inbound_connects_account(3, c->udpclient->portaccount); /* "3" = udp, not listening.. */ /* set up peer serverid to username */ strncpy(c->username, pe->serverid, sizeof(c->username)); c->username[sizeof(c->username)-1] = 0; c->username_len = strlen(c->username); /* convert client address to string */ s = strsockaddr( &c->udpaddr.sa, c->udpaddrlen ); /* text format of client's IP address + port */ strncpy(c->addr_rem, s, sizeof(c->addr_rem)); c->addr_rem[sizeof(c->addr_rem)-1] = 0; hfree(s); /* hex format of client's IP address + port */ s = hexsockaddr( &c->udpaddr.sa, c->udpaddrlen ); strncpy(c->addr_hex, s, sizeof(c->addr_hex)); c->addr_hex[sizeof(c->addr_hex)-1] = 0; hfree(s); /* text format of servers' connected IP address + port */ addr_len = sizeof(sa); if (getsockname(c->udpclient->fd, &sa.sa, &addr_len) == 0) { /* Fails very rarely.. */ /* present my socket end address as a malloced string... */ s = strsockaddr( &sa.sa, addr_len ); } else { hlog(LOG_ERR, "Peer config: getsockname on udpclient->fd failed: %s", strerror(errno)); s = hstrdup( "um" ); /* Server's bound IP address.. TODO: what? */ } strncpy(c->addr_loc, s, sizeof(c->addr_loc)); c->addr_loc[sizeof(c->addr_loc)-1] = 0; hfree(s); /* pass the client to the first worker thread */ if (pass_client_to_worker(worker_threads, c)) { hlog(LOG_ERR, "Failed to pass UDP peer %s (%s) to worker", pe->name, pe->host); client_free(c); } } }
struct client_t *accept_client_for_listener(struct listen_t *l, int fd, char *addr_s, union sockaddr_u *sa, unsigned addr_len) { struct client_t *c; char *s; int i; union sockaddr_u sa_loc; /* local address */ socklen_t addr_len_loc = sizeof(sa_loc); c = client_alloc(); if (!c) return NULL; c->fd = fd; c->listener_id = l->listener_id; c->addr = *sa; c->ai_protocol = l->ai_protocol; c->portnum = l->portnum; c->hidden = l->hidden; c->flags = l->client_flags; c->udpclient = client_udp_find(udpclients, sa->sa.sa_family, l->portnum); c->portaccount = l->portaccount; c->last_read = tick; /* not simulated time */ inbound_connects_account(1, c->portaccount); /* account all ports + port-specifics */ /* text format of client's IP address + port */ strncpy(c->addr_rem, addr_s, sizeof(c->addr_rem)); c->addr_rem[sizeof(c->addr_rem)-1] = 0; /* hex format of client's IP address + port */ s = hexsockaddr( &sa->sa, addr_len ); strncpy(c->addr_hex, s, sizeof(c->addr_hex)); c->addr_hex[sizeof(c->addr_hex)-1] = 0; hfree(s); /* text format of servers' connected IP address + port */ if (getsockname(fd, &sa_loc.sa, &addr_len_loc) == 0) { /* Fails very rarely.. */ if (addr_len_loc > sizeof(sa_loc)) hlog(LOG_ERR, "accept_client_for_listener: getsockname for client %s truncated local address of %d to %d bytes", c->addr_rem, addr_len_loc, sizeof(sa_loc)); /* present my socket end address as a malloced string... */ s = strsockaddr( &sa_loc.sa, addr_len_loc ); } else { s = hstrdup( l->addr_s ); /* Server's bound IP address */ hlog(LOG_ERR, "accept_client_for_listener: getsockname for client %s failed: %s (using '%s' instead)", c->addr_rem, strerror(errno), s); } strncpy(c->addr_loc, s, sizeof(c->addr_loc)); c->addr_loc[sizeof(c->addr_loc)-1] = 0; hfree(s); /* apply predefined filters */ for (i = 0; i < (sizeof(l->filters)/sizeof(l->filters[0])); ++i) { if (l->filters[i]) { if (filter_parse(c, l->filters[i], 0) < 0) { /* system filters */ hlog(LOG_ERR, "Bad system filter definition: %s", l->filters[i]); } } } if (l->filter_s) { strncpy(c->filter_s, l->filter_s, sizeof(c->filter_s)); c->filter_s[FILTER_S_SIZE-1] = 0; } return c; }
int read_cfgfile(char *f, struct cfgcmd *cmds) { FILE *fp; FILE *tmp_file; char line[CFGLINE_LEN]; int ret, n = 0; char *conf_home_folder; char *conf_home_folder_name; tmp_file = fopen("/etc/gnuais.conf","r"); if(tmp_file != NULL){ hlog(LOG_WARNING, "gnuais does not use the configuration file /etc/gnuais.conf anymore. It is now in your home directory as .config/gnuais/config. /etc/gnuais.conf should be deleted to avoid confusion"); fclose(tmp_file); } fp = fopen(f, "r"); if(fp == NULL){ conf_home_folder_name = hstrdup(getenv("HOME")); conf_home_folder_name = str_append(conf_home_folder_name,"/.config"); ret = mkdir(conf_home_folder_name, 0777); conf_home_folder_name = str_append(conf_home_folder_name,"/gnuais"); conf_home_folder = hstrdup(conf_home_folder_name); conf_home_folder = str_append(conf_home_folder,"/config"); fp = fopen(conf_home_folder,"r"); if(fp == NULL){ hlog(LOG_INFO,"Creating directory: ~/.config/gnuais/"); ret = mkdir(conf_home_folder_name, 0777); if(ret != 0){ hlog(LOG_INFO,"~/.config/gnuais/ already exists"); } tmp_file = fopen("/etc/gnuais.conf","r"); ret = 0; if(tmp_file == NULL){ tmp_file = fopen("/usr/local/share/doc/gnuais/gnuais.conf-example","r"); if(tmp_file == NULL){ tmp_file = fopen("/usr/share/doc/gnuais/gnuais.conf-example","r"); if(tmp_file == NULL){ hlog(LOG_ERR,"No gnuais.conf-example found to be copied to ~/.config/gnuais/config"); } else { hlog(LOG_NOTICE, "Using gnuais.conf-example as a starting point for ~/.config/gnuais/config..."); ret = cpfile(conf_home_folder,"/usr/share/doc/gnuais/gnuais.conf-example"); if(ret == -1) hlog(LOG_ERR, "Could not copy configuration file to the home folder"); else hlog(LOG_NOTICE, "DONE creating configuration file (~/.config/gnuais/config). You should edit this file manually!"); } } else { hlog(LOG_NOTICE, "Using gnuais.conf-example as a starting point for ~/.config/gnuais/config..."); ret = cpfile(conf_home_folder,"/usr/local/share/doc/gnuais/gnuais.conf-example"); if(ret == -1) hlog(LOG_ERR, "Could not copy configuration file to the home folder"); else hlog(LOG_NOTICE, "DONE creating configuration file (~/.config/gnuais/config). You should edit this file manually!"); } } else { hlog(LOG_WARNING, "/etc/gnuais.conf found, but no ~/.config/gnuais/config found."); hlog(LOG_WARNING, "It will be copied to your home directory (~/.config/gnuais/config)..."); ret = cpfile(conf_home_folder,"/etc/gnuais.conf"); if(ret == -1) hlog(LOG_ERR, "Could not copy configuration file from /etc/gnuais.conf to your home directory"); else hlog(LOG_NOTICE, "DONE"); } if(ret != -1) { fp = fopen(conf_home_folder,"r"); if(fp == NULL){ hlog(LOG_ERR, "Could not open configuration file after copying it to the home directory"); } } } hfree(conf_home_folder_name); hfree(conf_home_folder); } if(fp == NULL){ hlog(LOG_ERR, "No configuration file found! Running with the default configuration. You should create a file ~/.config/gnuais/config. There should be an example to use in the source archive called gnuais.conf-example"); } else { while (fgets(line, CFGLINE_LEN, fp) != NULL) { n++; ret = cmdparse(cmds, line); if (ret < 0) { fprintf(stderr, "Problem in %s at line %d: %s\n", f, n, line); fclose(fp); return 2; } } fclose(fp); } return 0; }
int read_config(void) { int failed = 0; char *s; if (read_cfgfile(cfgfile, cfg_cmds)) return -1; /* these parameters will only be used when reading the configuration * for the first time. */ if(log_dir){ /* Check if logdir passed from command line. In that case config file parameter should be ignored*/ logdir = hstrdup(log_dir); } else if(!logdir) { /* Using current directory as default if not given neither in config file or command line */ if(log_dest == L_FILE) hlog(LOG_WARNING, "Config: logdir not defined. Using . as log directory"); logdir = hstrdup("."); } /* mycall is only applied when running for the first time. */ if (!mycall) { mycall = hstrdup("NOCALLDEFINED"); hlog(LOG_WARNING, "Config: mycall is not defined - using: %s.",mycall); //failed = 1; } else if (!valid_aprsis_call(mycall)) { hlog(LOG_CRIT, "Config: mycall '%s' is not valid.", mycall); failed = 1; } if (!myemail) { myemail = hstrdup("notdefined@notdefined"); hlog(LOG_WARNING, "Config: myemail is not defined - using: %s.",myemail); //failed = 1; } if (!sound_in_file && !sound_device) { sound_device = def_sound_device; hlog(LOG_WARNING, "Config: SoundDevice is not defined - using: %s", sound_device); } if (sound_in_file && sound_device) { if (sound_device != def_sound_device) hfree(sound_device); sound_device = NULL; } /* put in the new uplink config */ free_uplink_config(&uplink_config); uplink_config = new_uplink_config; if (uplink_config) uplink_config->prevp = &uplink_config; new_uplink_config = NULL; if (failed) return -1; if (!pidfile) { s = hmalloc(strlen(logdir) + 1 + strlen(logname) + 3 + 2); sprintf(s, "%s/%s.pid", logdir, logname); pidfile = s; } return 0; }