mowgli_linebuf_t * mowgli_linebuf_create(mowgli_linebuf_readline_cb_t *cb, void *userdata) { mowgli_linebuf_t *linebuf; if (linebuf_heap == NULL) linebuf_heap = mowgli_heap_create(sizeof(mowgli_linebuf_t), 16, BH_NOW); linebuf = mowgli_heap_alloc(linebuf_heap); /* Sane default */ mowgli_linebuf_delim(linebuf, "\r\n", "\r\n"); linebuf->readline_cb = cb; linebuf->flags = 0; linebuf->readbuf.buffer = NULL; linebuf->writebuf.buffer = NULL; mowgli_linebuf_setbuflen(&(linebuf->readbuf), 65536); mowgli_linebuf_setbuflen(&(linebuf->writebuf), 65536); linebuf->eventloop = NULL; linebuf->return_normal_strings = true; /* This is generally what you want, but beware of malicious \0's in input data! */ linebuf->userdata = userdata; linebuf->vio = mowgli_vio_create(linebuf); return linebuf; }
int mowgli_vio_openssl_setssl(mowgli_vio_t *vio, mowgli_vio_ssl_settings_t *settings, mowgli_vio_ops_t *ops) { mowgli_ssl_connection_t *connection; return_val_if_fail(vio, -255); if (!ssl_heap) ssl_heap = mowgli_heap_create(sizeof(mowgli_ssl_connection_t), 64, BH_NOW); connection = mowgli_heap_alloc(ssl_heap); vio->privdata = connection; if (settings) memcpy(&connection->settings, settings, sizeof(mowgli_vio_ssl_settings_t)); else /* Greatest compat without being terribly insecure */ connection->settings.ssl_version = MOWGLI_VIO_SSLFLAGS_SSLV3; if (ops == NULL) { if (!openssl_ops) { openssl_ops = mowgli_alloc(sizeof(mowgli_vio_ops_t)); memcpy(openssl_ops, &mowgli_vio_default_ops, sizeof(mowgli_vio_ops_t)); } vio->ops = openssl_ops; } else { vio->ops = ops; } /* Change ops */ mowgli_vio_ops_set_op(vio->ops, connect, mowgli_vio_openssl_default_connect); mowgli_vio_ops_set_op(vio->ops, read, mowgli_vio_openssl_default_read); mowgli_vio_ops_set_op(vio->ops, write, mowgli_vio_openssl_default_write); mowgli_vio_ops_set_op(vio->ops, close, mowgli_vio_openssl_default_close); mowgli_vio_ops_set_op(vio->ops, accept, mowgli_vio_openssl_default_accept); mowgli_vio_ops_set_op(vio->ops, listen, mowgli_vio_openssl_default_listen); /* SSL setup */ if (!openssl_init) { openssl_init = true; SSL_library_init(); SSL_load_error_strings(); ERR_load_BIO_strings(); OpenSSL_add_all_algorithms(); } return 0; }
static struct myentity * chanacs_validate_f(const char *param) { static const struct entity_chanacs_validation_vtable chanacs_ext_validate = { .match_entity = chanacs_ext_match_entity, .match_user = chanacs_ext_match_user, .can_register_channel = chanacs_ext_can_register_channel, .allow_foundership = chanacs_allow_foundership, }; char *name; struct this_exttarget *ext; size_t namelen; if (param == NULL) return NULL; if (*param == '\0') return NULL; // if we already have an object, return it from our tree. if ((ext = mowgli_patricia_retrieve(chanacs_exttarget_tree, param)) != NULL) return entity(ext); ext = mowgli_heap_alloc(chanacs_ext_heap); ext->channel = strshare_get(param); ext->checking = 0; // name the entity... $chanacs:param #define NAMEPREFIX "$chanacs:" namelen = sizeof NAMEPREFIX + strlen(param); name = smalloc(namelen); memcpy(name, NAMEPREFIX, sizeof NAMEPREFIX - 1); memcpy(name + sizeof NAMEPREFIX - 1, param, namelen - sizeof NAMEPREFIX + 1); entity(ext)->name = strshare_get(name); sfree(name); #undef NAMEPREFIX // hook up the entity's validation table. entity(ext)->chanacs_validate = &chanacs_ext_validate; entity(ext)->type = ENT_EXTTARGET; // initialize the object. atheme_object_init(atheme_object(ext), entity(ext)->name, (atheme_object_destructor_fn) chanacs_ext_delete); // add the object to the exttarget tree mowgli_patricia_add(chanacs_exttarget_tree, ext->channel, ext); // return the object as initially unowned by sinking the reference count. return atheme_object_sink_ref(ext); }
mowgli_queue_t * mowgli_queue_push(mowgli_queue_t *head, void *data) { mowgli_queue_t *out = mowgli_heap_alloc(mowgli_queue_heap); return_val_if_fail(head != NULL, NULL); out->prev = head; out->data = data; if (head != NULL) head->next = out; return out; }
mowgli_eventloop_t * mowgli_eventloop_create(void) { mowgli_eventloop_t *eventloop; if (eventloop_heap == NULL) eventloop_heap = mowgli_heap_create(sizeof(mowgli_eventloop_t), 16, BH_NOW); eventloop = mowgli_heap_alloc(eventloop_heap); eventloop->eventloop_ops = &_mowgli_null_pollops; #ifdef HAVE_SELECT eventloop->eventloop_ops = &_mowgli_select_pollops; #endif #ifdef HAVE_POLL_H eventloop->eventloop_ops = &_mowgli_poll_pollops; #endif #ifdef HAVE_SYS_EPOLL_H eventloop->eventloop_ops = &_mowgli_epoll_pollops; #endif #ifdef HAVE_KQUEUE eventloop->eventloop_ops = &_mowgli_kqueue_pollops; #endif #ifdef HAVE_DISPATCH_BLOCK eventloop->eventloop_ops = &_mowgli_qnx_pollops; #endif #ifdef HAVE_PORT_CREATE eventloop->eventloop_ops = &_mowgli_ports_pollops; #endif #if 0 eventloop->eventloop_ops = &_mowgli_winsock_pollops; #endif if (mowgli_mutex_init(&eventloop->mutex) != 0) { mowgli_log("couldn't create mutex for eventloop %p, aborting...", (void *) eventloop); abort(); } eventloop->eventloop_ops->pollsetup(eventloop); eventloop->deadline = -1; mowgli_eventloop_calibrate(eventloop); return eventloop; }
static myentity_t *chanacs_validate_f(const char *param) { char *name; chanacs_exttarget_t *ext; size_t namelen; if (param == NULL) return NULL; if (*param == '\0') return NULL; /* if we already have an object, return it from our tree. */ if ((ext = mowgli_patricia_retrieve(chanacs_exttarget_tree, param)) != NULL) return entity(ext); ext = mowgli_heap_alloc(chanacs_ext_heap); ext->channel = strshare_get(param); ext->checking = 0; /* name the entity... $chanacs:param */ #define NAMEPREFIX "$chanacs:" namelen = sizeof NAMEPREFIX + strlen(param); name = smalloc(namelen); memcpy(name, NAMEPREFIX, sizeof NAMEPREFIX - 1); memcpy(name + sizeof NAMEPREFIX - 1, param, namelen - sizeof NAMEPREFIX + 1); entity(ext)->name = strshare_get(name); free(name); #undef NAMEPREFIX /* hook up the entity's validation table. */ entity(ext)->chanacs_validate = &chanacs_ext_validate; entity(ext)->type = ENT_EXTTARGET; /* initialize the object. */ object_init(object(ext), entity(ext)->name, (destructor_t) chanacs_ext_delete); /* add the object to the exttarget tree */ mowgli_patricia_add(chanacs_exttarget_tree, ext->channel, ext); /* return the object as initially unowned by sinking the reference count. */ return object_sink_ref(ext); }
void pcommand_add(const char *token, void (*handler) (sourceinfo_t *si, int parc, char *parv[]), int minparc, int sourcetype) { pcommand_t *pcmd; if (pcommand_find(token)) { slog(LG_INFO, "pcommand_add(): token %s is already registered", token); return; } pcmd = mowgli_heap_alloc(pcommand_heap); pcmd->token = sstrdup(token); pcmd->handler = handler; pcmd->minparc = minparc; pcmd->sourcetype = sourcetype; mowgli_patricia_add(pcommands, pcmd->token, pcmd); }
mowgli_queue_t * mowgli_queue_shift(mowgli_queue_t *head, void *data) { mowgli_queue_t *out = mowgli_heap_alloc(mowgli_queue_heap); return_val_if_fail(head != NULL, NULL); out->next = head; out->data = data; if (head != NULL) { out->prev = head->prev; if (out->prev != NULL) out->prev->next = out; head->prev = out; } return out; }
static void os_cmd_resolve(sourceinfo_t *si, int parc, char *parv[]) { resolve_req_t *req; if (request_heap == NULL) request_heap = mowgli_heap_create(sizeof(resolve_req_t), 32, BH_LAZY); if (!parv[0]) { command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "RESOLVE"); return; } req = mowgli_heap_alloc(request_heap); req->si = si; req->dns_query.ptr = req; req->dns_query.callback = resolve_cb; gethost_byname_type(parv[0], &req->dns_query, T_A); object_ref(req->si); }
/* * server_add(const char *name, unsigned int hops, const char *uplink, * const char *id, const char *desc) * * Server object factory. * * Inputs: * - name of server object to create or NULL if it's a masked server * - amount of hops server has from services * - name of server's uplink or NULL if it's us * - SID of uplink if applicable otherwise NULL * - server's description * * Outputs: * - on success, a new server object * * Side Effects: * - the new server object is added to the server and sid DTree. */ server_t *server_add(const char *name, unsigned int hops, server_t *uplink, const char *id, const char *desc) { server_t *s; const char *tld; /* Masked servers must have a SID */ return_val_if_fail(name != NULL || id != NULL, NULL); /* Masked servers must be behind something else */ return_val_if_fail(name != NULL || uplink != NULL, NULL); if (uplink) { if (name == NULL) slog(LG_NETWORK, "server_add(): %s (%s), masked", uplink->name, id); else if (id != NULL) slog(LG_NETWORK, "server_add(): %s (%s), uplink %s", name, id, uplink->name); else slog(LG_NETWORK, "server_add(): %s, uplink %s", name, uplink->name); } else slog(LG_DEBUG, "server_add(): %s, root", name); s = mowgli_heap_alloc(serv_heap); if (id != NULL) { s->sid = sstrdup(id); mowgli_patricia_add(sidlist, s->sid, s); } /* check to see if it's hidden */ if (!strncmp(desc, "(H)", 3)) { s->flags |= SF_HIDE; desc += 3; if (*desc == ' ') desc++; } s->name = sstrdup(name != NULL ? name : uplink->name); s->desc = sstrdup(desc); s->hops = hops; s->connected_since = CURRTIME; if (name != NULL) mowgli_patricia_add(servlist, s->name, s); else s->flags |= SF_MASKED; if (uplink) { s->uplink = uplink; mowgli_node_add(s, mowgli_node_create(), &uplink->children); } /* tld list for global noticer */ tld = strrchr(s->name, '.'); if (tld != NULL) { if (!tld_find(tld)) tld_add(tld); } cnt.server++; hook_call_server_add(s); return s; }
/* * user_add(const char *nick, const char *user, const char *host, const char *vhost, const char *ip, * const char *uid, const char *gecos, server_t *server, time_t ts); * * User object factory. * * Inputs: * - nickname of new user * - username of new user * - hostname of new user * - virtual hostname of new user if applicable otherwise NULL * - ip of user if applicable otherwise NULL * - unique identifier (UID) of user if appliable otherwise NULL * - gecos of new user * - pointer to server new user is on * - user's timestamp * * Outputs: * - on success, a new user * - on failure, NULL * * Side Effects: * - if successful, a user is created and added to the users DTree. * - if unsuccessful, a kill has been sent if necessary */ user_t *user_add(const char *nick, const char *user, const char *host, const char *vhost, const char *ip, const char *uid, const char *gecos, server_t *server, time_t ts) { user_t *u, *u2; hook_user_nick_t hdata; slog(LG_DEBUG, "user_add(): %s (%s@%s) -> %s", nick, user, host, server->name); u2 = user_find_named(nick); if (u2 != NULL) { if (server == me.me) { /* caller should not let this happen */ slog(LG_ERROR, "user_add(): tried to add local nick %s which already exists", nick); return NULL; } slog(LG_INFO, "user_add(): nick collision on %s", nick); if (u2->server == me.me) { if (uid != NULL) { /* If the new client has a UID, our * client will have a UID too and the * remote server will send us a kill * if it kills our client. So just kill * their client and continue. */ kill_id_sts(NULL, uid, "Nick collision with services (new)"); return NULL; } if (ts == u2->ts || ((ts < u2->ts) ^ (!irccasecmp(user, u2->user) && !irccasecmp(host, u2->host)))) { /* If the TSes are equal, or if their TS * is less than our TS and the u@h differs, * or if our TS is less than their TS and * the u@h is equal, our client will be * killed. * * Hope that a kill has arrived just before * for our client; we will have reintroduced * it. */ return NULL; } else /* Our client will not be killed. */ return NULL; } else { wallops("Server %s is introducing nick %s which already exists on %s", server->name, nick, u2->server->name); if (uid != NULL && u2->uid != NULL) { kill_id_sts(NULL, uid, "Ghost detected via nick collision (new)"); kill_id_sts(NULL, u2->uid, "Ghost detected via nick collision (old)"); user_delete(u2, "Ghost detected via nick collision (old)"); } else { /* There is no way we can do this properly. */ kill_id_sts(NULL, nick, "Ghost detected via nick collision"); user_delete(u2, "Ghost detected via nick collision"); } return NULL; } } u = mowgli_heap_alloc(user_heap); object_init(object(u), nick, (destructor_t) user_delete); if (uid != NULL) { u->uid = strshare_get(uid); mowgli_patricia_add(uidlist, u->uid, u); } u->nick = strshare_get(nick); u->user = strshare_get(user); u->host = strshare_get(host); u->gecos = strshare_get(gecos); u->chost = strshare_get(vhost ? vhost : host); u->vhost = strshare_get(vhost ? vhost : host); if (ip && strcmp(ip, "0") && strcmp(ip, "0.0.0.0") && strcmp(ip, "255.255.255.255")) u->ip = strshare_get(ip); u->server = server; u->server->users++; mowgli_node_add(u, &u->snode, &u->server->userlist); u->ts = ts ? ts : CURRTIME; mowgli_patricia_add(userlist, u->nick, u); cnt.user++; hdata.u = u; hdata.oldnick = NULL; hook_call_user_add(&hdata); return hdata.u; }
/* * Implementation functions: load or unload a perl script. */ static module_t *do_script_load(const char *filename) { /* Remember, this must now be re-entrant. The use of the static * perl_error buffer is still OK, as it's only used immediately after * setting, without control passing from this function. */ perl_script_module_t *m = mowgli_heap_alloc(perl_script_module_heap); mowgli_strlcpy(m->filename, filename, sizeof(m->filename)); snprintf(perl_error, sizeof(perl_error), "Unknown error attempting to load perl script %s", filename); dSP; ENTER; SAVETMPS; PUSHMARK(SP); XPUSHs(newRV_noinc((SV*)get_cv("Atheme::Init::load_script", 0))); XPUSHs(sv_2mortal(newSVpv(filename, 0))); PUTBACK; int perl_return_count = call_pv("Atheme::Init::call_wrapper", G_EVAL | G_SCALAR); SPAGAIN; if (SvTRUE(ERRSV)) { mowgli_strlcpy(perl_error, SvPV_nolen(ERRSV), sizeof(perl_error)); goto fail; } if (1 != perl_return_count) { snprintf(perl_error, sizeof(perl_error), "Script load didn't return a package name"); goto fail; } /* load_script should have returned the package name that was just * loaded... */ const char *packagename = POPp; char info_varname[BUFSIZE]; snprintf(info_varname, BUFSIZE, "%s::Info", packagename); /* ... so use that name to grab the script information hash... */ HV *info_hash = get_hv(info_varname, 0); if (!info_hash) { snprintf(perl_error, sizeof(perl_error), "Couldn't get package info hash %s", info_varname); goto fail; } /* ..., extract the canonical name... */ SV **name_var = hv_fetch(info_hash, "name", 4, 0); if (!name_var) { snprintf(perl_error, sizeof(perl_error), "Couldn't find canonical name in package info hash"); goto fail; } mowgli_strlcpy(m->mod.name, SvPV_nolen(*name_var), sizeof(m->mod.name)); /* ... and dependency list. */ SV **deplist_var = hv_fetch(info_hash, "depends", 7, 0); /* Not declaring this is legal... */ if (deplist_var) { /* ... but having it as anything but an arrayref isn't. */ if (!SvROK(*deplist_var) || SvTYPE(SvRV(*deplist_var)) != SVt_PVAV) { snprintf(perl_error, sizeof(perl_error), "$Info::depends must be an array reference"); goto fail; } AV *deplist = (AV*)SvRV(*deplist_var); I32 len = av_len(deplist); /* av_len returns max index, not number of items */ for (I32 i = 0; i <= len; ++i) { SV **item = av_fetch(deplist, i, 0); if (!item) continue; const char *dep_name = SvPV_nolen(*item); if (!module_request(dep_name)) { snprintf(perl_error, sizeof(perl_error), "Dependent module %s failed to load", dep_name); goto fail; } module_t *dep_mod = module_find_published(dep_name); mowgli_node_add(dep_mod, mowgli_node_create(), &m->mod.deplist); mowgli_node_add(m, mowgli_node_create(), &dep_mod->dephost); } } FREETMPS; LEAVE; invalidate_object_references(); /* Now that everything's loaded, do the module housekeeping stuff. */ m->mod.unload_handler = perl_script_module_unload_handler; /* Can't do much better than the address of the module_t here */ m->mod.address = m; m->mod.can_unload = MODULE_UNLOAD_CAPABILITY_OK; return (module_t*)m; fail: slog(LG_ERROR, "Failed to load Perl script %s: %s", filename, perl_error); if (info_hash) SvREFCNT_dec((SV*)info_hash); do_script_unload(filename); mowgli_heap_free(perl_script_module_heap, m); POPs; FREETMPS; LEAVE; invalidate_object_references(); return NULL; }