/src/proftpd/src/proctitle.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * ProFTPD - FTP server daemon |
3 | | * Copyright (c) 2007-2018 The ProFTPD Project team |
4 | | * |
5 | | * This program is free software; you can redistribute it and/or modify |
6 | | * it under the terms of the GNU General Public License as published by |
7 | | * the Free Software Foundation; either version 2 of the License, or |
8 | | * (at your option) any later version. |
9 | | * |
10 | | * This program is distributed in the hope that it will be useful, |
11 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | | * GNU General Public License for more details. |
14 | | * |
15 | | * You should have received a copy of the GNU General Public License |
16 | | * along with this program; if not, write to the Free Software |
17 | | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. |
18 | | * |
19 | | * As a special exemption, The ProFTPD Project team and other respective |
20 | | * copyright holders give permission to link this program with OpenSSL, and |
21 | | * distribute the resulting executable, without including the source code for |
22 | | * OpenSSL in the source distribution. |
23 | | */ |
24 | | |
25 | | /* Proctitle management */ |
26 | | |
27 | | #include "conf.h" |
28 | | |
29 | | #if PF_ARGV_TYPE == PF_ARGV_PSTAT |
30 | | # ifdef HAVE_SYS_PSTAT_H |
31 | | # include <sys/pstat.h> |
32 | | # else |
33 | | # undef PF_ARGV_TYPE |
34 | | # define PF_ARGV_TYPE PF_ARGV_WRITEABLE |
35 | | # endif /* HAVE_SYS_PSTAT_H */ |
36 | | #endif /* PF_ARGV_PSTAT */ |
37 | | |
38 | | #if PF_ARGV_TYPE == PF_ARGV_PSSTRINGS |
39 | | # ifndef HAVE_SYS_EXEC_H |
40 | | # undef PF_ARGV_TYPE |
41 | | # define PF_ARGV_TYPE PF_ARGV_WRITEABLE |
42 | | # else |
43 | | # include <machine/vmparam.h> |
44 | | # include <sys/exec.h> |
45 | | # endif /* HAVE_SYS_EXEC_H */ |
46 | | #endif /* PF_ARGV_PSSTRINGS */ |
47 | | |
48 | | #ifdef HAVE___PROGNAME |
49 | | extern char *__progname, *__progname_full; |
50 | | #endif /* HAVE___PROGNAME */ |
51 | | extern char **environ; |
52 | | |
53 | | static char **prog_argv = NULL; |
54 | | static char *prog_last_argv = NULL; |
55 | | |
56 | | static int prog_argc = -1; |
57 | | static char proc_title_buf[BUFSIZ]; |
58 | | |
59 | | static unsigned int proc_flags = 0; |
60 | 0 | #define PR_PROCTITLE_FL_USE_STATIC 0x001 |
61 | | |
62 | 0 | void pr_proctitle_init(int argc, char *argv[], char *envp[]) { |
63 | 0 | register int i, j; |
64 | 0 | register size_t envpsize; |
65 | 0 | char **p; |
66 | | |
67 | | /* Move the environment so setproctitle can use the space. */ |
68 | 0 | for (i = envpsize = 0; envp[i] != NULL; i++) { |
69 | 0 | envpsize += strlen(envp[i]) + 1; |
70 | 0 | } |
71 | |
|
72 | 0 | p = (char **) calloc((i + 1), sizeof(char *)); |
73 | 0 | if (p != NULL) { |
74 | 0 | environ = p; |
75 | |
|
76 | 0 | j = 0; |
77 | 0 | for (i = 0; envp[i] != NULL; i++) { |
78 | 0 | size_t envp_len = strlen(envp[i]); |
79 | |
|
80 | 0 | if (envp_len > PR_TUNABLE_ENV_MAX) { |
81 | | /* Skip any environ variables that are too long. */ |
82 | 0 | continue; |
83 | 0 | } |
84 | | |
85 | 0 | environ[j] = malloc(envp_len + 1); |
86 | 0 | if (environ[j] != NULL) { |
87 | 0 | sstrncpy(environ[j], envp[i], envp_len + 1); |
88 | 0 | j++; |
89 | 0 | } |
90 | 0 | } |
91 | |
|
92 | 0 | } |
93 | |
|
94 | 0 | prog_argv = argv; |
95 | 0 | prog_argc = argc; |
96 | |
|
97 | 0 | for (i = 0; i < prog_argc; i++) { |
98 | 0 | if (!i || (prog_last_argv + 1 == argv[i])) { |
99 | 0 | prog_last_argv = argv[i] + strlen(argv[i]); |
100 | 0 | } |
101 | 0 | } |
102 | |
|
103 | 0 | for (i = 0; envp[i] != NULL; i++) { |
104 | 0 | if ((prog_last_argv + 1) == envp[i]) { |
105 | 0 | prog_last_argv = envp[i] + strlen(envp[i]); |
106 | 0 | } |
107 | 0 | } |
108 | |
|
109 | 0 | #ifdef HAVE___PROGNAME |
110 | | /* Set the __progname and __progname_full variables so glibc and company |
111 | | * don't go nuts. |
112 | | */ |
113 | 0 | __progname = strdup("proftpd"); |
114 | 0 | __progname_full = strdup(argv[0]); |
115 | 0 | #endif /* HAVE___PROGNAME */ |
116 | 0 | memset(proc_title_buf, '\0', sizeof(proc_title_buf)); |
117 | 0 | } |
118 | | |
119 | 0 | void pr_proctitle_free(void) { |
120 | | #ifdef PR_USE_DEVEL |
121 | | if (environ) { |
122 | | register unsigned int i; |
123 | | |
124 | | for (i = 0; environ[i] != NULL; i++) { |
125 | | free(environ[i]); |
126 | | } |
127 | | free(environ); |
128 | | environ = NULL; |
129 | | } |
130 | | |
131 | | # ifdef HAVE___PROGNAME |
132 | | free(__progname); |
133 | | __progname = NULL; |
134 | | free(__progname_full); |
135 | | __progname_full = NULL; |
136 | | # endif /* HAVE___PROGNAME */ |
137 | | #endif /* PR_USE_DEVEL */ |
138 | 0 | } |
139 | | |
140 | 0 | void pr_proctitle_set_str(const char *str) { |
141 | 0 | #ifndef HAVE_SETPROCTITLE |
142 | 0 | char *p; |
143 | 0 | int i, procbuflen, maxlen = (prog_last_argv - prog_argv[0]) - 2; |
144 | |
|
145 | | # if PF_ARGV_TYPE == PF_ARGV_PSTAT |
146 | | union pstun pst; |
147 | | # endif /* PF_ARGV_PSTAT */ |
148 | |
|
149 | 0 | if (proc_flags & PR_PROCTITLE_FL_USE_STATIC) { |
150 | 0 | return; |
151 | 0 | } |
152 | | |
153 | 0 | sstrncpy(proc_title_buf, str, sizeof(proc_title_buf)); |
154 | 0 | procbuflen = strlen(proc_title_buf); |
155 | |
|
156 | | # if PF_ARGV_TYPE == PF_ARGV_NEW |
157 | | /* We can just replace argv[] arguments. Nice and easy. */ |
158 | | prog_argv[0] = proc_title_buf; |
159 | | for (i = 1; i < prog_argc; i++) { |
160 | | prog_argv[i] = ""; |
161 | | } |
162 | | # endif /* PF_ARGV_NEW */ |
163 | |
|
164 | 0 | # if PF_ARGV_TYPE == PF_ARGV_WRITEABLE |
165 | | /* We can overwrite individual argv[] arguments. Semi-nice. */ |
166 | 0 | snprintf(prog_argv[0], maxlen, "%s", proc_title_buf); |
167 | 0 | p = &prog_argv[0][procbuflen]; |
168 | |
|
169 | 0 | while (p < prog_last_argv) { |
170 | 0 | *p++ = '\0'; |
171 | 0 | } |
172 | |
|
173 | 0 | for (i = 1; i < prog_argc; i++) { |
174 | 0 | prog_argv[i] = ""; |
175 | 0 | } |
176 | |
|
177 | 0 | # endif /* PF_ARGV_WRITEABLE */ |
178 | |
|
179 | | # if PF_ARGV_TYPE == PF_ARGV_PSSTRINGS |
180 | | PS_STRINGS->ps_nargvstr = 1; |
181 | | PS_STRINGS->ps_argvstr = proc_title_buf; |
182 | | # endif /* PF_ARGV_PSSTRINGS */ |
183 | |
|
184 | | #else |
185 | | if (proc_flags & PR_PROCTITLE_FL_USE_STATIC) { |
186 | | return; |
187 | | } |
188 | | |
189 | | setproctitle("%s", str); |
190 | | #endif /* HAVE_SETPROCTITLE */ |
191 | 0 | } |
192 | | |
193 | | /* Note that we deliberately do NOT use pr_vsnprintf() here, since truncation |
194 | | * of long strings is often normal for these entries; consider paths longer |
195 | | * than PR_TUNABLE_SCOREBOARD_BUFFER_SIZE (Issue#683). |
196 | | */ |
197 | 0 | void pr_proctitle_set(const char *fmt, ...) { |
198 | 0 | va_list msg; |
199 | |
|
200 | 0 | #ifndef HAVE_SETPROCTITLE |
201 | | # if PF_ARGV_TYPE == PF_ARGV_PSTAT |
202 | | union pstun pst; |
203 | | # endif /* PF_ARGV_PSTAT */ |
204 | 0 | char *p; |
205 | 0 | int i, procbuflen, maxlen = (prog_last_argv - prog_argv[0]) - 2; |
206 | 0 | #endif /* HAVE_SETPROCTITLE */ |
207 | |
|
208 | 0 | if (proc_flags & PR_PROCTITLE_FL_USE_STATIC) { |
209 | 0 | return; |
210 | 0 | } |
211 | | |
212 | 0 | if (fmt == NULL) { |
213 | 0 | return; |
214 | 0 | } |
215 | | |
216 | 0 | va_start(msg, fmt); |
217 | |
|
218 | 0 | memset(proc_title_buf, 0, sizeof(proc_title_buf)); |
219 | |
|
220 | | #ifdef HAVE_SETPROCTITLE |
221 | | # if __FreeBSD__ >= 4 && !defined(FREEBSD4_0) && !defined(FREEBSD4_1) |
222 | | /* FreeBSD's setproctitle() automatically prepends the process name. */ |
223 | | vsnprintf(proc_title_buf, sizeof(proc_title_buf)-1, fmt, msg); |
224 | | |
225 | | # else /* FREEBSD4 */ |
226 | | /* Manually append the process name for non-FreeBSD platforms. */ |
227 | | snprintf(proc_title_buf, sizeof(proc_title_buf)-1, "%s", "proftpd: "); |
228 | | vsnprintf(proc_title_buf + strlen(proc_title_buf), |
229 | | sizeof(proc_title_buf)-1 - strlen(proc_title_buf), fmt, msg); |
230 | | |
231 | | # endif /* FREEBSD4 */ |
232 | | setproctitle("%s", proc_title_buf); |
233 | | |
234 | | #else /* HAVE_SETPROCTITLE */ |
235 | | /* Manually append the process name for non-setproctitle() platforms. */ |
236 | 0 | snprintf(proc_title_buf, sizeof(proc_title_buf)-1, "%s", "proftpd: "); |
237 | 0 | vsnprintf(proc_title_buf + strlen(proc_title_buf), |
238 | 0 | sizeof(proc_title_buf)-1 - strlen(proc_title_buf), fmt, msg); |
239 | |
|
240 | 0 | #endif /* HAVE_SETPROCTITLE */ |
241 | |
|
242 | 0 | va_end(msg); |
243 | |
|
244 | | #ifdef HAVE_SETPROCTITLE |
245 | | return; |
246 | | #else |
247 | 0 | procbuflen = strlen(proc_title_buf); |
248 | |
|
249 | | # if PF_ARGV_TYPE == PF_ARGV_NEW |
250 | | /* We can just replace argv[] arguments. Nice and easy. */ |
251 | | prog_argv[0] = proc_title_buf; |
252 | | for (i = 1; i < prog_argc; i++) { |
253 | | prog_argv[i] = ""; |
254 | | } |
255 | | # endif /* PF_ARGV_NEW */ |
256 | |
|
257 | 0 | # if PF_ARGV_TYPE == PF_ARGV_WRITEABLE |
258 | | /* We can overwrite individual argv[] arguments. Semi-nice. */ |
259 | 0 | snprintf(prog_argv[0], maxlen, "%s", proc_title_buf); |
260 | 0 | p = &prog_argv[0][procbuflen]; |
261 | |
|
262 | 0 | while (p < prog_last_argv) { |
263 | 0 | *p++ = '\0'; |
264 | 0 | } |
265 | |
|
266 | 0 | for (i = 1; i < prog_argc; i++) { |
267 | 0 | prog_argv[i] = ""; |
268 | 0 | } |
269 | |
|
270 | 0 | # endif /* PF_ARGV_WRITEABLE */ |
271 | |
|
272 | | # if PF_ARGV_TYPE == PF_ARGV_PSTAT |
273 | | pst.pst_command = proc_title_buf; |
274 | | pstat(PSTAT_SETCMD, pst, procbuflen, 0, 0); |
275 | | |
276 | | # endif /* PF_ARGV_PSTAT */ |
277 | |
|
278 | | # if PF_ARGV_TYPE == PF_ARGV_PSSTRINGS |
279 | | PS_STRINGS->ps_nargvstr = 1; |
280 | | PS_STRINGS->ps_argvstr = proc_title_buf; |
281 | | # endif /* PF_ARGV_PSSTRINGS */ |
282 | 0 | #endif /* HAVE_SETPROCTITLE */ |
283 | 0 | } |
284 | | |
285 | 0 | void pr_proctitle_set_static_str(const char *buf) { |
286 | 0 | if (buf != NULL) { |
287 | 0 | pr_proctitle_set_str(buf); |
288 | 0 | proc_flags |= PR_PROCTITLE_FL_USE_STATIC; |
289 | |
|
290 | 0 | } else { |
291 | | /* Reset. */ |
292 | 0 | proc_flags = 0; |
293 | 0 | } |
294 | 0 | } |
295 | | |
296 | 0 | int pr_proctitle_get(char *buf, size_t bufsz) { |
297 | 0 | if (buf == NULL || |
298 | 0 | bufsz == 0) { |
299 | | |
300 | | /* If the caller didn't provide an input buffer, they are simply |
301 | | * querying for the length of the current process title. Easy enough |
302 | | * to acquiesce to that request. |
303 | | */ |
304 | 0 | return strlen(proc_title_buf); |
305 | 0 | } |
306 | | |
307 | 0 | sstrncpy(buf, proc_title_buf, bufsz); |
308 | 0 | return strlen(buf); |
309 | 0 | } |