/* * Sendhercules * * This program connects to the HTTP server port of a local or remote Hercules * instance and uses HTTP POST to send a Hercules command to it for execution. * The HTTP response sent back by Hercules is discarded. * * Copyright 2014 Peter Coghlan. * * See http://software.beyondthepale.ie/hercules/sendhercules/license.txt * for terms of use. * * Some inspiration and code from fetch_http in the OSU webserver by * David Jones, Ohio State University * * 16-Aug-2014 V1.0 Initial version * 11-Sep-2014 V1.1 Added #include to pick up close. (Thanks Enrico!) * * Please send bug reports and suggestions by email to: * software at beyondthepale dot ie * * Usage: * * sendhercules address:port command * * Arguments: * * address:port Domain name or ip address and HTTP port number of * Hercules instance to send command to. * * command Command to send. * */ #include #include #include #include #include #include #include #include #include #include #include /* The following constants must be changed if they are changed in Hercules */ #define PATH "/cgi-bin/tasks/syslog" #define PREFIX "command=" void main ( int argc, char **argv ) { int i, status, sd, port; void urlencode(); struct sockaddr local, remote; struct hostent *hostinfo; char *arguments, *command, *host, *hostandport, *request; /* Are there enough arguments to proceed? */ if (argc < 3) { fprintf(stderr,"\nUsage:\n\n" " sendhercules address:port command\n\n" " Where address:port specifies the domain name or TCP/IP network\n" " address and HTTP server port of the Hercules instance to send\n" " the command to.\n\n"); exit(EXIT_SUCCESS); } /* First argument is the address and port of the Hercules instance */ hostandport = argv[1]; /* Subsequent arguments comprise the command to be sent. If there is more than one more argument, contatenate them with spaces between. */ arguments = NULL; for ( i = 2; i < argc; i++ ) { int length; if (arguments == NULL) length = 0; else length = strlen(arguments) + 1; arguments = realloc(arguments, (length + strlen(argv[i]) + 1) * sizeof(char)); if (arguments == NULL) { fprintf(stderr, "Cannot allocate memory for argument %d\n", i); exit(EXIT_FAILURE); } if (i == 2) arguments[0] = '\0'; else strcat(arguments, " "); strcat(arguments, argv[i]); } /* Allocate enough memory for the maximum possible length of the urlencoded command */ command = malloc(strlen(arguments) * sizeof(char) * 3 + 1); if (command == NULL) { free(arguments); fprintf(stderr, "Cannot allocate memory for command string\n"); exit(EXIT_FAILURE); } /* Encode the command for transmission as a URL */ urlencode(command, arguments); /* Free up the original string which is no longer required */ free(arguments); /* Make a copy of the host and port string */ host = strdup(hostandport); /* * Remove the port specification leaving just the name of the remote host * Save the port number separately as an integer */ port = 80; /* Default to port 80 if port is not specified */ for (i = 0; host[i]; i++) if (host[i] == ':') { port = atoi(&host[i+1]); if ((port <= 0) || (port > 65535)) { fprintf(stderr,"Port %s is not valid", &host[i+1]); free(command); exit(EXIT_FAILURE); } host[i] = '\0'; break; } /* * Create socket on first available port. */ sd = socket ( AF_INET, SOCK_STREAM, 0 ); if ( sd < 0 ) { fprintf(stderr,"Error creating socket: %s\n", strerror(errno) ); free(command); exit(EXIT_FAILURE); } local.sa_family = AF_INET; for ( i = 0; i < sizeof(local.sa_data); i++ ) local.sa_data[i] = '\0'; status = bind ( sd, &local, sizeof ( local ) ); if ( status < 0 ) { fprintf(stderr,"Error binding socket: %s\n", strerror(errno) ); free(command); close(sd); exit(EXIT_FAILURE); } /* * Lookup host. */ hostinfo = gethostbyname ( host ); if ( !hostinfo ) { fprintf(stderr, "Could not find resolve address '%s'\n", host ); free(command); close(sd); exit(EXIT_FAILURE); } remote.sa_family = hostinfo->h_addrtype; for ( i = 0; i < hostinfo->h_length; i++ ) { remote.sa_data[i+2] = hostinfo->h_addr_list[0][i]; } remote.sa_data[0] = port >> 8; remote.sa_data[1] = port & 255; /* * Connect to remote host. */ status = connect ( sd, &remote, sizeof(remote) ); if ( status == 0 ) { int length; /* Build POST request */ length = strlen(PREFIX) + strlen(command); request = malloc( (length + strlen(hostandport) + strlen(PATH) + 256) * sizeof(char)); if (request == NULL) { fprintf(stderr, "Cannot allocate memory for POST request\n"); free(command); close(sd); exit(EXIT_FAILURE); } sprintf ( request, "POST %s HTTP/1.0\r\n" "Host: %s\r\n" "Content-Type: application/x-www-form-urlencoded\r\n" "Content-Length: %d\r\n" "\r\n" PREFIX "%s", PATH, hostandport, length, command ); free(command); status = send ( sd, request, strlen(request), 0 ); if ( status < 0 ) { fprintf(stderr,"Error sending command to '%s': %s\n", hostandport, strerror(errno) ); free(request); close(sd); exit(EXIT_FAILURE); } free(request); } else { fprintf(stderr, "Error connecting to '%s': %s\n", hostandport, strerror(errno) ); close(sd); exit(EXIT_FAILURE); } close ( sd ); exit(EXIT_SUCCESS); } /* Encode a string for transmission as a URL */ void urlencode(char *output, char *input) { int i, j; for (i = j = 0; i < strlen(input); i++) { if (isspace(input[i])) output[j++] = '+'; else if (isalnum(input[i])) output[j++] = input[i]; else j = j + sprintf(output + j, "%%%2.2X", input[i]); } output[j] = '\0'; return; }