case 'A':
*kick_type_r = KICK_TYPE_ADMIN_SOCKET;
break;
+ case 'W':
+ *kick_type_r = KICK_TYPE_SIGNAL_WITH_SOCKET;
+ break;
default:
return -1;
}
}
break;
case KICK_TYPE_ADMIN_SOCKET:
+ case KICK_TYPE_SIGNAL_WITH_SOCKET:
str_truncate(cmd, 0);
- str_append(cmd, "KICK-USER\t");
+ if (result.kick_type == KICK_TYPE_SIGNAL_WITH_SOCKET)
+ str_append(cmd, "KICK-USER-SIGNAL\t");
+ else
+ str_append(cmd, "KICK-USER\t");
str_append_tabescaped(cmd, result.username);
if (!guid_128_is_empty(result.conn_guid) &&
add_conn_guid) {
kick->cmd_refcount++;
admin_cmd_send(result.service, result.pid, str_c(cmd),
kick_user_callback, kick);
+ if (result.kick_type == KICK_TYPE_SIGNAL_WITH_SOCKET) {
+ if (kill(result.pid, SIGTERM) == 0)
+ kick->kick_count++;
+ else if (errno != ESRCH) {
+ i_error("kill(%ld) failed: %m",
+ (long)result.pid);
+ }
+ }
break;
}
prev_pid = result.pid;
/* User kicking should be done by sending KICK-USER command to the
process's admin socket or the existing anvil connection. */
KICK_TYPE_ADMIN_SOCKET,
+ /* Use KICK-USER command together with TERM signal. The SIGTERM handler
+ reads and processes the KICK-USER command. This way if there's a
+ race condition wrong process isn't killed. */
+ KICK_TYPE_SIGNAL_WITH_SOCKET,
};
struct connect_limit_key {