/* Hurd standard password server. Copyright (C) 1999, 2013 Free Software Foundation Written by Mark Kettenis. 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 #include #include "password_S.h" const char *argp_program_version = STANDARD_HURD_VERSION (password); /* Port bucket we service requests on. */ struct port_bucket *port_bucket; /* Trivfs hooks. */ int trivfs_fstype = FSTYPE_MISC; int trivfs_fsid = 0; int trivfs_support_read = 0; int trivfs_support_write = 0; int trivfs_support_exec = 0; int trivfs_allow_open = 0; struct port_class *trivfs_protid_portclasses[1]; struct port_class *trivfs_cntl_portclasses[1]; int trivfs_protid_nportclasses = 1; int trivfs_cntl_nportclasses = 1; static int password_demuxer (mach_msg_header_t *inp, mach_msg_header_t *outp) { extern int password_server (mach_msg_header_t *inp, mach_msg_header_t *outp); return password_server (inp, outp) || trivfs_demuxer (inp, outp); } int main (int argc, char *argv[]) { error_t err; mach_port_t bootstrap; struct trivfs_control *fsys; const struct argp argp = { 0, 0, 0, "Hurd standard password server." }; argp_parse (&argp, argc, argv, 0, 0, 0); task_get_bootstrap_port (mach_task_self (), &bootstrap); if (bootstrap == MACH_PORT_NULL) error (1, 0, "must be started as a translator"); port_bucket = ports_create_bucket (); trivfs_cntl_portclasses[0] = ports_create_class (trivfs_clean_cntl, 0); trivfs_protid_portclasses[0] = ports_create_class (trivfs_clean_protid, 0); /* Reply to our parent. */ err = trivfs_startup (bootstrap, 0, trivfs_cntl_portclasses[0], port_bucket, trivfs_protid_portclasses[0], port_bucket, &fsys); mach_port_deallocate (mach_task_self (), bootstrap); if (err) error (3, err, "Contacting parent"); /* Launch. */ do ports_manage_port_operations_multithread (port_bucket, password_demuxer, 2 * 60 * 1000, 10 * 60 * 1000, 0); /* That returns when 10 minutes pass without an RPC. Try shutting down as if sent fsys_goaway; if we have any users who need us to stay around, this returns EBUSY and we loop to service more RPCs. */ while (trivfs_goaway (fsys, 0)); return 0; } void trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st) { } error_t trivfs_goaway (struct trivfs_control *fsys, int flags) { int count; /* Stop new requests. */ ports_inhibit_class_rpcs (trivfs_cntl_portclasses[0]); ports_inhibit_class_rpcs (trivfs_protid_portclasses[0]); /* Are there any extant user ports for the /servers/password file? */ count = ports_count_class (trivfs_protid_portclasses[0]); if (count > 0 && !(flags & FSYS_GOAWAY_FORCE)) { /* We won't go away, so start things going again... */ ports_enable_class (trivfs_protid_portclasses[0]); ports_resume_class_rpcs (trivfs_cntl_portclasses[0]); ports_resume_class_rpcs (trivfs_protid_portclasses[0]); return EBUSY; } exit (0); } /* Implement password_check_user as described in . */ kern_return_t S_password_check_user (struct trivfs_protid *cred, uid_t user, char *pw, mach_port_t *port, mach_msg_type_name_t *port_type) { struct ugids ugids = UGIDS_INIT; auth_t auth; error_t err; char *getpass (const char *prompt, uid_t id, int is_group, void *pwd_or_group, void *hook) { assert (! is_group && id == user); return strdup (pw); } if (! cred) return EOPNOTSUPP; if (cred->pi.bucket != port_bucket || cred->pi.class != trivfs_protid_portclasses[0]) { ports_port_deref (cred); return EOPNOTSUPP; } /* Verify password. */ err = ugids_add_user (&ugids, user, 1); if (!err) err = ugids_verify (&ugids, 0, 0, getpass, 0, 0, 0); if (!err) { auth = getauth (); err = auth_makeauth (auth, 0, MACH_MSG_TYPE_COPY_SEND, 0, 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, port); mach_port_deallocate (mach_task_self (), auth); *port_type = MACH_MSG_TYPE_MOVE_SEND; } ugids_fini (&ugids); return err; } /* Implement password_check_group as described in . */ kern_return_t S_password_check_group (struct trivfs_protid *cred, uid_t group, char *pw, mach_port_t *port, mach_msg_type_name_t *port_type) { struct ugids ugids = UGIDS_INIT; auth_t auth; error_t err; char *getpass (const char *prompt, uid_t id, int is_group, void *pwd_or_group, void *hook) { assert (is_group && id == group); return strdup (pw); } if (! cred) return EOPNOTSUPP; if (cred->pi.bucket != port_bucket || cred->pi.class != trivfs_protid_portclasses[0]) { ports_port_deref (cred); return EOPNOTSUPP; } /* Verify password. */ err = ugids_add_gid (&ugids, group, 1); if (!err) err = ugids_verify (&ugids, 0, 0, getpass, 0, 0, 0); if (!err) { auth = getauth (); err = auth_makeauth (auth, 0, MACH_MSG_TYPE_COPY_SEND, 0, 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, port); mach_port_deallocate (mach_task_self (), auth); *port_type = MACH_MSG_TYPE_MOVE_SEND; } ugids_fini (&ugids); return err; }