diff options
Diffstat (limited to 'login/programs/request.c')
-rw-r--r-- | login/programs/request.c | 646 |
1 files changed, 0 insertions, 646 deletions
diff --git a/login/programs/request.c b/login/programs/request.c deleted file mode 100644 index 33f5524c32..0000000000 --- a/login/programs/request.c +++ /dev/null @@ -1,646 +0,0 @@ -/* Copyright (C) 1997 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the GNU C Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - -#include <assert.h> -#include <errno.h> -#include <string.h> -#include <unistd.h> -#include <utmp.h> -#include <libintl.h> - -#include "utmpd.h" -#include "utmpd-private.h" - - -/* Prototypes for the local functions. */ -static int process_request (client_connection *connection); -static int send_reply (client_connection *connect, const reply_header *reply); - -static int do_setutent (client_connection *connection); -static int do_getutent (client_connection *connection); -static int do_endutent (client_connection *connection); -static int do_getutline (client_connection *connection); -static int do_getutid (client_connection *connection); -static int do_pututline (client_connection *connection); -static int do_updwtmp (client_connection *connection); - -static int internal_getut_r (client_connection *connection, - const struct utmp *id, struct utmp *buffer); - - -/* Read data from the client on CONNECTION. */ -int -read_data (client_connection *connection) -{ - ssize_t nbytes; - - assert (connection); - assert ((connection->read_end - connection->read_ptr) > 0); - - /* Read data. */ - nbytes = read (connection->sock, connection->read_ptr, - connection->read_end - connection->read_ptr); - if (nbytes > 0) - { - size_t total_bytes; - - /* Update read pointer. */ - connection->read_ptr += nbytes; - - /* Check if we have a complete request header. */ - total_bytes = connection->read_ptr - connection->read_base; - if (total_bytes >= sizeof (request_header)) - { - request_header *header; - - /* Check if we have a complete request. */ - header = (request_header *)connection->read_base; - if (total_bytes >= header->size) - { - /* Process the request. */ - if (process_request (connection) < 0) - return -1; - - /* Adjust read pointer, and flush buffer. */ - connection->read_ptr -= header->size; - memmove (connection->read_base, - connection->read_base + header->size, - connection->read_ptr - connection->read_base); - } - } - - return 0; - } - - if (nbytes < 0) - error (0, errno, _("cannot read from client")); - - return -1; -} - - -/* Write data to the client on CONNECTION. */ -int -write_data (client_connection *connection) -{ - ssize_t nbytes; - - assert (connection); - assert ((connection->write_ptr - connection->write_base) > 0); - - /* Write data. */ - nbytes = write (connection->sock, connection->write_base, - connection->write_ptr - connection->write_base); - if (nbytes > 0) - { - /* Adjust write pointer and flush buffer. */ - connection->write_ptr -= nbytes; - memmove (connection->write_base, connection->write_base + nbytes, - connection->write_ptr - connection->write_base); - - return 0; - } - - if (nbytes < 0) - error (0, errno, _("cannot write to client")); - - return -1; -} - - -/* Process the request received on CONNECTION. Returns 0 if - successful, -1 if not. */ -static int -process_request (client_connection *connection) -{ - request_header *header; - - assert (connection); - assert (connection->read_base); - - header = (request_header *)connection->read_base; - if (header->version != UTMPD_VERSION) - { - warning (EINVAL, "invalid protocol version"); - return -1; - } - - switch (header->type) - { - case UTMPD_REQ_SETUTENT: return do_setutent (connection); - case UTMPD_REQ_GETUTENT: return do_getutent (connection); - case UTMPD_REQ_ENDUTENT: return do_endutent (connection); - case UTMPD_REQ_GETUTLINE: return do_getutline (connection); - case UTMPD_REQ_GETUTID: return do_getutid (connection); - case UTMPD_REQ_PUTUTLINE: return do_pututline (connection); - case UTMPD_REQ_UPDWTMP: return do_updwtmp (connection); - default: - warning (EINVAL, "invalid request type"); - return -1; - } -} - - -/* Send the reply specified by HEADER to the client on CONNECTION. - Returns 0 if successful, -1 if not. */ -static int -send_reply (client_connection *connection, const reply_header *reply) -{ - /* Check if the reply fits in the buffer. */ - if ((size_t) (connection->write_end - connection->write_ptr) < reply->size) - { - error (0, 0, _("buffer overflow")); - return -1; - } - - /* Copy reply to buffer, and adjust write pointer. */ - memcpy (connection->write_ptr, reply, reply->size); - connection->write_ptr += reply->size; - - return 0; -} - - -static int -do_setutent (client_connection *connection) -{ - setutent_request *request; - setutent_reply reply; - - /* The request size varies, so don't check it. */ - request = (setutent_request *)connection->read_base; - - /* Initialize reply. */ - reply.header.version = UTMPD_VERSION; - reply.header.size = sizeof (setutent_reply); - reply.header.type = UTMPD_REQ_SETUTENT; - - /* Select database. */ - if (!strncmp (request->file, _PATH_UTMP, - request->header.size - sizeof (setutent_request))) - connection->database = utmp_db; - else - { - errno = EINVAL; - goto return_error; - } - - /* Initialize position pointer. */ - connection->position = 0; - -#if _HAVE_UT_TYPE - 0 - /* Make sure the entry won't match. */ - connection->last_entry.ut_type = -1; -#endif - - reply.errnum = 0; - reply.result = 0; - return send_reply (connection, &reply.header); - -return_error: - reply.errnum = errno; - reply.result = -1; - return send_reply (connection, &reply.header); -} - - -static int -do_getutent (client_connection *connection) -{ - getutent_request *request; - getutent_reply reply; - - request = (getutent_request *)connection->read_base; - if (request->header.size != sizeof (getutent_request)) - { - warning (EINVAL, "invalid request size"); - return -1; - } - - /* Initialize reply. */ - reply.header.version = UTMPD_VERSION; - reply.header.size = sizeof (getutent_reply); - reply.header.type = UTMPD_REQ_GETUTENT; - - if (connection->database == NULL || connection->position == -1) - { - errno = ESRCH; - goto return_error; - } - - /* Make sure we're in synch with the ordinary file. */ - if (synchronize_database (connection->database) < 0) - { - errno = ESRCH; - goto return_error; - } - - /* Read the next entry from the database. */ - if (read_entry (connection->database, connection->position, - &connection->last_entry) < 0) - { - connection->position = -1; - errno = ESRCH; - goto return_error; - } - - /* Update position pointer. */ - connection->position++; - - memcpy (&reply.entry, &connection->last_entry, sizeof (struct utmp)); - reply.errnum = 0; - reply.result = 0; - return send_reply (connection, (reply_header *)&reply); - -return_error: - memset (&reply.entry, 0, sizeof (struct utmp)); - reply.errnum = errno; - reply.result = -1; - return send_reply (connection, &reply.header); -} - - -static int -do_endutent (client_connection *connection) -{ - endutent_request *request; - endutent_reply reply; - - request = (endutent_request *)connection->read_base; - if (request->header.size != sizeof (endutent_request)) - { - warning (EINVAL, "invalid request size"); - return -1; - } - - /* Deselect database. */ - connection->database = NULL; - - /* Formulate reply. */ - reply.header.version = UTMPD_VERSION; - reply.header.size = sizeof (endutent_reply); - reply.header.type = UTMPD_REQ_ENDUTENT; - reply.errnum = 0; - reply.result = 0; - - return send_reply (connection, &reply.header); -} - - -static int -do_getutline (client_connection *connection) -{ - getutline_request *request; - getutline_reply reply; - - request = (getutline_request *)connection->read_base; - if (request->header.size != sizeof (getutline_request)) - { - warning (EINVAL, "invalid request size"); - return -1; - } - - /* Initialize reply. */ - reply.header.version = UTMPD_VERSION; - reply.header.size = sizeof (getutline_reply); - reply.header.type = UTMPD_REQ_GETUTLINE; - - if (connection->database == NULL || connection->position == -1) - { - errno = ESRCH; - goto return_error; - } - - /* Make sure we're in synch with the ordinary file. */ - if (synchronize_database (connection->database) < 0) - { - errno = ESRCH; - goto return_error; - } - - while (1) - { - /* Read the next entry. */ - if (read_entry (connection->database, connection->position, - &connection->last_entry) < 0) - { - connection->position = -1; - errno = ESRCH; - goto return_error; - } - connection->position++; - - /* Stop if we found a user or login entry. */ - if ( -#if _HAVE_UT_TYPE - 0 - (connection->last_entry.ut_type == USER_PROCESS - || connection->last_entry.ut_type == LOGIN_PROCESS) - && -#endif - !strncmp (request->line.ut_line, connection->last_entry.ut_line, - sizeof request->line.ut_line)) - break; - } - - memcpy (&reply.entry, &connection->last_entry, sizeof (struct utmp)); - reply.errnum = 0; - reply.result = 0; - return send_reply (connection, &reply.header); - -return_error: - memset (&reply.entry, 0, sizeof (struct utmp)); - reply.errnum = errno; - reply.result = -1; - return send_reply (connection, &reply.header); -} - - -static int -do_getutid (client_connection *connection) -{ - getutid_request *request; - getutid_reply reply; - - request = (getutid_request *)connection->read_base; - if (request->header.size != sizeof (getutid_request)) - { - warning (EINVAL, "invalid request size"); - return -1; - } - - /* Initialize reply. */ - reply.header.version = UTMPD_VERSION; - reply.header.size = sizeof (getutid_reply); - reply.header.type = UTMPD_REQ_GETUTID; - - if (connection->database == NULL || connection->position == -1) - { - errno = ESRCH; - goto return_error; - } - - /* Make sure we're in synch with the ordinary file. */ - if (synchronize_database (connection->database) < 0) - { - errno = ESRCH; - goto return_error; - } - - if (internal_getut_r (connection, &request->id, - &connection->last_entry) < 0) - { - errno = ESRCH; - goto return_error; - } - - reply.errnum = 0; - reply.result = 0; - memcpy (&reply.entry, &connection->last_entry, sizeof (struct utmp)); - return send_reply (connection, &reply.header); - -return_error: - memset (&reply.entry, 0, sizeof (struct utmp)); - reply.errnum = errno; - reply.result = -1; - return send_reply (connection, &reply.header); -} - - -static int -do_pututline (client_connection *connection) -{ - pututline_request *request; - pututline_reply reply; - struct utmp buffer; - int found; - - request = (pututline_request *)connection->read_base; - if (request->header.size != sizeof (pututline_request)) - { - warning (EINVAL, "invalid request size"); - return -1; - } - - /* Initialize reply. */ - reply.header.version = UTMPD_VERSION; - reply.header.size = sizeof (pututline_reply); - reply.header.type = UTMPD_REQ_PUTUTLINE; - - if (!(connection->access & W_OK)) - { - errno = EPERM; - goto return_error; - } - - if (connection->database == NULL) - { - errno = ESRCH; - goto return_error; - } - - /* Make sure we're in synch with the ordinary file. */ - if (synchronize_database (connection->database) < 0) - { - errno = ESRCH; - goto return_error; - } - - /* Find the correct place to insert the data. */ - if (connection->position > 0 - && ( -#if _HAVE_UT_TYPE - 0 - (connection->last_entry.ut_type == request->utmp.ut_type - && (connection->last_entry.ut_type == RUN_LVL - || connection->last_entry.ut_type == BOOT_TIME - || connection->last_entry.ut_type == OLD_TIME - || connection->last_entry.ut_type == NEW_TIME)) - || -#endif - proc_utmp_eq (&connection->last_entry, &request->utmp))) - found = 1; - else - found = internal_getut_r (connection, &request->utmp, &buffer); - - if (found < 0) - { - /* We append the next entry. */ - connection->position = - append_entry (connection->database, &request->utmp); - if (connection->position < 0) - goto return_error; - } - else - { - /* We replace the just read entry. */ - connection->position--; - if (write_entry (connection->database, connection->position, - &request->utmp) < 0) - goto return_error; - } - - /* Write the entry to the compatibility file. */ - write_old_entry (connection->database, connection->position, &request->utmp); - - /* Update position pointer. */ - connection->position++; - - reply.errnum = 0; - reply.result = 0; - return send_reply (connection, &reply.header); - -return_error: - reply.errnum = errno; - reply.result = -1; - return send_reply (connection, &reply.header); -} - - -static int -do_updwtmp (client_connection *connection) -{ - updwtmp_request *request; - updwtmp_reply reply; - utmp_database *database; - - /* The request size varies, so don't check it. */ - request = (updwtmp_request *)connection->read_base; - - /* Initialize reply. */ - reply.header.version = UTMPD_VERSION; - reply.header.size = sizeof (updwtmp_reply); - reply.header.type = UTMPD_REQ_UPDWTMP; - - if (!(connection->access & W_OK)) - { - errno = EPERM; - goto return_error; - } - - /* Select database. */ - if (!strncmp (request->file, _PATH_UTMP, - request->header.size - sizeof (updwtmp_request))) - database = utmp_db; - else - { - errno = EINVAL; - goto return_error; - } - - /* Make sure we're in synch with the ordinary file. */ - if (synchronize_database (database) < 0) - { - errno = ESRCH; - goto return_error; - } - - /* Append the entry. */ - if (append_entry (database, &request->utmp) < 0) - goto return_error; - - reply.errnum = 0; - reply.result = 0; - return send_reply (connection, &reply.header); - -return_error: - reply.errnum = errno; - reply.result = -1; - return send_reply (connection, &reply.header); -} - - -/* This function is identical to the one in login/utmp_file.c. */ -int -proc_utmp_eq (const struct utmp *entry, const struct utmp *match) -{ - return - ( -#if _HAVE_UT_TYPE - 0 - (entry->ut_type == INIT_PROCESS - || entry->ut_type == LOGIN_PROCESS - || entry->ut_type == USER_PROCESS - || entry->ut_type == DEAD_PROCESS) - && - (match->ut_type == INIT_PROCESS - || match->ut_type == LOGIN_PROCESS - || match->ut_type == USER_PROCESS - || match->ut_type == DEAD_PROCESS) - && -#endif -#if _HAVE_UT_ID - 0 - (entry->ut_id[0] && match->ut_id[0] - ? strncmp (entry->ut_id, match->ut_id, sizeof match->ut_id) == 0 - : strncmp (entry->ut_line, match->ut_line, sizeof match->ut_line) == 0) -#else - strncmp (entry->ut_line, match->ut_line, sizeof match->ut_line) == 0 -#endif - ); -} - - -/* This function is derived from the one in login/utmp_file.c. */ -static int -internal_getut_r (client_connection *connection, - const struct utmp *id, struct utmp *buffer) -{ -#if _HAVE_UT_TYPE - 0 - if (id->ut_type == RUN_LVL || id->ut_type == BOOT_TIME - || id->ut_type == OLD_TIME || id->ut_type == NEW_TIME) - { - /* Search for next entry with type RUN_LVL, BOOT_TIME, - OLD_TIME, or NEW_TIME. */ - - while (1) - { - /* Read the next entry. */ - if (read_entry (connection->database, connection->position, - buffer) < 0) - { - connection->position = -1; - return -1; - } - connection->position++; - - if (id->ut_type == buffer->ut_type) - break; - } - } - else -#endif /* _HAVE_UT_TYPE */ - { - /* Search for the next entry with the specified ID and with type - INIT_PROCESS, LOGIN_PROCESS, USER_PROCESS, or DEAD_PROCESS. */ - - while (1) - { - /* Read the next entry. */ - if (read_entry (connection->database, connection->position, - buffer) < 0) - { - connection->position = -1; - return -1; - } - connection->position++; - - if (proc_utmp_eq (buffer, id)) - break; - } - } - - return 0; -} |