Commit 6b5d5c5e 6b5d5c5ea1edd68da30f082c17aa308589a37b82 by Sergey Poznyakoff

New file.

1 parent 48cfc81c
1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2008 Free Software Foundation, Inc.
3
4 GNU Mailutils is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 GNU Mailutils is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with GNU Mailutils; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17 MA 02110-1301 USA */
18
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
22 #include <stdlib.h>
23 #include <string.h>
24 #include <pwd.h>
25 #include <grp.h>
26 #include <unistd.h>
27 #include <mailutils/assoc.h>
28 #include <mailutils/errno.h>
29 #include <mailutils/error.h>
30 #include <mailutils/errno.h>
31 #include <mailutils/nls.h>
32 #include <mailutils/list.h>
33 #include <mailutils/iterator.h>
34 #include <xalloc.h>
35
36 /* Switch to the given UID/GID */
37 int
38 mu_switch_to_privs (uid_t uid, gid_t gid, mu_list_t retain_groups)
39 {
40 int rc = 0;
41 gid_t *emptygidset;
42 size_t size = 1, j = 1;
43 mu_iterator_t itr;
44
45 if (uid == 0)
46 return 0;
47
48 /* Create a list of supplementary groups */
49 mu_list_count (retain_groups, &size);
50 size++;
51 emptygidset = xmalloc (size * sizeof emptygidset[0]);
52 emptygidset[0] = gid ? gid : getegid ();
53
54 if (mu_list_get_iterator (retain_groups, &itr) == 0)
55 {
56 for (mu_iterator_first (itr);
57 !mu_iterator_is_done (itr); mu_iterator_next (itr))
58 mu_iterator_current (itr,
59 (void **)(emptygidset + j++));
60 mu_iterator_destroy (&itr);
61 }
62
63 /* Reset group permissions */
64 if (geteuid () == 0 && setgroups (j, emptygidset))
65 {
66 mu_error(_("setgroups(1, %lu) failed: %s"),
67 (unsigned long) emptygidset[0], mu_strerror (errno));
68 rc = 1;
69 }
70 free (emptygidset);
71
72 /* Switch to the user's gid. On some OSes the effective gid must
73 be reset first */
74
75 #if defined(HAVE_SETEGID)
76 if ((rc = setegid (gid)) < 0)
77 mu_error (_("setegid(%lu) failed: %s"),
78 (unsigned long) gid, mu_strerror (errno));
79 #elif defined(HAVE_SETREGID)
80 if ((rc = setregid (gid, gid)) < 0)
81 mu_error (_("setregid(%lu,%lu) failed: %s"),
82 (unsigned long) gid, (unsigned long) gid,
83 mu_strerror (errno));
84 #elif defined(HAVE_SETRESGID)
85 if ((rc = setresgid (gid, gid, gid)) < 0)
86 mu_error (_("setresgid(%lu,%lu,%lu) failed: %s"),
87 (unsigned long) gid,
88 (unsigned long) gid,
89 (unsigned long) gid,
90 mu_strerror (errno));
91 #endif
92
93 if (rc == 0 && gid != 0)
94 {
95 if ((rc = setgid (gid)) < 0 && getegid () != gid)
96 mu_error (_("setgid(%lu) failed: %s"),
97 (unsigned long) gid, mu_strerror (errno));
98 if (rc == 0 && getegid () != gid)
99 {
100 mu_error (_("Cannot set effective gid to %lu"),
101 (unsigned long) gid);
102 rc = 1;
103 }
104 }
105
106 /* Now reset uid */
107 if (rc == 0 && uid != 0)
108 {
109 uid_t euid;
110
111 if (setuid (uid) || geteuid () != uid
112 || (getuid () != uid && (geteuid () == 0 || getuid () == 0)))
113 {
114 #if defined(HAVE_SETREUID)
115 if (geteuid () != uid)
116 {
117 if (setreuid (uid, -1) < 0)
118 {
119 mu_error (_("setreuid(%lu,-1) failed: %s"),
120 (unsigned long) uid,
121 mu_strerror (errno));
122 rc = 1;
123 }
124 if (setuid (uid) < 0)
125 {
126 mu_error (_("second setuid(%lu) failed: %s"),
127 (unsigned long) uid, mu_strerror (errno));
128 rc = 1;
129 }
130 } else
131 #endif
132 {
133 mu_error (_("setuid(%lu) failed: %s"),
134 (unsigned long) uid,
135 mu_strerror (errno));
136 rc = 1;
137 }
138 }
139
140 euid = geteuid ();
141 if (uid != 0 && setuid (0) == 0)
142 {
143 mu_error (_("seteuid(0) succeeded when it should not"));
144 rc = 1;
145 }
146 else if (uid != euid && setuid (euid) == 0)
147 {
148 mu_error (_("Cannot drop non-root setuid privileges"));
149 rc = 1;
150 }
151 }
152 return rc;
153 }
154
155