/* * Copyright (C) 2012 Andrew Ayer * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * Except as contained in this notice, the name(s) of the above copyright * holders shall not be used in advertising or otherwise to promote the * sale, use or other dealings in this Software without prior written * authorization. */ #include #include #include #include #include #include #include #include #include #define XDMCP_TIMEOUT 3 static const char xdmcp_query_packet[] = { 0, 1, 0, 2, 0, 1, 0 }; /* returns: 1 == willing, 0 == unwilling, <0 == timeout/error */ static int xdmcp_status (void) { struct timeval timeout = { XDMCP_TIMEOUT, 0 }; char reply[128]; int sock = socket(AF_INET, SOCK_DGRAM, 0); struct sockaddr_in addr; ssize_t res; fd_set read_fds; if (sock == -1) { return -errno; } memset(&addr, '\0', sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); addr.sin_port = htons(177); res = sendto(sock, xdmcp_query_packet, sizeof(xdmcp_query_packet), 0, (struct sockaddr*)&addr, sizeof(addr)); if (res == -1) { res = -errno; close(sock); return res; } FD_ZERO(&read_fds); FD_SET(sock, &read_fds); res = select(sock + 1, &read_fds, NULL, NULL, &timeout); if (res == -1) { res = -errno; close(sock); return res; } else if (res == 0) { close(sock); return -ETIMEDOUT; } res = recvfrom(sock, reply, sizeof(reply), 0, NULL, NULL); if (res == -1) { res = -errno; close(sock); return res; } close(sock); if (res >= 4 && reply[2] == 0 && reply[3] == 5) { /* Willing */ return 1; } if (res >= 4 && reply[2] == 0 && reply[3] == 6) { /* Unwilling */ return 0; } return -EIO; } int main (int argc, char** argv) { int quiet = 0; int silent = 0; int res; if (argc >= 2 && strcmp(argv[1], "-q") == 0) { /* Quiet - only print error messages */ quiet = 1; } else if (argc >= 2 && strcmp(argv[1], "-s") == 0) { /* Silent - print nothing */ quiet = 1; silent = 1; } res = xdmcp_status(); if (res < 0) { if (!silent) { fprintf(stdout, "Error: %s\n", strerror(-res)); } return 3; } else if (res == 0) { if (!silent) { fprintf(stdout, "Unwilling\n"); } return 1; } else { if (!quiet) { fprintf(stdout, "Willing\n"); } return 0; } }