#include "rpc.h" #include "util.h" #include "main.h" #include "userlist.h" #include #include #include #include #include #include #include #include #include #include #define SOCKPATH "/run/idle-daemon" static void handleClient( int fd, struct ucred *user ); int rpcOpen() { int fd = socket( AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0 ); if ( fd == -1 ) { perror( "Cannot create local RPC socket" ); return -1; } struct sockaddr_un address = { .sun_family = AF_UNIX, .sun_path = SOCKPATH, }; unlink( SOCKPATH ); if ( bind( fd, (struct sockaddr *)&address, sizeof(address) ) == -1 ) { perror( "Could not bind RPC socket" ); close( fd ); return -1; } chmod( SOCKPATH, 0777 ); if ( listen( fd, 10 ) == -1 ) { perror( "Could not listen() on RPC socket" ); close( fd ); return -1; } return fd; } void rpcWait( int listenFd, int seconds ) { waitRead( listenFd, seconds * 1000 ); } void rpcHandle( int listenFd ) { int fd; while ( ( fd = accept( listenFd, NULL, NULL ) ) != -1 ) { // Determine who connected socklen_t len; struct ucred ucred; len = sizeof(struct ucred); if ( getsockopt( fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len ) == -1 ) { perror( "Could not get credentials of connection" ); close( fd ); // TODO: Allow more for root (eg. cancel reboot/poweroff) continue; } if ( ! doublefork() ) continue; // Parent continues handleClient( fd, &ucred ); exit( 0 ); } if ( errno != EAGAIN && errno != EWOULDBLOCK ) { perror( "accept() on RPC socket failed" ); } } static void handleClient( int fd, struct ucred *user ) { //printf( "Credentials from SO_PEERCRED: pid=%ld, euid=%ld, egid=%ld\n", // (long) ucred.pid, (long) ucred.uid, (long) ucred.gid ); // Make socket blocking (should be default on linux after accept() but...) (void)user; int flags = fcntl( fd, F_GETFL, 0 ); if ( flags != -1 ) { fcntl( fd, F_SETFL, flags & ~O_NONBLOCK ); } // But set timeouts struct timeval tv = { .tv_sec = 2, }; setsockopt( fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(tv) ); setsockopt( fd, SOL_SOCKET, SO_SNDTIMEO, (const char*)&tv, sizeof(tv) ); // Now read request char buffer[1000]; ssize_t len = read( fd, buffer, sizeof(buffer) - 1 ); if ( len <= 0 ) return; buffer[len] = '\0'; if ( strncmp( buffer, "get", 3 ) != 0 ) { write( fd, "error", 5 ); } else { // Get request FILE *s = fdopen( fd, "w" ); if ( s == NULL ) { perror( "Cannot wrap socket in stream" ); return; } // 1) Global state time_t deadline; const char *name = "none"; main_getStatus( &name, &deadline ); fprintf( s, "[General]\n" "nextAction=%s\n" "nextActionTime=%lld\n", name, (long long)deadline ); // 2) Requested sessions char *tok = strtok( buffer + 4, " \t\n\r" ); while ( tok != NULL ) { struct user *user = main_getUser( tok ); if ( user != NULL ) { fprintf( s, "[%s]\n" "logoutTime=%lld\n" "locked=%d\n", tok, (long long)user->logoutTime, (int)user->isLocked ); } tok = strtok( NULL, " \t\n\r" ); } fflush( s ); } shutdown( fd, SHUT_WR ); read( fd, buffer, sizeof(buffer) ); close( fd ); }