1 /* $NetBSD: sys_compat.c,v 1.3 2020/03/18 19:05:22 christos Exp $ */
2
3 /*++
4 /* NAME
5 /* sys_compat 3
6 /* SUMMARY
7 /* compatibility routines
8 /* SYNOPSIS
9 /* #include <sys_defs.h>
10 /*
11 /* void closefrom(int lowfd)
12 /* int lowfd;
13 /*
14 /* const char *strerror(err)
15 /* int err;
16 /*
17 /* int setenv(name, value, clobber)
18 /* const char *name;
19 /* const char *value;
20 /* int clobber;
21 /*
22 /* int unsetenv(name)
23 /* const char *name;
24 /*
25 /* int seteuid(euid)
26 /* uid_t euid;
27 /*
28 /* int setegid(egid)
29 /* gid_t euid;
30 /*
31 /* int mkfifo(path, mode)
32 /* char *path;
33 /* int mode;
34 /*
35 /* int waitpid(pid, statusp, options)
36 /* int pid;
37 /* WAIT_STATUS_T *statusp;
38 /* int options;
39 /*
40 /* int setsid()
41 /*
42 /* void dup2_pass_on_exec(int oldd, int newd)
43 /*
44 /* char *inet_ntop(af, src, dst, size)
45 /* int af;
46 /* const void *src;
47 /* char *dst;
48 /* SOCKADDR_SIZE size;
49 /*
50 /* int inet_pton(af, src, dst)
51 /* int af;
52 /* const char *src;
53 /* void *dst;
54 /* DESCRIPTION
55 /* These routines are compiled for platforms that lack the functionality
56 /* or that have broken versions that we prefer to stay away from.
57 /* LICENSE
58 /* .ad
59 /* .fi
60 /* The Secure Mailer license must be distributed with this software.
61 /* AUTHOR(S)
62 /* Wietse Venema
63 /* IBM T.J. Watson Research
64 /* P.O. Box 704
65 /* Yorktown Heights, NY 10598, USA
66 /*
67 /* Wietse Venema
68 /* Google, Inc.
69 /* 111 8th Avenue
70 /* New York, NY 10011, USA
71 /*--*/
72
73 /* System library. */
74
75 #include "sys_defs.h"
76
77 /*
78 * ANSI strerror() emulation
79 */
80 #ifdef MISSING_STRERROR
81
82 extern int errno;
83 extern char *sys_errlist[];
84 extern int sys_nerr;
85
86 #include <vstring.h>
87
88 /* strerror - print text corresponding to error */
89
strerror(int err)90 const char *strerror(int err)
91 {
92 static VSTRING *buf;
93
94 if (err < 0 || err >= sys_nerr) {
95 if (buf == 0)
96 buf = vstring_alloc(10);
97 vstring_sprintf(buf, "Unknown error %d", err);
98 return (vstring_str(buf));
99 } else {
100 return (sys_errlist[errno]);
101 }
102 }
103
104 #endif
105
106 /*
107 * setenv() emulation on top of putenv().
108 */
109 #ifdef MISSING_SETENV
110
111 #include <stdio.h>
112 #include <string.h>
113 #include <stdlib.h>
114
115 /* setenv - update or insert environment (name,value) pair */
116
setenv(const char * name,const char * value,int clobber)117 int setenv(const char *name, const char *value, int clobber)
118 {
119 char *cp;
120
121 if (clobber == 0 && getenv(name) != 0)
122 return (0);
123 if ((cp = malloc(strlen(name) + strlen(value) + 2)) == 0)
124 return (1);
125 sprintf(cp, "%s=%s", name, value);
126 return (putenv(cp));
127 }
128
129 /* unsetenv - remove all instances of the name */
130
unsetenv(const char * name)131 int unsetenv(const char *name)
132 {
133 extern char **environ;
134 ssize_t name_len = strlen(name);
135 char **src_pp;
136 char **dst_pp;
137
138 for (dst_pp = src_pp = environ; *src_pp; src_pp++, dst_pp++) {
139 if (strncmp(*src_pp, name, name_len) == 0
140 && *(*src_pp + name_len) == '=') {
141 dst_pp--;
142 } else if (dst_pp != src_pp) {
143 *dst_pp = *src_pp;
144 }
145 }
146 *dst_pp = 0;
147 return (0);
148 }
149
150 #endif
151
152 /*
153 * seteuid() and setegid() emulation, the HP-UX way
154 */
155 #ifdef MISSING_SETEUID
156 #ifdef HAVE_SETRESUID
157 #include <unistd.h>
158
seteuid(uid_t euid)159 int seteuid(uid_t euid)
160 {
161 return setresuid(-1, euid, -1);
162 }
163
164 #else
165 #error MISSING_SETEUID
166 #endif
167
168 #endif
169
170 #ifdef MISSING_SETEGID
171 #ifdef HAVE_SETRESGID
172 #include <unistd.h>
173
setegid(gid_t egid)174 int setegid(gid_t egid)
175 {
176 return setresgid(-1, egid, -1);
177 }
178
179 #else
180 #error MISSING_SETEGID
181 #endif
182
183 #endif
184
185 /*
186 * mkfifo() emulation - requires superuser privileges
187 */
188 #ifdef MISSING_MKFIFO
189
190 #include <sys/stat.h>
191
mkfifo(char * path,int mode)192 int mkfifo(char *path, int mode)
193 {
194 return mknod(path, (mode & ~_S_IFMT) | _S_IFIFO, 0);
195 }
196
197 #endif
198
199 /*
200 * waitpid() emulation on top of Berkeley UNIX wait4()
201 */
202 #ifdef MISSING_WAITPID
203 #ifdef HAS_WAIT4
204
205 #include <sys/wait.h>
206 #include <errno.h>
207
waitpid(int pid,WAIT_STATUS_T * status,int options)208 int waitpid(int pid, WAIT_STATUS_T *status, int options)
209 {
210 if (pid == -1)
211 pid = 0;
212 return wait4(pid, status, options, (struct rusage *) 0);
213 }
214
215 #else
216 #error MISSING_WAITPID
217 #endif
218
219 #endif
220
221 /*
222 * setsid() emulation, the Berkeley UNIX way
223 */
224 #ifdef MISSING_SETSID
225
226 #include <sys/ioctl.h>
227 #include <unistd.h>
228 #include <fcntl.h>
229 #include <errno.h>
230
231 #ifdef TIOCNOTTY
232
233 #include <msg.h>
234
setsid(void)235 int setsid(void)
236 {
237 int p = getpid();
238 int fd;
239
240 if (setpgrp(p, p))
241 return -1;
242
243 fd = open("/dev/tty", O_RDONLY, 0);
244 if (fd >= 0 || errno != ENXIO) {
245 if (fd < 0) {
246 msg_warn("open /dev/tty: %m");
247 return -1;
248 }
249 if (ioctl(fd, TIOCNOTTY, 0)) {
250 msg_warn("ioctl TIOCNOTTY: %m");
251 return -1;
252 }
253 close(fd);
254 }
255 return 0;
256 }
257
258 #else
259 #error MISSING_SETSID
260 #endif
261
262 #endif
263
264 /*
265 * dup2_pass_on_exec() - dup2() and clear close-on-exec flag on the result
266 */
267 #ifdef DUP2_DUPS_CLOSE_ON_EXEC
268
269 #include "iostuff.h"
270
dup2_pass_on_exec(int oldd,int newd)271 int dup2_pass_on_exec(int oldd, int newd)
272 {
273 int res;
274
275 if ((res = dup2(oldd, newd)) >= 0)
276 close_on_exec(newd, PASS_ON_EXEC);
277
278 return res;
279 }
280
281 #endif
282
283 #ifndef HAS_CLOSEFROM
284
285 #include <unistd.h>
286 #include <errno.h>
287 #include <iostuff.h>
288
289 /* closefrom() - closes all file descriptors from the given one up */
290
closefrom(int lowfd)291 int closefrom(int lowfd)
292 {
293 int fd_limit = open_limit(0);
294 int fd;
295
296 /*
297 * lowfrom does not have an easy to determine upper limit. A process may
298 * have files open that were inherited from a parent process with a less
299 * restrictive resource limit.
300 */
301 if (lowfd < 0) {
302 errno = EBADF;
303 return (-1);
304 }
305 if (fd_limit > 500)
306 fd_limit = 500;
307 for (fd = lowfd; fd < fd_limit; fd++)
308 (void) close(fd);
309
310 return (0);
311 }
312
313 #endif
314
315 #ifdef MISSING_INET_NTOP
316
317 #include <sys/types.h>
318 #include <sys/socket.h>
319 #include <netinet/in.h>
320 #include <arpa/inet.h>
321 #include <stdio.h>
322 #include <string.h>
323 #include <errno.h>
324
325 /* inet_ntop - convert binary address to printable address */
326
inet_ntop(int af,const void * src,char * dst,SOCKADDR_SIZE size)327 const char *inet_ntop(int af, const void *src, char *dst, SOCKADDR_SIZE size)
328 {
329 const unsigned char *addr;
330 char buffer[sizeof("255.255.255.255")];
331 int len;
332
333 if (af != AF_INET) {
334 errno = EAFNOSUPPORT;
335 return (0);
336 }
337 addr = (const unsigned char *) src;
338 #if (CHAR_BIT > 8)
339 sprintf(buffer, "%d.%d.%d.%d", addr[0] & 0xff,
340 addr[1] & 0xff, addr[2] & 0xff, addr[3] & 0xff);
341 #else
342 sprintf(buffer, "%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]);
343 #endif
344 if ((len = strlen(buffer)) >= size) {
345 errno = ENOSPC;
346 return (0);
347 } else {
348 memcpy(dst, buffer, len + 1);
349 return (dst);
350 }
351 }
352
353 #endif
354
355 #ifdef MISSING_INET_PTON
356
357 #include <sys/types.h>
358 #include <sys/socket.h>
359 #include <netinet/in.h>
360 #include <arpa/inet.h>
361 #include <string.h>
362 #include <errno.h>
363
364 #ifndef INADDR_NONE
365 #define INADDR_NONE 0xffffffff
366 #endif
367
368 /* inet_pton - convert printable address to binary address */
369
inet_pton(int af,const char * src,void * dst)370 int inet_pton(int af, const char *src, void *dst)
371 {
372 struct in_addr addr;
373
374 /*
375 * inet_addr() accepts a wider range of input formats than inet_pton();
376 * the former accepts 1-, 2-, or 3-part dotted addresses, while the
377 * latter requires dotted quad form.
378 */
379 if (af != AF_INET) {
380 errno = EAFNOSUPPORT;
381 return (-1);
382 } else if ((addr.s_addr = inet_addr(src)) == INADDR_NONE
383 && strcmp(src, "255.255.255.255") != 0) {
384 return (0);
385 } else {
386 memcpy(dst, (void *) &addr, sizeof(addr));
387 return (1);
388 }
389 }
390
391 #endif
392