/* Verify user/group passwords and authenticate accordingly Copyright (C) 1997 Free Software Foundation, Inc. Written by Miles Bader 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 this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ #include #include #include #include #include #include #include #include #include #include #include "ugids.h" /* XXXX these are dummies to use until libc gets re-installed. */ error_t password_check_user (io_t a, uid_t b, const char *c, auth_t *d) { return ENOSYS; } error_t password_check_group (io_t a, uid_t b, const char *c, auth_t *d) { return ENOSYS; } /* Accumulated information from authentication various passwords. */ struct svma_state { /* The password server. */ file_t server; /* An auth port for each password that was verify by the server. */ auth_t *auths; size_t num_auths; }; /* Append the auth ports in AUTHS, of length NUM_AUTHS, to the auth port vector in SS, returning 0 if successful, or an error. */ static error_t svma_state_add_auths (struct svma_state *ss, const auth_t *auths, size_t num_auths) { auth_t *new = realloc (ss->auths, ss->num_auths + num_auths); if (new) { ss->auths = new; while (num_auths--) ss->auths[ss->num_auths++] = *auths++; return 0; } else return ENOMEM; } /* Get authentication from PASSWORD using the hurd password server. */ static error_t server_verify_make_auth (const char *password, uid_t id, int is_group, void *pwd_or_grp, void *hook) { auth_t auth; struct svma_state *svma_state = hook; error_t (*check) (io_t server, uid_t id, const char *passwd, auth_t *auth) = is_group ? password_check_user : password_check_group; error_t err = (*check) (svma_state->server, id, password, &auth); if (! err) /* PASSWORD checked out ok; the corresponding authentication is in AUTH. */ { err = svma_state_add_auths (svma_state, &auth, 1); if (err) mach_port_deallocate (mach_task_self (), auth); } return err; } /* Verify that we have the right to the ids in UGIDS, given that we already possess those in HAVE_UIDS and HAVE_GIDS (asking for passwords where necessary), and return corresponding authentication in AUTH; the auth ports in FROM, of length NUM_FROM, are used to supplement the auth port of the current process if necessary. 0 is returned if access should be allowed, otherwise EINVAL if an incorrect password was entered, or an error relating to resource failure. GETPASS_FN and GETPASS_HOOK are as for the idvec_verify function in . */ error_t ugids_verify_make_auth (const struct ugids *ugids, const struct idvec *have_uids, const struct idvec *have_gids, char *(*getpass_fn) (const char *prompt, uid_t id, int is_group, void *pwd_or_grp, void *hook), void *getpass_hook, const auth_t *from, size_t num_from, auth_t *auth) { error_t err; /* By default, get authentication from the password server. */ struct svma_state svma_state = { 0 }; error_t (*verify_fn) (const char *password, uid_t id, int is_group, void *pwd_or_grp, void *hook) = server_verify_make_auth; void *verify_hook = &svma_state; /* Try to open the hurd password server. */ svma_state.server = file_name_lookup (_SERVERS_PASSWORD, 0, 0); if (svma_state.server == MACH_PORT_NULL) /* Can't open the password server, try to use our own authority in the traditional unix manner. */ { verify_fn = 0; verify_hook = 0; } /* Check passwords. */ err = ugids_verify (ugids, have_uids, have_gids, getpass_fn, getpass_hook, verify_fn, verify_hook); if (! err) /* The user apparently has access to all the ids, try to grant the corresponding authentication. */ if (verify_fn) /* Merge the authentication we got from the password server into our result. */ { if (num_from > 0) /* Use FROM as well as the passwords to get authentication. */ err = svma_state_add_auths (&svma_state, from, num_from); if (! err) { auth_t cur_auth = getauth (); err = auth_makeauth (cur_auth, svma_state.auths, MACH_MSG_TYPE_COPY_SEND, svma_state.num_auths, ugids->eff_uids.ids, ugids->eff_uids.num, ugids->avail_uids.ids, ugids->avail_uids.num, ugids->eff_gids.ids, ugids->eff_gids.num, ugids->avail_gids.ids, ugids->avail_gids.num, auth); mach_port_deallocate (mach_task_self (), cur_auth); /* Avoid deallocating FROM when we clean up SVMA_STATE. */ svma_state.num_auths -= num_from; } } else /* Try to authenticate the old fashioned way... */ err = ugids_make_auth (ugids, from, num_from, auth); if (verify_fn) /* Clean up any left over state. */ { int i; /* Get rid of auth ports. */ for (i = 0; i < svma_state.num_auths; i++) mach_port_deallocate (mach_task_self (), svma_state.auths[i]); /* Close password server. */ mach_port_deallocate (mach_task_self (), svma_state.server); if (svma_state.num_auths > 0) free (svma_state.auths); } return err; }