diff options
| -rw-r--r-- | activitypub.c | 50 | ||||
| -rw-r--r-- | data.c | 2 | ||||
| -rw-r--r-- | sandbox.c | 31 | ||||
| -rw-r--r-- | snac.h | 1 | ||||
| -rw-r--r-- | utils.c | 52 | ||||
| -rw-r--r-- | xs_curl.h | 36 |
6 files changed, 125 insertions, 47 deletions
diff --git a/activitypub.c b/activitypub.c index cade0d9..4cb779a 100644 --- a/activitypub.c +++ b/activitypub.c | |||
| @@ -1017,17 +1017,20 @@ void notify(snac *snac, const char *type, const char *utype, const char *actor, | |||
| 1017 | 1017 | ||
| 1018 | xs *subject = xs_fmt("snac notify for @%s@%s", | 1018 | xs *subject = xs_fmt("snac notify for @%s@%s", |
| 1019 | xs_dict_get(snac->config, "uid"), xs_dict_get(srv_config, "host")); | 1019 | xs_dict_get(snac->config, "uid"), xs_dict_get(srv_config, "host")); |
| 1020 | xs *from = xs_fmt("snac-daemon <snac-daemon@%s>", xs_dict_get(srv_config, "host")); | 1020 | xs *from = xs_fmt("<snac-daemon@%s>", xs_dict_get(srv_config, "host")); |
| 1021 | xs *header = xs_fmt( | 1021 | xs *header = xs_fmt( |
| 1022 | "From: %s\n" | 1022 | "From: snac-daemon %s\n" |
| 1023 | "To: %s\n" | 1023 | "To: %s\n" |
| 1024 | "Subject: %s\n" | 1024 | "Subject: %s\n" |
| 1025 | "\n", | 1025 | "\n", |
| 1026 | from, email, subject); | 1026 | from, email, subject); |
| 1027 | 1027 | ||
| 1028 | xs *email_body = xs_fmt("%s%s", header, body); | 1028 | xs *mailinfo = xs_dict_new(); |
| 1029 | xs_dict_append(mailinfo, "from", from); | ||
| 1030 | xs_dict_append(mailinfo, "to", email); | ||
| 1031 | xs_dict_append(mailinfo, "body", xs_fmt("%s%s", header, body)); | ||
| 1029 | 1032 | ||
| 1030 | enqueue_email(email_body, 0); | 1033 | enqueue_email(mailinfo, 0); |
| 1031 | } | 1034 | } |
| 1032 | 1035 | ||
| 1033 | /* telegram */ | 1036 | /* telegram */ |
| @@ -2524,32 +2527,19 @@ int process_input_message(snac *snac, const xs_dict *msg, const xs_dict *req) | |||
| 2524 | } | 2527 | } |
| 2525 | 2528 | ||
| 2526 | 2529 | ||
| 2527 | int send_email(const char *msg) | 2530 | int send_email(const xs_dict *mailinfo) |
| 2528 | /* invoke sendmail with email headers and body in msg */ | 2531 | /* invoke curl */ |
| 2529 | { | 2532 | { |
| 2530 | FILE *f; | 2533 | const xs_dict *smtp_cfg = xs_dict_get(srv_config, "email_notifications"); |
| 2531 | int status; | 2534 | const char |
| 2532 | int fds[2]; | 2535 | *url = xs_dict_get(smtp_cfg, "url"), |
| 2533 | pid_t pid; | 2536 | *user = xs_dict_get(smtp_cfg, "username"), |
| 2534 | if (pipe(fds) == -1) return -1; | 2537 | *pass = xs_dict_get(smtp_cfg, "password"), |
| 2535 | pid = vfork(); | 2538 | *from = xs_dict_get(mailinfo, "from"), |
| 2536 | if (pid == -1) return -1; | 2539 | *to = xs_dict_get(mailinfo, "to"), |
| 2537 | else if (pid == 0) { | 2540 | *body = xs_dict_get(mailinfo, "body"); |
| 2538 | dup2(fds[0], 0); | 2541 | |
| 2539 | close(fds[0]); | 2542 | return xs_smtp_request(url, user, pass, from, to, body); |
| 2540 | close(fds[1]); | ||
| 2541 | execl("/usr/sbin/sendmail", "sendmail", "-t", (char *) NULL); | ||
| 2542 | _exit(1); | ||
| 2543 | } | ||
| 2544 | close(fds[0]); | ||
| 2545 | if ((f = fdopen(fds[1], "w")) == NULL) { | ||
| 2546 | close(fds[1]); | ||
| 2547 | return -1; | ||
| 2548 | } | ||
| 2549 | fprintf(f, "%s\n", msg); | ||
| 2550 | fclose(f); | ||
| 2551 | if (waitpid(pid, &status, 0) == -1) return -1; | ||
| 2552 | return status; | ||
| 2553 | } | 2543 | } |
| 2554 | 2544 | ||
| 2555 | 2545 | ||
| @@ -2812,7 +2802,7 @@ void process_queue_item(xs_dict *q_item) | |||
| 2812 | else | 2802 | else |
| 2813 | if (strcmp(type, "email") == 0) { | 2803 | if (strcmp(type, "email") == 0) { |
| 2814 | /* send this email */ | 2804 | /* send this email */ |
| 2815 | const xs_str *msg = xs_dict_get(q_item, "message"); | 2805 | const xs_dict *msg = xs_dict_get(q_item, "message"); |
| 2816 | int retries = xs_number_get(xs_dict_get(q_item, "retries")); | 2806 | int retries = xs_number_get(xs_dict_get(q_item, "retries")); |
| 2817 | 2807 | ||
| 2818 | if (!send_email(msg)) | 2808 | if (!send_email(msg)) |
| @@ -3195,7 +3195,7 @@ void enqueue_output_by_actor(snac *snac, const xs_dict *msg, | |||
| 3195 | } | 3195 | } |
| 3196 | 3196 | ||
| 3197 | 3197 | ||
| 3198 | void enqueue_email(const xs_str *msg, int retries) | 3198 | void enqueue_email(const xs_dict *msg, int retries) |
| 3199 | /* enqueues an email message to be sent */ | 3199 | /* enqueues an email message to be sent */ |
| 3200 | { | 3200 | { |
| 3201 | xs *qmsg = _new_qmsg("email", msg, retries); | 3201 | xs *qmsg = _new_qmsg("email", msg, retries); |
| @@ -8,8 +8,6 @@ void sbox_enter(const char *basedir) | |||
| 8 | { | 8 | { |
| 9 | const char *address = xs_dict_get(srv_config, "address"); | 9 | const char *address = xs_dict_get(srv_config, "address"); |
| 10 | 10 | ||
| 11 | int smail = !xs_is_true(xs_dict_get(srv_config, "disable_email_notifications")); | ||
| 12 | |||
| 13 | if (xs_is_true(xs_dict_get(srv_config, "disable_openbsd_security"))) { | 11 | if (xs_is_true(xs_dict_get(srv_config, "disable_openbsd_security"))) { |
| 14 | srv_log(xs_dup("OpenBSD security disabled by admin")); | 12 | srv_log(xs_dup("OpenBSD security disabled by admin")); |
| 15 | return; | 13 | return; |
| @@ -24,9 +22,6 @@ void sbox_enter(const char *basedir) | |||
| 24 | unveil("/etc/ssl/cert.pem", "r"); | 22 | unveil("/etc/ssl/cert.pem", "r"); |
| 25 | unveil("/usr/share/zoneinfo", "r"); | 23 | unveil("/usr/share/zoneinfo", "r"); |
| 26 | 24 | ||
| 27 | if (smail) | ||
| 28 | unveil("/usr/sbin/sendmail", "x"); | ||
| 29 | |||
| 30 | if (*address == '/') | 25 | if (*address == '/') |
| 31 | unveil(address, "rwc"); | 26 | unveil(address, "rwc"); |
| 32 | 27 | ||
| @@ -36,9 +31,6 @@ void sbox_enter(const char *basedir) | |||
| 36 | 31 | ||
| 37 | xs *p = xs_str_new("stdio rpath wpath cpath flock inet proc dns fattr"); | 32 | xs *p = xs_str_new("stdio rpath wpath cpath flock inet proc dns fattr"); |
| 38 | 33 | ||
| 39 | if (smail) | ||
| 40 | p = xs_str_cat(p, " exec"); | ||
| 41 | |||
| 42 | if (*address == '/') | 34 | if (*address == '/') |
| 43 | p = xs_str_cat(p, " unix"); | 35 | p = xs_str_cat(p, " unix"); |
| 44 | 36 | ||
| @@ -55,7 +47,7 @@ void sbox_enter(const char *basedir) | |||
| 55 | #include "landloc.h" | 47 | #include "landloc.h" |
| 56 | 48 | ||
| 57 | static | 49 | static |
| 58 | LL_BEGIN(sbox_enter_linux_, const char* basedir, const char *address, int smail) { | 50 | LL_BEGIN(sbox_enter_linux_, const char* basedir, const char *address, int smtp_port) { |
| 59 | 51 | ||
| 60 | const unsigned long long | 52 | const unsigned long long |
| 61 | rd = LANDLOCK_ACCESS_FS_READ_DIR, | 53 | rd = LANDLOCK_ACCESS_FS_READ_DIR, |
| @@ -101,9 +93,6 @@ LL_BEGIN(sbox_enter_linux_, const char* basedir, const char *address, int smail) | |||
| 101 | LL_PATH(sdir, s); | 93 | LL_PATH(sdir, s); |
| 102 | } | 94 | } |
| 103 | 95 | ||
| 104 | if (smail && mtime("/usr/sbin/sendmail") > 0) | ||
| 105 | LL_PATH("/usr/sbin/sendmail", x); | ||
| 106 | |||
| 107 | if (*address != '/') { | 96 | if (*address != '/') { |
| 108 | unsigned short listen_port = xs_number_get(xs_dict_get(srv_config, "port")); | 97 | unsigned short listen_port = xs_number_get(xs_dict_get(srv_config, "port")); |
| 109 | LL_PORT(listen_port, LANDLOCK_ACCESS_NET_BIND_TCP_COMPAT); | 98 | LL_PORT(listen_port, LANDLOCK_ACCESS_NET_BIND_TCP_COMPAT); |
| @@ -111,24 +100,34 @@ LL_BEGIN(sbox_enter_linux_, const char* basedir, const char *address, int smail) | |||
| 111 | 100 | ||
| 112 | LL_PORT(80, LANDLOCK_ACCESS_NET_CONNECT_TCP_COMPAT); | 101 | LL_PORT(80, LANDLOCK_ACCESS_NET_CONNECT_TCP_COMPAT); |
| 113 | LL_PORT(443, LANDLOCK_ACCESS_NET_CONNECT_TCP_COMPAT); | 102 | LL_PORT(443, LANDLOCK_ACCESS_NET_CONNECT_TCP_COMPAT); |
| 103 | if (smtp_port > 0) | ||
| 104 | LL_PORT((unsigned short)smtp_port, LANDLOCK_ACCESS_NET_CONNECT_TCP_COMPAT); | ||
| 114 | 105 | ||
| 115 | } LL_END | 106 | } LL_END |
| 116 | 107 | ||
| 117 | void sbox_enter(const char *basedir) | 108 | void sbox_enter(const char *basedir) |
| 118 | { | 109 | { |
| 110 | const xs_val *v; | ||
| 111 | const char *errstr; | ||
| 119 | const char *address = xs_dict_get(srv_config, "address"); | 112 | const char *address = xs_dict_get(srv_config, "address"); |
| 120 | 113 | int smtp_port = -1; | |
| 121 | int smail = !xs_is_true(xs_dict_get(srv_config, "disable_email_notifications")); | ||
| 122 | 114 | ||
| 123 | if (xs_is_true(xs_dict_get(srv_config, "disable_sandbox"))) { | 115 | if (xs_is_true(xs_dict_get(srv_config, "disable_sandbox"))) { |
| 124 | srv_debug(1, xs_dup("Linux sandbox disabled by admin")); | 116 | srv_debug(1, xs_dup("Linux sandbox disabled by admin")); |
| 125 | return; | 117 | return; |
| 126 | } | 118 | } |
| 127 | 119 | ||
| 128 | if (sbox_enter_linux_(basedir, address, smail) == 0) | 120 | if ((v = xs_dict_get(srv_config, "email_notifications")) && |
| 121 | (v = xs_dict_get(v, "url"))) { | ||
| 122 | smtp_port = parse_port((const char *)v, &errstr); | ||
| 123 | if (errstr) | ||
| 124 | srv_debug(0, xs_fmt("Couldn't determine port from '%s': %s", (const char *)v, errstr)); | ||
| 125 | } | ||
| 126 | |||
| 127 | if (sbox_enter_linux_(basedir, address, smtp_port) == 0) | ||
| 129 | srv_debug(1, xs_dup("Linux sandbox enabled")); | 128 | srv_debug(1, xs_dup("Linux sandbox enabled")); |
| 130 | else | 129 | else |
| 131 | srv_debug(1, xs_dup("Linux sandbox failed")); | 130 | srv_debug(0, xs_dup("Linux sandbox failed")); |
| 132 | } | 131 | } |
| 133 | 132 | ||
| 134 | #else /* defined(WITH_LINUX_SANDBOX) */ | 133 | #else /* defined(WITH_LINUX_SANDBOX) */ |
| @@ -417,6 +417,7 @@ void import_blocked_accounts_csv(snac *user, const char *fn); | |||
| 417 | void import_following_accounts_csv(snac *user, const char *fn); | 417 | void import_following_accounts_csv(snac *user, const char *fn); |
| 418 | void import_list_csv(snac *user, const char *fn); | 418 | void import_list_csv(snac *user, const char *fn); |
| 419 | void import_csv(snac *user); | 419 | void import_csv(snac *user); |
| 420 | int parse_port(const char *url, const char **errstr); | ||
| 420 | 421 | ||
| 421 | typedef enum { | 422 | typedef enum { |
| 422 | #define HTTP_STATUS(code, name, text) HTTP_STATUS_ ## name = code, | 423 | #define HTTP_STATUS(code, name, text) HTTP_STATUS_ ## name = code, |
| @@ -908,3 +908,55 @@ void import_csv(snac *user) | |||
| 908 | else | 908 | else |
| 909 | snac_log(user, xs_fmt("Cannot open file %s", fn)); | 909 | snac_log(user, xs_fmt("Cannot open file %s", fn)); |
| 910 | } | 910 | } |
| 911 | |||
| 912 | static const struct { | ||
| 913 | const char *proto; | ||
| 914 | unsigned short default_port; | ||
| 915 | } FALLBACK_PORTS[] = { | ||
| 916 | /* caution: https > http, smpts > smtp */ | ||
| 917 | {"https", 443}, | ||
| 918 | {"http", 80}, | ||
| 919 | {"smtps", 465}, | ||
| 920 | {"smtp", 25} | ||
| 921 | }; | ||
| 922 | |||
| 923 | int parse_port(const char *url, const char **errstr) | ||
| 924 | { | ||
| 925 | const char *col, *rcol; | ||
| 926 | int tmp, ret = -1; | ||
| 927 | |||
| 928 | if (errstr) | ||
| 929 | *errstr = NULL; | ||
| 930 | |||
| 931 | if (!(col = strchr(url, ':'))) { | ||
| 932 | if (errstr) | ||
| 933 | *errstr = "bad url"; | ||
| 934 | return -1; | ||
| 935 | } | ||
| 936 | |||
| 937 | for (size_t i = 0; i < sizeof(FALLBACK_PORTS) / sizeof(*FALLBACK_PORTS); ++i) { | ||
| 938 | if (memcmp(url, FALLBACK_PORTS[i].proto, strlen(FALLBACK_PORTS[i].proto)) == 0) { | ||
| 939 | ret = FALLBACK_PORTS[i].default_port; | ||
| 940 | break; | ||
| 941 | } | ||
| 942 | } | ||
| 943 | |||
| 944 | if (!(rcol = strchr(col + 1, ':'))) | ||
| 945 | rcol = col; | ||
| 946 | |||
| 947 | if (rcol) { | ||
| 948 | tmp = atoi(rcol + 1); | ||
| 949 | if (tmp == 0) { | ||
| 950 | if (ret != -1) | ||
| 951 | return ret; | ||
| 952 | |||
| 953 | *errstr = strerror(errno); | ||
| 954 | return -1; | ||
| 955 | } | ||
| 956 | |||
| 957 | return tmp; | ||
| 958 | } | ||
| 959 | |||
| 960 | *errstr = "unknown protocol"; | ||
| 961 | return -1; | ||
| 962 | } | ||
| @@ -9,6 +9,9 @@ xs_dict *xs_http_request(const char *method, const char *url, | |||
| 9 | const xs_str *body, int b_size, int *status, | 9 | const xs_str *body, int b_size, int *status, |
| 10 | xs_str **payload, int *p_size, int timeout); | 10 | xs_str **payload, int *p_size, int timeout); |
| 11 | 11 | ||
| 12 | int xs_smtp_request(const char *url, const char *user, const char *pass, | ||
| 13 | const char *from, const char *to, const xs_str *body); | ||
| 14 | |||
| 12 | #ifdef XS_IMPLEMENTATION | 15 | #ifdef XS_IMPLEMENTATION |
| 13 | 16 | ||
| 14 | #include <curl/curl.h> | 17 | #include <curl/curl.h> |
| @@ -194,6 +197,39 @@ xs_dict *xs_http_request(const char *method, const char *url, | |||
| 194 | return response; | 197 | return response; |
| 195 | } | 198 | } |
| 196 | 199 | ||
| 200 | int xs_smtp_request(const char *url, const char *user, const char *pass, | ||
| 201 | const char *from, const char *to, const xs_str *body) | ||
| 202 | { | ||
| 203 | CURL *curl; | ||
| 204 | CURLcode res = CURLE_OK; | ||
| 205 | struct curl_slist *rcpt = NULL; | ||
| 206 | struct _payload_data pd = { | ||
| 207 | .data = (char *)body, | ||
| 208 | .size = xs_size(body), | ||
| 209 | .offset = 0 | ||
| 210 | }; | ||
| 211 | |||
| 212 | curl = curl_easy_init(); | ||
| 213 | |||
| 214 | curl_easy_setopt(curl, CURLOPT_URL, url); | ||
| 215 | curl_easy_setopt(curl, CURLOPT_USERNAME, user); | ||
| 216 | curl_easy_setopt(curl, CURLOPT_PASSWORD, pass); | ||
| 217 | |||
| 218 | curl_easy_setopt(curl, CURLOPT_MAIL_FROM, from); | ||
| 219 | curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, rcpt = curl_slist_append(rcpt, to)); | ||
| 220 | |||
| 221 | curl_easy_setopt(curl, CURLOPT_READDATA, &pd); | ||
| 222 | curl_easy_setopt(curl, CURLOPT_READFUNCTION, _post_callback); | ||
| 223 | curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); | ||
| 224 | |||
| 225 | res = curl_easy_perform(curl); | ||
| 226 | |||
| 227 | curl_slist_free_all(rcpt); | ||
| 228 | curl_easy_cleanup(curl); | ||
| 229 | |||
| 230 | return (int)res; | ||
| 231 | } | ||
| 232 | |||
| 197 | #endif /* XS_IMPLEMENTATION */ | 233 | #endif /* XS_IMPLEMENTATION */ |
| 198 | 234 | ||
| 199 | #endif /* _XS_CURL_H */ | 235 | #endif /* _XS_CURL_H */ |