/* * npfctl_sessions_save: construct a list of sessions and export for saving. */ int npfctl_sessions_save(u_long cmd, void *data) { struct plistref *pref = data; prop_dictionary_t sesdict; prop_array_t selist, nplist; int error; /* Create a dictionary and two lists. */ sesdict = prop_dictionary_create(); selist = prop_array_create(); nplist = prop_array_create(); /* Save the sessions. */ error = npf_session_save(selist, nplist); if (error) { goto fail; } /* Set the session list, NAT policy list and export the dictionary. */ prop_dictionary_set(sesdict, "session-list", selist); prop_dictionary_set(sesdict, "nat-policy-list", nplist); error = prop_dictionary_copyout_ioctl(pref, cmd, sesdict); fail: prop_object_release(sesdict); return error; }
int npfctl_remove_rule(u_long cmd, void *data) { struct plistref *pref = data; prop_dictionary_t dict, errdict; prop_object_t obj; const char *name; int error, numrules; /* Retrieve and construct the rule. */ error = prop_dictionary_copyin_ioctl(pref, cmd, &dict); if (error) { return error; } /* Dictionary for error reporting. */ errdict = prop_dictionary_create(); obj = prop_dictionary_get(dict, "name"); name = prop_string_cstring_nocopy(obj); npf_rule_t *rl; error = npf_mk_singlerule(dict, prop_array_create(), &rl, errdict); npf_core_enter(); numrules = npf_named_ruleset_remove(name, npf_core_ruleset(), rl); npf_core_exit(); prop_object_release(dict); /* Error report. */ prop_dictionary_set_int32(errdict, "errno", error); prop_dictionary_set_int32(errdict, "numrules", numrules); prop_dictionary_copyout_ioctl(pref, cmd, errdict); prop_object_release(errdict); return error; }
int npfctl_getconf(u_long cmd, void *data) { struct plistref *pref = data; prop_dictionary_t npf_dict; int error; npf_core_enter(); npf_dict = npf_core_dict(); prop_dictionary_set_bool(npf_dict, "active", npf_pfil_registered_p()); error = prop_dictionary_copyout_ioctl(pref, cmd, npf_dict); npf_core_exit(); return error; }
static int dmioctl(struct dev_ioctl_args *ap) { cdev_t dev = ap->a_head.a_dev; u_long cmd = ap->a_cmd; void *data = ap->a_data; int r, err; prop_dictionary_t dm_dict_in; err = r = 0; aprint_debug("dmioctl called\n"); KKASSERT(data != NULL); if (( r = disk_ioctl_switch(dev, cmd, data)) == ENOTTY) { struct plistref *pref = (struct plistref *) data; /* Check if we were called with NETBSD_DM_IOCTL ioctl otherwise quit. */ if ((r = dm_ioctl_switch(cmd)) != 0) return r; if((r = prop_dictionary_copyin_ioctl(pref, cmd, &dm_dict_in)) != 0) return r; if ((r = dm_check_version(dm_dict_in)) != 0) goto cleanup_exit; /* run ioctl routine */ if ((err = dm_cmd_to_fun(dm_dict_in)) != 0) goto cleanup_exit; cleanup_exit: r = prop_dictionary_copyout_ioctl(pref, cmd, dm_dict_in); prop_object_release(dm_dict_in); } /* * Return the error of the actual command if one one has * happened. Otherwise return 'r' which indicates errors * that occurred during helper operations. */ return (err != 0)?err:r; }
/* * npfctl_update_rule: reload a specific rule identified by the name. */ int npfctl_update_rule(u_long cmd, void *data) { struct plistref *pref = data; prop_dictionary_t dict, errdict; prop_array_t subrules; prop_object_t obj; npf_ruleset_t *rlset; const char *name; int error; /* Retrieve and construct the rule. */ error = prop_dictionary_copyin_ioctl(pref, cmd, &dict); if (error) { return error; } /* Dictionary for error reporting. */ errdict = prop_dictionary_create(); /* Create the ruleset and construct sub-rules. */ rlset = npf_ruleset_create(); subrules = prop_dictionary_get(dict, "subrules"); error = npf_mk_subrules(rlset, subrules, NULL, errdict); if (error) { goto out; } /* Lookup the rule by name, and replace its subset (sub-rules). */ obj = prop_dictionary_get(dict, "name"); name = prop_string_cstring_nocopy(obj); if (npf_ruleset_replace(name, rlset) == NULL) { /* Not found. */ error = ENOENT; out: /* Error path. */ npf_ruleset_destroy(rlset); } prop_object_release(dict); /* Error report. */ prop_dictionary_set_int32(errdict, "errno", error); prop_dictionary_copyout_ioctl(pref, cmd, errdict); prop_object_release(errdict); return error; }
static int dmioctl(dev_t dev, const u_long cmd, void *data, int flag, struct lwp *l) { int r; prop_dictionary_t dm_dict_in; r = 0; aprint_debug("dmioctl called\n"); KASSERT(data != NULL); if (( r = disk_ioctl_switch(dev, cmd, data)) == ENOTTY) { struct plistref *pref = (struct plistref *) data; /* Check if we were called with NETBSD_DM_IOCTL ioctl otherwise quit. */ if ((r = dm_ioctl_switch(cmd)) != 0) return r; if((r = prop_dictionary_copyin_ioctl(pref, cmd, &dm_dict_in)) != 0) return r; if ((r = dm_check_version(dm_dict_in)) != 0) goto cleanup_exit; /* run ioctl routine */ if ((r = dm_cmd_to_fun(dm_dict_in)) != 0) goto cleanup_exit; cleanup_exit: r = prop_dictionary_copyout_ioctl(pref, cmd, dm_dict_in); prop_object_release(dm_dict_in); } return r; }
int npfctl_add_nat_rule(u_long cmd, void *data) { struct plistref *pref = data; prop_dictionary_t dict, errdict; int error; /* Retrieve and construct the rule. */ error = prop_dictionary_copyin_ioctl(pref, cmd, &dict); if (error) { return error; } /* Dictionary for error reporting. */ errdict = prop_dictionary_create(); npf_insert_nat_rule(dict, errdict); prop_object_release(dict); prop_dictionary_copyout_ioctl(pref, cmd, errdict); prop_object_release(errdict); return error; }
/* * npfctl_rule: add or remove dynamic rules in the specified ruleset. */ int npfctl_rule(u_long cmd, void *data) { struct plistref *pref = data; prop_dictionary_t npf_rule, retdict = NULL; npf_ruleset_t *rlset; npf_rule_t *rl = NULL; const char *ruleset_name; uint32_t rcmd = 0; int error; error = prop_dictionary_copyin_ioctl(pref, cmd, &npf_rule); if (error) { return error; } prop_dictionary_get_uint32(npf_rule, "command", &rcmd); if (!prop_dictionary_get_cstring_nocopy(npf_rule, "ruleset-name", &ruleset_name)) { error = EINVAL; goto out; } if (rcmd == NPF_CMD_RULE_ADD) { retdict = prop_dictionary_create(); if (npf_mk_singlerule(npf_rule, NULL, &rl, retdict) != 0) { error = EINVAL; goto out; } } npf_config_enter(); rlset = npf_config_ruleset(); switch (rcmd) { case NPF_CMD_RULE_ADD: { if ((error = npf_ruleset_add(rlset, ruleset_name, rl)) == 0) { /* Success. */ uint64_t id = npf_rule_getid(rl); prop_dictionary_set_uint64(retdict, "id", id); rl = NULL; } break; } case NPF_CMD_RULE_REMOVE: { uint64_t id; if (!prop_dictionary_get_uint64(npf_rule, "id", &id)) { error = EINVAL; break; } error = npf_ruleset_remove(rlset, ruleset_name, id); break; } case NPF_CMD_RULE_REMKEY: { prop_object_t obj = prop_dictionary_get(npf_rule, "key"); const void *key = prop_data_data_nocopy(obj); size_t len = prop_data_size(obj); if (len == 0 || len > NPF_RULE_MAXKEYLEN) { error = EINVAL; break; } error = npf_ruleset_remkey(rlset, ruleset_name, key, len); break; } case NPF_CMD_RULE_LIST: { retdict = npf_ruleset_list(rlset, ruleset_name); if (!retdict) { error = ESRCH; } break; } case NPF_CMD_RULE_FLUSH: { error = npf_ruleset_flush(rlset, ruleset_name); break; } default: error = EINVAL; break; } /* Destroy any removed rules. */ if (!error && rcmd != NPF_CMD_RULE_ADD && rcmd != NPF_CMD_RULE_LIST) { npf_config_sync(); npf_ruleset_gc(rlset); } npf_config_exit(); if (rl) { KASSERT(error); npf_rule_free(rl); } out: if (retdict) { prop_object_release(npf_rule); prop_dictionary_copyout_ioctl(pref, cmd, retdict); prop_object_release(retdict); } return error; }
/* * npfctl_save: export the config dictionary as it was submitted, * including the current snapshot of the connections. Additionally, * indicate whether the ruleset is currently active. */ int npfctl_save(u_long cmd, void *data) { struct plistref *pref = data; prop_array_t rulelist, natlist, tables, rprocs, conlist; prop_dictionary_t npf_dict = NULL; int error; rulelist = prop_array_create(); natlist = prop_array_create(); tables = prop_array_create(); rprocs = prop_array_create(); conlist = prop_array_create(); /* * Serialise the connections and NAT policies. */ npf_config_enter(); error = npf_conndb_export(conlist); if (error) { goto out; } error = npf_ruleset_export(npf_config_ruleset(), rulelist); if (error) { goto out; } error = npf_ruleset_export(npf_config_natset(), natlist); if (error) { goto out; } error = npf_tableset_export(npf_config_tableset(), tables); if (error) { goto out; } error = npf_rprocset_export(npf_config_rprocs(), rprocs); if (error) { goto out; } prop_array_t alglist = npf_alg_export(); npf_dict = prop_dictionary_create(); prop_dictionary_set_uint32(npf_dict, "version", NPF_VERSION); prop_dictionary_set_and_rel(npf_dict, "algs", alglist); prop_dictionary_set_and_rel(npf_dict, "rules", rulelist); prop_dictionary_set_and_rel(npf_dict, "nat", natlist); prop_dictionary_set_and_rel(npf_dict, "tables", tables); prop_dictionary_set_and_rel(npf_dict, "rprocs", rprocs); prop_dictionary_set_and_rel(npf_dict, "conn-list", conlist); prop_dictionary_set_bool(npf_dict, "active", npf_pfil_registered_p()); error = prop_dictionary_copyout_ioctl(pref, cmd, npf_dict); out: npf_config_exit(); if (!npf_dict) { prop_object_release(rulelist); prop_object_release(natlist); prop_object_release(tables); prop_object_release(rprocs); prop_object_release(conlist); } else { prop_object_release(npf_dict); } return error; }
/* * npfctl_load: store passed data i.e. update settings, create passed * tables, rules and atomically activate all them. */ int npfctl_load(u_long cmd, void *data) { struct plistref *pref = data; prop_dictionary_t npf_dict, errdict; prop_array_t alglist, natlist, tables, rprocs, rules, conlist; npf_tableset_t *tblset = NULL; npf_rprocset_t *rpset = NULL; npf_ruleset_t *rlset = NULL; npf_ruleset_t *nset = NULL; npf_conndb_t *conndb = NULL; uint32_t ver = 0; size_t nitems; bool flush; int error; /* Retrieve the dictionary. */ #ifndef _NPF_TESTING error = prop_dictionary_copyin_ioctl(pref, cmd, &npf_dict); if (error) return error; #else npf_dict = (prop_dictionary_t)pref; #endif /* Dictionary for error reporting and version check. */ errdict = prop_dictionary_create(); prop_dictionary_get_uint32(npf_dict, "version", &ver); if (ver != NPF_VERSION) { error = EPROGMISMATCH; goto fail; } /* ALGs. */ alglist = prop_dictionary_get(npf_dict, "algs"); error = npf_mk_algs(alglist, errdict); if (error) { goto fail; } /* NAT policies. */ natlist = prop_dictionary_get(npf_dict, "nat"); if ((nitems = prop_array_count(natlist)) > NPF_MAX_RULES) { error = E2BIG; goto fail; } nset = npf_ruleset_create(nitems); error = npf_mk_natlist(nset, natlist, errdict); if (error) { goto fail; } /* Tables. */ tables = prop_dictionary_get(npf_dict, "tables"); if ((nitems = prop_array_count(tables)) > NPF_MAX_TABLES) { error = E2BIG; goto fail; } tblset = npf_tableset_create(nitems); error = npf_mk_tables(tblset, tables, errdict); if (error) { goto fail; } /* Rule procedures. */ rprocs = prop_dictionary_get(npf_dict, "rprocs"); if ((nitems = prop_array_count(rprocs)) > NPF_MAX_RPROCS) { error = E2BIG; goto fail; } rpset = npf_rprocset_create(); error = npf_mk_rprocs(rpset, rprocs, errdict); if (error) { goto fail; } /* Rules. */ rules = prop_dictionary_get(npf_dict, "rules"); if ((nitems = prop_array_count(rules)) > NPF_MAX_RULES) { error = E2BIG; goto fail; } rlset = npf_ruleset_create(nitems); error = npf_mk_rules(rlset, rules, rpset, errdict); if (error) { goto fail; } /* Connections (if loading any). */ if ((conlist = prop_dictionary_get(npf_dict, "conn-list")) != NULL) { error = npf_mk_connlist(conlist, nset, &conndb, errdict); if (error) { goto fail; } } flush = false; prop_dictionary_get_bool(npf_dict, "flush", &flush); /* * Finally - perform the load. */ npf_config_load(rlset, tblset, nset, rpset, conndb, flush); /* Done. Since data is consumed now, we shall not destroy it. */ tblset = NULL; rpset = NULL; rlset = NULL; nset = NULL; fail: /* * Note: destroy rulesets first, to drop references to the tableset. */ KASSERT(error == 0 || (nset || rpset || rlset || tblset)); if (nset) { npf_ruleset_destroy(nset); } if (rlset) { npf_ruleset_destroy(rlset); } if (rpset) { npf_rprocset_destroy(rpset); } if (tblset) { npf_tableset_destroy(tblset); } prop_object_release(npf_dict); /* Error report. */ #ifndef _NPF_TESTING prop_dictionary_set_int32(errdict, "errno", error); prop_dictionary_copyout_ioctl(pref, cmd, errdict); prop_object_release(errdict); error = 0; #endif return error; }
/* * disk_ioctl -- * Generic disk ioctl handling. */ int disk_ioctl(struct disk *dk, dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) { struct dkwedge_info *dkw; struct partinfo *pi; struct partition *dp; #ifdef __HAVE_OLD_DISKLABEL struct disklabel newlabel; #endif switch (cmd) { case DIOCGDISKINFO: if (dk->dk_info == NULL) return ENOTSUP; return prop_dictionary_copyout_ioctl(data, cmd, dk->dk_info); case DIOCGSECTORSIZE: *(u_int *)data = dk->dk_geom.dg_secsize; return 0; case DIOCGMEDIASIZE: *(off_t *)data = (off_t)dk->dk_geom.dg_secsize * dk->dk_geom.dg_secperunit; return 0; default: break; } if (dev == NODEV) return EPASSTHROUGH; /* The following should be moved to dk_ioctl */ switch (cmd) { case DIOCGDINFO: if (dk->dk_label == NULL) return EBUSY; memcpy(data, dk->dk_label, sizeof (*dk->dk_label)); return 0; #ifdef __HAVE_OLD_DISKLABEL case ODIOCGDINFO: if (dk->dk_label == NULL) return EBUSY; memcpy(&newlabel, dk->dk_label, sizeof(newlabel)); if (newlabel.d_npartitions > OLDMAXPARTITIONS) return ENOTTY; memcpy(data, &newlabel, sizeof(struct olddisklabel)); return 0; #endif case DIOCGPARTINFO: pi = data; memset(pi, 0, sizeof(*pi)); pi->pi_secsize = dk->dk_geom.dg_secsize; pi->pi_bsize = BLKDEV_IOSIZE; if (DISKPART(dev) == RAW_PART) { pi->pi_size = dk->dk_geom.dg_secperunit; return 0; } if (dk->dk_label == NULL) return EBUSY; dp = &dk->dk_label->d_partitions[DISKPART(dev)]; pi->pi_offset = dp->p_offset; pi->pi_size = dp->p_size; pi->pi_fstype = dp->p_fstype; pi->pi_frag = dp->p_frag; pi->pi_fsize = dp->p_fsize; pi->pi_cpg = dp->p_cpg; /* * dholland 20130616: XXX this logic should not be * here. It is here because the old buffer cache * demands that all accesses to the same blocks need * to be the same size; but it only works for FFS and * nowadays I think it'll fail silently if the size * info in the disklabel is wrong. (Or missing.) The * buffer cache needs to be smarter; or failing that * we need a reliable way here to get the right block * size; or a reliable way to guarantee that (a) the * fs is not mounted when we get here and (b) any * buffers generated here will get purged when the fs * does get mounted. */ if (dp->p_fstype == FS_BSDFFS && dp->p_frag != 0 && dp->p_fsize != 0) pi->pi_bsize = dp->p_frag * dp->p_fsize; return 0; case DIOCAWEDGE: if ((flag & FWRITE) == 0) return EBADF; dkw = data; strlcpy(dkw->dkw_parent, dk->dk_name, sizeof(dkw->dkw_parent)); return dkwedge_add(dkw); case DIOCDWEDGE: if ((flag & FWRITE) == 0) return EBADF; dkw = data; strlcpy(dkw->dkw_parent, dk->dk_name, sizeof(dkw->dkw_parent)); return dkwedge_del(dkw); case DIOCLWEDGES: return dkwedge_list(dk, data, l); case DIOCMWEDGES: if ((flag & FWRITE) == 0) return EBADF; dkwedge_discover(dk); return 0; default: return EPASSTHROUGH; } }
/* * disk_ioctl -- * Generic disk ioctl handling. */ int disk_ioctl(struct disk *dk, dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) { struct dkwedge_info *dkw; struct partinfo *pt; #ifdef __HAVE_OLD_DISKLABEL struct disklabel newlabel; #endif switch (cmd) { case DIOCGDISKINFO: if (dk->dk_info == NULL) return ENOTSUP; return prop_dictionary_copyout_ioctl(data, cmd, dk->dk_info); case DIOCGSECTORSIZE: *(u_int *)data = dk->dk_geom.dg_secsize; return 0; case DIOCGMEDIASIZE: *(off_t *)data = (off_t)dk->dk_geom.dg_secsize * dk->dk_geom.dg_secperunit; return 0; default: break; } if (dev == NODEV) return EPASSTHROUGH; /* The following should be moved to dk_ioctl */ switch (cmd) { case DIOCGDINFO: memcpy(data, dk->dk_label, sizeof (*dk->dk_label)); return 0; #ifdef __HAVE_OLD_DISKLABEL case ODIOCGDINFO: memcpy(&newlabel, dk->dk_label, sizeof(newlabel)); if (newlabel.d_npartitions > OLDMAXPARTITIONS) return ENOTTY; memcpy(data, &newlabel, sizeof(struct olddisklabel)); return 0; #endif case DIOCGPART: if (dk->dk_label == NULL) return EBUSY; pt = data; pt->disklab = dk->dk_label; pt->part = &dk->dk_label->d_partitions[DISKPART(dev)]; return 0; case DIOCAWEDGE: if ((flag & FWRITE) == 0) return EBADF; dkw = data; strlcpy(dkw->dkw_parent, dk->dk_name, sizeof(dkw->dkw_parent)); return dkwedge_add(dkw); case DIOCDWEDGE: if ((flag & FWRITE) == 0) return EBADF; dkw = data; strlcpy(dkw->dkw_parent, dk->dk_name, sizeof(dkw->dkw_parent)); return dkwedge_del(dkw); case DIOCLWEDGES: return dkwedge_list(dk, data, l); case DIOCMWEDGES: if ((flag & FWRITE) == 0) return EBADF; dkwedge_discover(dk); return 0; default: return EPASSTHROUGH; } }
static int disk_ioctl_switch(dev_t dev, u_long cmd, void *data) { dm_dev_t *dmv; /* disk ioctls make sense only on block devices */ if (minor(dev) == 0) return ENOTTY; switch(cmd) { case DIOCGWEDGEINFO: { struct dkwedge_info *dkw = (void *) data; unsigned secsize; if ((dmv = dm_dev_lookup(NULL, NULL, minor(dev))) == NULL) return ENODEV; aprint_debug("DIOCGWEDGEINFO ioctl called\n"); strlcpy(dkw->dkw_devname, dmv->name, 16); strlcpy(dkw->dkw_wname, dmv->name, DM_NAME_LEN); strlcpy(dkw->dkw_parent, dmv->name, 16); dkw->dkw_offset = 0; dm_table_disksize(&dmv->table_head, &dkw->dkw_size, &secsize); strcpy(dkw->dkw_ptype, DKW_PTYPE_FFS); dm_dev_unbusy(dmv); break; } case DIOCGDISKINFO: { struct plistref *pref = (struct plistref *) data; if ((dmv = dm_dev_lookup(NULL, NULL, minor(dev))) == NULL) return ENODEV; if (dmv->diskp->dk_info == NULL) { dm_dev_unbusy(dmv); return ENOTSUP; } else prop_dictionary_copyout_ioctl(pref, cmd, dmv->diskp->dk_info); dm_dev_unbusy(dmv); break; } case DIOCCACHESYNC: { dm_table_entry_t *table_en; dm_table_t *tbl; if ((dmv = dm_dev_lookup(NULL, NULL, minor(dev))) == NULL) return ENODEV; /* Select active table */ tbl = dm_table_get_entry(&dmv->table_head, DM_TABLE_ACTIVE); /* * Call sync target routine for all table entries. Target sync * routine basically call DIOCCACHESYNC on underlying devices. */ SLIST_FOREACH(table_en, tbl, next) { (void)table_en->target->sync(table_en); } dm_table_release(&dmv->table_head, DM_TABLE_ACTIVE); dm_dev_unbusy(dmv); break; } default: aprint_debug("unknown disk_ioctl called\n"); return ENOTTY; break; /* NOT REACHED */ }
/* * npfctl_reload: store passed data i.e. update settings, create passed * tables, rules and atomically activate all them. */ int npfctl_reload(u_long cmd, void *data) { struct plistref *pref = data; prop_dictionary_t npf_dict, errdict; prop_array_t natlist, tables, rprocs, rules; npf_tableset_t *tblset = NULL; npf_ruleset_t *rlset = NULL; npf_ruleset_t *nset = NULL; bool flush; int error; /* Retrieve the dictionary. */ #ifndef _NPF_TESTING error = prop_dictionary_copyin_ioctl(pref, cmd, &npf_dict); if (error) return error; #else npf_dict = (prop_dictionary_t)pref; #endif /* Dictionary for error reporting. */ errdict = prop_dictionary_create(); /* NAT policies. */ nset = npf_ruleset_create(); natlist = prop_dictionary_get(npf_dict, "translation"); error = npf_mk_natlist(nset, natlist, errdict); if (error) { goto fail; } /* Tables. */ tblset = npf_tableset_create(); tables = prop_dictionary_get(npf_dict, "tables"); error = npf_mk_tables(tblset, tables, errdict); if (error) { goto fail; } /* Rules and rule procedures. */ rlset = npf_ruleset_create(); rprocs = prop_dictionary_get(npf_dict, "rprocs"); rules = prop_dictionary_get(npf_dict, "rules"); error = npf_mk_rules(rlset, rules, rprocs, errdict); if (error) { goto fail; } flush = false; prop_dictionary_get_bool(npf_dict, "flush", &flush); /* * Finally - reload ruleset, tableset and NAT policies. * Operation will be performed as a single transaction. */ npf_reload(npf_dict, rlset, tblset, nset, flush); /* Turn on/off session tracking accordingly. */ npf_session_tracking(!flush); /* Done. Since data is consumed now, we shall not destroy it. */ tblset = NULL; rlset = NULL; nset = NULL; fail: /* * Note: destroy rulesets first, to drop references to the tableset. */ KASSERT(error == 0 || (nset || rlset || tblset)); if (nset) { npf_ruleset_destroy(nset); } if (rlset) { npf_ruleset_destroy(rlset); } if (tblset) { npf_tableset_destroy(tblset); } if (error) { prop_object_release(npf_dict); } /* Error report. */ prop_dictionary_set_int32(errdict, "errno", error); #ifndef _NPF_TESTING prop_dictionary_copyout_ioctl(pref, cmd, errdict); #endif prop_object_release(errdict); return 0; }