diff options
Diffstat (limited to 'auth/auth.c')
-rw-r--r-- | auth/auth.c | 302 |
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); } |