aboutsummaryrefslogtreecommitdiff
path: root/auth/auth.c
diff options
context:
space:
mode:
Diffstat (limited to 'auth/auth.c')
-rw-r--r--auth/auth.c302
1 files changed, 166 insertions, 136 deletions
diff --git a/auth/auth.c b/auth/auth.c
index d77c484e..11db0f8f 100644
--- a/auth/auth.c
+++ b/auth/auth.c
@@ -1,5 +1,5 @@
/* Authentication server.
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996,97,98,99,2002 Free Software Foundation, Inc.
Written by Roland McGrath.
This file is part of the GNU Hurd.
@@ -18,6 +18,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <mach.h>
@@ -29,12 +30,13 @@
#include <idvec.h>
#include <assert.h>
#include <argp.h>
+#include <error.h>
+#include <version.h>
#include "auth_S.h"
#include "auth_reply_U.h"
-#define AUTH_VERSION "0.0"
+const char *argp_program_version = STANDARD_HURD_VERSION(auth);
-char *argp_program_version = "auth " AUTH_VERSION " (GNU " HURD_RELEASE ")";
/* Auth handles are server ports with sets of ids. */
struct authhandle
@@ -81,7 +83,8 @@ auth_port_to_handle (auth_t auth)
/* id management. */
-inline void idvec_copyout (struct idvec *idvec, uid_t **ids, uid_t *nids)
+static inline void
+idvec_copyout (struct idvec *idvec, uid_t **ids, size_t *nids)
{
if (idvec->num > *nids)
*ids = idvec->ids;
@@ -98,13 +101,13 @@ inline void idvec_copyout (struct idvec *idvec, uid_t **ids, uid_t *nids)
kern_return_t
S_auth_getids (struct authhandle *auth,
uid_t **euids,
- u_int *neuids,
+ size_t *neuids,
uid_t **auids,
- u_int *nauids,
+ size_t *nauids,
uid_t **egids,
- u_int *negids,
+ size_t *negids,
uid_t **agids,
- u_int *nagids)
+ size_t *nagids)
{
if (! auth)
return EOPNOTSUPP;
@@ -117,17 +120,17 @@ S_auth_getids (struct authhandle *auth,
/* Implement auth_makeauth as described in <hurd/auth.defs>. */
kern_return_t
S_auth_makeauth (struct authhandle *auth,
- mach_port_t *authpts, u_int nauths,
- uid_t *euids, u_int neuids,
- uid_t *auids, u_int nauids,
- uid_t *egids, u_int negids,
- uid_t *agids, u_int nagids,
+ mach_port_t *authpts, size_t nauths,
+ uid_t *euids, size_t neuids,
+ uid_t *auids, size_t nauids,
+ uid_t *egids, size_t negids,
+ uid_t *agids, size_t nagids,
mach_port_t *newhandle)
{
struct authhandle *newauth, *auths[1 + nauths];
int hasroot = 0;
error_t err;
- u_int i, j;
+ size_t i, j;
if (!auth)
return EOPNOTSUPP;
@@ -137,7 +140,7 @@ S_auth_makeauth (struct authhandle *auth,
/* Fetch the auth structures for all the ports passed in. */
for (i = 0; i < nauths; i++)
auths[i + 1] = auth_port_to_handle (authpts[i]);
-
+
++nauths;
/* Verify that the union of the handles passed in either contains euid 0
@@ -248,15 +251,22 @@ S_auth_makeauth (struct authhandle *auth,
/* Transaction handling. */
-/* Table of pending transactions keyed on RENDEZVOUS. */
-struct ihash *pending_users, *pending_servers;
-struct mutex pending_lock = MUTEX_INITIALIZER;
-
-/* A pending transaction. */
-struct pending
+/* Since the user is responsible for freeing the rendezvous port, it has to
+ * wait for the server to have finished transmitting uids.
+ *
+ * The server thus waits for the user to give it uids (unless it was already
+ * there), transmits them and provides the passthrough port.
+ *
+ * The user gives the uids and waits for the passthrough port from the server.
+ *
+ * If the user is early, it has to tell the server it arrived.
+ */
+
+/* A pending user. */
+struct pending_user
{
- void **locp; /* Position in one of the ihash tables. */
- struct condition wakeup; /* The waiter is blocked on this condition. */
+ hurd_ihash_locp_t locp; /* Position in the pending_users ihash table. */
+ struct condition wakeup; /* The reader is blocked on this condition. */
/* The user's auth handle. */
struct authhandle *user;
@@ -265,76 +275,87 @@ struct pending
mach_port_t passthrough;
};
+/* A pending server. */
+struct pending_server
+ {
+ hurd_ihash_locp_t locp; /* Position in the pending_servers ihash table. */
+ struct condition wakeup; /* The server is blocked on this condition. */
+ };
+
+/* Table of pending transactions keyed on RENDEZVOUS. */
+struct hurd_ihash pending_users
+ = HURD_IHASH_INITIALIZER (offsetof (struct pending_user, locp));
+struct hurd_ihash pending_servers
+ = HURD_IHASH_INITIALIZER (offsetof (struct pending_server, locp));
+struct mutex pending_lock = MUTEX_INITIALIZER;
+
/* Implement auth_user_authenticate as described in <hurd/auth.defs>. */
kern_return_t
S_auth_user_authenticate (struct authhandle *userauth,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
mach_port_t rendezvous,
mach_port_t *newport,
mach_msg_type_name_t *newporttype)
{
- struct pending *s;
+ struct pending_server *s;
+ struct pending_user u;
+ error_t err;
if (! userauth)
return EOPNOTSUPP;
- mutex_lock (&pending_lock);
+ if (rendezvous == MACH_PORT_DEAD) /* Port died in transit. */
+ return EINVAL;
- /* Look for this port in the server list. */
- s = ihash_find (pending_servers, rendezvous);
- if (s)
- {
- /* Found it! Extract the port. */
- *newport = s->passthrough;
- *newporttype = MACH_MSG_TYPE_MOVE_SEND;
+ u.user = userauth;
+ condition_init (&u.wakeup);
- /* Remove it from the pending list. */
- ihash_locp_remove (pending_servers, s->locp);
+ mutex_lock (&pending_lock);
- /* Give the server the auth port and wake the RPC up.
- We need to add a ref in case the port dies. */
- s->user = userauth;
- ports_port_ref (userauth);
+ err = hurd_ihash_add (&pending_users, rendezvous, &u);
+ if (err) {
+ mutex_unlock (&pending_lock);
+ return err;
+ }
+
+ /* Give the server the auth port.
+ We need to add a ref in case the port dies. */
+ ports_port_ref (userauth);
+
+ /* Look for this rendezvous in the server list. */
+ s = hurd_ihash_find (&pending_servers, rendezvous);
+ if (s) {
+ /* Found it! */
+
+ /* Remove it from the pending list. */
+ hurd_ihash_locp_remove (&pending_servers, s->locp);
+
+ /* Tell it we eventually arrived. */
+ condition_signal (&s->wakeup);
+ }
+
+ ports_interrupt_self_on_port_death (userauth, rendezvous);
+ /* Wait for server answer. */
+ if (hurd_condition_wait (&u.wakeup, &pending_lock) &&
+ hurd_ihash_find (&pending_users, rendezvous))
+ /* We were interrupted; remove our record. */
+ {
+ hurd_ihash_locp_remove (&pending_users, u.locp);
+ err = EINTR;
+ }
- condition_signal (&s->wakeup);
- mutex_unlock (&pending_lock);
+ mutex_unlock (&pending_lock);
+ if (! err)
+ {
+ /* Extract the port. */
+ *newport = u.passthrough;
+ *newporttype = MACH_MSG_TYPE_MOVE_SEND;
mach_port_deallocate (mach_task_self (), rendezvous);
- return 0;
}
- else
- {
- /* No pending server RPC for this port.
- Create a pending user RPC record. */
- struct pending u;
- error_t err;
- err = ihash_add (pending_users, rendezvous, &u, &u.locp);
- if (! err)
- {
- /* Store the user auth port and wait for the server RPC to wake
- us up. */
- u.user = userauth;
- condition_init (&u.wakeup);
- ports_interrupt_self_on_port_death (userauth, rendezvous);
- if (hurd_condition_wait (&u.wakeup, &pending_lock))
- /* We were interrupted; remove our record. */
- {
- ihash_locp_remove (pending_users, u.locp);
- err = EINTR;
- }
- }
- /* The server side has already removed U from the ihash table. */
- mutex_unlock (&pending_lock);
-
- if (! err)
- {
- /* The server RPC has set the port and signalled U.wakeup. */
- *newport = u.passthrough;
- *newporttype = MACH_MSG_TYPE_MOVE_SEND;
- mach_port_deallocate (mach_task_self (), rendezvous);
- }
- return err;
- }
+ return err;
}
/* Implement auth_server_authenticate as described in <hurd/auth.defs>. */
@@ -346,79 +367,89 @@ S_auth_server_authenticate (struct authhandle *serverauth,
mach_port_t newport,
mach_msg_type_name_t newport_type,
uid_t **euids,
- u_int *neuids,
+ size_t *neuids,
uid_t **auids,
- u_int *nauids,
+ size_t *nauids,
uid_t **egids,
- u_int *negids,
+ size_t *negids,
uid_t **agids,
- u_int *nagids)
+ size_t *nagids)
{
- struct pending *u;
+ struct pending_user *u;
struct authhandle *user;
+ error_t err;
if (! serverauth)
return EOPNOTSUPP;
+ if (rendezvous == MACH_PORT_DEAD) /* Port died in transit. */
+ return EINVAL;
+
mutex_lock (&pending_lock);
- /* Look for this port in the user list. */
- u = ihash_find (pending_users, rendezvous);
+ /* Look for this rendezvous in the user list. */
+ u = hurd_ihash_find (&pending_users, rendezvous);
+ if (! u)
+ {
+ /* User not here yet, have to wait for it. */
+ struct pending_server s;
+ condition_init (&s.wakeup);
+ err = hurd_ihash_add (&pending_servers, rendezvous, &s);
+ if (! err)
+ {
+ ports_interrupt_self_on_port_death (serverauth, rendezvous);
+ if (hurd_condition_wait (&s.wakeup, &pending_lock) &&
+ hurd_ihash_find (&pending_servers, rendezvous))
+ /* We were interrupted; remove our record. */
+ {
+ hurd_ihash_locp_remove (&pending_servers, s.locp);
+ err = EINTR;
+ }
+ else
+ {
+ u = hurd_ihash_find (&pending_users, rendezvous);
+ if (! u)
+ /* User still not here, odd! */
+ err = EINTR;
+ }
+ }
+ }
+
if (u)
{
+ error_t err2;
+
/* Remove it from the pending list. */
- ihash_locp_remove (pending_users, u->locp);
+ hurd_ihash_locp_remove (&pending_users, u->locp);
- /* Found it! We must add a ref because the one held by the
- user RPC might die as soon as we unlock pending_lock. */
+ /* Found it! */
user = u->user;
- ports_port_ref (user);
+
+ mutex_unlock (&pending_lock);
+
+ /* Tell third party. */
+ err2 = auth_server_authenticate_reply (reply, reply_type, 0,
+ user->euids.ids, user->euids.num,
+ user->auids.ids, user->auids.num,
+ user->egids.ids, user->egids.num,
+ user->agids.ids, user->agids.num);
+
+ if (err2)
+ mach_port_deallocate (mach_task_self (), reply);
+
+ mutex_lock (&pending_lock);
/* Give the user the new port and wake the RPC up. */
u->passthrough = newport;
condition_signal (&u->wakeup);
- mutex_unlock (&pending_lock);
}
- else
- {
- /* No pending user RPC for this port.
- Create a pending server RPC record. */
- struct pending s;
- error_t err;
-
- err = ihash_add (pending_servers, rendezvous, &s, &s.locp);
- if (! err)
- {
- /* Store the new port and wait for the user RPC to wake us up. */
- s.passthrough = newport;
- condition_init (&s.wakeup);
- ports_interrupt_self_on_port_death (serverauth, rendezvous);
- if (hurd_condition_wait (&s.wakeup, &pending_lock))
- /* We were interrupted; remove our record. */
- {
- ihash_locp_remove (pending_servers, s.locp);
- err = EINTR;
- }
- }
- /* The user side has already removed S from the ihash table. */
- mutex_unlock (&pending_lock);
- if (err)
- return err;
+ mutex_unlock (&pending_lock);
- /* The user RPC has set the port (with a ref) and signalled S.wakeup. */
- user = s.user;
- }
+ if (err)
+ return err;
- /* Extract the ids. We must use a separate reply stub so
- we can deref the user auth handle after the reply uses its
- contents. */
- auth_server_authenticate_reply (reply, reply_type, 0,
- user->euids.ids, user->euids.num,
- user->auids.ids, user->auids.num,
- user->egids.ids, user->egids.num,
- user->agids.ids, user->agids.num);
ports_port_deref (user);
mach_port_deallocate (mach_task_self (), rendezvous);
return MIG_NO_REPLY;
@@ -444,8 +475,9 @@ main (int argc, char **argv)
process_t proc;
mach_port_t hostpriv, masterdev;
struct authhandle *firstauth;
+ struct argp argp = { 0, 0, 0, "Hurd standard authentication server." };
- argp_parse (0, argc, argv, 0, 0, 0);
+ argp_parse (&argp, argc, argv, 0, 0, 0);
auth_bucket = ports_create_bucket ();
authhandle_portclass = ports_create_class (&destroy_authhandle, 0);
@@ -460,16 +492,21 @@ main (int argc, char **argv)
idvec_merge (&firstauth->agids, &firstauth->auids);
/* Fetch our bootstrap port and contact the bootstrap filesystem. */
- task_get_bootstrap_port (mach_task_self (), &boot);
- startup_authinit (boot, ports_get_right (firstauth),
- MACH_MSG_TYPE_MAKE_SEND, &proc);
+ err = task_get_bootstrap_port (mach_task_self (), &boot);
+ assert_perror (err);
+ if (boot == MACH_PORT_NULL)
+ error (2, 0, "auth server can only be run by init during boot");
+ err = startup_authinit (boot, ports_get_right (firstauth),
+ MACH_MSG_TYPE_MAKE_SEND, &proc);
+ if (err)
+ error (2, err, "cannot contact init for bootstrap");
/* Register ourselves with the proc server and then start signals. */
proc_getprivports (proc, &hostpriv, &masterdev);
- proc_register_version (proc, hostpriv, "auth", HURD_RELEASE, AUTH_VERSION);
+ proc_register_version (proc, hostpriv, "auth", "", HURD_VERSION);
mach_port_deallocate (mach_task_self (), masterdev);
_hurd_port_set (&_hurd_ports[INIT_PORT_PROC], proc);
- _hurd_proc_init (argv);
+ _hurd_proc_init (argv, NULL, 0);
/* Init knows intimately that we will be ready for messages
as soon as this returns. */
@@ -478,16 +515,9 @@ main (int argc, char **argv)
mach_port_deallocate (mach_task_self (), boot);
mach_port_deallocate (mach_task_self (), hostpriv);
- /* Allocate the hash tables. */
- err = ihash_create (&pending_users);
- assert_perror (err);
- err = ihash_create (&pending_servers);
- assert_perror (err);
-
/* Be a server. */
while (1)
ports_manage_port_operations_multithread (auth_bucket,
auth_demuxer,
- 30 * 1000, 0,
- 0, MACH_PORT_NULL);
+ 30 * 1000, 0, 0);
}