summaryrefslogtreecommitdiff
path: root/auth
diff options
context:
space:
mode:
Diffstat (limited to 'auth')
-rw-r--r--auth/auth.c657
1 files changed, 657 insertions, 0 deletions
diff --git a/auth/auth.c b/auth/auth.c
new file mode 100644
index 00000000..5b51e5e7
--- /dev/null
+++ b/auth/auth.c
@@ -0,0 +1,657 @@
+/* Authentication server
+ Copyright (C) 1992, 1993, 1994 Free Software Foundation
+
+This file is part of the GNU Hurd.
+
+The GNU Hurd is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+The GNU Hurd 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the GNU Hurd; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Written by Michael I. Bushnell. */
+
+#include "auth_S.h"
+#include "auth_reply_U.h"
+#include <hurd/startup.h>
+#include <mach/error.h>
+#include <errno.h>
+#include <mach/mig_errors.h>
+#include <mach/notify.h>
+#include <stdlib.h>
+#include <hurd.h>
+#include <mach.h>
+#include <string.h>
+
+/* This represents a request from a call to auth_user_authenticate
+ which is waiting for the corresponding call. */
+struct saved_user
+{
+ struct saved_user *next; /* hash link */
+
+ mach_port_t rendezvous; /* rendezvous port */
+ mach_port_t rendezvous2; /* secondary rendezvous port */
+
+ struct apt *userid; /* to be passed to server */
+
+ mach_port_t reply; /* where to send the answer */
+ mach_msg_type_name_t reply_type; /* type of reply port */
+};
+
+/* This represents a request from a call to auth_server_authenticate
+ which is waiting for the corresponding call. */
+struct saved_server
+{
+ struct saved_server *next; /* hash link */
+
+ mach_port_t rendezvous; /* rendezvous port */
+ mach_port_t rendezvous2; /* secondary rendezvous port */
+
+ struct apt *server; /* who made the call? */
+ mach_port_t passthrough; /* new port to be given to user */
+
+ mach_port_t reply; /* where to send the answer */
+ mach_msg_type_name_t reply_type; /* type of reply port */
+};
+
+struct saved_user *userlist;
+struct saved_server *serverlist;
+
+struct apt
+{
+ mach_port_t port;
+ uid_t *gen_uids, *aux_uids;
+ uid_t *gen_gids, *aux_gids;
+ int ngen_uids, naux_uids, ngen_gids, naux_gids;
+ struct apt *next, **prevp;
+};
+
+struct apt *allapts;
+
+struct apt *getauthstruct (void);
+void auth_nosenders (struct apt *);
+
+mach_port_t auth_pset;
+
+/* Our version number */
+char *auth_version = "0.0 pre-alpha";
+
+
+/* Demultiplex an incoming message. */
+int
+request_server (mach_msg_header_t *inp,
+ mach_msg_header_t *outp)
+{
+ extern int auth_server (), notify_server ();
+
+ return (auth_server (inp, outp)
+ || notify_server (inp, outp));
+
+}
+
+void
+main (int argc, char **argv)
+{
+ mach_port_t boot;
+ struct apt *firstauth;
+ process_t proc;
+ extern int mach_msg_server ();
+ mach_port_t hostpriv, masterdev;
+
+ mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_PORT_SET,
+ &auth_pset);
+
+ task_get_bootstrap_port (mach_task_self (), &boot);
+
+ firstauth = getauthstruct ();
+ firstauth->gen_uids = malloc (sizeof (uid_t) * 1);
+ firstauth->aux_uids = malloc (sizeof (uid_t) * 2);
+ firstauth->gen_gids = malloc (sizeof (uid_t) * 1);
+ firstauth->aux_gids = malloc (sizeof (uid_t) * 2);
+ firstauth->gen_uids[0] = 0;
+ firstauth->aux_uids[0] = firstauth->aux_uids[1] = 0;
+ firstauth->gen_gids[0] = 0;
+ firstauth->aux_gids[0] = firstauth->aux_gids[1] = 0;
+ firstauth->ngen_uids = firstauth->ngen_gids = 1;
+ firstauth->naux_uids = firstauth->naux_gids = 2;
+
+ startup_authinit (boot, firstauth->port, MACH_MSG_TYPE_MAKE_SEND, &proc);
+ proc_getprivports (proc, &hostpriv, &masterdev);
+ proc_register_version (proc, hostpriv, "auth", HURD_RELEASE, auth_version);
+ mach_port_deallocate (mach_task_self (), masterdev);
+ _hurd_port_set (&_hurd_ports[INIT_PORT_PROC], proc);
+ _hurd_proc_init (argv);
+
+ /* Init knows intimately that we will be ready for messages
+ as soon as this returns. */
+ startup_essential_task (boot, mach_task_self (), MACH_PORT_NULL, "auth",
+ hostpriv);
+ mach_port_deallocate (mach_task_self (), boot);
+ mach_port_deallocate (mach_task_self (), hostpriv);
+
+ while (1)
+ mach_msg_server (request_server, vm_page_size * 2, auth_pset);
+}
+
+
+/* Server routines: */
+
+/* Called when an auth port has no more senders. */
+error_t
+_S_do_mach_notify_no_senders (mach_port_t notify,
+ mach_port_mscount_t mscount)
+{
+ auth_nosenders (convert_auth_to_apt (notify));
+ return 0;
+}
+
+/* A given auth handle has no more senders; deallocate all state referring
+ to this handle. */
+void
+auth_nosenders (struct apt *auth)
+{
+ /* Remove all references to this from the saved lists */
+ {
+ struct saved_user *s, **prevp, *tmp;
+ for (s = userlist, prevp = &userlist; s;)
+ {
+ if (s->userid == auth)
+ {
+ *prevp = s->next;
+ tmp = s;
+ prevp = &s->next;
+ s = s->next;
+
+ mach_port_deallocate (mach_task_self (), tmp->rendezvous);
+ mach_port_deallocate (mach_task_self (), tmp->reply);
+ free (tmp);
+ }
+ else
+ {
+ prevp = &s->next;
+ s = s->next;
+ }
+ }
+ }
+ {
+ struct saved_server *s, **prevp, *tmp;
+ for (s = serverlist, prevp = &serverlist; s;)
+ {
+ if (s->server == auth)
+ {
+ *prevp = s->next;
+ tmp = s;
+ prevp = &s->next;
+ s = s->next;
+
+ mach_port_deallocate (mach_task_self (), tmp->rendezvous);
+ mach_port_deallocate (mach_task_self (), tmp->reply);
+ if (tmp->passthrough)
+ mach_port_deallocate (mach_task_self (), tmp->passthrough);
+ free (tmp);
+ }
+ else
+ {
+ prevp = &s->next;
+ s = s->next;
+ }
+ }
+ }
+
+ /* Take off allapts list */
+ *auth->prevp = auth->next;
+ if (auth->next)
+ auth->next->prevp = auth->prevp;
+
+ /* Delete its storage and port. */
+ mach_port_mod_refs (mach_task_self (), auth->port,
+ MACH_PORT_RIGHT_RECEIVE, -1);
+ free (auth->gen_uids);
+ free (auth->aux_uids);
+ free (auth->gen_gids);
+ free (auth->aux_gids);
+ free (auth);
+}
+
+
+/* Return true iff TEST is a genuine or auxiliary group id in AUTH. */
+inline int
+groupmember (gid_t test,
+ struct apt *auth)
+{
+ int i;
+
+ for (i = 0; i < auth->ngen_gids; i++)
+ if (test == auth->gen_gids[i])
+ return 1;
+ for (i = 0; i < auth->naux_gids; i++)
+ if (test == auth->aux_gids[i])
+ return 1;
+ return 0;
+}
+
+/* Return true iff TEST is a genuine or auxiliary uid in AUTH. */
+inline int
+isuid (uid_t test,
+ struct apt *auth)
+{
+ int i;
+
+ for (i = 0; i < auth->ngen_uids; i++)
+ if (test == auth->gen_uids[i])
+ return 1;
+ for (i = 0; i < auth->naux_uids; i++)
+ if (test == auth->aux_uids[i])
+ return 1;
+ return 0;
+}
+
+/* Return true if the the given auth handle is root (uid 0). */
+inline int
+isroot (struct apt *idblock)
+{
+ return isuid (0, idblock);
+}
+
+/* Allocate a new auth handle, complete with port. */
+struct apt *
+getauthstruct ()
+{
+ struct apt *newauth;
+ mach_port_t unused;
+
+ newauth = malloc (sizeof (struct apt));
+ mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE,
+ &newauth->port);
+ mach_port_request_notification (mach_task_self (), newauth->port,
+ MACH_NOTIFY_NO_SENDERS, 1, newauth->port,
+ MACH_MSG_TYPE_MAKE_SEND_ONCE, &unused);
+ mach_port_move_member (mach_task_self (), newauth->port, auth_pset);
+ newauth->next = allapts;
+ if (newauth->next)
+ newauth->next->prevp = &newauth->next;
+ newauth->prevp = &allapts;
+ allapts = newauth;
+ return newauth;
+}
+
+
+
+/* Client requests */
+
+/* Implement auth_getids as described in <hurd/auth.defs>. */
+kern_return_t
+S_auth_getids (struct apt *auth,
+ uid_t **gen_uids,
+ u_int *ngen_uids,
+ uid_t **aux_uids,
+ u_int *naux_uids,
+ uid_t **gen_gids,
+ u_int *ngen_gids,
+ uid_t **aux_gids,
+ u_int *naux_gids)
+{
+ if (!auth)
+ return EOPNOTSUPP;
+
+ if (auth->ngen_uids > *ngen_uids)
+ *gen_uids = auth->gen_uids;
+ else
+ bcopy (auth->gen_uids, *gen_uids, sizeof (uid_t) * auth->ngen_uids);
+ *ngen_uids = auth->ngen_uids;
+
+ if (auth->naux_uids > *naux_uids)
+ *aux_uids = auth->aux_uids;
+ else
+ bcopy (auth->aux_uids, *aux_uids, sizeof (uid_t) * auth->naux_uids);
+ *naux_uids = auth->naux_uids;
+
+ if (auth->ngen_gids > *ngen_gids)
+ *gen_gids = auth->gen_gids;
+ else
+ bcopy (auth->gen_gids, *gen_gids, sizeof (uid_t) * auth->ngen_gids);
+ *ngen_gids = auth->ngen_gids;
+
+ if (auth->naux_gids > *naux_gids)
+ *aux_gids = auth->aux_gids;
+ else
+ bcopy (auth->aux_gids, *aux_gids, sizeof (uid_t) * auth->naux_gids);
+ *naux_gids = auth->naux_gids;
+
+ return 0;
+}
+
+/* Implement auth_makeauth as described in <hurd/auth.defs>. */
+kern_return_t
+S_auth_makeauth (struct apt *auth,
+ mach_port_t *authpts,
+ u_int nauths,
+ uid_t *gen_uids,
+ u_int ngen_uids,
+ uid_t *aux_uids,
+ u_int naux_uids,
+ uid_t *gen_gids,
+ u_int ngen_gids,
+ uid_t *aux_gids,
+ u_int naux_gids,
+ mach_port_t *newhandle)
+{
+ int i, j;
+ struct apt *newauth;
+ struct apt **auths = alloca ((nauths + 1) * sizeof (struct apt *));
+ int hasroot = 0;
+
+ if (!auth)
+ return EOPNOTSUPP;
+ auths[0] = auth;
+
+ for (i = 0; i < nauths; i++)
+ if (!(auths[i + 1] = convert_auth_to_apt (authpts[i])))
+ return EINVAL;
+
+ nauths++;
+
+ for (i = 0; i < nauths; i++)
+ if (isroot (auth))
+ {
+ hasroot = 1;
+ break;
+ }
+
+ if (!hasroot)
+ {
+ int has_it;
+
+ for (i = 0; i < ngen_uids; i++)
+ {
+ has_it = 0;
+ for (j = 0; j < nauths; j++)
+ if (isuid (gen_uids[i], auths[j]))
+ {
+ has_it = 1;
+ break;
+ }
+ if (!has_it)
+ return EPERM;
+ }
+
+ for (i = 0; i < naux_uids; i++)
+ {
+ has_it = 0;
+ for (j = 0; j < nauths; j++)
+ if (isuid (aux_uids[i], auths[j]))
+ {
+ has_it = 1;
+ break;
+ }
+ if (!has_it)
+ return EPERM;
+ }
+
+ for (i = 0; i < ngen_gids; i++)
+ {
+ has_it = 0;
+ for (j = 0; j < nauths; j++)
+ if (groupmember (gen_gids[i], auths[j]))
+ {
+ has_it = 1;
+ break;
+ }
+ if (!has_it)
+ return EPERM;
+ }
+
+ for (i = 0; i < naux_gids; i++)
+ {
+ has_it = 0;
+ for (j = 0; j < nauths; j++)
+ if (groupmember (aux_gids[i], auths[j]))
+ {
+ has_it = 1;
+ break;
+ }
+ if (!has_it)
+ return EPERM;
+ }
+ }
+
+ for (j = 0; j < nauths - 1; j++)
+ mach_port_deallocate (mach_task_self (), authpts[j]);
+
+ newauth = getauthstruct ();
+ newauth->gen_uids = malloc (sizeof (uid_t) * ngen_uids);
+ newauth->aux_uids = malloc (sizeof (uid_t) * naux_uids);
+ newauth->gen_gids = malloc (sizeof (uid_t) * ngen_gids);
+ newauth->aux_gids = malloc (sizeof (uid_t) * naux_gids);
+ newauth->ngen_uids = ngen_uids;
+ newauth->naux_uids = naux_uids;
+ newauth->ngen_gids = ngen_gids;
+ newauth->naux_gids = naux_gids;
+ bcopy (gen_uids, newauth->gen_uids, ngen_uids * sizeof (uid_t));
+ bcopy (aux_uids, newauth->aux_uids, naux_uids * sizeof (uid_t));
+ bcopy (gen_gids, newauth->gen_gids, ngen_gids * sizeof (uid_t));
+ bcopy (aux_gids, newauth->aux_gids, naux_gids * sizeof (uid_t));
+
+ *newhandle = newauth->port;
+ return 0;
+}
+
+/* Implement auth_user_authenticate as described in <hurd/auth.defs>. */
+kern_return_t
+S_auth_user_authenticate (struct apt *userauth,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_porttype,
+ mach_port_t rendezvous,
+ mach_port_t rendezvous2,
+ mach_port_t *newport,
+ mach_msg_type_name_t *newporttype)
+{
+ struct saved_server *sv, **spp;
+ struct saved_user *u;
+
+ if (!userauth)
+ return EOPNOTSUPP;
+
+ /* Look for this port in the server list. */
+ for (sv = serverlist, spp = &serverlist; sv;)
+ {
+ if (sv->rendezvous == rendezvous && sv->rendezvous2 == rendezvous2)
+ {
+ *spp = sv->next;
+ break;
+ }
+ else
+ {
+ spp = &sv->next;
+ sv = sv->next;
+ }
+ }
+
+ if (sv)
+ {
+ *newport = sv->passthrough;
+ *newporttype = MACH_MSG_TYPE_MOVE_SEND;
+ auth_server_authenticate_reply (sv->reply, sv->reply_type, 0,
+ userauth->gen_uids, userauth->ngen_uids,
+ userauth->aux_uids, userauth->naux_uids,
+ userauth->gen_gids, userauth->ngen_uids,
+ userauth->aux_gids, userauth->naux_uids);
+ free (sv);
+
+ /* Drop both rights from the call. */
+ mach_port_mod_refs (mach_task_self (), rendezvous, MACH_PORT_RIGHT_SEND,
+ -2);
+ mach_port_mod_refs (mach_task_self (), rendezvous2, MACH_PORT_RIGHT_SEND,
+ -2);
+ return 0;
+ }
+
+ /* User got here first. */
+ u = malloc (sizeof (struct saved_user));
+
+ u->rendezvous = rendezvous;
+ u->rendezvous2 = rendezvous2;
+ u->userid = userauth;
+
+ u->reply = reply;
+ u->reply_type = reply_porttype;
+
+ u->next = userlist;
+ userlist = u;
+
+ return MIG_NO_REPLY;
+}
+
+/* Implement auth_server_authenticate as described in <hurd/auth.defs>. */
+kern_return_t
+S_auth_server_authenticate (struct apt *serverauth,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_porttype,
+ mach_port_t rendezvous,
+ mach_port_t rendezvous2,
+ mach_port_t newport,
+ uid_t **gen_uids,
+ u_int *ngen_uids,
+ uid_t **aux_uids,
+ u_int *naux_uids,
+ uid_t **gen_gids,
+ u_int *ngen_gids,
+ uid_t **aux_gids,
+ u_int *naux_gids)
+{
+ struct saved_user *su, **sup;
+ struct saved_server *v;
+ struct apt *uauth;
+
+ if (!serverauth)
+ return EOPNOTSUPP;
+
+ /* Look for this port in the user list. */
+ for (su = userlist, sup = &userlist; su;)
+ {
+ if (su->rendezvous == rendezvous && su->rendezvous2 == rendezvous2)
+ {
+ *sup = su->next;
+ break;
+ }
+ else
+ {
+ sup = &su->next;
+ su = su->next;
+ }
+ }
+ if (su)
+ {
+ auth_user_authenticate_reply (su->reply, su->reply_type, 0, newport,
+ MACH_MSG_TYPE_MOVE_SEND);
+
+ uauth = su->userid;
+
+ if (uauth->ngen_uids > *ngen_uids)
+ *gen_uids = uauth->gen_uids;
+ else
+ bcopy (uauth->gen_uids, *gen_uids, sizeof (uid_t) * uauth->ngen_uids);
+ *ngen_uids = uauth->ngen_uids;
+
+ if (uauth->naux_uids > *naux_uids)
+ *aux_uids = uauth->aux_uids;
+ else
+ bcopy (uauth->aux_uids, *aux_uids, sizeof (uid_t) * uauth->naux_uids);
+ *naux_uids = uauth->naux_uids;
+
+ if (uauth->ngen_gids > *ngen_gids)
+ *gen_gids = uauth->gen_gids;
+ else
+ bcopy (uauth->gen_gids, *gen_gids, sizeof (uid_t) * uauth->ngen_gids);
+ *ngen_gids = uauth->ngen_gids;
+
+ if (uauth->naux_gids > *naux_gids)
+ *aux_gids = uauth->aux_gids;
+ else
+ bcopy (uauth->aux_gids, *aux_gids, sizeof (uid_t) * uauth->naux_gids);
+ *naux_gids = uauth->naux_gids;
+
+ free (su);
+
+ mach_port_mod_refs (mach_task_self (), rendezvous, MACH_PORT_RIGHT_SEND,
+ -2);
+ mach_port_mod_refs (mach_task_self (), rendezvous2, MACH_PORT_RIGHT_SEND,
+ -2);
+ return 0;
+ }
+
+ /* Server got here first. */
+ v = malloc (sizeof (struct saved_server));
+
+ v->rendezvous = rendezvous;
+ v->rendezvous2 = rendezvous2;
+ v->passthrough = newport;
+
+ v->reply = reply;
+ v->reply_type = reply_porttype;
+
+ v->next = serverlist;
+ serverlist = v;
+
+ return MIG_NO_REPLY;
+}
+
+/* Convert an auth port into an auth handle structure. */
+struct apt *
+convert_auth_to_apt (auth_t auth)
+{
+ struct apt *a;
+ for (a = allapts; a; a = a->next)
+ if (a->port == auth)
+ return a;
+ return 0;
+}
+
+/* Unneeded notification stubs: */
+error_t
+_S_do_mach_notify_port_deleted (mach_port_t notify,
+ mach_port_seqno_t seqno,
+ mach_port_t name)
+{
+ return 0;
+}
+
+error_t
+_S_do_mach_notify_msg_accepted (mach_port_t notify,
+ mach_port_seqno_t seqno,
+ mach_port_t name)
+{
+ return 0;
+}
+
+error_t
+_S_do_mach_notify_port_destroyed (mach_port_t notify,
+ mach_port_seqno_t seqno,
+ mach_port_t name)
+{
+ return 0;
+}
+
+error_t
+_S_do_mach_notify_send_once (mach_port_t notify,
+ mach_port_seqno_t seqno)
+{
+ return 0;
+}
+
+error_t
+_S_do_mach_notify_dead_name (mach_port_t notify,
+ mach_port_seqno_t seqno,
+ mach_port_t name)
+{
+ return 0;
+}
+