{ 'x', T_KEYEXCH, "key exchange" },
{ 'm', T_KEYMGMT, "key management" },
{ 'l', T_CHAL, "challenge management" },
+ { 'v', T_PRIVSEP, "privilege separation" },
{ 'p', T_PACKET, "packet contents" },
{ 'c', T_CRYPTO, "crypto details" },
{ 'A', T_ALL, "all of the above" },
*
* Returns: ---
*
- * Use: Main message token formatting driver.
+ * Use: Main message token formatting driver. The arguments are
+ * interleaved formatting tokens and their parameters, finally
+ * terminated by an entry @A_END@.
+ *
+ * Tokens recognized:
+ *
+ * * "*..." ... -- pretokenized @dstr_putf@-like string
+ *
+ * * "?ADDR" SOCKADDR -- a socket address, to be converted
+ *
+ * * "?B64" BUFFER SIZE -- binary data to be base64-encoded
+ *
+ * * "?TOKENS" VECTOR -- null-terminated vector of tokens
+ *
+ * * "?PEER" PEER -- peer's name
+ *
+ * * "?ERRNO" ERRNO -- system error code
+ *
+ * * "[!]..." ... -- @dstr_putf@-like string as single token
*/
-static void a_vformat(dstr *d, const char *fmt, va_list ap)
+void a_vformat(dstr *d, const char *fmt, va_list ap)
{
dstr dd = DSTR_INIT;
while (fmt) {
if (*fmt == '*') {
- dstr_putc(d, ' ');
+ if (d->len) dstr_putc(d, ' ');
dstr_vputf(d, fmt + 1, &ap);
} else if (*fmt == '?') {
if (strcmp(fmt, "?ADDR") == 0) {
close(sock.fd);
unlink(sockname);
FOREACH_PEER(p, { p_destroy(p); });
+ ps_quit();
exit(0);
}
static void a_destroypending(void)
{
- admin *a, *aa;
+ admin *a, *aa, *head;
admin_bgop *bg, *bbg;
admin_service *svc, *ssvc;
- /* --- Destroy connections marked as pending --- */
+ /* --- Destroy connections marked as pending --- *
+ *
+ * Slightly messy. Killing clients may cause others to finally die. Make
+ * sure that they can be put on the list without clobbering anything or
+ * getting lost.
+ */
- for (a = a_dead; a; a = aa) {
- aa = a->next;
- assert(a->f & AF_DEAD);
+ while (a_dead) {
+ head = a_dead;
+ a_dead = 0;
+ for (a = head; a; a = aa) {
+ aa = a->next;
+ assert(a->f & AF_DEAD);
- /* --- Report what we're doing --- */
+ /* --- Report what we're doing --- */
- T( trace(T_ADMIN, "admin: completing destruction of connection %u",
- a->seq); )
+ T( trace(T_ADMIN, "admin: completing destruction of connection %u",
+ a->seq); )
- /* --- If this is the foreground client then shut down --- */
+ /* --- If this is the foreground client then shut down --- */
- if (a->f & AF_FOREGROUND) {
- T( trace(T_ADMIN, "admin: foreground client quit: shutting down"); )
- a_warn("SERVER", "quit", "foreground-eof", A_END);
- a_quit();
- }
+ if (a->f & AF_FOREGROUND) {
+ T( trace(T_ADMIN, "admin: foreground client quit: shutting down"); )
+ a_warn("SERVER", "quit", "foreground-eof", A_END);
+ a_quit();
+ }
- /* --- Abort any background jobs in progress --- */
+ /* --- Abort any background jobs in progress --- */
- for (bg = a->bg; bg; bg = bbg) {
- bbg = bg->next;
- bg->cancel(bg);
- if (bg->tag) xfree(bg->tag);
- xfree(bg);
- }
+ for (bg = a->bg; bg; bg = bbg) {
+ bbg = bg->next;
+ bg->cancel(bg);
+ if (bg->tag) xfree(bg->tag);
+ xfree(bg);
+ }
- /* --- Release services I hold, and abort pending jobs --- */
+ /* --- Release services I hold, and abort pending jobs --- */
- for (svc = a->svcs; svc; svc = ssvc) {
- ssvc = svc->next;
- a_svcrelease(svc);
- }
- a_jobtablefinal(&a->j);
+ for (svc = a->svcs; svc; svc = ssvc) {
+ ssvc = svc->next;
+ a_svcrelease(svc);
+ }
+ a_jobtablefinal(&a->j);
- /* --- Close file descriptors and selectory --- */
+ /* --- Close file descriptors and selectory --- */
- selbuf_destroy(&a->b);
- if (a->b.reader.fd != a->w.fd) close(a->b.reader.fd);
- close(a->w.fd);
- if (a_stdin == a) a_stdin = 0;
+ selbuf_destroy(&a->b);
+ if (a->b.reader.fd != a->w.fd) close(a->b.reader.fd);
+ close(a->w.fd);
+ if (a_stdin == a) a_stdin = 0;
- /* --- Done --- */
+ /* --- Done --- */
- DESTROY(a);
+ DESTROY(a);
+ }
}
-
- /* --- All pending destruction completed --- */
-
- a_dead = 0;
}
/* --- @a_destroy@ --- *
/* --- @a_init@ --- *
*
* Arguments: @const char *name@ = socket name to create
+ * @uid_t u@ = user to own the socket
+ * @gid_t g@ = group to own the socket
*
* Returns: ---
*
* Use: Creates the admin listening socket.
*/
-void a_init(const char *name)
+void a_init(const char *name, uid_t u, gid_t g)
{
int fd;
int n = 5;
goto again;
}
chmod(sun.sun_path, 0600);
+ if (chown(sun.sun_path, u, g)) {
+ T( trace(T_ADMIN,
+ "admin: failed to give away socket: %s",
+ strerror(errno)); )
+ }
fdflags(fd, O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC);
if (listen(fd, 5))
die(EXIT_FAILURE, "couldn't listen on socket: %s", strerror(errno));