commit 2880100ab9ccb2f797b41e2c8c615e947eb42f77 from: Stefan Sperling via: Thomas Adam date: Fri Mar 21 13:22:46 2025 UTC send notification targets to notify process This removes the need for the notify process to read gotd.conf, ensuring consistent run-time behaviour when gotd.conf is edited while gotd is running. commit - 8b10295ec9ddde4f3bfef322b31d3601d6040c62 commit + 2880100ab9ccb2f797b41e2c8c615e947eb42f77 blob - 1210e46dd5c67d6073935d5542ac84dc5a6f6a15 blob + bc9167c11f07085a6c16b8b189afe0d91b2930f0 --- gotd/gotd.c +++ gotd/gotd.c @@ -866,6 +866,8 @@ gotd_shutdown(void) } kill_proc(gotd.listen_proc, 0); + + free(gotd.default_sender); log_info("terminating"); exit(0); @@ -1293,7 +1295,202 @@ done: /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); event_loopexit(NULL); + } +} + +static const struct got_error * +send_notification_target_email(struct gotd_imsgev *iev, const char *repo_name, + struct gotd_notification_target *target) +{ + struct gotd_imsg_notitfication_target_email itarget; + struct ibuf *wbuf = NULL; + + memset(&itarget, 0, sizeof(itarget)); + + if (target->conf.email.sender) + itarget.sender_len = strlen(target->conf.email.sender); + else + itarget.sender_len = strlen(gotd.default_sender); + if (target->conf.email.recipient) + itarget.recipient_len = strlen(target->conf.email.recipient); + if (target->conf.email.responder) + itarget.responder_len = strlen(target->conf.email.responder); + if (target->conf.email.hostname) + itarget.hostname_len = strlen(target->conf.email.hostname); + if (target->conf.email.port) + itarget.port_len = strlen(target->conf.email.port); + itarget.repo_name_len = strlen(repo_name); + + wbuf = imsg_create(&iev->ibuf, GOTD_IMSG_NOTIFICATION_TARGET_EMAIL, + 0, 0, sizeof(itarget) + itarget.sender_len + itarget.recipient_len + + itarget.responder_len + itarget.hostname_len + itarget.port_len + + itarget.repo_name_len); + if (wbuf == NULL) { + return got_error_from_errno("imsg_create " + "NOTIFICATION_TARGET_EMAIL"); + } + + if (imsg_add(wbuf, &itarget, sizeof(itarget)) == -1) { + return got_error_from_errno("imsg_add " + "NOTIFICATION_TARGET_EMAIL"); + } + if (target->conf.email.sender) { + if (imsg_add(wbuf, target->conf.email.sender, + itarget.sender_len) == -1) { + return got_error_from_errno("imsg_add " + "NOTIFICATION_TARGET_EMAIL"); + } + } else { + if (imsg_add(wbuf, gotd.default_sender, + itarget.sender_len) == -1) { + return got_error_from_errno("imsg_add " + "NOTIFICATION_TARGET_EMAIL"); + } + } + if (target->conf.email.recipient) { + if (imsg_add(wbuf, target->conf.email.recipient, + itarget.recipient_len) == -1) { + return got_error_from_errno("imsg_add " + "NOTIFICATION_TARGET_EMAIL"); + } + } + if (target->conf.email.responder) { + if (imsg_add(wbuf, target->conf.email.responder, + itarget.responder_len) == -1) { + return got_error_from_errno("imsg_add " + "NOTIFICATION_TARGET_EMAIL"); + } + } + if (target->conf.email.hostname) { + if (imsg_add(wbuf, target->conf.email.hostname, + itarget.hostname_len) == -1) { + return got_error_from_errno("imsg_add " + "NOTIFICATION_TARGET_EMAIL"); + } + } + if (target->conf.email.port) { + if (imsg_add(wbuf, target->conf.email.port, + itarget.port_len) == -1) { + return got_error_from_errno("imsg_add " + "NOTIFICATION_TARGET_EMAIL"); + } + } + if (imsg_add(wbuf, repo_name, itarget.repo_name_len) == -1) { + return got_error_from_errno("imsg_add " + "NOTIFICATION_TARGET_EMAIL"); + } + + imsg_close(&iev->ibuf, wbuf); + return gotd_imsg_flush(&iev->ibuf); +} + +static const struct got_error * +send_notification_target_http(struct gotd_imsgev *iev, const char *repo_name, + struct gotd_notification_target *target) +{ + struct gotd_imsg_notitfication_target_http itarget; + struct ibuf *wbuf = NULL; + + memset(&itarget, 0, sizeof(itarget)); + + itarget.tls = target->conf.http.tls; + itarget.hostname_len = strlen(target->conf.http.hostname); + itarget.port_len = strlen(target->conf.http.port); + itarget.path_len = strlen(target->conf.http.path); + if (target->conf.http.auth) + itarget.auth_len = strlen(target->conf.http.auth); + if (target->conf.http.hmac) + itarget.hmac_len = strlen(target->conf.http.hmac); + itarget.repo_name_len = strlen(repo_name); + + wbuf = imsg_create(&iev->ibuf, GOTD_IMSG_NOTIFICATION_TARGET_HTTP, + 0, 0, sizeof(itarget) + itarget.hostname_len + itarget.port_len + + itarget.path_len + itarget.auth_len + itarget.hmac_len + + itarget.repo_name_len); + if (wbuf == NULL) { + return got_error_from_errno("imsg_create " + "NOTIFICATION_TARGET_HTTP"); + } + + if (imsg_add(wbuf, &itarget, sizeof(itarget)) == -1) { + return got_error_from_errno("imsg_add " + "NOTIFICATION_TARGET_HTTP"); + } + if (imsg_add(wbuf, target->conf.http.hostname, + itarget.hostname_len) == -1) { + return got_error_from_errno("imsg_add " + "NOTIFICATION_TARGET_HTTP"); + } + if (imsg_add(wbuf, target->conf.http.port, + itarget.port_len) == -1) { + return got_error_from_errno("imsg_add " + "NOTIFICATION_TARGET_HTTP"); + } + if (imsg_add(wbuf, target->conf.http.path, + itarget.path_len) == -1) { + return got_error_from_errno("imsg_add " + "NOTIFICATION_TARGET_HTTP"); + } + + if (target->conf.http.auth) { + if (imsg_add(wbuf, target->conf.http.auth, + itarget.auth_len) == -1) { + return got_error_from_errno("imsg_add " + "NOTIFICATION_TARGET_HTTP"); + } + } + if (target->conf.http.hmac) { + if (imsg_add(wbuf, target->conf.http.hmac, + itarget.hmac_len) == -1) { + return got_error_from_errno("imsg_add " + "NOTIFICATION_TARGET_HTTP"); + } + } + if (imsg_add(wbuf, repo_name, itarget.repo_name_len) == -1) { + return got_error_from_errno("imsg_add " + "NOTIFICATION_TARGET_HTTP"); + } + + imsg_close(&iev->ibuf, wbuf); + return gotd_imsg_flush(&iev->ibuf); +} + +static const struct got_error * +send_notification_target(struct gotd_imsgev *iev, const char *repo_name, + struct gotd_notification_target *target) +{ + const struct got_error *err = NULL; + + switch (target->type) { + case GOTD_NOTIFICATION_VIA_EMAIL: + err = send_notification_target_email(iev, repo_name, target); + break; + case GOTD_NOTIFICATION_VIA_HTTP: + err = send_notification_target_http(iev, repo_name, target); + break; + default: + log_warn("unsupported notification target type %d", + target->type); + break; + } + + return err; +} + +static const struct got_error * +send_notification_targets(struct gotd_imsgev *iev, const char *repo_name, + struct gotd_notification_targets *targets) +{ + const struct got_error *err = NULL; + struct gotd_notification_target *target; + + STAILQ_FOREACH(target, targets, entry) { + err = send_notification_target(iev, repo_name, target); + if (err) + return err; } + + return NULL; } static void @@ -1333,6 +1530,17 @@ gotd_dispatch_notifier(int fd, short event, void *arg) break; switch (imsg.hdr.type) { + case GOTD_IMSG_NOTIFIER_READY: { + struct gotd_repo *repo; + + TAILQ_FOREACH(repo, &gotd.repos, entry) { + err = send_notification_targets(iev, + repo->name, &repo->notification_targets); + if (err) + break; + } + break; + } default: log_debug("unexpected imsg %d", imsg.hdr.type); break; @@ -1849,175 +2057,15 @@ send_request_timeout(struct gotd_imsgev *iev, struct t } return NULL; -} - -static const struct got_error * -send_notification_target_email(struct gotd_imsgev *iev, - struct gotd_notification_target *target) -{ - struct gotd_imsg_notitfication_target_email itarget; - struct ibuf *wbuf = NULL; - - memset(&itarget, 0, sizeof(itarget)); - - if (target->conf.email.sender) - itarget.sender_len = strlen(target->conf.email.sender); - if (target->conf.email.recipient) - itarget.recipient_len = strlen(target->conf.email.recipient); - if (target->conf.email.responder) - itarget.responder_len = strlen(target->conf.email.responder); - if (target->conf.email.hostname) - itarget.hostname_len = strlen(target->conf.email.hostname); - if (target->conf.email.port) - itarget.port_len = strlen(target->conf.email.port); - - wbuf = imsg_create(&iev->ibuf, GOTD_IMSG_NOTIFICATION_TARGET_EMAIL, - 0, 0, sizeof(itarget) + itarget.sender_len + itarget.recipient_len + - itarget.responder_len + itarget.hostname_len + itarget.port_len); - if (wbuf == NULL) { - return got_error_from_errno("imsg_create " - "NOTIFICATION_TARGET_EMAIL"); - } - - if (imsg_add(wbuf, &itarget, sizeof(itarget)) == -1) { - return got_error_from_errno("imsg_add " - "NOTIFICATION_TARGET_EMAIL"); - } - if (target->conf.email.sender) { - if (imsg_add(wbuf, target->conf.email.sender, - itarget.sender_len) == -1) { - return got_error_from_errno("imsg_add " - "NOTIFICATION_TARGET_EMAIL"); - } - } - if (target->conf.email.recipient) { - if (imsg_add(wbuf, target->conf.email.recipient, - itarget.recipient_len) == -1) { - return got_error_from_errno("imsg_add " - "NOTIFICATION_TARGET_EMAIL"); - } - } - if (target->conf.email.responder) { - if (imsg_add(wbuf, target->conf.email.responder, - itarget.responder_len) == -1) { - return got_error_from_errno("imsg_add " - "NOTIFICATION_TARGET_EMAIL"); - } - } - if (target->conf.email.hostname) { - if (imsg_add(wbuf, target->conf.email.hostname, - itarget.hostname_len) == -1) { - return got_error_from_errno("imsg_add " - "NOTIFICATION_TARGET_EMAIL"); - } - } - if (target->conf.email.port) { - if (imsg_add(wbuf, target->conf.email.port, - itarget.port_len) == -1) { - return got_error_from_errno("imsg_add " - "NOTIFICATION_TARGET_EMAIL"); - } - } - - imsg_close(&iev->ibuf, wbuf); - return gotd_imsg_flush(&iev->ibuf); } static const struct got_error * -send_notification_target_http(struct gotd_imsgev *iev, - struct gotd_notification_target *target) -{ - struct gotd_imsg_notitfication_target_http itarget; - struct ibuf *wbuf = NULL; - - memset(&itarget, 0, sizeof(itarget)); - - itarget.tls = target->conf.http.tls; - itarget.hostname_len = strlen(target->conf.http.hostname); - itarget.port_len = strlen(target->conf.http.port); - itarget.path_len = strlen(target->conf.http.path); - if (target->conf.http.auth) - itarget.auth_len = strlen(target->conf.http.auth); - if (target->conf.http.hmac) - itarget.hmac_len = strlen(target->conf.http.hmac); - - wbuf = imsg_create(&iev->ibuf, GOTD_IMSG_NOTIFICATION_TARGET_HTTP, - 0, 0, sizeof(itarget) + itarget.hostname_len + itarget.port_len + - itarget.path_len + itarget.auth_len + itarget.hmac_len); - if (wbuf == NULL) { - return got_error_from_errno("imsg_create " - "NOTIFICATION_TARGET_HTTP"); - } - - if (imsg_add(wbuf, &itarget, sizeof(itarget)) == -1) { - return got_error_from_errno("imsg_add " - "NOTIFICATION_TARGET_HTTP"); - } - if (imsg_add(wbuf, target->conf.http.hostname, - itarget.hostname_len) == -1) { - return got_error_from_errno("imsg_add " - "NOTIFICATION_TARGET_HTTP"); - } - if (imsg_add(wbuf, target->conf.http.port, - itarget.port_len) == -1) { - return got_error_from_errno("imsg_add " - "NOTIFICATION_TARGET_HTTP"); - } - if (imsg_add(wbuf, target->conf.http.path, - itarget.path_len) == -1) { - return got_error_from_errno("imsg_add " - "NOTIFICATION_TARGET_HTTP"); - } - - if (target->conf.http.auth) { - if (imsg_add(wbuf, target->conf.http.auth, - itarget.auth_len) == -1) { - return got_error_from_errno("imsg_add " - "NOTIFICATION_TARGET_HTTP"); - } - } - if (target->conf.http.hmac) { - if (imsg_add(wbuf, target->conf.http.hmac, - itarget.hmac_len) == -1) { - return got_error_from_errno("imsg_add " - "NOTIFICATION_TARGET_HTTP"); - } - } - - imsg_close(&iev->ibuf, wbuf); - return gotd_imsg_flush(&iev->ibuf); -} - -static const struct got_error * -send_notification_target(struct gotd_imsgev *iev, - struct gotd_notification_target *target) -{ - const struct got_error *err = NULL; - - switch (target->type) { - case GOTD_NOTIFICATION_VIA_EMAIL: - err = send_notification_target_email(iev, target); - break; - case GOTD_NOTIFICATION_VIA_HTTP: - err = send_notification_target_http(iev, target); - break; - default: - log_warn("unsupported notification target type %d", - target->type); - break; - } - - return err; -} - -static const struct got_error * send_notification_config(struct gotd_imsgev *iev, char *repo_name) { const struct got_error *err = NULL; struct gotd_repo *repo; struct got_pathlist_entry *pe; struct gotd_imsg_pathlist ilist; - struct gotd_notification_target *target; memset(&ilist, 0, sizeof(ilist)); @@ -2059,13 +2107,8 @@ send_notification_config(struct gotd_imsgev *iev, char } } - STAILQ_FOREACH(target, &repo->notification_targets, entry) { - err = send_notification_target(iev, target); - if (err) - return err; - } - - return NULL; + return send_notification_targets(iev, repo->name, + &repo->notification_targets); } static void @@ -2617,6 +2660,7 @@ start_notifier(char *argv0, const char *confpath, int proc->iev.handler_arg = NULL; event_set(&proc->iev.ev, proc->iev.ibuf.fd, EV_READ, gotd_dispatch_notifier, &proc->iev); + gotd_imsg_event_add(&proc->iev); gotd.notify_proc = proc; } @@ -2895,7 +2939,6 @@ main(int argc, char **argv) struct event evsigint, evsigterm, evsighup, evsigusr1, evsigchld; int *pack_fds = NULL, *temp_fds = NULL; struct gotd_repo *repo = NULL; - char *default_sender = NULL; char hostname[_POSIX_HOST_NAME_MAX + 1]; FILE *fp; FILE *diff_f1 = NULL, *diff_f2 = NULL, *tmp_f1 = NULL, *tmp_f2 = NULL; @@ -2993,7 +3036,7 @@ main(int argc, char **argv) if (proc_id != GOTD_PROC_LISTEN && proc_id != GOTD_PROC_AUTH && proc_id != GOTD_PROC_REPO_WRITE && - proc_id != GOTD_PROC_SESSION_WRITE) { + proc_id != GOTD_PROC_SESSION_WRITE && proc_id != GOTD_PROC_NOTIFY) { if (gotd_parse_config(confpath, proc_id, secrets, &gotd) != 0) return 1; @@ -3050,7 +3093,7 @@ main(int argc, char **argv) if (gethostname(hostname, sizeof(hostname)) == -1) fatal("gethostname"); - if (asprintf(&default_sender, "%s@%s", pw->pw_name, + if (asprintf(&gotd.default_sender, "%s@%s", pw->pw_name, hostname) == -1) fatal("asprintf"); } @@ -3252,9 +3295,7 @@ main(int argc, char **argv) */ unveil_notification_helpers(); - drop_privs(pw); - - notify_main(title, &gotd.repos, default_sender); + notify_main(title); /* NOTREACHED */ exit(0); default: @@ -3340,7 +3381,6 @@ main(int argc, char **argv) free(repo_path); free(secretspath); - free(default_sender); gotd_shutdown(); return 0; blob - 95ebcef04adc3f9d2afc5df131874ee0f9170ed7 blob + f04ba7601ab2f6ff8ec1e20c104c69749cacf93a --- gotd/gotd.h +++ gotd/gotd.h @@ -181,6 +181,7 @@ struct gotd { struct gotd_uid_connection_limit *connection_limits; size_t nconnection_limits; struct gotd_secrets *secrets; + char *default_sender; char *argv0; const char *confpath; @@ -273,6 +274,7 @@ enum gotd_imsg_type { GOTD_IMSG_PROTECTED_BRANCHES_ELEM, /* Notify child process. */ + GOTD_IMSG_NOTIFIER_READY, GOTD_IMSG_NOTIFICATION_REFS, GOTD_IMSG_NOTIFICATION_REFS_ELEM, GOTD_IMSG_NOTIFICATION_REF_NAMESPACES, @@ -591,10 +593,11 @@ struct gotd_imsg_notitfication_target_email { size_t responder_len; size_t hostname_len; size_t port_len; + size_t repo_name_len; /* * Followed by sender_len + responder_len + responder_len + - * hostname_len + port_len bytes. + * hostname_len + port_len + repo_name_len bytes. */ }; @@ -606,10 +609,11 @@ struct gotd_imsg_notitfication_target_http { size_t path_len; size_t auth_len; size_t hmac_len;; + size_t repo_name_len; /* * Followed by hostname_len + port_len + path_len + auth_len + - * hmac_len bytes. + * hmac_len + repo_name_len bytes. */ }; @@ -645,6 +649,7 @@ struct gotd_uid_connection_limit *gotd_find_uid_connec int gotd_parseuid(const char *s, uid_t *uid); const struct got_error *gotd_parse_url(char **, char **, char **, char **, const char *); +const struct got_error *gotd_conf_new_repo(struct gotd_repo **, const char *); /* imsg.c */ const struct got_error *gotd_imsg_flush(struct imsgbuf *); @@ -668,3 +673,8 @@ void gotd_imsg_send_nak(struct got_object_id *, struct const struct got_error *gotd_imsg_recv_pathlist(size_t *, struct imsg *); const struct got_error *gotd_imsg_recv_pathlist_elem(struct imsg *, struct got_pathlist_head *); +void gotd_free_notification_target(struct gotd_notification_target *); +const struct got_error *gotd_imsg_recv_notification_target_email(char **, + struct gotd_notification_target **, struct imsg *); +const struct got_error *gotd_imsg_recv_notification_target_http(char **, + struct gotd_notification_target **, struct imsg *); blob - e0c130803906829b51d5f392e75336ea4f953991 blob + ee2ae7e5319116d7f867753f8682273729ff9f20 --- gotd/imsg.c +++ gotd/imsg.c @@ -250,5 +250,284 @@ gotd_imsg_recv_pathlist_elem(struct imsg *imsg, struct if (err || pe == NULL) free(path); return err; +} + +void +gotd_free_notification_target(struct gotd_notification_target *target) +{ + if (target == NULL) + return; + + switch (target->type) { + case GOTD_NOTIFICATION_VIA_EMAIL: + free(target->conf.email.sender); + free(target->conf.email.recipient); + free(target->conf.email.responder); + free(target->conf.email.hostname); + free(target->conf.email.port); + break; + case GOTD_NOTIFICATION_VIA_HTTP: + free(target->conf.http.hostname); + free(target->conf.http.port); + free(target->conf.http.path); + free(target->conf.http.auth); + free(target->conf.http.hmac); + break; + default: + break; + } + + free(target); } +const struct got_error * +gotd_imsg_recv_notification_target_email(char **repo_name, + struct gotd_notification_target **new_target, struct imsg *imsg) +{ + const struct got_error *err = NULL; + struct gotd_imsg_notitfication_target_email itarget; + struct gotd_notification_target *target; + size_t datalen; + + if (repo_name) + *repo_name = NULL; + *new_target = NULL; + + datalen = imsg->hdr.len - IMSG_HEADER_SIZE; + if (datalen < sizeof(itarget)) + return got_error(GOT_ERR_PRIVSEP_LEN); + memcpy(&itarget, imsg->data, sizeof(itarget)); + + if (datalen != sizeof(itarget) + itarget.sender_len + + itarget.recipient_len + itarget.responder_len + + itarget.hostname_len + itarget.port_len + itarget.repo_name_len) + return got_error(GOT_ERR_PRIVSEP_LEN); + if (itarget.sender_len == 0 || itarget.recipient_len == 0 || + itarget.repo_name_len == 0) + return got_error(GOT_ERR_PRIVSEP_LEN); + + target = calloc(1, sizeof(*target)); + if (target == NULL) + return got_error_from_errno("calloc"); + + target->type = GOTD_NOTIFICATION_VIA_EMAIL; + + if (itarget.sender_len) { + target->conf.email.sender = strndup(imsg->data + + sizeof(itarget), itarget.sender_len); + if (target->conf.email.sender == NULL) { + err = got_error_from_errno("strndup"); + goto done; + } + if (strlen(target->conf.email.sender) != itarget.sender_len) { + err = got_error(GOT_ERR_PRIVSEP_LEN); + goto done; + } + } + + target->conf.email.recipient = strndup(imsg->data + sizeof(itarget) + + itarget.sender_len, itarget.recipient_len); + if (target->conf.email.recipient == NULL) { + err = got_error_from_errno("strndup"); + goto done; + } + if (strlen(target->conf.email.recipient) != itarget.recipient_len) { + err = got_error(GOT_ERR_PRIVSEP_LEN); + goto done; + } + + if (itarget.responder_len) { + target->conf.email.responder = strndup(imsg->data + + sizeof(itarget) + itarget.sender_len + itarget.recipient_len, + itarget.responder_len); + if (target->conf.email.responder == NULL) { + err = got_error_from_errno("strndup"); + goto done; + } + if (strlen(target->conf.email.responder) != + itarget.responder_len) { + err = got_error(GOT_ERR_PRIVSEP_LEN); + goto done; + } + } + + if (itarget.hostname_len) { + target->conf.email.hostname = strndup(imsg->data + + sizeof(itarget) + itarget.sender_len + + itarget.recipient_len + itarget.responder_len, + itarget.hostname_len); + if (target->conf.email.hostname == NULL) { + err = got_error_from_errno("strndup"); + goto done; + } + if (strlen(target->conf.email.hostname) != + itarget.hostname_len) { + err = got_error(GOT_ERR_PRIVSEP_LEN); + goto done; + } + } + + if (itarget.port_len) { + target->conf.email.port = strndup(imsg->data + + sizeof(itarget) + itarget.sender_len + + itarget.recipient_len + itarget.responder_len + + itarget.hostname_len, itarget.port_len); + if (target->conf.email.port == NULL) { + err = got_error_from_errno("strndup"); + goto done; + } + if (strlen(target->conf.email.port) != itarget.port_len) { + err = got_error(GOT_ERR_PRIVSEP_LEN); + goto done; + } + } + + if (repo_name) { + *repo_name = strndup(imsg->data + + sizeof(itarget) + itarget.sender_len + + itarget.recipient_len + itarget.responder_len + + itarget.hostname_len + itarget.port_len, + itarget.repo_name_len); + if (*repo_name == NULL) { + err = got_error_from_errno("strndup"); + goto done; + } + if (strlen(*repo_name) != itarget.repo_name_len) { + err = got_error(GOT_ERR_PRIVSEP_LEN); + free(*repo_name); + *repo_name = NULL; + goto done; + } + } + + *new_target = target; +done: + if (err) + gotd_free_notification_target(target); + return err; +} + +const struct got_error * +gotd_imsg_recv_notification_target_http(char **repo_name, + struct gotd_notification_target **new_target, struct imsg *imsg) +{ + const struct got_error *err = NULL; + struct gotd_imsg_notitfication_target_http itarget; + struct gotd_notification_target *target; + size_t datalen; + + if (repo_name) + *repo_name = NULL; + + datalen = imsg->hdr.len - IMSG_HEADER_SIZE; + if (datalen < sizeof(itarget)) + return got_error(GOT_ERR_PRIVSEP_LEN); + memcpy(&itarget, imsg->data, sizeof(itarget)); + + if (datalen != sizeof(itarget) + itarget.hostname_len + + itarget.port_len + itarget.path_len + itarget.auth_len + + itarget.hmac_len + itarget.repo_name_len) + return got_error(GOT_ERR_PRIVSEP_LEN); + + if (itarget.hostname_len == 0 || itarget.port_len == 0 || + itarget.path_len == 0 || itarget.repo_name_len == 0) + return got_error(GOT_ERR_PRIVSEP_LEN); + + target = calloc(1, sizeof(*target)); + if (target == NULL) + return got_error_from_errno("calloc"); + + target->type = GOTD_NOTIFICATION_VIA_HTTP; + + target->conf.http.tls = itarget.tls; + + target->conf.http.hostname = strndup(imsg->data + + sizeof(itarget), itarget.hostname_len); + if (target->conf.http.hostname == NULL) { + err = got_error_from_errno("strndup"); + goto done; + } + if (strlen(target->conf.http.hostname) != itarget.hostname_len) { + err = got_error(GOT_ERR_PRIVSEP_LEN); + goto done; + } + + target->conf.http.port = strndup(imsg->data + sizeof(itarget) + + itarget.hostname_len, itarget.port_len); + if (target->conf.http.port == NULL) { + err = got_error_from_errno("strndup"); + goto done; + } + if (strlen(target->conf.http.port) != itarget.port_len) { + err = got_error(GOT_ERR_PRIVSEP_LEN); + goto done; + } + + target->conf.http.path = strndup(imsg->data + + sizeof(itarget) + itarget.hostname_len + itarget.port_len, + itarget.path_len); + if (target->conf.http.path == NULL) { + err = got_error_from_errno("strndup"); + goto done; + } + if (strlen(target->conf.http.path) != itarget.path_len) { + err = got_error(GOT_ERR_PRIVSEP_LEN); + goto done; + } + + if (itarget.auth_len) { + target->conf.http.auth = strndup(imsg->data + + sizeof(itarget) + itarget.hostname_len + + itarget.port_len + itarget.path_len, + itarget.auth_len); + if (target->conf.http.auth == NULL) { + err = got_error_from_errno("strndup"); + goto done; + } + if (strlen(target->conf.http.auth) != itarget.auth_len) { + err = got_error(GOT_ERR_PRIVSEP_LEN); + goto done; + } + } + + if (itarget.hmac_len) { + target->conf.http.hmac = strndup(imsg->data + + sizeof(itarget) + itarget.hostname_len + + itarget.port_len + itarget.path_len + + itarget.auth_len, itarget.hmac_len); + if (target->conf.http.hmac == NULL) { + err = got_error_from_errno("strndup"); + goto done; + } + if (strlen(target->conf.http.hmac) != itarget.hmac_len) { + err = got_error(GOT_ERR_PRIVSEP_LEN); + goto done; + } + } + + if (repo_name) { + *repo_name = strndup(imsg->data + + sizeof(itarget) + itarget.hostname_len + + itarget.port_len + itarget.path_len + + itarget.auth_len + itarget.hmac_len, + itarget.repo_name_len); + if (*repo_name == NULL) { + err = got_error_from_errno("strndup"); + goto done; + } + if (strlen(*repo_name) != itarget.repo_name_len) { + err = got_error(GOT_ERR_PRIVSEP_LEN); + free(*repo_name); + *repo_name = NULL; + goto done; + } + } + + *new_target = target; +done: + if (err) + gotd_free_notification_target(target); + return err; +} + + blob - 78a75d6ba9a3cacdcae284eeba502b2011158558 blob + 2713d529309f6d5bc43ac78227353480490cb126 --- gotd/notify.c +++ gotd/notify.c @@ -50,8 +50,7 @@ static struct gotd_notify { pid_t pid; const char *title; struct gotd_imsgev parent_iev; - struct gotd_repolist *repos; - const char *default_sender; + struct gotd_repolist repos; } gotd_notify; struct gotd_notify_session { @@ -239,10 +238,7 @@ notify_email(struct gotd_notification_target *target, argv[i++] = GOTD_PATH_PROG_NOTIFY_EMAIL; argv[i++] = "-f"; - if (target->conf.email.sender) - argv[i++] = target->conf.email.sender; - else - argv[i++] = gotd_notify.default_sender; + argv[i++] = target->conf.email.sender; if (target->conf.email.responder) { argv[i++] = "-r"; @@ -331,7 +327,7 @@ send_notification(struct imsg *imsg, struct gotd_imsge if (datalen != sizeof(inotify) + inotify.username_len) return got_error(GOT_ERR_PRIVSEP_LEN); - repo = gotd_find_repo_by_name(inotify.repo_name, gotd_notify.repos); + repo = gotd_find_repo_by_name(inotify.repo_name, &gotd_notify.repos); if (repo == NULL) return got_error(GOT_ERR_PRIVSEP_MSG); @@ -501,6 +497,24 @@ notify_ibuf_get_str(char **ret, struct ibuf *ibuf) return NULL; } +static const struct got_error * +add_notification_target(const char *repo_name, + struct gotd_notification_target *target) +{ + const struct got_error *err = NULL; + struct gotd_repo *repo; + + repo = gotd_find_repo_by_name(repo_name, &gotd_notify.repos); + if (repo == NULL) { + err = gotd_conf_new_repo(&repo, repo_name); + if (err) + return err; + TAILQ_INSERT_TAIL(&gotd_notify.repos, repo, entry); + } + + STAILQ_INSERT_TAIL(&repo->notification_targets, target, entry); + return NULL; +} static void notify_dispatch(int fd, short event, void *arg) { @@ -538,6 +552,32 @@ notify_dispatch(int fd, short event, void *arg) break; switch (imsg.hdr.type) { + case GOTD_IMSG_NOTIFICATION_TARGET_EMAIL: { + struct gotd_notification_target *target; + char *repo_name; + + err = gotd_imsg_recv_notification_target_email( + &repo_name, &target, &imsg); + if (err) + break; + err = add_notification_target(repo_name, target); + if (err) + gotd_free_notification_target(target); + break; + } + case GOTD_IMSG_NOTIFICATION_TARGET_HTTP: { + struct gotd_notification_target *target; + char *repo_name; + + err = gotd_imsg_recv_notification_target_http( + &repo_name, &target, &imsg); + if (err) + break; + err = add_notification_target(repo_name, target); + if (err) + gotd_free_notification_target(target); + break; + } case GOTD_IMSG_CONNECT_SESSION: err = recv_session(&imsg); break; @@ -602,8 +642,7 @@ done: } void -notify_main(const char *title, struct gotd_repolist *repos, - const char *default_sender) +notify_main(const char *title) { const struct got_error *err = NULL; struct event evsigint, evsigterm, evsighup, evsigusr1; @@ -611,9 +650,8 @@ notify_main(const char *title, struct gotd_repolist *r arc4random_buf(&sessions_hash_key, sizeof(sessions_hash_key)); gotd_notify.title = title; - gotd_notify.repos = repos; - gotd_notify.default_sender = default_sender; gotd_notify.pid = getpid(); + TAILQ_INIT(&gotd_notify.repos); signal_set(&evsigint, SIGINT, gotd_notify_sighdlr, NULL); signal_set(&evsigterm, SIGTERM, gotd_notify_sighdlr, NULL); @@ -635,7 +673,9 @@ notify_main(const char *title, struct gotd_repolist *r gotd_notify.parent_iev.handler_arg = NULL; event_set(&gotd_notify.parent_iev.ev, gotd_notify.parent_iev.ibuf.fd, EV_READ, notify_dispatch, &gotd_notify.parent_iev); - gotd_imsg_event_add(&gotd_notify.parent_iev); + if (gotd_imsg_compose_event(&gotd_notify.parent_iev, + GOTD_IMSG_NOTIFIER_READY, GOTD_PROC_NOTIFY, -1, NULL, 0) == -1) + fatal("imsg compose NOTIFIER_READY"); event_dispatch(); blob - 8173549e2a96f7a2443ff8bd53806411e4312d57 blob + 8f9d9538652602ced40b216c70debce37cbda0db --- gotd/notify.h +++ gotd/notify.h @@ -14,4 +14,4 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -void notify_main(const char *, struct gotd_repolist *, const char *); +void notify_main(const char *); blob - daaf2c2aa310ab499970f60fa62149dff6b06347 blob + df4c6ae0933e6455023be61dfd1d6524ea69cbb3 --- gotd/parse.y +++ gotd/parse.y @@ -327,8 +327,7 @@ notifyflags_l : notifyflags optnl notifyflags_l ; notifyflags : BRANCH STRING { - if (gotd_proc_id == GOTD_PROC_GOTD || - gotd_proc_id == GOTD_PROC_NOTIFY) { + if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_branch(new_repo, $2)) { free($2); YYERROR; @@ -337,8 +336,7 @@ notifyflags : BRANCH STRING { free($2); } | REFERENCE NAMESPACE STRING { - if (gotd_proc_id == GOTD_PROC_GOTD || - gotd_proc_id == GOTD_PROC_NOTIFY) { + if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_ref_namespace(new_repo, $3)) { free($3); YYERROR; @@ -347,8 +345,7 @@ notifyflags : BRANCH STRING { free($3); } | EMAIL TO STRING { - if (gotd_proc_id == GOTD_PROC_GOTD || - gotd_proc_id == GOTD_PROC_NOTIFY) { + if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_email(new_repo, NULL, $3, NULL, NULL, NULL)) { free($3); @@ -358,8 +355,7 @@ notifyflags : BRANCH STRING { free($3); } | EMAIL FROM STRING TO STRING { - if (gotd_proc_id == GOTD_PROC_GOTD || - gotd_proc_id == GOTD_PROC_NOTIFY) { + if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_email(new_repo, $3, $5, NULL, NULL, NULL)) { free($3); @@ -371,8 +367,7 @@ notifyflags : BRANCH STRING { free($5); } | EMAIL TO STRING REPLY TO STRING { - if (gotd_proc_id == GOTD_PROC_GOTD || - gotd_proc_id == GOTD_PROC_NOTIFY) { + if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_email(new_repo, NULL, $3, $6, NULL, NULL)) { free($3); @@ -384,8 +379,7 @@ notifyflags : BRANCH STRING { free($6); } | EMAIL FROM STRING TO STRING REPLY TO STRING { - if (gotd_proc_id == GOTD_PROC_GOTD || - gotd_proc_id == GOTD_PROC_NOTIFY) { + if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_email(new_repo, $3, $5, $8, NULL, NULL)) { free($3); @@ -399,8 +393,7 @@ notifyflags : BRANCH STRING { free($8); } | EMAIL TO STRING RELAY STRING { - if (gotd_proc_id == GOTD_PROC_GOTD || - gotd_proc_id == GOTD_PROC_NOTIFY) { + if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_email(new_repo, NULL, $3, NULL, $5, NULL)) { free($3); @@ -412,8 +405,7 @@ notifyflags : BRANCH STRING { free($5); } | EMAIL FROM STRING TO STRING RELAY STRING { - if (gotd_proc_id == GOTD_PROC_GOTD || - gotd_proc_id == GOTD_PROC_NOTIFY) { + if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_email(new_repo, $3, $5, NULL, $7, NULL)) { free($3); @@ -427,8 +419,7 @@ notifyflags : BRANCH STRING { free($7); } | EMAIL TO STRING REPLY TO STRING RELAY STRING { - if (gotd_proc_id == GOTD_PROC_GOTD || - gotd_proc_id == GOTD_PROC_NOTIFY) { + if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_email(new_repo, NULL, $3, $6, $8, NULL)) { free($3); @@ -442,8 +433,7 @@ notifyflags : BRANCH STRING { free($8); } | EMAIL FROM STRING TO STRING REPLY TO STRING RELAY STRING { - if (gotd_proc_id == GOTD_PROC_GOTD || - gotd_proc_id == GOTD_PROC_NOTIFY) { + if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_email(new_repo, $3, $5, $8, $10, NULL)) { free($3); @@ -459,8 +449,7 @@ notifyflags : BRANCH STRING { free($10); } | EMAIL TO STRING RELAY STRING PORT STRING { - if (gotd_proc_id == GOTD_PROC_GOTD || - gotd_proc_id == GOTD_PROC_NOTIFY) { + if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_email(new_repo, NULL, $3, NULL, $5, $7)) { free($3); @@ -474,8 +463,7 @@ notifyflags : BRANCH STRING { free($7); } | EMAIL FROM STRING TO STRING RELAY STRING PORT STRING { - if (gotd_proc_id == GOTD_PROC_GOTD || - gotd_proc_id == GOTD_PROC_NOTIFY) { + if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_email(new_repo, $3, $5, NULL, $7, $9)) { free($3); @@ -491,8 +479,7 @@ notifyflags : BRANCH STRING { free($9); } | EMAIL TO STRING REPLY TO STRING RELAY STRING PORT STRING { - if (gotd_proc_id == GOTD_PROC_GOTD || - gotd_proc_id == GOTD_PROC_NOTIFY) { + if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_email(new_repo, NULL, $3, $6, $8, $10)) { free($3); @@ -508,8 +495,7 @@ notifyflags : BRANCH STRING { free($10); } | EMAIL FROM STRING TO STRING REPLY TO STRING RELAY STRING PORT STRING { - if (gotd_proc_id == GOTD_PROC_GOTD || - gotd_proc_id == GOTD_PROC_NOTIFY) { + if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_email(new_repo, $3, $5, $8, $10, $12)) { free($3); @@ -527,8 +513,7 @@ notifyflags : BRANCH STRING { free($12); } | EMAIL TO STRING RELAY STRING PORT NUMBER { - if (gotd_proc_id == GOTD_PROC_GOTD || - gotd_proc_id == GOTD_PROC_NOTIFY) { + if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_email(new_repo, NULL, $3, NULL, $5, port_sprintf($7))) { free($3); @@ -540,8 +525,7 @@ notifyflags : BRANCH STRING { free($5); } | EMAIL FROM STRING TO STRING RELAY STRING PORT NUMBER { - if (gotd_proc_id == GOTD_PROC_GOTD || - gotd_proc_id == GOTD_PROC_NOTIFY) { + if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_email(new_repo, $3, $5, NULL, $7, port_sprintf($9))) { free($3); @@ -555,8 +539,7 @@ notifyflags : BRANCH STRING { free($7); } | EMAIL TO STRING REPLY TO STRING RELAY STRING PORT NUMBER { - if (gotd_proc_id == GOTD_PROC_GOTD || - gotd_proc_id == GOTD_PROC_NOTIFY) { + if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_email(new_repo, NULL, $3, $6, $8, port_sprintf($10))) { free($3); @@ -570,8 +553,7 @@ notifyflags : BRANCH STRING { free($8); } | EMAIL FROM STRING TO STRING REPLY TO STRING RELAY STRING PORT NUMBER { - if (gotd_proc_id == GOTD_PROC_GOTD || - gotd_proc_id == GOTD_PROC_NOTIFY) { + if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_email(new_repo, $3, $5, $8, $10, port_sprintf($12))) { free($3); @@ -587,8 +569,7 @@ notifyflags : BRANCH STRING { free($10); } | URL STRING { - if (gotd_proc_id == GOTD_PROC_GOTD || - gotd_proc_id == GOTD_PROC_NOTIFY) { + if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_http(new_repo, $2, NULL, NULL, 0)) { free($2); @@ -598,8 +579,7 @@ notifyflags : BRANCH STRING { free($2); } | URL STRING AUTH STRING { - if (gotd_proc_id == GOTD_PROC_GOTD || - gotd_proc_id == GOTD_PROC_NOTIFY) { + if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_http(new_repo, $2, $4, NULL, 0)) { free($2); @@ -611,8 +591,7 @@ notifyflags : BRANCH STRING { free($4); } | URL STRING AUTH STRING INSECURE { - if (gotd_proc_id == GOTD_PROC_GOTD || - gotd_proc_id == GOTD_PROC_NOTIFY) { + if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_http(new_repo, $2, $4, NULL, 1)) { free($2); @@ -624,8 +603,7 @@ notifyflags : BRANCH STRING { free($4); } | URL STRING HMAC STRING { - if (gotd_proc_id == GOTD_PROC_GOTD || - gotd_proc_id == GOTD_PROC_NOTIFY) { + if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_http(new_repo, $2, NULL, $4, 0)) { free($2); @@ -637,8 +615,7 @@ notifyflags : BRANCH STRING { free($4); } | URL STRING AUTH STRING HMAC STRING { - if (gotd_proc_id == GOTD_PROC_GOTD || - gotd_proc_id == GOTD_PROC_NOTIFY) { + if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_http(new_repo, $2, $4, $6, 0)) { free($2); @@ -652,8 +629,7 @@ notifyflags : BRANCH STRING { free($6); } | URL STRING AUTH STRING INSECURE HMAC STRING { - if (gotd_proc_id == GOTD_PROC_GOTD || - gotd_proc_id == GOTD_PROC_NOTIFY) { + if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_http(new_repo, $2, $4, $7, 1)) { free($2); @@ -680,8 +656,7 @@ repository : REPOSITORY STRING { } if (gotd_proc_id == GOTD_PROC_GOTD || - gotd_proc_id == GOTD_PROC_GITWRAPPER | - gotd_proc_id == GOTD_PROC_NOTIFY) { + gotd_proc_id == GOTD_PROC_GITWRAPPER) { new_repo = conf_new_repo($2); } free($2); @@ -691,8 +666,7 @@ repository : REPOSITORY STRING { repoopts1 : PATH STRING { if (gotd_proc_id == GOTD_PROC_GOTD || - gotd_proc_id == GOTD_PROC_GITWRAPPER || - gotd_proc_id == GOTD_PROC_NOTIFY) { + gotd_proc_id == GOTD_PROC_GITWRAPPER) { if (!got_path_is_absolute($2)) { yyerror("%s: path %s is not absolute", __func__, $2); @@ -1279,22 +1253,14 @@ conf_limit_user_connections(const char *user, int maxi return 0; } -static struct gotd_repo * -conf_new_repo(const char *name) +const struct got_error * +gotd_conf_new_repo(struct gotd_repo **new_repo, const char *name) { struct gotd_repo *repo; - - if (name[0] == '\0') { - fatalx("syntax error: empty repository name found in %s", - file->name); - } - if (strchr(name, '\n') != NULL) - fatalx("repository names must not contain linefeeds: %s", name); - repo = calloc(1, sizeof(*repo)); if (repo == NULL) - fatalx("%s: calloc", __func__); + return got_error_from_errno("calloc"); STAILQ_INIT(&repo->rules); RB_INIT(&repo->protected_tag_namespaces); @@ -1306,9 +1272,34 @@ conf_new_repo(const char *name) STAILQ_INIT(&repo->notification_targets); if (strlcpy(repo->name, name, sizeof(repo->name)) >= - sizeof(repo->name)) - fatalx("%s: strlcpy", __func__); + sizeof(repo->name)) { + free(repo); + return got_error_msg(GOT_ERR_NO_SPACE, + "repository name too long"); + } + *new_repo = repo; + return NULL; +} + +static struct gotd_repo * +conf_new_repo(const char *name) +{ + const struct got_error *err; + struct gotd_repo *repo; + + if (name[0] == '\0') { + fatalx("syntax error: empty repository name found in %s", + file->name); + } + + if (strchr(name, '\n') != NULL) + fatalx("repository names must not contain linefeeds: %s", name); + + err = gotd_conf_new_repo(&repo, name); + if (err) + fatalx("%s", err->msg); + TAILQ_INSERT_TAIL(&gotd->repos, repo, entry); gotd->nrepos++; blob - d139091dacf9e073b2a167c8dca8537a36c7c461 blob + 8ab93f57b38a1436a2f09373f54f92d6d3f6aa96 --- gotd/session_write.c +++ gotd/session_write.c @@ -1762,240 +1762,6 @@ recv_repo_child(struct imsg *imsg) fatal("pledge"); return NULL; -} - -static void -free_notification_target(struct gotd_notification_target *target) -{ - if (target == NULL) - return; - - switch (target->type) { - case GOTD_NOTIFICATION_VIA_EMAIL: - free(target->conf.email.sender); - free(target->conf.email.recipient); - free(target->conf.email.responder); - free(target->conf.email.hostname); - free(target->conf.email.port); - break; - case GOTD_NOTIFICATION_VIA_HTTP: - free(target->conf.http.hostname); - free(target->conf.http.port); - free(target->conf.http.path); - free(target->conf.http.auth); - free(target->conf.http.hmac); - break; - default: - break; - } - - free(target); -} - -static const struct got_error * -recv_notification_target_email(struct imsg *imsg) -{ - const struct got_error *err = NULL; - struct gotd_imsg_notitfication_target_email itarget; - struct gotd_notification_target *target; - size_t datalen; - - datalen = imsg->hdr.len - IMSG_HEADER_SIZE; - if (datalen < sizeof(itarget)) - return got_error(GOT_ERR_PRIVSEP_LEN); - memcpy(&itarget, imsg->data, sizeof(itarget)); - - if (datalen != sizeof(itarget) + itarget.sender_len + - itarget.recipient_len + itarget.responder_len + - itarget.hostname_len + itarget.port_len) - return got_error(GOT_ERR_PRIVSEP_LEN); - if (itarget.recipient_len == 0) - return got_error(GOT_ERR_PRIVSEP_LEN); - - target = calloc(1, sizeof(*target)); - if (target == NULL) - return got_error_from_errno("calloc"); - - target->type = GOTD_NOTIFICATION_VIA_EMAIL; - - if (itarget.sender_len) { - target->conf.email.sender = strndup(imsg->data + - sizeof(itarget), itarget.sender_len); - if (target->conf.email.sender == NULL) { - err = got_error_from_errno("strndup"); - goto done; - } - if (strlen(target->conf.email.sender) != itarget.sender_len) { - err = got_error(GOT_ERR_PRIVSEP_LEN); - goto done; - } - } - - target->conf.email.recipient = strndup(imsg->data + sizeof(itarget) + - itarget.sender_len, itarget.recipient_len); - if (target->conf.email.recipient == NULL) { - err = got_error_from_errno("strndup"); - goto done; - } - if (strlen(target->conf.email.recipient) != itarget.recipient_len) { - err = got_error(GOT_ERR_PRIVSEP_LEN); - goto done; - } - - if (itarget.responder_len) { - target->conf.email.responder = strndup(imsg->data + - sizeof(itarget) + itarget.sender_len + itarget.recipient_len, - itarget.responder_len); - if (target->conf.email.responder == NULL) { - err = got_error_from_errno("strndup"); - goto done; - } - if (strlen(target->conf.email.responder) != - itarget.responder_len) { - err = got_error(GOT_ERR_PRIVSEP_LEN); - goto done; - } - } - - if (itarget.hostname_len) { - target->conf.email.hostname = strndup(imsg->data + - sizeof(itarget) + itarget.sender_len + - itarget.recipient_len + itarget.responder_len, - itarget.hostname_len); - if (target->conf.email.hostname == NULL) { - err = got_error_from_errno("strndup"); - goto done; - } - if (strlen(target->conf.email.hostname) != - itarget.hostname_len) { - err = got_error(GOT_ERR_PRIVSEP_LEN); - goto done; - } - } - - if (itarget.port_len) { - target->conf.email.port = strndup(imsg->data + - sizeof(itarget) + itarget.sender_len + - itarget.recipient_len + itarget.responder_len + - itarget.hostname_len, itarget.port_len); - if (target->conf.email.port == NULL) { - err = got_error_from_errno("strndup"); - goto done; - } - if (strlen(target->conf.email.port) != itarget.port_len) { - err = got_error(GOT_ERR_PRIVSEP_LEN); - goto done; - } - } - - STAILQ_INSERT_TAIL(&gotd_session.notification_targets, target, entry); - target = NULL; -done: - if (err) - free_notification_target(target); - return err; -} - -static const struct got_error * -recv_notification_target_http(struct imsg *imsg) -{ - const struct got_error *err = NULL; - struct gotd_imsg_notitfication_target_http itarget; - struct gotd_notification_target *target; - size_t datalen; - - datalen = imsg->hdr.len - IMSG_HEADER_SIZE; - if (datalen < sizeof(itarget)) - return got_error(GOT_ERR_PRIVSEP_LEN); - memcpy(&itarget, imsg->data, sizeof(itarget)); - - if (datalen != sizeof(itarget) + itarget.hostname_len + - itarget.port_len + itarget.path_len + itarget.auth_len + - itarget.hmac_len) - return got_error(GOT_ERR_PRIVSEP_LEN); - - if (itarget.hostname_len == 0 || itarget.port_len == 0 || - itarget.path_len == 0) - return got_error(GOT_ERR_PRIVSEP_LEN); - - target = calloc(1, sizeof(*target)); - if (target == NULL) - return got_error_from_errno("calloc"); - - target->type = GOTD_NOTIFICATION_VIA_HTTP; - - target->conf.http.tls = itarget.tls; - - target->conf.http.hostname = strndup(imsg->data + - sizeof(itarget), itarget.hostname_len); - if (target->conf.http.hostname == NULL) { - err = got_error_from_errno("strndup"); - goto done; - } - if (strlen(target->conf.http.hostname) != itarget.hostname_len) { - err = got_error(GOT_ERR_PRIVSEP_LEN); - goto done; - } - - target->conf.http.port = strndup(imsg->data + sizeof(itarget) + - itarget.hostname_len, itarget.port_len); - if (target->conf.http.port == NULL) { - err = got_error_from_errno("strndup"); - goto done; - } - if (strlen(target->conf.http.port) != itarget.port_len) { - err = got_error(GOT_ERR_PRIVSEP_LEN); - goto done; - } - - target->conf.http.path = strndup(imsg->data + - sizeof(itarget) + itarget.hostname_len + itarget.port_len, - itarget.path_len); - if (target->conf.http.path == NULL) { - err = got_error_from_errno("strndup"); - goto done; - } - if (strlen(target->conf.http.path) != itarget.path_len) { - err = got_error(GOT_ERR_PRIVSEP_LEN); - goto done; - } - - if (itarget.auth_len) { - target->conf.http.auth = strndup(imsg->data + - sizeof(itarget) + itarget.hostname_len + - itarget.port_len + itarget.path_len, - itarget.auth_len); - if (target->conf.http.auth == NULL) { - err = got_error_from_errno("strndup"); - goto done; - } - if (strlen(target->conf.http.auth) != itarget.auth_len) { - err = got_error(GOT_ERR_PRIVSEP_LEN); - goto done; - } - } - - if (itarget.hmac_len) { - target->conf.http.hmac = strndup(imsg->data + - sizeof(itarget) + itarget.hostname_len + - itarget.port_len + itarget.path_len + - itarget.auth_len, itarget.hmac_len); - if (target->conf.http.hmac == NULL) { - err = got_error_from_errno("strndup"); - goto done; - } - if (strlen(target->conf.http.hmac) != itarget.hmac_len) { - err = got_error(GOT_ERR_PRIVSEP_LEN); - goto done; - } - } - - STAILQ_INSERT_TAIL(&gotd_session.notification_targets, target, entry); - target = NULL; -done: - if (err) - free_notification_target(target); - return err; } static void @@ -2097,12 +1863,28 @@ session_dispatch(int fd, short event, void *arg) gotd_session.num_notification_refs_needed = 0; } break; - case GOTD_IMSG_NOTIFICATION_TARGET_EMAIL: - err = recv_notification_target_email(&imsg); - break; - case GOTD_IMSG_NOTIFICATION_TARGET_HTTP: - err = recv_notification_target_http(&imsg); + case GOTD_IMSG_NOTIFICATION_TARGET_EMAIL: { + struct gotd_notification_target *target; + + err = gotd_imsg_recv_notification_target_email(NULL, + &target, &imsg); + if (err) + break; + STAILQ_INSERT_TAIL(&gotd_session.notification_targets, + target, entry); break; + } + case GOTD_IMSG_NOTIFICATION_TARGET_HTTP: { + struct gotd_notification_target *target; + + err = gotd_imsg_recv_notification_target_http(NULL, + &target, &imsg); + if (err) + break; + STAILQ_INSERT_TAIL(&gotd_session.notification_targets, + target, entry); + break; + } case GOTD_IMSG_CONNECT_NOTIFIER: err = recv_notifier(&imsg); break;