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