1/*++
2/* NAME
3/*	chroot_uid 3
4/* SUMMARY
5/*	limit possible damage a process can do
6/* SYNOPSIS
7/*	#include <chroot_uid.h>
8/*
9/*	void	chroot_uid(root_dir, user_name)
10/*	const char *root_dir;
11/*	const char *user_name;
12/* DESCRIPTION
13/*	\fBchroot_uid\fR changes the process root to \fIroot_dir\fR and
14/*	changes process privileges to those of \fIuser_name\fR.
15/* DIAGNOSTICS
16/*	System call errors are reported via the msg(3) interface.
17/*	All errors are fatal.
18/* LICENSE
19/* .ad
20/* .fi
21/*	The Secure Mailer license must be distributed with this software.
22/* AUTHOR(S)
23/*	Wietse Venema
24/*	IBM T.J. Watson Research
25/*	P.O. Box 704
26/*	Yorktown Heights, NY 10598, USA
27/*--*/
28
29/* System library. */
30
31#include <sys_defs.h>
32#include <pwd.h>
33#include <unistd.h>
34#include <grp.h>
35
36/* Utility library. */
37
38#include "msg.h"
39#include "chroot_uid.h"
40
41/* chroot_uid - restrict the damage that this program can do */
42
43void    chroot_uid(const char *root_dir, const char *user_name)
44{
45    struct passwd *pwd;
46    uid_t   uid;
47    gid_t   gid;
48
49    /*
50     * Look up the uid/gid before entering the jail, and save them so they
51     * can't be clobbered. Set up the primary and secondary groups.
52     */
53    if (user_name != 0) {
54	if ((pwd = getpwnam(user_name)) == 0)
55	    msg_fatal("unknown user: %s", user_name);
56	uid = pwd->pw_uid;
57	gid = pwd->pw_gid;
58	if (setgid(gid) < 0)
59	    msg_fatal("setgid(%ld): %m", (long) gid);
60	if (initgroups(user_name, gid) < 0)
61	    msg_fatal("initgroups: %m");
62    }
63
64    /*
65     * Enter the jail.
66     */
67    if (root_dir) {
68	if (chroot(root_dir))
69	    msg_fatal("chroot(%s): %m", root_dir);
70	if (chdir("/"))
71	    msg_fatal("chdir(/): %m");
72    }
73
74    /*
75     * Drop the user privileges.
76     */
77    if (user_name != 0)
78	if (setuid(uid) < 0)
79	    msg_fatal("setuid(%ld): %m", (long) uid);
80
81    /*
82     * Give the desperate developer a clue of what is happening.
83     */
84    if (msg_verbose > 1)
85	msg_info("chroot %s user %s",
86		 root_dir ? root_dir : "(none)",
87		 user_name ? user_name : "(none)");
88}
89