1/* This file is part of the KDE libraries
2 Copyright (c) 2000 Stephan Kulow <coolo@kde.org>
3 Copyright (c) 2002 Dirk Mueller <mueller@kde.org>
4 Copyright (c) 2002 Oswald Buddenhagen <ossi@kde.org>
5 Copyright (c) 2003 Joseph Wenninger <kde@jowenn.at>
6 Copyright (c) 2005 Jarosław Staniek <staniek@kde.org>
7 Copyright (c) 2007 Rafael Fernández López <ereslibre@kde.org>
8
9 unsetenv() taken from the GNU C Library.
10 Copyright (C) 1992,1995-1999,2000-2002 Free Software Foundation, Inc. <gnu@gnu.org>
11
12 getgrouplist() taken from the FreeBSD libc. The copyright notice
13 in the file /usr/src/lib/libc/gen/getgrouplist.c on FreeBSD is out
14 of date, as it has incorrect copyright years and still names the
15 4-clause BSD license -- however, the Regents of the University of
16 California at Berkeley have declared that clause 3 is void; only
17 clauses 1,2 and 4 apply. See the full license text below.
18 Copyright (c) 1991, 1993
19 The Regents of the University of California. All rights reserved.
20
21
22
23 This library is free software; you can redistribute it and/or
24 modify it under the terms of the GNU Library General Public
25 License version 2 as published by the Free Software Foundation.
26
27 This library is distributed in the hope that it will be useful,
28 but WITHOUT ANY WARRANTY; without even the implied warranty of
29 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
30 Library General Public License for more details.
31
32 You should have received a copy of the GNU Library General Public License
33 along with this library; see the file COPYING.LIB. If not, write to
34 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
35 Boston, MA 02110-1301, USA.
36*/
37
38#include <kdecore_export.h>
39
40#include <config.h>
41
42
43
44#define KDE_open open
45#define KDE_mkdir mkdir
46
47
48#ifndef HAVE_SETENV
49
50#ifdef HAVE_ALLOCA_H
51#include <alloca.h>
52#endif
53#ifdef HAVE_STRING_H
54#include <string.h>
55#endif
56#ifdef HAVE_STDLIB_H
57#include <stdlib.h>
58#endif
59#ifdef HAVE_UNISTD_H
60#include <unistd.h>
61#endif
62
63KDECORE_EXPORT int setenv(const char *name, const char *value, int overwrite) {
64 int i;
65 char * a;
66
67 if (!overwrite && getenv(name)) return 0;
68
69 i = strlen(name) + strlen(value) + 2;
70 a = (char*)malloc(i);
71 if (!a) return 1;
72
73 strcpy(a, name);
74 strcat(a, "=");
75 strcat(a, value);
76
77 return putenv(a);
78}
79#endif /* !HAVE_SETENV */
80
81#ifndef HAVE_UNSETENV
82
83#ifdef HAVE_ALLOCA_H
84#include <alloca.h>
85#endif
86#ifdef HAVE_STRING_H
87#include <string.h>
88#endif
89#ifdef HAVE_STDLIB_H
90#include <stdlib.h>
91#endif
92#ifdef HAVE_ERRNO_H
93#include <errno.h>
94#endif
95#ifdef HAVE_UNISTD_H
96#include <unistd.h>
97#endif
98
99#ifndef environ
100extern char ** environ;
101#endif
102
103KDECORE_EXPORT int unsetenv (const char *name)
104{
105 size_t len;
106 char **ep;
107
108 if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
109 {
110 errno = EINVAL;
111 return -1;
112 }
113
114 len = strlen (name);
115
116 ep = environ;
117 while (*ep != NULL)
118 if (!strncmp (*ep, name, len) && (*ep)[len] == '=')
119 {
120 /* Found it. Remove this pointer by moving later ones back. */
121 char **dp = ep;
122
123 do
124 dp[0] = dp[1];
125 while (*dp++);
126 /* Continue the loop in case NAME appears again. */
127 }
128 else
129 ++ep;
130
131 return 0;
132}
133
134#endif /* !HAVE_UNSETENV */
135
136#ifndef HAVE_USLEEP
137
138#if TIME_WITH_SYS_TIME
139# include <sys/time.h>
140# include <time.h>
141#else
142# if defined(HAVE_SYS_TIME_H)
143# include <sys/time.h>
144# else
145# include <time.h>
146# endif
147#endif
148
149#ifdef HAVE_SYS_SELECT_H
150#include <sys/select.h>
151#endif
152
153#ifdef __cplusplus /* this is supposed to be a C source file but still.. */
154extern "C" {
155#endif
156
157void usleep(unsigned int usec) {
158 struct timeval _usleep_tv;
159 _usleep_tv.tv_sec = usec/1000000;
160 _usleep_tv.tv_usec = usec%1000000;
161 select(0,0,0,0,&_usleep_tv);
162}
163
164#ifdef __cplusplus
165}
166#endif
167
168#endif /* !HAVE_USLEEP */
169
170#ifndef HAVE_RANDOM
171long int random()
172{
173 return lrand48();
174}
175
176void srandom(unsigned int seed)
177{
178 srand48(seed);
179}
180#endif /* !HAVE_RANDOM */
181
182#ifndef HAVE_SETEUID
183int seteuid(uid_t euid)
184{
185 return setreuid(-1, euid); /* Well, if you have neither you are in trouble :) */
186}
187#endif /* !HAVE_SETEUID */
188
189#ifndef HAVE_MKSTEMPS
190#ifdef HAVE_SYS_TYPES_H
191#include <sys/types.h>
192#endif
193#ifdef HAVE_SYS_STAT_H
194#include <sys/stat.h>
195#endif
196#include <fcntl.h>
197#ifdef HAVE_STRING_H
198#include <string.h>
199#endif
200#ifdef HAVE_STRINGS_H
201#include <strings.h>
202#endif
203#ifdef HAVE_STDLIB_H
204#include <stdlib.h>
205#endif
206
207/* this is based on code taken from the GNU libc, distributed under the LGPL license */
208
209/* Generate a unique temporary file name from TEMPLATE.
210
211 TEMPLATE has the form:
212
213 <path>/ccXXXXXX<suffix>
214
215 SUFFIX_LEN tells us how long <suffix> is (it can be zero length).
216
217 The last six characters of TEMPLATE before <suffix> must be "XXXXXX";
218 they are replaced with a string that makes the filename unique.
219
220 Returns a file descriptor open on the file for reading and writing. */
221
222KDECORE_EXPORT int mkstemps (char* _template, int suffix_len)
223{
224 static const char letters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
225 char *XXXXXX;
226 int len;
227 int count;
228 int value;
229
230 len = strlen (_template);
231
232 if ((int) len < 6 + suffix_len || strncmp (&_template[len - 6 - suffix_len], "XXXXXX", 6))
233 return -1;
234
235 XXXXXX = &_template[len - 6 - suffix_len];
236
237 value = rand();
238 for (count = 0; count < 256; ++count)
239 {
240 int v = value;
241 int fd;
242
243 /* Fill in the random bits. */
244 XXXXXX[0] = letters[v % 62];
245 v /= 62;
246 XXXXXX[1] = letters[v % 62];
247 v /= 62;
248 XXXXXX[2] = letters[v % 62];
249 v /= 62;
250 XXXXXX[3] = letters[v % 62];
251 v /= 62;
252 XXXXXX[4] = letters[v % 62];
253 v /= 62;
254 XXXXXX[5] = letters[v % 62];
255
256 fd = KDE_open (_template, O_RDWR|O_CREAT|O_EXCL, 0600);
257 if (fd >= 0)
258 /* The file does not exist. */
259 return fd;
260
261 /* This is a random value. It is only necessary that the next
262 TMP_MAX values generated by adding 7777 to VALUE are different
263 with (module 2^32). */
264 value += 7777;
265 }
266 /* We return the null string if we can't find a unique file name. */
267 _template[0] = '\0';
268 return -1;
269}
270
271#endif /* !HAVE_MKSTEMPS */
272
273#ifndef HAVE_MKSTEMP
274KDECORE_EXPORT int mkstemp (char* _template)
275{
276 return mkstemps( _template, 0 );
277}
278#endif /* !HAVE_MKSTEMP */
279
280#ifndef HAVE_MKDTEMP
281
282#ifndef HAVE_MKSTEMPS
283#ifdef HAVE_SYS_TYPES_H
284#include <sys/types.h>
285#endif
286#ifdef HAVE_SYS_STAT_H
287#include <sys/stat.h>
288#endif
289#endif
290
291/* Generate a unique temporary directory name from TEMPLATE.
292
293 TEMPLATE has the form:
294
295 <path>/ccXXXXXX
296
297
298 The last six characters of TEMPLATE must be "XXXXXX";
299 they are replaced with a string that makes the filename unique.
300
301 Returns a file descriptor open on the file for reading and writing. */
302
303KDECORE_EXPORT char* mkdtemp (char* _template)
304{
305 static const char letters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
306 char *XXXXXX;
307 int len;
308 int count;
309 int value;
310
311 len = strlen (_template);
312
313 if ((int) len < 6 || strncmp (&_template[len - 6], "XXXXXX", 6))
314 return 0;
315
316 XXXXXX = &_template[len - 6];
317
318 value = rand();
319 for (count = 0; count < 256; ++count)
320 {
321 int v = value;
322
323 /* Fill in the random bits. */
324 XXXXXX[0] = letters[v % 62];
325 v /= 62;
326 XXXXXX[1] = letters[v % 62];
327 v /= 62;
328 XXXXXX[2] = letters[v % 62];
329 v /= 62;
330 XXXXXX[3] = letters[v % 62];
331 v /= 62;
332 XXXXXX[4] = letters[v % 62];
333 v /= 62;
334 XXXXXX[5] = letters[v % 62];
335
336 /* This is a random value. It is only necessary that the next
337 TMP_MAX values generated by adding 7777 to VALUE are different
338 with (module 2^32). */
339 value += 7777;
340
341 if (!KDE_mkdir(_template,0700))
342 return _template;
343 }
344 return 0;
345}
346#endif /* !HAVE_MKDTEMP */
347
348#ifndef HAVE_STRLCPY
349
350#ifdef HAVE_STRING_H
351#include <string.h>
352#endif
353
354KDECORE_EXPORT unsigned long strlcpy(char* d, const char* s, unsigned long bufsize)
355{
356 unsigned long len, ret = strlen(s);
357
358 if (ret >= bufsize) {
359 if (bufsize) {
360 len = bufsize - 1;
361 memcpy(d, s, len);
362 d[len] = '\0';
363 }
364 } else
365 memcpy(d, s, ret + 1);
366
367 return ret;
368}
369#endif /* !HAVE_STRLCPY */
370
371/*
372 * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
373 * All rights reserved.
374 *
375 * Redistribution and use in source and binary forms, with or without
376 * modification, are permitted provided that the following conditions
377 * are met:
378 * 1. Redistributions of source code must retain the above copyright
379 * notice, this list of conditions and the following disclaimer.
380 * 2. Redistributions in binary form must reproduce the above copyright
381 * notice, this list of conditions and the following disclaimer in the
382 * documentation and/or other materials provided with the distribution.
383 * 3. The name of the author may not be used to endorse or promote products
384 * derived from this software without specific prior written permission.
385 *
386 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
387 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
388 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
389 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
390 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
391 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
392 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
393 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
394 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
395 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
396 *
397 * $OpenBSD: strlcat.c,v 1.2 1999/06/17 16:28:58 millert Exp $
398 * $FreeBSD: src/lib/libc/string/strlcat.c,v 1.2.4.2 2001/07/09 23:30:06 obrien Exp $
399 * $DragonFly: src/sys/libkern/strlcat.c,v 1.5 2007/06/07 23:45:02 dillon Exp $
400 */
401
402/*
403 * Appends src to string dst of size siz (unlike strncat, siz is the
404 * full size of dst, not space left). At most siz-1 characters
405 * will be copied. Always NUL terminates (unless siz <= strlen(dst)).
406 * Returns strlen(initial dst) + strlen(src); if retval >= siz,
407 * truncation occurred.
408 */
409
410#ifndef HAVE_STRLCAT
411
412#ifdef HAVE_STRING_H
413#include <string.h>
414#endif
415
416KDECORE_EXPORT unsigned long strlcat(char *dst, const char *src, unsigned long siz)
417{
418 char *d = dst;
419 const char *s = src;
420 unsigned long n = siz;
421 unsigned long dlen;
422
423 /* Find the end of dst and adjust bytes left but don't go past end */
424 while (n-- != 0 && *d != '\0')
425 d++;
426 dlen = d - dst;
427 n = siz - dlen;
428
429 if (n == 0)
430 return(dlen + strlen(s));
431 while (*s != '\0') {
432 if (n != 1) {
433 *d++ = *s;
434 n--;
435 }
436 s++;
437 }
438 *d = '\0';
439
440 return(dlen + (s - src)); /* count does not include NUL */
441}
442#endif /* !HAVE_STRLCAT */
443
444#ifndef HAVE_STRCASESTR
445/*
446 * My personal strstr() implementation that beats most other algorithms.
447 * Until someone tells me otherwise, I assume that this is the
448 * fastest implementation of strstr() in C.
449 * I deliberately chose not to comment it. You should have at least
450 * as much fun trying to understand it, as I had to write it :-).
451 *
452 * Stephen R. van den Berg, berg@pool.informatik.rwth-aachen.de */
453
454#include <ctype.h>
455
456KDECORE_EXPORT char *strcasestr (phaystack, pneedle)
457 const char *phaystack;
458 const char *pneedle;
459{
460 register const unsigned char *haystack, *needle;
461 register unsigned b, c;
462
463 haystack = (const unsigned char *) phaystack;
464 needle = (const unsigned char *) pneedle;
465
466 b = tolower (*needle);
467 if (b != '\0')
468 {
469 haystack--; /* possible ANSI violation */
470 do
471 {
472 c = *++haystack;
473 if (c == '\0')
474 goto ret0;
475 }
476 while (tolower (c) != (int) b);
477
478 c = tolower (*++needle);
479 if (c == '\0')
480 goto foundneedle;
481 ++needle;
482 goto jin;
483
484 for (;;)
485 {
486 register unsigned a;
487 register const unsigned char *rhaystack, *rneedle;
488
489 do
490 {
491 a = *++haystack;
492 if (a == '\0')
493 goto ret0;
494 if (tolower (a) == (int) b)
495 break;
496 a = *++haystack;
497 if (a == '\0')
498 goto ret0;
499shloop:
500 ;
501 }
502 while (tolower (a) != (int) b);
503
504jin: a = *++haystack;
505 if (a == '\0')
506 goto ret0;
507
508 if (tolower (a) != (int) c)
509 goto shloop;
510
511 rhaystack = haystack-- + 1;
512 rneedle = needle;
513 a = tolower (*rneedle);
514
515 if (tolower (*rhaystack) == (int) a)
516 do
517 {
518 if (a == '\0')
519 goto foundneedle;
520 ++rhaystack;
521 a = tolower (*++needle);
522 if (tolower (*rhaystack) != (int) a)
523 break;
524 if (a == '\0')
525 goto foundneedle;
526 ++rhaystack;
527 a = tolower (*++needle);
528 }
529 while (tolower (*rhaystack) == (int) a);
530
531 needle = rneedle; /* took the register-poor approach */
532
533 if (a == '\0')
534 break;
535 }
536 }
537foundneedle:
538 return (char*) haystack;
539ret0:
540 return 0;
541}
542#endif /* !HAVE_STRCASESTR */
543
544#ifndef HAVE_TRUNC
545
546#include <math.h> /* floor */
547
548/*
549 * Here we simulate the trunc() function behavior. This function is not
550 * available for not C99 compatible systems.
551 *
552 * For example, Solaris 8.
553 */
554
555KDECORE_EXPORT double trunc (double x)
556{
557 return x < 0 ? -floor(-x) : floor(x);
558}
559#endif /* !HAVE_TRUNC */
560
561
562#ifndef HAVE_GETGROUPLIST
563/* Although this full license text is 4-clause BSD, it is taken directly
564 from the FreeBSD source tree; the Regents of the University of
565 California have deleted clause 3. See
566 http://www.freebsd.org/copyright/license.html
567 In addition, FreeBSD itself is now under a 2-clause BSD license,
568 which strikes clause 4 itself. That makes the *effective* license
569 on this file a 2-clause BSD license. I am including the complete
570 file, unmodified except for the #if 0 which is needed to avoid
571 the FreeBSD SCCS IDs.
572*/
573/*-
574 * Copyright (c) 1991, 1993
575 * The Regents of the University of California. All rights reserved.
576 *
577 * Redistribution and use in source and binary forms, with or without
578 * modification, are permitted provided that the following conditions
579 * are met:
580 * 1. Redistributions of source code must retain the above copyright
581 * notice, this list of conditions and the following disclaimer.
582 * 2. Redistributions in binary form must reproduce the above copyright
583 * notice, this list of conditions and the following disclaimer in the
584 * documentation and/or other materials provided with the distribution.
585 * 3. All advertising materials mentioning features or use of this software
586 * must display the following acknowledgement:
587 * This product includes software developed by the University of
588 * California, Berkeley and its contributors.
589 * 4. Neither the name of the University nor the names of its contributors
590 * may be used to endorse or promote products derived from this software
591 * without specific prior written permission.
592 *
593 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
594 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
595 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
596 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
597 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
598 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
599 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
600 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
601 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
602 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
603 * SUCH DAMAGE.
604 */
605
606#if 0
607#if defined(LIBC_SCCS) && !defined(lint)
608static char sccsid[] = "@(#)getgrouplist.c 8.2 (Berkeley) 12/8/94";
609#endif /* LIBC_SCCS and not lint */
610#include <sys/cdefs.h>
611__FBSDID("$FreeBSD: src/lib/libc/gen/getgrouplist.c,v 1.14 2005/05/03 16:20:03 delphij Exp $");
612#endif
613
614/*
615 * get credential
616 */
617#include <sys/types.h>
618
619#include <grp.h>
620#include <string.h>
621#include <unistd.h>
622
623int
624getgrouplist(const char *uname, gid_t agroup, gid_t *groups, int *grpcnt)
625{
626 const struct group *grp;
627 int i, maxgroups, ngroups, ret;
628
629 ret = 0;
630 ngroups = 0;
631 maxgroups = *grpcnt;
632 /*
633 * When installing primary group, duplicate it;
634 * the first element of groups is the effective gid
635 * and will be overwritten when a setgid file is executed.
636 */
637 groups[ngroups++] = agroup;
638 if (maxgroups > 1)
639 groups[ngroups++] = agroup;
640 /*
641 * Scan the group file to find additional groups.
642 */
643 setgrent();
644 while ((grp = getgrent()) != NULL) {
645 for (i = 0; i < ngroups; i++) {
646 if (grp->gr_gid == groups[i])
647 goto skip;
648 }
649 for (i = 0; grp->gr_mem[i]; i++) {
650 if (!strcmp(grp->gr_mem[i], uname)) {
651 if (ngroups >= maxgroups) {
652 ret = -1;
653 break;
654 }
655 groups[ngroups++] = grp->gr_gid;
656 break;
657 }
658 }
659skip:
660 ;
661 }
662 endgrent();
663 *grpcnt = ngroups;
664 return (ret);
665}
666#endif
667
668