summaryrefslogtreecommitdiff
path: root/accel-pppd/extra/chap-secrets.c
diff options
context:
space:
mode:
Diffstat (limited to 'accel-pppd/extra/chap-secrets.c')
-rw-r--r--accel-pppd/extra/chap-secrets.c281
1 files changed, 281 insertions, 0 deletions
diff --git a/accel-pppd/extra/chap-secrets.c b/accel-pppd/extra/chap-secrets.c
new file mode 100644
index 00000000..35503473
--- /dev/null
+++ b/accel-pppd/extra/chap-secrets.c
@@ -0,0 +1,281 @@
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "pwdb.h"
+#include "ipdb.h"
+#include "ppp.h"
+#include "events.h"
+#include "triton.h"
+#include "log.h"
+
+#include "memdebug.h"
+
+static char *def_chap_secrets = "/etc/ppp/chap-secrets";
+static char *conf_chap_secrets;
+static in_addr_t conf_gw_ip_address = 0;
+
+static void *pd_key;
+static struct ipdb_t ipdb;
+
+struct cs_pd_t
+{
+ struct ppp_pd_t pd;
+ struct ipdb_item_t ip;
+ char *passwd;
+ char *rate;
+};
+
+static char *skip_word(char *ptr)
+{
+ char quote = 0;
+
+ if (*ptr == '\'' || *ptr == '"') {
+ quote = *ptr;
+ ptr++;
+ }
+
+ for(; *ptr; ptr++) {
+ if (quote) {
+ if (*ptr == '\n')
+ break;
+ if (*ptr == '\\' && ptr[1] && ptr[1] != '\n') {
+ memmove(ptr, ptr + 1, strlen(ptr));
+ continue;
+ }
+ if (*ptr == quote) {
+ *ptr = ' ';
+ break;
+ }
+ } else if (*ptr == ' ' || *ptr == '\t' || *ptr == '\n')
+ break;
+ }
+ return ptr;
+}
+static char *skip_space(char *ptr)
+{
+ for(; *ptr; ptr++)
+ if (*ptr != ' ' && *ptr != '\t')
+ break;
+ return ptr;
+}
+static int split(char *buf, char **ptr)
+{
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ buf = skip_word(buf);
+ if (!*buf)
+ return i;
+
+ *buf = 0;
+
+ buf = skip_space(buf + 1);
+ if (!*buf)
+ return i;
+
+ if (*buf == '"' || *buf == '\'')
+ ptr[i] = buf + 1;
+ else
+ ptr[i] = buf;
+ }
+
+ buf = skip_word(buf);
+ //if (*buf == '\n')
+ *buf = 0;
+ //else if (*buf)
+ // return -1;
+
+ return i;
+}
+
+
+static struct cs_pd_t *create_pd(struct ppp_t *ppp, const char *username)
+{
+ FILE *f;
+ char *buf;
+ char *ptr[5];
+ int n;
+ struct cs_pd_t *pd;
+
+ if (!conf_chap_secrets)
+ return NULL;
+
+ f = fopen(conf_chap_secrets, "r");
+ if (!f) {
+ log_error("chap-secrets: open '%s': %s\n", conf_chap_secrets, strerror(errno));
+ return NULL;
+ }
+
+ buf = _malloc(4096);
+ if (!buf) {
+ log_emerg("chap-secrets: out of memory\n");
+ fclose(f);
+ return NULL;
+ }
+
+ while (fgets(buf, 4096, f)) {
+ if (buf[0] == '#')
+ continue;
+ n = split(buf, ptr);
+ if (n < 3)
+ continue;
+ if (*buf == '\'' || *buf == '"') {
+ if (!strcmp(buf + 1, username))
+ goto found;
+ } else {
+ if (!strcmp(buf, username))
+ goto found;
+ }
+ }
+
+out:
+ fclose(f);
+ _free(buf);
+ return NULL;
+
+found:
+ pd = _malloc(sizeof(*pd));
+ if (!pd) {
+ log_emerg("chap-secrets: out of memory\n");
+ goto out;
+ }
+
+ memset(pd, 0, sizeof(*pd));
+ pd->pd.key = &pd_key;
+ pd->passwd = _strdup(ptr[1]);
+ if (!pd->passwd) {
+ log_emerg("chap-secrets: out of memory\n");
+ _free(pd);
+ goto out;
+ }
+
+ pd->ip.addr = conf_gw_ip_address;
+ if (n >= 3)
+ pd->ip.peer_addr = inet_addr(ptr[2]);
+ pd->ip.owner = &ipdb;
+
+ if (n == 4)
+ pd->rate = _strdup(ptr[3]);
+
+ list_add_tail(&pd->pd.entry, &ppp->pd_list);
+
+ fclose(f);
+ _free(buf);
+
+ return pd;
+}
+
+static struct cs_pd_t *find_pd(struct ppp_t *ppp)
+{
+ struct ppp_pd_t *pd;
+
+ list_for_each_entry(pd, &ppp->pd_list, entry) {
+ if (pd->key == &pd_key) {
+ return container_of(pd, typeof(struct cs_pd_t), pd);
+ }
+ }
+
+ return NULL;
+}
+
+static void ev_ppp_finished(struct ppp_t *ppp)
+{
+ struct cs_pd_t *pd = find_pd(ppp);
+
+ if (!pd)
+ return;
+
+ list_del(&pd->pd.entry);
+ _free(pd->passwd);
+ if (pd->rate)
+ _free(pd->rate);
+ _free(pd);
+}
+
+static void ev_ppp_pre_up(struct ppp_t *ppp)
+{
+ struct cs_pd_t *pd = find_pd(ppp);
+ struct ev_shaper_t ev = {
+ .ppp = ppp,
+ };
+
+ if (!pd)
+ return;
+
+ if (pd->rate) {
+ ev.val = pd->rate;
+ triton_event_fire(EV_SHAPER, &ev);
+ }
+}
+
+static struct ipdb_item_t *get_ip(struct ppp_t *ppp)
+{
+ struct cs_pd_t *pd;
+
+ if (!conf_gw_ip_address)
+ return NULL;
+
+ pd = find_pd(ppp);
+
+ if (!pd)
+ return NULL;
+
+ if (!pd->ip.addr)
+ return NULL;
+
+ return &pd->ip;
+}
+
+static char* get_passwd(struct pwdb_t *pwdb, struct ppp_t *ppp, const char *username)
+{
+ struct cs_pd_t *pd = find_pd(ppp);
+
+ if (!pd)
+ pd = create_pd(ppp, username);
+
+ if (!pd)
+ return NULL;
+
+ return _strdup(pd->passwd);
+}
+
+static struct ipdb_t ipdb = {
+ .get = get_ip,
+};
+
+static struct pwdb_t pwdb = {
+ .get_passwd = get_passwd,
+};
+
+static void load_config(void)
+{
+ const char *opt;
+
+ if (conf_chap_secrets && conf_chap_secrets != def_chap_secrets)
+ _free(conf_chap_secrets);
+ opt = conf_get_opt("chap-secrets", "chap-secrets");
+ if (opt)
+ conf_chap_secrets = _strdup(opt);
+ else
+ conf_chap_secrets = def_chap_secrets;
+
+ opt = conf_get_opt("chap-secrets", "gw-ip-address");
+ if (opt)
+ conf_gw_ip_address = inet_addr(opt);
+}
+
+static void __init init(void)
+{
+ load_config();
+
+ pwdb_register(&pwdb);
+ ipdb_register(&ipdb);
+
+ triton_event_register_handler(EV_PPP_FINISHED, (triton_event_func)ev_ppp_finished);
+ triton_event_register_handler(EV_PPP_PRE_UP, (triton_event_func)ev_ppp_pre_up);
+ triton_event_register_handler(EV_CONFIG_RELOAD, (triton_event_func)load_config);
+}
+