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 :
38 : void replace_dummy(void);
39 0 : void replace_dummy(void) {}
40 :
41 : #ifndef HAVE_FTRUNCATE
42 : /*******************************************************************
43 : ftruncate for operating systems that don't have it
44 : ********************************************************************/
45 : int 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 */
67 : size_t rep_strlcpy(char *d, const char *s, size_t bufsize)
68 18 : {
69 18 : size_t len = strlen(s);
70 18 : size_t ret = len;
71 18 : if (bufsize <= 0) return 0;
72 18 : if (len >= bufsize) len = bufsize-1;
73 18 : memcpy(d, s, len);
74 18 : d[len] = 0;
75 18 : 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 */
83 : size_t rep_strlcat(char *d, const char *s, size_t bufsize)
84 0 : {
85 0 : size_t len1 = strlen(d);
86 0 : size_t len2 = strlen(s);
87 0 : size_t ret = len1 + len2;
88 :
89 0 : if (len1+len2 >= bufsize) {
90 0 : if (bufsize < (len1+1)) {
91 0 : return ret;
92 : }
93 0 : len2 = bufsize - (len1+1);
94 : }
95 0 : if (len2 > 0) {
96 0 : memcpy(d+len1, s, len2);
97 0 : d[len1+len2] = 0;
98 : }
99 0 : return ret;
100 : }
101 : #endif
102 :
103 : #ifndef HAVE_MKTIME
104 : /*******************************************************************
105 : a mktime() replacement for those who don't have it - contributed by
106 : C.A. Lademann <cal@zls.com>
107 : Corrections 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
114 : time_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 : ****************************************************************************/
167 : int 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() */
219 : long nap(long milliseconds) {
220 : return syscall(0x0c28, milliseconds);
221 : }
222 : #endif
223 :
224 :
225 : #ifndef HAVE_MEMMOVE
226 : /*******************************************************************
227 : safely copies memory, ensuring no overlap problems.
228 : this is only used if the machine does not have its own memmove().
229 : this is not the fastest algorithm in town, but it will do for our
230 : needs.
231 : ********************************************************************/
232 : void *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 : /****************************************************************************
288 : duplicate a string
289 : ****************************************************************************/
290 : char *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
306 : void 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
314 : void 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 : **/
347 : char *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)
363 : int 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
370 : int 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
382 : int 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 : /*******************************************************************
394 : os/2 also doesn't have chroot
395 : ********************************************************************/
396 : #ifndef HAVE_CHROOT
397 : int 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
409 : int rep_mkstemp(char *template)
410 : {
411 : /* have a reasonable go at emulating it. Hope that
412 : the system mktemp() isn't completely 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
421 : char *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
440 : ssize_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
454 : ssize_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
464 : char *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 */
480 : char *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
506 : long 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
522 : unsigned 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
537 : int 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
569 : int 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
599 : int rep_utime(const char *filename, const struct utimbuf *buf)
600 : {
601 : errno = ENOSYS;
602 : return -1;
603 : }
604 : #endif
605 :
606 : #ifndef HAVE_UTIMES
607 : int 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
626 : int rep_dup2(int oldfd, int newfd)
627 : {
628 : errno = ENOSYS;
629 : return -1;
630 : }
631 : #endif
632 :
633 : #ifndef HAVE_CHOWN
634 : /**
635 : chown isn't used much but OS/2 doesn't have it
636 : **/
637 : int 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
645 : int rep_link(const char *oldpath, const char *newpath)
646 : {
647 : errno = ENOSYS;
648 : return -1;
649 : }
650 : #endif
651 :
652 : #ifndef HAVE_READLINK
653 : int 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
661 : int rep_symlink(const char *oldpath, const char *newpath)
662 : {
663 : errno = ENOSYS;
664 : return -1;
665 : }
666 : #endif
667 :
668 : #ifndef HAVE_LCHOWN
669 : int 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
677 : char *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 :
685 :
686 : #ifndef HAVE_MEMMEM
687 : void *rep_memmem(const void *haystack, size_t haystacklen,
688 : const void *needle, size_t needlelen)
689 : {
690 : if (needlelen == 0) {
691 : return discard_const(haystack);
692 : }
693 : while (haystacklen >= needlelen) {
694 : char *p = (char *)memchr(haystack, *(const char *)needle,
695 : haystacklen-(needlelen-1));
696 : if (!p) return NULL;
697 : if (memcmp(p, needle, needlelen) == 0) {
698 : return p;
699 : }
700 : haystack = p+1;
701 : haystacklen -= (p - (const char *)haystack) + 1;
702 : }
703 : return NULL;
704 : }
705 : #endif
706 :
707 : #ifndef HAVE_VDPRINTF
708 : int rep_vdprintf(int fd, const char *format, va_list ap)
709 : {
710 : char *s = NULL;
711 : int ret;
712 :
713 : vasprintf(&s, format, ap);
714 : if (s == NULL) {
715 : errno = ENOMEM;
716 : return -1;
717 : }
718 : ret = write(fd, s, strlen(s));
719 : free(s);
720 : return ret;
721 : }
722 : #endif
723 :
724 : #ifndef HAVE_DPRINTF
725 : int rep_dprintf(int fd, const char *format, ...)
726 : {
727 : int ret;
728 : va_list ap;
729 :
730 : va_start(ap, format);
731 : ret = vdprintf(fd, format, ap);
732 : va_end(ap);
733 :
734 : return ret;
735 : }
736 : #endif
737 :
738 : #ifndef HAVE_GET_CURRENT_DIR_NAME
739 : char *rep_get_current_dir_name(void)
740 : {
741 : char buf[PATH_MAX+1];
742 : char *p;
743 : p = getcwd(buf, sizeof(buf));
744 : if (p == NULL) {
745 : return NULL;
746 : }
747 : return strdup(p);
748 : }
749 : #endif
750 :
751 : #if !defined(HAVE_STRERROR_R) || !defined(STRERROR_R_PROTO_COMPATIBLE)
752 : int rep_strerror_r(int errnum, char *buf, size_t buflen)
753 0 : {
754 0 : char *s = strerror(errnum);
755 0 : if (strlen(s)+1 > buflen) {
756 0 : errno = ERANGE;
757 0 : return -1;
758 : }
759 0 : strncpy(buf, s, buflen);
760 0 : return 0;
761 : }
762 : #endif
|