1/*
2   Unix SMB/CIFS implementation.
3   replacement routines for broken systems
4   Copyright (C) Andrew Tridgell 1992-1998
5   Copyright (C) Jelmer Vernooij 2005-2008
6
7     ** NOTE! The following LGPL license applies to the replace
8     ** library. This does NOT imply that all of Samba is released
9     ** under the LGPL
10
11   This library is free software; you can redistribute it and/or
12   modify it under the terms of the GNU Lesser General Public
13   License as published by the Free Software Foundation; either
14   version 3 of the License, or (at your option) any later version.
15
16   This library is distributed in the hope that it will be useful,
17   but WITHOUT ANY WARRANTY; without even the implied warranty of
18   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19   Lesser General Public License for more details.
20
21   You should have received a copy of the GNU Lesser General Public
22   License along with this library; if not, see <http://www.gnu.org/licenses/>.
23*/
24
25#include "replace.h"
26
27#include "system/filesys.h"
28#include "system/time.h"
29#include "system/passwd.h"
30#include "system/syslog.h"
31#include "system/locale.h"
32#include "system/wait.h"
33
34#ifdef _WIN32
35#define mkdir(d,m) _mkdir(d)
36#endif
37
38void replace_dummy(void);
39void replace_dummy(void) {}
40
41#ifndef HAVE_FTRUNCATE
42 /*******************************************************************
43ftruncate for operating systems that don't have it
44********************************************************************/
45int rep_ftruncate(int f, off_t l)
46{
47#ifdef HAVE_CHSIZE
48      return chsize(f,l);
49#elif defined(F_FREESP)
50      struct  flock   fl;
51
52      fl.l_whence = 0;
53      fl.l_len = 0;
54      fl.l_start = l;
55      fl.l_type = F_WRLCK;
56      return fcntl(f, F_FREESP, &fl);
57#else
58#error "you must have a ftruncate function"
59#endif
60}
61#endif /* HAVE_FTRUNCATE */
62
63
64#ifndef HAVE_STRLCPY
65/* like strncpy but does not 0 fill the buffer and always null
66   terminates. bufsize is the size of the destination buffer */
67size_t rep_strlcpy(char *d, const char *s, size_t bufsize)
68{
69	size_t len = strlen(s);
70	size_t ret = len;
71	if (bufsize <= 0) return 0;
72	if (len >= bufsize) len = bufsize-1;
73	memcpy(d, s, len);
74	d[len] = 0;
75	return ret;
76}
77#endif
78
79#ifndef HAVE_STRLCAT
80/* like strncat but does not 0 fill the buffer and always null
81   terminates. bufsize is the length of the buffer, which should
82   be one more than the maximum resulting string length */
83size_t rep_strlcat(char *d, const char *s, size_t bufsize)
84{
85	size_t len1 = strlen(d);
86	size_t len2 = strlen(s);
87	size_t ret = len1 + len2;
88
89	if (len1+len2 >= bufsize) {
90		if (bufsize < (len1+1)) {
91			return ret;
92		}
93		len2 = bufsize - (len1+1);
94	}
95	if (len2 > 0) {
96		memcpy(d+len1, s, len2);
97		d[len1+len2] = 0;
98	}
99	return ret;
100}
101#endif
102
103#ifndef HAVE_MKTIME
104/*******************************************************************
105a mktime() replacement for those who don't have it - contributed by
106C.A. Lademann <cal@zls.com>
107Corrections by richard.kettlewell@kewill.com
108********************************************************************/
109
110#define  MINUTE  60
111#define  HOUR    60*MINUTE
112#define  DAY             24*HOUR
113#define  YEAR    365*DAY
114time_t rep_mktime(struct tm *t)
115{
116  struct tm       *u;
117  time_t  epoch = 0;
118  int n;
119  int             mon [] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
120  y, m, i;
121
122  if(t->tm_year < 70)
123    return((time_t)-1);
124
125  n = t->tm_year + 1900 - 1;
126  epoch = (t->tm_year - 70) * YEAR +
127    ((n / 4 - n / 100 + n / 400) - (1969 / 4 - 1969 / 100 + 1969 / 400)) * DAY;
128
129  y = t->tm_year + 1900;
130  m = 0;
131
132  for(i = 0; i < t->tm_mon; i++) {
133    epoch += mon [m] * DAY;
134    if(m == 1 && y % 4 == 0 && (y % 100 != 0 || y % 400 == 0))
135      epoch += DAY;
136
137    if(++m > 11) {
138      m = 0;
139      y++;
140    }
141  }
142
143  epoch += (t->tm_mday - 1) * DAY;
144  epoch += t->tm_hour * HOUR + t->tm_min * MINUTE + t->tm_sec;
145
146  if((u = localtime(&epoch)) != NULL) {
147    t->tm_sec = u->tm_sec;
148    t->tm_min = u->tm_min;
149    t->tm_hour = u->tm_hour;
150    t->tm_mday = u->tm_mday;
151    t->tm_mon = u->tm_mon;
152    t->tm_year = u->tm_year;
153    t->tm_wday = u->tm_wday;
154    t->tm_yday = u->tm_yday;
155    t->tm_isdst = u->tm_isdst;
156  }
157
158  return(epoch);
159}
160#endif /* !HAVE_MKTIME */
161
162
163#ifndef HAVE_INITGROUPS
164/****************************************************************************
165 some systems don't have an initgroups call
166****************************************************************************/
167int rep_initgroups(char *name, gid_t id)
168{
169#ifndef HAVE_SETGROUPS
170	/* yikes! no SETGROUPS or INITGROUPS? how can this work? */
171	errno = ENOSYS;
172	return -1;
173#else /* HAVE_SETGROUPS */
174
175#include <grp.h>
176
177	gid_t *grouplst = NULL;
178	int max_gr = NGROUPS_MAX;
179	int ret;
180	int    i,j;
181	struct group *g;
182	char   *gr;
183
184	if((grouplst = malloc(sizeof(gid_t) * max_gr)) == NULL) {
185		errno = ENOMEM;
186		return -1;
187	}
188
189	grouplst[0] = id;
190	i = 1;
191	while (i < max_gr && ((g = (struct group *)getgrent()) != (struct group *)NULL)) {
192		if (g->gr_gid == id)
193			continue;
194		j = 0;
195		gr = g->gr_mem[0];
196		while (gr && (*gr != (char)NULL)) {
197			if (strcmp(name,gr) == 0) {
198				grouplst[i] = g->gr_gid;
199				i++;
200				gr = (char *)NULL;
201				break;
202			}
203			gr = g->gr_mem[++j];
204		}
205	}
206	endgrent();
207	ret = setgroups(i, grouplst);
208	free(grouplst);
209	return ret;
210#endif /* HAVE_SETGROUPS */
211}
212#endif /* HAVE_INITGROUPS */
213
214
215#if (defined(SecureWare) && defined(SCO))
216/* This is needed due to needing the nap() function but we don't want
217   to include the Xenix libraries since that will break other things...
218   BTW: system call # 0x0c28 is the same as calling nap() */
219long nap(long milliseconds) {
220	 return syscall(0x0c28, milliseconds);
221 }
222#endif
223
224
225#ifndef HAVE_MEMMOVE
226/*******************************************************************
227safely copies memory, ensuring no overlap problems.
228this is only used if the machine does not have its own memmove().
229this is not the fastest algorithm in town, but it will do for our
230needs.
231********************************************************************/
232void *rep_memmove(void *dest,const void *src,int size)
233{
234	unsigned long d,s;
235	int i;
236	if (dest==src || !size) return(dest);
237
238	d = (unsigned long)dest;
239	s = (unsigned long)src;
240
241	if ((d >= (s+size)) || (s >= (d+size))) {
242		/* no overlap */
243		memcpy(dest,src,size);
244		return(dest);
245	}
246
247	if (d < s) {
248		/* we can forward copy */
249		if (s-d >= sizeof(int) &&
250		    !(s%sizeof(int)) &&
251		    !(d%sizeof(int)) &&
252		    !(size%sizeof(int))) {
253			/* do it all as words */
254			int *idest = (int *)dest;
255			int *isrc = (int *)src;
256			size /= sizeof(int);
257			for (i=0;i<size;i++) idest[i] = isrc[i];
258		} else {
259			/* simplest */
260			char *cdest = (char *)dest;
261			char *csrc = (char *)src;
262			for (i=0;i<size;i++) cdest[i] = csrc[i];
263		}
264	} else {
265		/* must backward copy */
266		if (d-s >= sizeof(int) &&
267		    !(s%sizeof(int)) &&
268		    !(d%sizeof(int)) &&
269		    !(size%sizeof(int))) {
270			/* do it all as words */
271			int *idest = (int *)dest;
272			int *isrc = (int *)src;
273			size /= sizeof(int);
274			for (i=size-1;i>=0;i--) idest[i] = isrc[i];
275		} else {
276			/* simplest */
277			char *cdest = (char *)dest;
278			char *csrc = (char *)src;
279			for (i=size-1;i>=0;i--) cdest[i] = csrc[i];
280		}
281	}
282	return(dest);
283}
284#endif /* HAVE_MEMMOVE */
285
286#ifndef HAVE_STRDUP
287/****************************************************************************
288duplicate a string
289****************************************************************************/
290char *rep_strdup(const char *s)
291{
292	size_t len;
293	char *ret;
294
295	if (!s) return(NULL);
296
297	len = strlen(s)+1;
298	ret = (char *)malloc(len);
299	if (!ret) return(NULL);
300	memcpy(ret,s,len);
301	return(ret);
302}
303#endif /* HAVE_STRDUP */
304
305#ifndef HAVE_SETLINEBUF
306void rep_setlinebuf(FILE *stream)
307{
308	setvbuf(stream, (char *)NULL, _IOLBF, 0);
309}
310#endif /* HAVE_SETLINEBUF */
311
312#ifndef HAVE_VSYSLOG
313#ifdef HAVE_SYSLOG
314void rep_vsyslog (int facility_priority, const char *format, va_list arglist)
315{
316	char *msg = NULL;
317	vasprintf(&msg, format, arglist);
318	if (!msg)
319		return;
320	syslog(facility_priority, "%s", msg);
321	free(msg);
322}
323#endif /* HAVE_SYSLOG */
324#endif /* HAVE_VSYSLOG */
325
326#ifndef HAVE_STRNLEN
327/**
328 Some platforms don't have strnlen
329**/
330 size_t rep_strnlen(const char *s, size_t max)
331{
332        size_t len;
333
334        for (len = 0; len < max; len++) {
335                if (s[len] == '\0') {
336                        break;
337                }
338        }
339        return len;
340}
341#endif
342
343#ifndef HAVE_STRNDUP
344/**
345 Some platforms don't have strndup.
346**/
347char *rep_strndup(const char *s, size_t n)
348{
349	char *ret;
350
351	n = strnlen(s, n);
352	ret = malloc(n+1);
353	if (!ret)
354		return NULL;
355	memcpy(ret, s, n);
356	ret[n] = 0;
357
358	return ret;
359}
360#endif
361
362#if !defined(HAVE_WAITPID) && defined(HAVE_WAIT4)
363int rep_waitpid(pid_t pid,int *status,int options)
364{
365  return wait4(pid, status, options, NULL);
366}
367#endif
368
369#ifndef HAVE_SETEUID
370int rep_seteuid(uid_t euid)
371{
372#ifdef HAVE_SETRESUID
373	return setresuid(-1, euid, -1);
374#else
375	errno = ENOSYS;
376	return -1;
377#endif
378}
379#endif
380
381#ifndef HAVE_SETEGID
382int rep_setegid(gid_t egid)
383{
384#ifdef HAVE_SETRESGID
385	return setresgid(-1, egid, -1);
386#else
387	errno = ENOSYS;
388	return -1;
389#endif
390}
391#endif
392
393/*******************************************************************
394os/2 also doesn't have chroot
395********************************************************************/
396#ifndef HAVE_CHROOT
397int rep_chroot(const char *dname)
398{
399	errno = ENOSYS;
400	return -1;
401}
402#endif
403
404/*****************************************************************
405 Possibly replace mkstemp if it is broken.
406*****************************************************************/
407
408#ifndef HAVE_SECURE_MKSTEMP
409int rep_mkstemp(char *template)
410{
411	/* have a reasonable go at emulating it. Hope that
412	   the system mktemp() isn't completly hopeless */
413	char *p = mktemp(template);
414	if (!p)
415		return -1;
416	return open(p, O_CREAT|O_EXCL|O_RDWR, 0600);
417}
418#endif
419
420#ifndef HAVE_MKDTEMP
421char *rep_mkdtemp(char *template)
422{
423	char *dname;
424
425	if ((dname = mktemp(template))) {
426		if (mkdir(dname, 0700) >= 0) {
427			return dname;
428		}
429	}
430
431	return NULL;
432}
433#endif
434
435/*****************************************************************
436 Watch out: this is not thread safe.
437*****************************************************************/
438
439#ifndef HAVE_PREAD
440ssize_t rep_pread(int __fd, void *__buf, size_t __nbytes, off_t __offset)
441{
442	if (lseek(__fd, __offset, SEEK_SET) != __offset) {
443		return -1;
444	}
445	return read(__fd, __buf, __nbytes);
446}
447#endif
448
449/*****************************************************************
450 Watch out: this is not thread safe.
451*****************************************************************/
452
453#ifndef HAVE_PWRITE
454ssize_t rep_pwrite(int __fd, const void *__buf, size_t __nbytes, off_t __offset)
455{
456	if (lseek(__fd, __offset, SEEK_SET) != __offset) {
457		return -1;
458	}
459	return write(__fd, __buf, __nbytes);
460}
461#endif
462
463#ifndef HAVE_STRCASESTR
464char *rep_strcasestr(const char *haystack, const char *needle)
465{
466	const char *s;
467	size_t nlen = strlen(needle);
468	for (s=haystack;*s;s++) {
469		if (toupper(*needle) == toupper(*s) &&
470		    strncasecmp(s, needle, nlen) == 0) {
471			return (char *)((uintptr_t)s);
472		}
473	}
474	return NULL;
475}
476#endif
477
478#ifndef HAVE_STRTOK_R
479/* based on GLIBC version, copyright Free Software Foundation */
480char *rep_strtok_r(char *s, const char *delim, char **save_ptr)
481{
482	char *token;
483
484	if (s == NULL) s = *save_ptr;
485
486	s += strspn(s, delim);
487	if (*s == '\0') {
488		*save_ptr = s;
489		return NULL;
490	}
491
492	token = s;
493	s = strpbrk(token, delim);
494	if (s == NULL) {
495		*save_ptr = token + strlen(token);
496	} else {
497		*s = '\0';
498		*save_ptr = s + 1;
499	}
500
501	return token;
502}
503#endif
504
505#ifndef HAVE_STRTOLL
506long long int rep_strtoll(const char *str, char **endptr, int base)
507{
508#ifdef HAVE_STRTOQ
509	return strtoq(str, endptr, base);
510#elif defined(HAVE___STRTOLL)
511	return __strtoll(str, endptr, base);
512#elif SIZEOF_LONG == SIZEOF_LONG_LONG
513	return (long long int) strtol(str, endptr, base);
514#else
515# error "You need a strtoll function"
516#endif
517}
518#endif
519
520
521#ifndef HAVE_STRTOULL
522unsigned long long int rep_strtoull(const char *str, char **endptr, int base)
523{
524#ifdef HAVE_STRTOUQ
525	return strtouq(str, endptr, base);
526#elif defined(HAVE___STRTOULL)
527	return __strtoull(str, endptr, base);
528#elif SIZEOF_LONG == SIZEOF_LONG_LONG
529	return (unsigned long long int) strtoul(str, endptr, base);
530#else
531# error "You need a strtoull function"
532#endif
533}
534#endif
535
536#ifndef HAVE_SETENV
537int rep_setenv(const char *name, const char *value, int overwrite)
538{
539	char *p;
540	size_t l1, l2;
541	int ret;
542
543	if (!overwrite && getenv(name)) {
544		return 0;
545	}
546
547	l1 = strlen(name);
548	l2 = strlen(value);
549
550	p = malloc(l1+l2+2);
551	if (p == NULL) {
552		return -1;
553	}
554	memcpy(p, name, l1);
555	p[l1] = '=';
556	memcpy(p+l1+1, value, l2);
557	p[l1+l2+1] = 0;
558
559	ret = putenv(p);
560	if (ret != 0) {
561		free(p);
562	}
563
564	return ret;
565}
566#endif
567
568#ifndef HAVE_UNSETENV
569int rep_unsetenv(const char *name)
570{
571	extern char **environ;
572	size_t len = strlen(name);
573	size_t i, count;
574
575	if (environ == NULL || getenv(name) == NULL) {
576		return 0;
577	}
578
579	for (i=0;environ[i];i++) /* noop */ ;
580
581	count=i;
582
583	for (i=0;i<count;) {
584		if (strncmp(environ[i], name, len) == 0 && environ[i][len] == '=') {
585			/* note: we do _not_ free the old variable here. It is unsafe to
586			   do so, as the pointer may not have come from malloc */
587			memmove(&environ[i], &environ[i+1], (count-i)*sizeof(char *));
588			count--;
589		} else {
590			i++;
591		}
592	}
593
594	return 0;
595}
596#endif
597
598#ifndef HAVE_UTIME
599int rep_utime(const char *filename, const struct utimbuf *buf)
600{
601	errno = ENOSYS;
602	return -1;
603}
604#endif
605
606#ifndef HAVE_UTIMES
607int rep_utimes(const char *filename, const struct timeval tv[2])
608{
609	struct utimbuf u;
610
611	u.actime = tv[0].tv_sec;
612	if (tv[0].tv_usec > 500000) {
613		u.actime += 1;
614	}
615
616	u.modtime = tv[1].tv_sec;
617	if (tv[1].tv_usec > 500000) {
618		u.modtime += 1;
619	}
620
621	return utime(filename, &u);
622}
623#endif
624
625#ifndef HAVE_DUP2
626int rep_dup2(int oldfd, int newfd)
627{
628	errno = ENOSYS;
629	return -1;
630}
631#endif
632
633#ifndef HAVE_CHOWN
634/**
635chown isn't used much but OS/2 doesn't have it
636**/
637int rep_chown(const char *fname, uid_t uid, gid_t gid)
638{
639	errno = ENOSYS;
640	return -1;
641}
642#endif
643
644#ifndef HAVE_LINK
645int rep_link(const char *oldpath, const char *newpath)
646{
647	errno = ENOSYS;
648	return -1;
649}
650#endif
651
652#ifndef HAVE_READLINK
653int rep_readlink(const char *path, char *buf, size_t bufsiz)
654{
655	errno = ENOSYS;
656	return -1;
657}
658#endif
659
660#ifndef HAVE_SYMLINK
661int rep_symlink(const char *oldpath, const char *newpath)
662{
663	errno = ENOSYS;
664	return -1;
665}
666#endif
667
668#ifndef HAVE_LCHOWN
669int rep_lchown(const char *fname,uid_t uid,gid_t gid)
670{
671	errno = ENOSYS;
672	return -1;
673}
674#endif
675
676#ifndef HAVE_REALPATH
677char *rep_realpath(const char *path, char *resolved_path)
678{
679	/* As realpath is not a system call we can't return ENOSYS. */
680	errno = EINVAL;
681	return NULL;
682}
683#endif
684