1 /***************************************************************************
2 *
3 * util_helper.c - HAL utilities for helper (as e.g. prober/addons) et al.
4 *
5 * Copyright (C) 2006 David Zeuthen, <david@fubar.dk>
6 *
7 * Licensed under the Academic Free License version 2.1
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 *
23 **************************************************************************/
24
25 #ifdef HAVE_CONFIG_H
26 # include <config.h>
27 #endif
28
29 #include <grp.h>
30 #include <stdarg.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <sys/time.h>
34 #include <time.h>
35 #include <pwd.h>
36 #include <unistd.h>
37
38 #include "logger.h"
39
40 #include "util_helper.h"
41
42 #ifdef __linux__
43 extern char **environ;
44 #endif
45
46 static char **argv_buffer = NULL;
47 static size_t argv_size = 0;
48
49 #ifdef sun
50 #include <priv.h>
51 void
drop_privileges(int keep_auxgroups)52 drop_privileges(int keep_auxgroups)
53 {
54 priv_set_t *pPrivSet;
55
56 /*
57 * Start with the 'basic' privilege set and then remove any
58 * of the 'basic' privileges that will not be needed.
59 */
60 if ((pPrivSet = priv_allocset()) == NULL) {
61 return;
62 }
63
64 /*
65 * Establish the basic set of privileges.
66 * Note: fork/exec required for libdevinfo devlink
67 * interfaces are included in the basic set.
68 */
69 priv_basicset(pPrivSet);
70
71 /* Clear privileges we will not need from the 'basic' set */
72 (void) priv_delset(pPrivSet, PRIV_FILE_LINK_ANY);
73 (void) priv_delset(pPrivSet, PRIV_PROC_INFO);
74 (void) priv_delset(pPrivSet, PRIV_PROC_SESSION);
75
76 /* for sysevent need to be root and have this privilege */
77 (void) priv_addset(pPrivSet, PRIV_SYS_CONFIG);
78
79 /* need proc_audit privilege */
80 (void) priv_addset(pPrivSet, PRIV_PROC_AUDIT);
81
82 /* Set the permitted privilege set. */
83 (void) setppriv(PRIV_SET, PRIV_PERMITTED, pPrivSet);
84
85 /* Set the limit privilege set. */
86 (void) setppriv(PRIV_SET, PRIV_LIMIT, pPrivSet);
87
88 priv_freeset(pPrivSet);
89 }
90 #else /* !sun */
91
92 /** Drop root privileges: Set the running user id to HAL_USER and
93 * group to HAL_GROUP, and optionally retain auxiliary groups of HAL_USER.
94 */
95 void
drop_privileges(int keep_auxgroups)96 drop_privileges (int keep_auxgroups)
97 {
98 struct passwd *pw = NULL;
99 struct group *gr = NULL;
100
101 /* determine user id */
102 pw = getpwnam (HAL_USER);
103 if (!pw) {
104 HAL_DEBUG (("drop_privileges: user " HAL_USER " does not exist"));
105 exit (-1);
106 }
107
108 /* determine primary group id */
109 gr = getgrnam (HAL_GROUP);
110 if (!gr) {
111 HAL_DEBUG (("drop_privileges: group " HAL_GROUP " does not exist"));
112 exit (-1);
113 }
114
115 if (keep_auxgroups) {
116 if (initgroups (HAL_USER, gr->gr_gid)) {
117 HAL_DEBUG(("drop_privileges: could not initialize groups"));
118 exit (-1);
119 }
120 }
121
122 if (setgid (gr->gr_gid)) {
123 HAL_DEBUG (("drop_privileges: could not set group id"));
124 exit (-1);
125 }
126
127 if (setuid (pw->pw_uid)) {
128 HAL_DEBUG (("drop_privileges: could not set user id"));
129 exit (-1);
130 }
131 }
132 #endif /* !sun */
133
134 void
hal_set_proc_title_init(int argc,char * argv[])135 hal_set_proc_title_init (int argc, char *argv[])
136 {
137 #ifdef __linux__
138 unsigned int i;
139 char **new_environ, *endptr;
140
141 /* This code is really really ugly. We make some memory layout
142 * assumptions and reuse the environment array as memory to store
143 * our process title in */
144
145 for (i = 0; environ[i] != NULL; i++)
146 ;
147
148 endptr = i ? environ[i-1] + strlen (environ[i-1]) : argv[argc-1] + strlen (argv[argc-1]);
149
150 argv_buffer = argv;
151 argv_size = endptr - argv_buffer[0];
152
153 /* Make a copy of environ */
154
155 new_environ = malloc (sizeof(char*) * (i + 1));
156 for (i = 0; environ[i] != NULL; i++)
157 new_environ[i] = strdup (environ[i]);
158 new_environ[i] = NULL;
159
160 environ = new_environ;
161 #endif
162 }
163
164 /* this code borrowed from avahi-daemon's setproctitle.c (LGPL v2) */
165 void
hal_set_proc_title(const char * format,...)166 hal_set_proc_title (const char *format, ...)
167 {
168 #ifdef __linux__
169 size_t len;
170 va_list ap;
171
172 if (argv_buffer == NULL)
173 goto out;
174
175 va_start (ap, format);
176 vsnprintf (argv_buffer[0], argv_size, format, ap);
177 va_end (ap);
178
179 len = strlen (argv_buffer[0]);
180
181 memset (argv_buffer[0] + len, 0, argv_size - len);
182 argv_buffer[1] = NULL;
183 out:
184 ;
185 #endif
186 }
187
188