source: trunk/src/slib.c @ 174

Last change on this file since 174 was 174, checked in by katerina, 13 years ago

Fix for tickets #112, #113 (dnmalloc deadlock on fork, hostname portability in test script).

File size: 61.4 KB
Line 
1#include "config_xor.h"
2
3
4#include <stdio.h>
5#include <stdlib.h>
6#include <stdarg.h>
7#include <string.h>
8#include <limits.h>
9#ifdef HAVE_STDINT_H
10/* for SIZE_MAX */
11#include <stdint.h>
12#endif
13
14#include <unistd.h>
15#include <sys/stat.h>
16#include <sys/types.h>
17#include <fcntl.h>
18#include <signal.h>
19
20#if TIME_WITH_SYS_TIME
21#include <sys/time.h>
22#include <time.h>
23#else
24#if HAVE_SYS_TIME_H
25#include <sys/time.h>
26#else
27#include <time.h>
28#endif
29#endif
30
31#ifdef HAVE_MEMORY_H
32#include <memory.h>
33#endif
34#ifdef HAVE_SYS_SELECT_H
35#include <sys/select.h>
36#endif
37
38#ifndef FD_SET
39#define NFDBITS         32
40#define FD_SET(n, p)    ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
41#define FD_CLR(n, p)    ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
42#define FD_ISSET(n, p)  ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
43#endif /* !FD_SET */
44#ifndef FD_SETSIZE
45#define FD_SETSIZE      32
46#endif
47#ifndef FD_ZERO
48#define FD_ZERO(p)      memset((char *)(p), '\0', sizeof(*(p)))
49#endif
50
51#define SH_REAL_SET
52
53#include "slib.h"
54#include "sh_calls.h"
55#define SH_NEED_PWD_GRP 1
56#include "sh_static.h"
57#include "sh_pthread.h"
58#include "sh_string.h"
59
60#undef  FIL__
61#define FIL__  _("slib.c")
62
63const uid_t sh_uid_neg = ((uid_t) -1);
64const gid_t sh_gid_neg = ((gid_t) -1);
65 
66#undef BREAKEXIT
67#if defined(SCREW_IT_UP) && defined(__linux__) && defined(__i386__)
68
69#ifdef SH_DEBUG
70#define BREAKEXIT(expr) \
71  do { \
72    int ixi; \
73    for (ixi = 0; ixi < 8; ++ixi) { \
74      if ((*(volatile unsigned *)((unsigned) expr + ixi) & 0xff) == 0xcc)  \
75        { dlog(0, FIL__, __LINE__, _("BREAKEXIT")); _exit(EXIT_FAILURE); } \
76      } \
77    } \
78  while (1 == 0)
79#else
80#define BREAKEXIT(expr) \
81  do { \
82    int ixi; \
83    for (ixi = 0; ixi < 8; ++ixi) { \
84      if ((*(volatile unsigned *)((unsigned) expr + ixi) & 0xff) == 0xcc) \
85        _exit(EXIT_FAILURE); \
86      } \
87    } \
88  while (1 == 0)
89#endif
90
91#else
92#define BREAKEXIT(expr)
93#endif
94
95/****************************************************************
96 *
97 *  The debug/trace subsystem
98 *
99 ****************************************************************/
100
101int slib_do_trace          = 0;
102int slib_trace_fd          = -1;
103
104static char trace_log[256] = { '\0' };
105static int trace_level     = 0;
106static FILE * trace_fp     = NULL;
107
108int  sl_trace_use (const char * dummy)
109{
110  (void) dummy;
111  slib_do_trace = 1;
112  return 0;
113}
114
115int  sl_trace_file (const char * str)
116{
117  if (!str)
118    return -1;
119  if (str[0] != '/')
120    return -1;
121  sl_strlcpy(trace_log, str, 256);
122  return 0;
123}
124
125FILE * sl_tracefile_open(const char * file, const char * mode)
126{
127  FILE * xp = NULL;
128  slib_trace_fd = open(file, O_WRONLY|O_CREAT|O_APPEND, 0600);
129  if (slib_trace_fd >= 0)
130    xp = fdopen(slib_trace_fd, mode);
131  return xp;
132}
133
134void sl_trace_in(const char * str, const char * file, int line)
135{
136  int    i;
137  if (trace_log[0] == '\0')
138    {
139      fprintf(stderr, "++ ");
140      for (i = 0; i < trace_level; ++i)
141        fprintf(stderr, ".  ");
142      fprintf(stderr, "[%2d] %s \t - File %c%s%c at line %d\n", 
143             trace_level, str, 0x22, file, 0x22, line);
144    }
145  else if (!sl_is_suid())
146    {
147      if (!trace_fp)
148        trace_fp = sl_tracefile_open(trace_log, "a");
149      if (trace_fp)
150        {
151          fprintf(trace_fp, "++ ");
152          for (i = 0; i < trace_level; ++i)
153            fprintf(trace_fp, ".  ");
154          fprintf(trace_fp, "[%2d] %s \t - File %c%s%c at line %d\n", 
155                 trace_level, str, 0x22, file, 0x22, line);
156          fflush(trace_fp);
157        }
158      else
159        {
160          perror(_("sl_trace_in: fopen"));
161          _exit(1);
162        }
163    }
164  ++trace_level;
165}
166
167void sl_trace_out(const char * str, const char * file, int line)
168{
169  int    i;
170
171  --trace_level; if (trace_level < 0) trace_level = 0;
172
173  if (trace_log[0] == '\0')
174    {
175      fprintf(stderr, "-- ");
176      for (i = 0; i < trace_level; ++i)
177        fprintf(stderr, ".  ");
178      fprintf(stderr, _("[%2d] %s \t - File %c%s%c at line %d\n"), 
179             trace_level, str, 0x22, file, 0x22, line);
180    }
181  else if (!sl_is_suid())
182    {
183      if (!trace_fp)
184        trace_fp = sl_tracefile_open(trace_log, "a");
185      if (trace_fp)
186        {
187          fprintf(trace_fp, "-- ");
188          for (i = 0; i < trace_level; ++i)
189            fprintf(trace_fp, ".  ");
190          fprintf(trace_fp, _("[%2d] %s \t - File %c%s%c at line %d\n"), 
191                 trace_level, str, 0x22, file, 0x22, line);
192          fflush(trace_fp);
193        }
194      else
195        {
196          perror(_("sl_trace_out: fopen"));
197          _exit(1);
198        }
199    }
200}
201
202extern int sh_log_console (const char * msg);
203
204static int dlogActive = 0;
205
206/* this is called from sh_error_setprint()
207 */
208void dlog_set_active(int flag)
209{
210  dlogActive = flag;
211}
212
213/* flag = 0 debug messages
214 *      = 1 descriptive error messages
215 *      = 3 backtrace
216 */
217int dlog (int flag, const char * file, int line,  const char *fmt, ...)
218{
219  va_list     ap;
220  char        val[81];
221  char        msg[512];
222  char        tmp[512];
223  int         retval = 0;
224  int         i;
225
226#ifdef SH_STEALTH
227  /*
228   * do not even print descriptive failure messages in stealth mode
229   */
230  if (dlogActive == 0)
231    return 0;
232  if (dlogActive == 1 && flag == 0) /* debug requires debug level */
233    return 0;
234#else
235  if (dlogActive <= 1 && flag == 0) /* debug requires debug level */
236    return 0;
237#endif
238
239  if (flag == 1)
240    {
241      sl_snprintf    (val, 81, _("\n---------  %10s "), file);
242      sl_strlcpy     (msg,    val,   80);
243      sl_snprintf    (val, 81, _(" --- %6d ---------\n"), line);
244      sl_strlcat     (msg,     val,   80);
245      sh_log_console (msg);
246    }
247
248  va_start (ap, fmt);
249  if (flag == 1)
250    sl_strlcpy(tmp, fmt, 512);
251  else
252    sl_strlcpy(tmp, fmt, 256);
253  retval = sl_strlen(tmp);
254  if (retval > 0 && tmp[retval-1] == '\n')
255    tmp[retval-1] = '\0';
256  retval = 0;
257  if (flag == 1)
258    {
259      sl_vsnprintf (msg, 511, tmp, ap);
260    }
261  else
262    {
263      sl_strlcpy   (msg,    "## ", 256);
264      for (i = 0; i < trace_level; ++i)
265        sl_strlcat (msg, ".  ", 256);
266      sprintf      (val, _("[%2d] "), trace_level);
267      sl_strlcat   (msg,     val,   256);
268      sl_vsnprintf (&msg[sl_strlen(msg)], 255, tmp, ap);
269      sl_snprintf  (tmp, 255, _(" \t - File %c%s%c at line %d"), 
270                    0x22, file, 0x22, line);
271      sl_strlcat   (msg,     tmp,   512);
272    }
273  va_end (ap);
274  if (flag != 0 || sl_is_suid())
275    retval = sh_log_console (msg);
276  else
277    {
278      if (trace_log[0] == '\0')
279        {
280          /* sh_log_console (msg); */
281          fprintf(stderr, "%s\n", msg);
282        }
283      else
284        {
285          if (!trace_fp)
286            trace_fp = sl_tracefile_open(trace_log, "a");
287          if (trace_fp)
288            {
289              fprintf(trace_fp, "%s\n", msg);
290            }
291          else
292            {
293              perror(_("dlog: fopen"));
294              _exit(1);
295            }
296        }
297    }
298  if (flag == 1)
299    sh_log_console (_("\n----------------------------------------------\n"));
300  return retval;
301}
302
303extern char aud_err_message[64];
304static char alt_err_message[64];
305char * sl_get_errmsg()
306{
307  if (aud_err_message[0] == '\0')
308    {
309      sl_strlcpy(alt_err_message, sl_error_string(sl_errno), 64);
310      return &alt_err_message[0];
311    }
312  return &aud_err_message[0];
313}
314
315
316#if defined(SL_DEBUG)
317#define SL_MAX_MYSTACK 128
318
319static char sl_mystack[SL_MAX_MYSTACK][32];
320static int  sl_mystack_count = 0; 
321
322void sl_stack_push(char * c, char * file, int line )
323{
324  if (slib_do_trace)
325    sl_trace_in(c, file, line);
326  if (c && sl_mystack_count < SL_MAX_MYSTACK)
327    {
328      strncpy(sl_mystack[sl_mystack_count], c, 31);
329      sl_mystack[sl_mystack_count][31] = '\0';
330      ++sl_mystack_count;
331      /*
332      fprintf(stderr, "#%03d %s\n", sl_mystack_count,
333              sl_mystack[sl_mystack_count-1]);
334      */
335    }
336  return;
337}
338
339void sl_stack_pop(char * c, char * file, int line)
340{
341  if (slib_do_trace)
342    sl_trace_out(c, file, line);
343  if (sl_mystack_count > 0)
344    {
345      /*
346      fprintf(stderr, " <- #%03d %s\n", sl_mystack_count,
347              sl_mystack[sl_mystack_count-1]);
348      */
349      --sl_mystack_count;
350    }
351  return;
352}
353
354void sl_stack_print()
355{
356  int  i;
357  /* FILE * dfile; */
358
359  if (sl_mystack_count > 0)
360    {
361      sh_log_console(_("\nBacktrace:\n"));
362      /* dlog(3, FIL__, __LINE__, _("\nBacktrace:\n")); */
363      for (i = 0; i < sl_mystack_count; ++i)
364        sh_log_console(sl_mystack[i]);
365      /* dlog(3, FIL__, __LINE__, _("#%03d %s\n"), i, sl_mystack[i]); */
366    } 
367  return;
368}
369
370#endif
371
372
373/*
374 *  The global errno.
375 *  On error, this is set to the return value of the function.
376 */
377long int sl_errno;
378
379
380/* ----------------------------------------------------------------
381 *
382 *    Capability routines
383 *
384 * ---------------------------------------------------------------- */
385
386int sl_useCaps = 0;
387
388#ifdef FANCY_LIBCAP
389#include <sys/capability.h>
390
391/*
392 * While these routines are tested and work, we don't use POSIX
393 * capabilities, as they don't seem to be useful (root can write
394 * to root-owned files anyway). Things would be more interesting
395 * if we could switch to a non-root UID with just a few capabilities
396 * enabled.
397 */
398int sl_drop_cap ()
399{
400  int              error;
401  cap_t            caps;
402  cap_flag_t       capflag;
403  cap_flag_value_t capfval = CAP_CLEAR;
404  cap_value_t      capvals_e[] =
405  { 
406    CAP_CHOWN,            CAP_FOWNER,        CAP_FSETID,
407    CAP_LINUX_IMMUTABLE,  CAP_MKNOD,         CAP_NET_ADMIN,
408    CAP_NET_BIND_SERVICE, CAP_NET_BROADCAST, CAP_NET_RAW,
409    CAP_SYS_ADMIN,        CAP_SYS_BOOT,      CAP_SYS_CHROOT,
410    CAP_SYS_PACCT,        CAP_SYS_PTRACE,    CAP_SYS_RAWIO,
411    CAP_SYS_RESOURCE,     CAP_SYS_TIME,      CAP_SYS_TTY_CONFIG,
412    CAP_SETGID,           CAP_SETUID,        CAP_KILL,
413    CAP_DAC_OVERRIDE,
414#if !defined(WITH_MESSAGE_QUEUE)
415    CAP_IPC_OWNER,
416#endif
417    CAP_SYS_MODULE,       CAP_LEASE
418  };
419  cap_value_t      capvals_p[] =
420  { 
421    CAP_CHOWN,            CAP_LEASE,         CAP_FSETID,
422    CAP_LINUX_IMMUTABLE,  CAP_MKNOD,         CAP_NET_ADMIN,
423    CAP_NET_BIND_SERVICE, CAP_NET_BROADCAST, CAP_NET_RAW,
424    CAP_SYS_ADMIN,        CAP_SYS_BOOT,      CAP_SYS_CHROOT,
425    CAP_SYS_PACCT,        CAP_SYS_PTRACE,    CAP_SYS_RAWIO,
426    CAP_SYS_RESOURCE,     CAP_SYS_TIME,      CAP_SYS_TTY_CONFIG,
427#if !defined(WITH_EXTERNAL) && !defined(HAVE_UNIX_RANDOM)
428    CAP_SETGID,           CAP_SETUID,        CAP_KILL,
429#endif
430#if !defined(SH_USE_SUIDCHK)
431    CAP_DAC_OVERRIDE,     CAP_FOWNER,       
432#endif
433#if !defined(WITH_MESSAGE_QUEUE)
434    CAP_IPC_OWNER,
435#endif
436    CAP_SYS_MODULE
437  };
438
439  if (0 == sl_useCaps) /* 0 = S_FALSE */
440    {
441      return 0;
442    }
443
444  if(NULL == (caps = cap_get_proc()))
445    {
446      return errno;
447    }
448
449  capflag = CAP_EFFECTIVE;
450  if (0 != cap_set_flag(caps, capflag, sizeof(capvals_e)/sizeof(cap_value_t),
451                        capvals_e, capfval))
452    {
453      error = errno;
454      cap_free(caps);
455      return error;
456    }
457  if (0 != cap_set_proc(caps))
458    {
459      error = errno;
460      cap_free(caps);
461      return error;
462    }
463
464  capflag = CAP_PERMITTED;
465  if (0 != cap_set_flag(caps, capflag, sizeof(capvals_p)/sizeof(cap_value_t),
466                        capvals_p, capfval))
467    {
468      error = errno;
469      cap_free(caps);
470      return error;
471    }
472  if (0 != cap_set_proc(caps))
473    {
474      error = errno;
475      cap_free(caps);
476      return error;
477    }
478  cap_free(caps);
479  return 0;
480}
481
482int sl_drop_cap_int(int what)
483{
484#if defined(SL_DEBUG)
485  char           * captext;
486#endif
487  cap_flag_t       capflag = CAP_EFFECTIVE;
488  cap_flag_value_t capfval = CAP_CLEAR;
489  cap_value_t      capvals_a[] = { CAP_SETGID, CAP_SETUID, CAP_KILL };
490  cap_value_t      capvals_b[] = { CAP_DAC_OVERRIDE, CAP_FOWNER };
491  cap_value_t    * capvals;
492  int              nvals;
493  int              error = 0;
494  cap_t            caps = cap_get_proc();
495
496  if (0 == sl_useCaps) /* 0 = S_FALSE */
497    {
498      return 0;
499    }
500
501  if (caps == NULL)
502    {
503      return errno;
504    }
505
506  switch (what) {
507    case 1:
508      capvals = capvals_a;
509      nvals   = 3;
510      capfval = CAP_CLEAR;
511      break;
512    case 2:
513      capvals = capvals_a;
514      nvals   = 3;
515      capfval = CAP_SET;
516      break;
517    case 3:
518      capvals = capvals_b;
519      nvals   = 2;
520      capfval = CAP_CLEAR;
521      break;
522    case 4:
523      capvals = capvals_b;
524      nvals   = 2;
525      capfval = CAP_SET;
526      break;
527    default:
528      return (0);
529  }
530
531  if (0 != cap_set_flag(caps, capflag, nvals, capvals, capfval))
532    {
533      error = errno;
534      cap_free(caps);
535      return error;
536    }
537  if (0 != cap_set_proc(caps))
538    {
539      error = errno;
540      cap_free(caps);
541      return error;
542    }
543#if defined(SL_DEBUG)
544  captext = cap_to_text(caps, NULL);
545  TPT(( 0, FIL__, __LINE__, _("msg=<cap_int %d: %s>\n"), what, captext));
546  cap_free(captext);
547#endif
548  cap_free(caps);
549  return 0;
550}
551
552int sl_drop_cap_sub()  { return sl_drop_cap_int(1); }
553int sl_get_cap_sub()   { return sl_drop_cap_int(2); }
554int sl_drop_cap_qdel() { return sl_drop_cap_int(3); }
555int sl_get_cap_qdel()  { return sl_drop_cap_int(4); }
556
557#else
558int sl_drop_cap ()     { return 0; }
559int sl_drop_cap_sub()  { return 0; }
560int sl_get_cap_sub()   { return 0; }
561int sl_drop_cap_qdel() { return 0; }
562int sl_get_cap_qdel()  { return 0; }
563#endif
564
565/* ----------------------------------------------------------------
566 *
567 *    String handling routines
568 *
569 * ---------------------------------------------------------------- */
570 
571/*
572 * Have memset in a different translation unit (i.e. this) to prevent
573 * it to get optimized away
574 */
575void *sl_memset(void *s, int c, size_t n)
576{
577  return memset(s, c,n);
578}
579
580
581#if !defined (VA_COPY)
582#if defined (__GNUC__) && defined (__PPC__) && (defined (_CALL_SYSV) || defined (_WIN32))
583#define VA_COPY(ap1, ap2)     (*(ap1) = *(ap2))
584#elif defined (VA_COPY_AS_ARRAY)
585#define VA_COPY(ap1, ap2)     memmove ((ap1), (ap2), sizeof (va_list))
586#else /* va_list is a pointer */
587#define VA_COPY(ap1, ap2)     ((ap1) = (ap2))
588#endif
589#endif
590
591#if !defined(HAVE_VSNPRINTF) || defined(HAVE_BROKEN_VSNPRINTF)
592static
593size_t sl_printf_count (const char * fmt, va_list  vl)
594{
595  size_t  length       = 1;
596  int  fini         = 0;
597  int  islong       = 0;
598  int  islonglong   = 0;
599  int  islongdouble = 0;
600  char * string_arg;
601
602  SL_ENTER(_("sl_printf_count"));
603
604  if (fmt == NULL)
605    SL_IRETURN(SL_ENULL, _("sl_printf_count"));
606
607  while (*fmt) {
608
609    if ( (*fmt) == '%' ) { /* a format specifier */
610
611      fmt++;        /* point to first char after '%' */
612
613      fini = 0;
614      islong = 0;
615      islongdouble = 0;
616
617      while (*fmt && (fini == 0) ) {
618       
619        switch (*fmt) {
620
621        case '*':      /* field width supplied by an integer */
622          length = length + va_arg (vl, int);
623          ++fmt;
624          break;
625        case '1':
626        case '2':
627        case '3':
628        case '4':
629        case '5':
630        case '6':
631        case '7':
632        case '8':
633        case '9':
634          length = length + strtol (fmt, (char**) &fmt, 10);
635          /* strtol makes FastForward to first invalid char */
636          break;
637
638        case 'l':   /* 'long' modifier */
639          if (islong == 0)
640            islong = 1;
641          else
642            {
643              islonglong = 1;
644              islong = 0;
645            }
646          ++fmt;
647          break;
648
649        case 'L':  /* 'long double' modifier */ 
650#ifdef HAVE_LONG_DOUBLE   
651          islongdouble = 1;
652#else
653          islong = 1;
654#endif
655          ++fmt;
656          break;
657
658        case 'd':
659        case 'i': 
660        case 'o':
661        case 'u':
662        case 'x':
663        case 'X':
664          if (islonglong == 1)
665#ifdef HAVE_LONG_LONG
666            (void) va_arg (vl, long long);
667#else
668            (void) va_arg (vl, long);
669#endif
670          else if (islong == 1)
671            (void) va_arg (vl, long);
672          else
673            (void) va_arg (vl, int);
674          islong = 0;
675          islonglong = 0;
676          length = length + 24;
677          ++fmt;
678          fini = 1;
679          break;
680
681        case 'D':
682        case 'O':
683        case 'U':
684          (void) va_arg (vl, long);
685          length = length + 24;
686          fmt++;
687          fini = 1;
688          break;
689
690        case 'e':
691        case 'E':
692        case 'f':
693        case 'g':
694#ifdef HAVE_LONG_DOUBLE   
695          if (islongdouble == 1) {
696            (void) va_arg (vl, long double);
697            islongdouble = 0;
698            length = length + 20;
699            }
700          else
701#endif
702            (void) va_arg (vl, double);
703          length = length + 20;
704          fini = 1;
705          ++fmt;
706          break;
707
708        case 's':
709          string_arg = va_arg (vl, char *);
710          if (string_arg != NULL)
711            length = length + sl_strlen (string_arg);
712          else
713            length = length + 16;
714          fini = 1;
715          ++fmt;
716          break;
717
718        case 'c':
719          (void) va_arg (vl, int);
720          length = length + 1;
721          fini = 1;
722          ++fmt;
723          break;
724
725        case 'p':
726        case 'n':
727          (void) va_arg (vl, void * );
728          length = length + 32;
729          fini = 1;
730          ++fmt;
731          break;
732
733        case '%':            /* %% will print '%' */
734          length = length + 1;
735          fini = 1;
736          ++fmt;
737          break;
738
739        default:
740          length = length + 1;
741          ++fmt;
742          break;
743
744        }  /* end switch */
745      }   
746      /* end parsing a single format specifier */
747    } else {
748      length = length + 1;
749      fmt++;
750    }
751  }
752  SL_IRETURN(length, _("sl_printf_count"));
753}
754#endif  /* #ifndef  HAVE_VSNPRINTF */
755
756/*
757 * An implementation of vsnprintf. va_start/va_end are in the caller
758 * function.
759 * Returns C99 (#bytes that would heve been written) on success.
760 */
761int sl_vsnprintf(char *str, size_t n,
762                 const char *format, va_list vl )
763{
764  int len = 0;
765#if !defined(HAVE_VSNPRINTF) || defined(HAVE_BROKEN_VSNPRINTF)
766  size_t         total;
767  va_list       vl2;
768#endif
769
770  SL_ENTER(_("sl_vsnprintf"));
771  if (str == NULL || format == NULL)
772    SL_IRETURN(0, _("sl_vsnprintf"));
773
774#if defined(HAVE_VSNPRINTF) && !defined(HAVE_BROKEN_VSNPRINTF)
775  len = vsnprintf (str, n, format, vl);                /* flawfinder: ignore */
776  str[n-1] = '\0';
777#else
778  VA_COPY (vl2, vl);                     /* save the argument list           */
779  total = sl_printf_count (format, vl);
780  len = (int) total;
781  if (total < n) 
782    {
783      /* flawfinder: ignore */
784      vsprintf (str, format, vl2);       /* program has checked that it fits */
785      str[n-1] = '\0';
786    }
787  else 
788    {
789      sl_strlcpy (str, format, n);
790      va_end(vl2);
791      SL_IRETURN(len, _("sl_vsnprintf"));
792    }
793  va_end(vl2);
794#endif
795  SL_IRETURN(len, _("sl_vsnprintf"));
796}
797
798/*
799 * An implementation of snprintf.
800 * Returns SL_ENONE on success.
801 * ENULL:  src || format == NULL
802 * ERANGE: n out of range
803 * ETRUNC: truncated (unimplemented)
804 */
805int sl_snprintf(char *str, size_t n,
806                const char *format, ... )
807{
808  va_list       vl;
809#if !defined(HAVE_VSNPRINTF) || defined(HAVE_BROKEN_VSNPRINTF)
810  size_t          total = 0;
811  va_list       vl2;
812#endif
813
814  SL_ENTER(_("sl_snprintf"));
815  if (str == NULL || format == NULL)
816    SL_IRETURN(SL_ENULL, _("sl_snprintf"));
817 
818  va_start (vl, format);
819#if defined(HAVE_VSNPRINTF) && !defined(HAVE_BROKEN_VSNPRINTF)
820  /* flawfinder: ignore */
821  vsnprintf (str, n, format, vl);
822  str[n-1] = '\0';
823#else
824  VA_COPY (vl2, vl);                   /* save the argument list           */
825  total = sl_printf_count (format, vl);
826  if (total < n) 
827    {
828      /* flawfinder: ignore */
829      vsprintf (str, format, vl2);     /* program has checked that it fits */
830      str[n-1] = '\0';
831    }
832  else 
833    {
834      sl_strlcpy (str, format, n);
835      va_end(vl2);
836      va_end(vl);
837      SL_IRETURN(SL_ETRUNC, _("sl_snprintf"));
838    }
839  va_end(vl2);
840#endif 
841  va_end(vl);
842  SL_IRETURN(SL_ENONE, _("sl_snprintf"));
843}
844
845/*
846 * Appends src to string dst of size siz (unlike strncat, siz is the
847 * full size of dst, not space left).  At most siz-1 characters
848 * will be copied.  Always NUL terminates (unless siz == 0).
849 * Returns SL_NONE on success, errcode on failure.
850 *
851 * ENULL:  dst == NULL
852 * ERANGE: siz out of range
853 * ETRUNC: src truncated
854 */
855int sl_strlcat(char * dst, /*@null@*/const char *src, size_t siz)
856{
857  register size_t dst_end;
858  register size_t dst_free;
859
860  register char       * p;
861  register const char * q;
862
863  if (!(dst == NULL || src == NULL || *src == '\0'))
864    {
865      if (siz > 0) 
866        {
867
868          /* How much free space do we have ?
869           */
870          dst_end  = strlen(dst);
871          dst_free = siz - dst_end - 1;
872         
873          p = &dst[dst_end];
874          q = src;
875         
876          while (dst_free > 0 && *q != '\0')
877            {
878              *p++ = *q++;
879              --dst_free;
880            }
881       
882          /* NULL terminate dst.
883           */
884          *p = '\0';
885       
886          if (*q == '\0')
887            return SL_ENONE;
888          else
889            return SL_ETRUNC;
890        }
891    }
892  return SL_ENONE;
893}
894
895/*
896 * An alternative implementation of the OpenBSD strlcpy() function.
897 *
898 * Copy src to string dst of size siz.  At most siz-1 characters
899 * will be copied.  Always NUL terminates (unless siz == 0).
900 * Returns SL_NONE on success, errcode on failure.
901 *
902 * ENULL:  dst == NULL
903 * ERANGE: siz out of range
904 * ETRUNC: src truncated
905 */
906int sl_strlcpy(char * dst, /*@null@*/const char * src, size_t siz)
907{
908  /* SL_ENTER(_("sl_strlcpy")); */
909
910  if (!((dst == NULL) || (src == NULL))) 
911    {
912      if (siz > 0) {
913        /* copy siz-1 characters
914         */
915        (void) strncpy(dst, src, siz-1);
916
917        /* NULL terminate
918         */
919        dst[siz-1] = '\0';
920      }
921      return SL_ENONE;
922    }
923  else if (src == NULL)
924    {
925      if (siz > 0) 
926        dst[0] = '\0';
927      return SL_ENONE;
928    }
929  else
930    {
931      return SL_ENULL;
932    } 
933}
934
935/*
936 * A robust drop-in replacement of strncpy. strlcpy is preferable.
937 */
938char * sl_strncpy(char *dst, const char *src, size_t size)
939{
940
941#ifdef SL_FAIL_ON_ERROR
942  SL_REQUIRE(dst != NULL, _("dst != NULL"));
943  SL_REQUIRE(src != NULL, _("src != NULL"));
944  SL_REQUIRE(size > 0, _("size > 0"));
945#endif
946
947  if (dst == NULL)
948    {
949      sl_errno = SL_ENULL;
950      return (NULL);
951    }
952  if (size < 1)
953    {
954      sl_errno = SL_ERANGE;
955      return (dst);
956    }
957  if (!src)
958    {
959      sl_errno = SL_ENULL;
960      dst[0] = '\0';
961    }
962  else if (src[0] == '\0')
963    dst[0] = '\0';
964  else
965    strncpy(dst, src, size);
966
967  if (sl_strlen(src) >= size)
968    {
969      errno = ENOSPC;
970      dst[size-1] = '\0';
971    }
972  return (dst);
973}
974
975/*
976 * A robust drop-in replacement of strncat. strlcat is preferable.
977 */
978char * sl_strncat(char *dst, const char *src, size_t n)
979{
980#ifdef SL_FAIL_ON_ERROR
981  SL_REQUIRE(dst != NULL, _("dst != NULL"));
982  SL_REQUIRE(src != NULL, _("src != NULL"));
983  SL_REQUIRE(n > 0, _("n > 0"));
984#endif
985
986  if (dst == NULL)
987    {
988      sl_errno = SL_ENULL;
989      return (NULL);
990    }
991  if (n < 1)
992    {
993      sl_errno = SL_ERANGE;
994      return (dst);
995    }
996  if (!src)
997    {
998      sl_errno = SL_ENULL;
999      return (dst);
1000    }
1001  else if (src[0] == '\0')
1002    dst[0] = '\0';
1003  else
1004    strncat(dst, src, n);
1005
1006  return (dst);
1007}
1008
1009#include <ctype.h>
1010int sl_strcasecmp(const char * one, const char * two)
1011{
1012#ifdef SL_FAIL_ON_ERROR
1013  SL_REQUIRE (one != NULL, _("one != NULL"));
1014  SL_REQUIRE (two != NULL, _("two != NULL"));
1015#endif
1016
1017  if (one && two)
1018    {
1019      do {
1020        if (*one && *two)
1021          {
1022            if (tolower(*one) == tolower(*two))
1023              {
1024                ++one; ++two;
1025              }
1026            else if (tolower(*one) < tolower(*two))
1027              return -1;
1028            else
1029              return 1;
1030          }
1031        else if (*one == '\0' && *two == '\0')
1032          return 0;
1033        else if (*one == '\0')
1034          return -1;
1035        else
1036          return 1;
1037      } while (1 == 1);
1038    }
1039  else if (one == NULL && two != NULL)
1040    return -1;
1041  else if (one != NULL && two == NULL)
1042    return 1;
1043  else
1044    return -7; /* default to not equal */
1045}
1046
1047int sl_strcmp(const char * a, const char * b)
1048{
1049#ifdef SL_FAIL_ON_ERROR
1050  SL_REQUIRE (a != NULL, _("a != NULL"));
1051  SL_REQUIRE (b != NULL, _("b != NULL"));
1052#endif
1053
1054  if (a != NULL && b != NULL)
1055    return (strcmp(a, b));
1056  else if (a == NULL && b != NULL)
1057    return (-1);
1058  else if (a != NULL && b == NULL)
1059    return (1);
1060  else
1061    return (-7); /* default to not equal */
1062}
1063
1064int sl_strncmp(const char * a, const char * b, size_t n)
1065{
1066#ifdef SL_FAIL_ON_ERROR
1067  SL_REQUIRE (a != NULL, _("a != NULL"));
1068  SL_REQUIRE (b != NULL, _("b != NULL"));
1069  SL_REQUIRE (n > 0, _("n > 0"));
1070#endif
1071
1072  if (a != NULL && b != NULL)
1073    return (strncmp(a, b, n));
1074  else if (a == NULL && b != NULL)
1075    return (-1);
1076  else if (a != NULL && b == NULL)
1077    return (1);
1078  else
1079    return (-7); /* default to not equal */
1080}
1081
1082/* string searching
1083 */
1084
1085char * sl_strstr (const char * haystack, const char * needle) 
1086{
1087#ifndef HAVE_STRSTR
1088  int             i;
1089  size_t          needle_len;
1090  size_t          haystack_len;
1091#endif
1092 
1093  if (haystack == NULL || needle == NULL)
1094    return NULL;
1095  if (*needle == '\0' || *haystack == '\0')
1096    return NULL;
1097
1098#if defined(HAVE_STRSTR)
1099  return (strstr(haystack, needle));
1100#else
1101  needle_len   = strlen(needle);
1102  haystack_len = strlen(haystack);
1103
1104  for (i = 0; i <= (haystack_len-needle_len); ++i)
1105    if (0 == sl_strncmp(&haystack[i], needle, needle_len))
1106      return (needle);
1107  return NULL;
1108#endif
1109}
1110
1111
1112/* ----------------------------------------------------------------
1113 *
1114 *    Privilege handling routines
1115 *
1116 * ---------------------------------------------------------------- */
1117
1118 
1119
1120static   uid_t   euid;
1121static   uid_t   ruid;
1122static   uid_t   ruid_orig;
1123static   gid_t   egid;
1124static   gid_t   rgid;
1125static   gid_t   rgid_orig;
1126
1127static   int     uids_are_stored = SL_FALSE;
1128static   int     suid_is_set     = SL_TRUE;
1129
1130#ifdef HAVE_SETRESUID
1131extern       int setresuid (uid_t truid, uid_t teuid, uid_t tsuid);
1132extern       int setresgid (gid_t trgid, gid_t tegid, gid_t tsgid);
1133#endif
1134
1135
1136/*
1137 * This function returns true if the program is SUID.
1138 * It calls abort() if the uid's are not saved already.
1139 */
1140int sl_is_suid()
1141{
1142  if (uids_are_stored == SL_FALSE)
1143    {
1144      if (getuid() == geteuid() && getgid() == getegid())
1145        return (0);     /* FALSE */
1146      else
1147        return (1);     /* TRUE  */
1148    }
1149  else
1150    {
1151      if (euid == ruid && egid == rgid)
1152        return (0);     /* FALSE */
1153      else
1154        return (1);     /* TRUE  */
1155    }
1156}
1157
1158/*
1159 * This function returns the saved euid.
1160 * It calls abort() if the uid's are not saved already.
1161 */
1162int sl_get_euid(uid_t * ret)
1163{
1164  SL_ENTER(_("sl_get_euid"));
1165  /* SL_REQUIRE(uids_are_stored == SL_TRUE, _("uids_are_stored == SL_TRUE"));*/
1166  if (uids_are_stored == SL_TRUE)
1167    *ret = euid;
1168  else
1169    *ret = geteuid();
1170  SL_IRETURN (SL_ENONE, _("sl_get_euid"));
1171}
1172
1173uid_t sl_ret_euid()
1174{
1175  /* SL_REQUIRE(uids_are_stored == SL_TRUE, _("uids_are_stored == SL_TRUE"));*/
1176  if (uids_are_stored == SL_TRUE)
1177    return (euid);
1178  else
1179    return (geteuid());
1180}
1181
1182/*
1183 * This function returns the saved egid.
1184 * It calls abort() if the uid's are not saved already.
1185 */
1186int sl_get_egid(gid_t * ret)
1187{
1188  SL_ENTER(_("sl_get_egid"));
1189  /* SL_REQUIRE(uids_are_stored == SL_TRUE, _("uids_are_stored == SL_TRUE"));*/
1190  if (uids_are_stored == SL_TRUE)
1191    *ret = egid;
1192  else
1193    *ret = getegid();
1194  SL_IRETURN (SL_ENONE, _("sl_get_egid"));
1195}
1196
1197/*
1198 * This function returns the saved ruid.
1199 * It calls abort() if the uid's are not saved already.
1200 */
1201int sl_get_ruid(uid_t * ret)
1202{
1203  SL_ENTER(_("sl_get_ruid"));
1204  /* SL_REQUIRE(uids_are_stored == SL_TRUE, _("uids_are_stored == SL_TRUE"));*/
1205  if (uids_are_stored == SL_TRUE)
1206    *ret = ruid;
1207  else
1208    *ret = getuid();
1209  SL_IRETURN (SL_ENONE, _("sl_get_ruid"));
1210}
1211
1212/*
1213 * This function returns the saved rgid.
1214 * It calls abort() if the uid's are not saved already.
1215 */
1216int sl_get_rgid(gid_t * ret)
1217{
1218  SL_ENTER(_("sl_get_rgid"));
1219  /* SL_REQUIRE(uids_are_stored == SL_TRUE, _("uids_are_stored == SL_TRUE"));*/
1220  if (uids_are_stored == SL_TRUE)
1221    *ret = rgid;
1222  else
1223    *ret = getgid();
1224  SL_IRETURN (SL_ENONE, _("sl_get_rgid"));
1225}
1226
1227/*
1228 * This function returns the saved original ruid.
1229 * It calls abort() if the uid's are not saved already.
1230 */
1231int sl_get_ruid_orig(uid_t * ret)
1232{
1233  SL_ENTER(_("sl_get_ruid_orig"));
1234  /* SL_REQUIRE(uids_are_stored == SL_TRUE, _("uids_are_stored == SL_TRUE"));*/
1235  if (uids_are_stored == SL_TRUE)
1236    *ret = ruid_orig;
1237  else
1238    *ret = getuid();
1239  SL_IRETURN (SL_ENONE, _("sl_get_ruid_orig"));
1240}
1241
1242/*
1243 * This function returns the saved original rgid.
1244 * It calls abort() if the uid's are not saved already.
1245 */
1246int sl_get_rgid_orig(gid_t * ret)
1247{
1248  SL_ENTER(_("sl_get_rgid_orig"));
1249  /* SL_REQUIRE(uids_are_stored == SL_TRUE, _("uids_are_stored == SL_TRUE"));*/
1250  if (uids_are_stored == SL_TRUE)
1251    *ret = rgid_orig;
1252  else
1253    *ret = getgid();
1254  SL_IRETURN (SL_ENONE, _("sl_get_rgid_orig"));
1255}
1256
1257static int suid_warn_flag = 1;
1258static void suid_warn(int a)
1259{
1260  fprintf(stderr, _("ERROR:  open set/unset suid !!! %d\n"), a);
1261  return;
1262}
1263
1264/*
1265 * This function sets the effective uid
1266 * to the saved effective uid.
1267 * It will abort on failure.
1268 */
1269int sl_set_suid ()
1270{
1271  int retval;
1272
1273  SL_ENTER(_("sl_set_suid"));
1274
1275  if (uids_are_stored == SL_FALSE)
1276    {
1277      SL_IRETURN(SL_ENONE, _("sl_set_suid"));
1278    }
1279
1280  SL_REQUIRE(uids_are_stored == SL_TRUE, _("uids_are_stored == SL_TRUE")); 
1281
1282  if (ruid == euid && rgid == egid) 
1283    {
1284      suid_is_set = SL_TRUE;
1285      SL_IRETURN(SL_ENONE, _("sl_set_suid"));
1286    } 
1287  SL_REQUIRE(suid_is_set     == SL_FALSE, _("suid_is_set == SL_FALSE")); 
1288
1289#if defined(HAVE_SETRESUID)
1290  retval = setresuid (sh_uid_neg, euid, sh_uid_neg);
1291  if (retval == 0) 
1292    retval = setresgid (sh_gid_neg, egid, sh_gid_neg);
1293
1294#elif defined(HAVE_SETEUID)
1295  retval = seteuid (egid);
1296  if (retval == 0) 
1297    retval = setegid (euid);
1298
1299  /* on AIX, setreuid does not behave well for non-root users.
1300   */
1301#elif defined(HAVE_SETREUID)
1302  retval = setreuid (ruid, euid);
1303  if (retval == 0) 
1304    retval = setregid (rgid, egid);
1305
1306#else
1307  retval = setuid (euid);
1308  if (retval == 0) 
1309    retval = setgid (egid);
1310#endif
1311  if (suid_warn_flag == 1)
1312    suid_warn(1);
1313  suid_warn_flag = 1;
1314
1315  SL_REQUIRE(retval == 0, _("retval == 0"));
1316  suid_is_set = SL_TRUE;
1317  SL_IRETURN(SL_ENONE, _("sl_set_suid"));
1318}
1319
1320/*
1321 * This function sets the effective uid to the real uid.
1322 * It will abort on failure.
1323 */
1324int sl_unset_suid ()
1325{
1326  register int retval;
1327
1328  SL_ENTER(_("sl_unset_suid"));
1329
1330  if (uids_are_stored == SL_FALSE)
1331    {
1332      SL_IRETURN(SL_ENONE, _("sl_unset_suid"));
1333    }
1334
1335  SL_REQUIRE(uids_are_stored == SL_TRUE, _("uids_are_stored == SL_TRUE"));
1336
1337  if (ruid == euid && rgid == egid)
1338    {
1339      suid_is_set = SL_FALSE;
1340      SL_IRETURN(SL_ENONE, _("sl_unset_suid"));
1341    } 
1342  SL_REQUIRE(suid_is_set     == SL_TRUE, _("suid_is_set == SL_TRUE")); 
1343
1344#if defined(HAVE_SETRESUID)
1345  retval = setresgid (sh_gid_neg, rgid, sh_gid_neg);
1346  if (retval == 0) 
1347    retval = setresuid (sh_uid_neg, ruid, sh_uid_neg);
1348
1349#elif defined(HAVE_SETEUID)
1350  retval = setegid (rgid);
1351  if (retval == 0) 
1352    retval = seteuid (ruid);
1353
1354#elif defined(HAVE_SETREUID)
1355  retval = setregid (egid, rgid);
1356  if (retval == 0) 
1357    retval = setreuid (euid, ruid);
1358
1359#else
1360  retval = setgid (rgid);
1361  if (retval == 0) 
1362    retval = setuid (ruid);
1363#endif
1364
1365  if (suid_warn_flag == 0)
1366    suid_warn(0);
1367  suid_warn_flag = 0;
1368
1369  SL_REQUIRE(retval == 0, _("retval == 0"));
1370  suid_is_set = SL_FALSE;
1371  SL_IRETURN(SL_ENONE, _("sl_unset_suid"));
1372}
1373
1374
1375/*
1376 * This function saves the uid's.
1377 */
1378int sl_save_uids()
1379{
1380  SL_ENTER(_("sl_save_uids"));
1381  if (uids_are_stored == SL_TRUE) 
1382    SL_IRETURN(SL_EREPEAT, _("sl_save_uids"));
1383
1384  ruid_orig = getuid();
1385  rgid_orig = getgid();
1386  egid = getegid();
1387  euid = geteuid();
1388  ruid = ruid_orig;
1389  rgid = rgid_orig;
1390  uids_are_stored = SL_TRUE;
1391
1392  SL_IRETURN(SL_ENONE, _("sl_save_uids"));
1393}
1394
1395/*
1396 * This function drops SUID privileges irrevocably.
1397 * It set the effective uid to the original real uid.
1398 */
1399extern int  sh_unix_initgroups2 (uid_t in_pid, gid_t in_gid);
1400int sl_drop_privileges()
1401{
1402  SL_ENTER(_("sl_drop_privileges"));
1403  SL_REQUIRE(uids_are_stored == SL_TRUE, _("uids_are_stored == SL_TRUE"));
1404
1405  SL_REQUIRE(setgid(rgid_orig) == 0, _("setgid(rgid_orig) == 0"));
1406  SL_REQUIRE(sh_unix_initgroups2(ruid_orig, rgid_orig) == 0, _("sh_unix_initgroups2(ruid_orig,rgid_orig) == 0"));
1407  SL_REQUIRE(setuid(ruid_orig) == 0, _("setuid(ruid_orig) == 0"));
1408
1409  /* make sure that setuid(0) fails
1410   */
1411  SL_REQUIRE(setuid(0) < 0, _("setuid(0) < 0"));
1412
1413  euid = ruid_orig;
1414  egid = rgid_orig;
1415  ruid = ruid_orig;
1416  rgid = rgid_orig;
1417
1418  SL_IRETURN(SL_ENONE, _("sl_drop_privileges"));
1419}
1420
1421/*
1422 * Define a policy: Stay root.
1423 * Do nothing if not SUID.
1424 */
1425int sl_policy_get_root()
1426{
1427  SL_ENTER(_("sl_policy_get_root"));
1428  SL_REQUIRE(uids_are_stored == SL_FALSE, _("uids_are_stored == SL_FALSE"));
1429
1430  SL_REQUIRE (sl_save_uids() == SL_ENONE, _("sl_save_uids() == SL_ENONE"));
1431
1432  if (euid != ruid || egid != rgid)
1433    {
1434      SL_REQUIRE(setgid(egid) == 0, _("setgid(egid) == 0"));
1435      SL_REQUIRE(setuid(euid) == 0, _("setuid(euid) == 0"));
1436      SL_REQUIRE(ruid == getuid() && rgid == getgid(),
1437                 _("ruid == getuid() && rgid == getgid()"));
1438      ruid = euid;
1439      rgid = egid;
1440    }
1441  suid_is_set = SL_TRUE;
1442  if (euid == 0)
1443    {
1444      SL_REQUIRE(sh_unix_initgroups2(euid, egid) == 0, _("sh_unix_initgroups2(euid,egid) == 0"));
1445    }
1446  SL_IRETURN(SL_ENONE, _("sl_policy_get_root"));
1447}
1448
1449#include <pwd.h>
1450
1451/*
1452 * Define a policy: Get real (irrevocably).
1453 * This function drops SUID privileges irrevocably.
1454 * Do nothing if not SUID (? not true - drops if root).
1455 */
1456
1457int sl_policy_get_real(char * user)
1458{
1459  SL_ENTER(_("sl_policy_get_real"));
1460  SL_REQUIRE(uids_are_stored == SL_FALSE, _("uids_are_stored == SL_FALSE"));
1461  SL_REQUIRE (sl_save_uids() == SL_ENONE, _("sl_save_uids() == SL_ENONE"));
1462
1463  if (euid == 0 || ruid == 0)
1464    {
1465#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
1466      struct passwd    pwd;
1467      char             buffer[SH_PWBUF_SIZE];
1468      struct passwd *  tempres;
1469      sh_getpwnam_r(user, &pwd, buffer, sizeof(buffer), &tempres);
1470#else
1471      struct passwd * tempres = sh_getpwnam(user);
1472#endif
1473
1474      SL_REQUIRE (NULL != tempres, _("tempres != NULL"));
1475 
1476      rgid_orig = tempres->pw_gid;
1477      ruid_orig = tempres->pw_uid;
1478    }
1479  else
1480    {
1481      rgid_orig = rgid;
1482      ruid_orig = ruid;
1483    }
1484
1485  SL_REQUIRE (sl_drop_privileges() == SL_ENONE,
1486              _("sl_drop_privileges() == SL_ENONE"));
1487
1488  suid_is_set = SL_TRUE;
1489  SL_IRETURN(SL_ENONE, _("sl_policy_get_real"));
1490}
1491
1492
1493/*
1494 * Define a policy: Get user.
1495 * Drops privileges.
1496 * Do nothing if not SUID.
1497 */
1498int sl_policy_get_user(const char * user)
1499{
1500  SL_ENTER(_("sl_policy_get_user"));
1501
1502  SL_REQUIRE(user != NULL, _("user != NULL"));
1503  SL_REQUIRE(uids_are_stored == SL_FALSE, _("uids_are_stored == SL_FALSE"));
1504  SL_REQUIRE (sl_save_uids() == SL_ENONE, _("sl_save_uids() == SL_ENONE"));
1505
1506  if (euid != ruid || egid != rgid)
1507    {
1508#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
1509      struct passwd    pwd;
1510      char             buffer[SH_PWBUF_SIZE];
1511      struct passwd *  tempres;
1512      sh_getpwnam_r(user, &pwd, buffer, sizeof(buffer), &tempres);
1513#else
1514      struct passwd * tempres = sh_getpwnam(user);
1515#endif
1516
1517      SL_REQUIRE (NULL != tempres, _("tempres != NULL"));
1518
1519      SL_REQUIRE (sl_drop_privileges() == SL_ENONE,
1520                  _("sl_drop_privileges() == SL_ENONE"));
1521    }
1522  SL_IRETURN(SL_ENONE, _("sl_policy_get_user"));
1523}
1524
1525
1526
1527/* ----------------------------------------------------------------
1528 *
1529 *    File access routines
1530 *
1531 * ---------------------------------------------------------------- */
1532
1533#define TOFFSET 0x1234
1534
1535/* this would prevent opening files if the first 16 fds are open :( */ 
1536/* #define MAXFD   FOPEN_MAX                                        */
1537
1538#define MAXFD   1024
1539
1540typedef struct openfiles {
1541  SL_TICKET ticket;     /* The unique  ID.      */ 
1542  int fd;               /* The file descriptor. */
1543  char * path;          /* The file path.       */
1544  sh_string * content;  /* The file content     */
1545} SL_OFILE; 
1546
1547static SL_OFILE * ofiles[MAXFD]; 
1548
1549SH_MUTEX_STATIC(mutex_ticket, PTHREAD_MUTEX_INITIALIZER);
1550
1551static unsigned int nonce_counter = TOFFSET;
1552
1553static
1554SL_TICKET sl_create_ticket (unsigned int myindex) 
1555{
1556  unsigned int high; /* index */ 
1557  unsigned int low;  /* nonce */
1558  SL_TICKET    retval = SL_EINTERNAL;
1559
1560  SL_ENTER(_("sl_create_ticket"));
1561
1562  if (myindex >= MAXFD)
1563    goto out_ticket;
1564
1565  /* mask out the high bit and check that it is not used
1566   * -> verify that it fits into 16 bits as positive
1567   */
1568  high = (myindex + TOFFSET) & 0x7fff; 
1569
1570  if (high != myindex + TOFFSET) 
1571    goto out_ticket;
1572
1573  SH_MUTEX_LOCK_UNSAFE(mutex_ticket);
1574
1575  low = nonce_counter & 0xffff;
1576
1577  /* Overflow -> nonce too big.
1578   */
1579  if ((low != nonce_counter++) || low == 0)
1580    goto out_ticket;
1581 
1582  /* Wrap around the nonce counter.
1583   * This is a dirty trick.
1584   */
1585  if (nonce_counter > 0x7fff)
1586    nonce_counter = TOFFSET;
1587
1588  retval = (SL_TICKET) ((high << 16) | low);
1589
1590 out_ticket:
1591  ;
1592
1593  SH_MUTEX_UNLOCK_UNSAFE(mutex_ticket);
1594  SL_RETURN (retval, _("sl_create_ticket")); 
1595}
1596
1597static 
1598int sl_read_ticket (SL_TICKET fno) 
1599{
1600  register unsigned myindex; 
1601  register SL_OFILE *of; 
1602
1603  myindex = ((fno >> 16) & 0xffff) - TOFFSET;
1604  if (myindex >= MAXFD)
1605    return (SL_ETICKET);
1606
1607  if (ofiles[myindex] == NULL)
1608    return (SL_ETICKET);
1609
1610  if (ofiles[myindex]->ticket != fno)
1611    return (SL_ETICKET);
1612
1613  if ((of = ofiles[myindex])->fd < 0 || of->fd >= MAXFD )
1614    return (SL_EINTERNAL);
1615
1616  if (((of->ticket) & 0xffff) == 0)
1617    return (SL_EINTERNAL); 
1618
1619  return (myindex); 
1620}
1621
1622SL_TICKET sl_make_ticket (int fd, const char * filename)
1623{
1624  size_t    len;
1625  SL_TICKET ticket;
1626  SL_ENTER(_("sl_make_ticket"));
1627  /* Make entry.
1628   */
1629  if (fd >= MAXFD || fd < 0)
1630     {
1631        SL_IRETURN(SL_TOOMANY, _("sl_make_ticket"));
1632     }
1633
1634   if (ofiles[fd] != NULL)
1635    {
1636      SL_IRETURN(SL_EINTERNAL, _("sl_make_ticket"));
1637    }
1638
1639  if ( (ofiles[fd] = (SL_OFILE *) malloc(sizeof(SL_OFILE))) == NULL)
1640    {
1641      SL_IRETURN(SL_EMEM, _("sl_make_ticket"));
1642    }
1643
1644  len = sl_strlen(filename)+1;
1645
1646  if ( (ofiles[fd]->path = (char *) malloc(len) ) == NULL)
1647    {
1648      free(ofiles[fd]);
1649      ofiles[fd] = NULL;
1650      SL_IRETURN(SL_EMEM, _("sl_make_ticket"));
1651    }
1652
1653  /* Get a ticket.
1654   */
1655  ticket = sl_create_ticket((unsigned int)fd);
1656
1657  if (SL_ISERROR(ticket))
1658    {
1659      (void) free (ofiles[fd]->path);
1660      (void) free (ofiles[fd]);
1661      SL_IRETURN(ticket, _("sl_make_ticket"));
1662    }
1663
1664  sl_strlcpy (ofiles[fd]->path, filename, len);
1665  ofiles[fd]->ticket  = ticket;
1666  ofiles[fd]->fd      = fd;
1667  ofiles[fd]->content = NULL;
1668
1669  SL_IRETURN(ticket, _("sl_make_ticket"));
1670}
1671
1672#define SL_OPEN_MIN          113
1673#define SL_OPEN_FOR_READ     113
1674#define SL_OPEN_FOR_WRITE    114
1675#define SL_OPEN_FOR_RDWR     115
1676#define SL_OPEN_FOR_WTRUNC   116
1677#define SL_OPEN_FOR_RWTRUNC  117
1678#define SL_OPEN_SAFE_RDWR    118
1679#define SL_OPEN_FOR_FASTREAD 119
1680#define SL_OPEN_MAX          119
1681
1682#if !defined(O_NOATIME)
1683#if defined(__linux__) && (defined(__i386__) || defined(__PPC__))
1684#define O_NOATIME 01000000
1685#else
1686  /*
1687   * bitwise 'or' with zero does not modify any bit
1688   */
1689#define O_NOATIME 0
1690#endif
1691#endif
1692
1693static int     o_noatime = O_NOATIME;
1694static mode_t  open_mode = (S_IWUSR|S_IRUSR|S_IRGRP);
1695
1696
1697static
1698int sl_open_file (const char *filename, int mode, int priv)
1699{
1700  struct stat   lbuf;
1701  struct stat   buf;
1702  int           lstat_return;
1703  int           stat_return;
1704  int           fd;
1705  int           sflags;
1706  size_t        len;
1707  SL_TICKET     ticket;
1708 
1709#if !defined(O_NONBLOCK)
1710#if defined(O_NDELAY)
1711#define O_NONBLOCK  O_NDELAY
1712#else
1713#define O_NONBLOCK  0
1714#endif
1715#endif
1716
1717  SL_ENTER(_("sl_open_file"));
1718
1719  if (filename == NULL)
1720    SL_IRETURN(SL_ENULL, _("sl_open_file"));
1721  if (mode < SL_OPEN_MIN || mode > SL_OPEN_MAX)
1722    SL_IRETURN(SL_EINTERNAL, _("sl_open_file"));
1723   
1724  /* "This system call always succeeds and the previous value of
1725   * the mask is returned."
1726   */
1727  (void) umask (0); 
1728
1729  if (mode == SL_OPEN_FOR_FASTREAD)
1730    {
1731      fd = aud_open_noatime (FIL__, __LINE__, priv, filename, 
1732                             O_RDONLY|O_NONBLOCK, 0, &o_noatime);
1733      /*
1734      if (fd >= 0) {
1735        sflags = retry_fcntl(FIL__, __LINE__, fd, F_GETFL, 0);
1736        retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags & ~O_NONBLOCK);
1737      }
1738      */
1739      if (fd < 0)
1740        SL_IRETURN(SL_EBADFILE, _("sl_open_file"));
1741      goto createTicket;
1742    }
1743
1744#ifdef USE_SUID
1745  if (priv == SL_YESPRIV)
1746    sl_set_suid();
1747#endif
1748  if (mode == SL_OPEN_FOR_READ)
1749    lstat_return = retry_stat (FIL__, __LINE__, filename, &lbuf);
1750  else
1751    lstat_return = retry_lstat(FIL__, __LINE__, filename, &lbuf);
1752#ifdef USE_SUID
1753  if (priv == SL_YESPRIV)
1754    sl_unset_suid();
1755#endif
1756
1757  if (lstat_return == -1)
1758    {
1759      lstat_return = ENOENT;
1760      if ( (mode == SL_OPEN_FOR_READ && lstat_return == ENOENT) ||
1761           (errno != ENOENT))
1762        {
1763          TPT(( 0, FIL__, __LINE__, _("msg=<lstat: %s> errno=<%d>\n"), 
1764            filename, errno));
1765          SL_IRETURN(SL_EBADFILE, _("sl_open_file"));
1766        }
1767    }
1768 
1769  if ( (mode != SL_OPEN_FOR_READ) && (lstat_return != ENOENT) &&
1770       ( S_ISDIR(lbuf.st_mode) || (S_IWOTH & lbuf.st_mode) ) 
1771      )
1772    SL_IRETURN(SL_EBADFILE, _("sl_open_file"));
1773
1774   
1775  /* O_NOATIME has an effect for read(). But write() ?.
1776   */
1777  switch (mode)
1778    {
1779    case SL_OPEN_FOR_READ:
1780      fd = aud_open_noatime (FIL__, __LINE__, priv, filename, 
1781                             O_RDONLY|O_NONBLOCK, 0, &o_noatime);
1782      if (fd >= 0) {
1783        sflags = retry_fcntl(FIL__, __LINE__, fd, F_GETFL, 0);
1784        retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags & ~O_NONBLOCK);
1785      }
1786      break;
1787    case SL_OPEN_FOR_WRITE:
1788      if (lstat_return == ENOENT)
1789        fd = aud_open (FIL__, __LINE__, priv, filename, 
1790                       O_WRONLY|O_CREAT|O_EXCL,    open_mode);
1791      else
1792        fd = aud_open (FIL__, __LINE__, priv, filename, 
1793                       O_WRONLY,                   open_mode);
1794      break;
1795    case SL_OPEN_SAFE_RDWR:
1796      if (lstat_return == ENOENT)
1797        fd = aud_open (FIL__, __LINE__, priv, filename, 
1798                       O_RDWR|O_CREAT|O_EXCL,      open_mode);
1799      else
1800        SL_IRETURN(SL_EBADFILE, _("sl_open_file"));
1801      break;
1802    case SL_OPEN_FOR_RDWR:
1803      if (lstat_return == ENOENT)
1804        fd = aud_open (FIL__, __LINE__, priv, filename, 
1805                       O_RDWR|O_CREAT|O_EXCL,      open_mode);
1806      else
1807        fd = aud_open (FIL__, __LINE__, priv, filename, 
1808                       O_RDWR,                     open_mode);
1809      break;
1810    case SL_OPEN_FOR_WTRUNC:
1811      if (lstat_return == ENOENT)
1812        fd = aud_open (FIL__, __LINE__, priv, filename, 
1813                       O_WRONLY|O_CREAT|O_EXCL,    open_mode);
1814      else
1815        fd = aud_open (FIL__, __LINE__, priv, filename, 
1816                       O_WRONLY|O_TRUNC,           open_mode);
1817      break;
1818    case SL_OPEN_FOR_RWTRUNC:
1819      if (lstat_return == ENOENT)
1820        fd = aud_open (FIL__, __LINE__, priv, filename, 
1821                       O_RDWR|O_CREAT|O_EXCL,      open_mode);
1822      else
1823        fd = aud_open (FIL__, __LINE__, priv, filename, 
1824                       O_RDWR|O_TRUNC,             open_mode);
1825      break;
1826    default:
1827      SL_IRETURN(SL_EINTERNAL, _("sl_open_file"));
1828    }
1829
1830  if (fd < 0)
1831    {
1832      TPT(( 0, FIL__, __LINE__, _("msg=<Error opening: %s> errno=<%d>\n"), 
1833            filename, errno));
1834      SL_IRETURN(SL_EBADFILE, _("sl_open_file"));
1835    }
1836
1837#ifdef USE_SUID
1838  if (priv == SL_YESPRIV)
1839    sl_set_suid();
1840#endif
1841  stat_return = retry_fstat(FIL__, __LINE__, fd, &buf);
1842#ifdef USE_SUID
1843  if (priv == SL_YESPRIV)
1844    sl_unset_suid();
1845#endif
1846
1847  if (stat_return < 0)
1848    {
1849      close (fd);
1850      SL_IRETURN(SL_EBADFILE, _("sl_open_file"));
1851    }
1852
1853  if (lstat_return != ENOENT && buf.st_ino != lbuf.st_ino)
1854    {
1855      close (fd);
1856      SL_IRETURN(SL_EBOGUS, _("sl_open_file"));
1857    }
1858
1859 createTicket:
1860
1861  /* Make entry.
1862   */
1863  if (fd >= MAXFD)
1864     {
1865        close(fd);
1866        SL_IRETURN(SL_TOOMANY, _("sl_open_file"));
1867     }
1868
1869   if (ofiles[fd] != NULL)
1870    {
1871      close(fd);
1872      SL_IRETURN(SL_EINTERNAL, _("sl_open_file"));
1873    }
1874
1875  if ( (ofiles[fd] = (SL_OFILE *) malloc(sizeof(SL_OFILE))) == NULL)
1876    {
1877      close(fd);
1878      SL_IRETURN(SL_EMEM, _("sl_open_file"));
1879    }
1880
1881  len = sl_strlen(filename)+1;
1882
1883  if ( (ofiles[fd]->path = (char *) malloc(len) ) == NULL)
1884    {
1885      free(ofiles[fd]);
1886      ofiles[fd] = NULL;
1887      close(fd);
1888      SL_IRETURN(SL_EMEM, _("sl_open_file"));
1889    }
1890
1891  /* Get a ticket.
1892   */
1893  ticket = sl_create_ticket(fd);
1894
1895  if (SL_ISERROR(ticket))
1896    {
1897      (void) free (ofiles[fd]->path);
1898      (void) free (ofiles[fd]);
1899      close(fd);
1900      SL_IRETURN(ticket, _("sl_open_file"));
1901    }
1902
1903  sl_strlcpy (ofiles[fd]->path, filename, len);
1904  ofiles[fd]->ticket  = ticket;
1905  ofiles[fd]->fd      = fd;
1906  ofiles[fd]->content = NULL;
1907
1908  SL_IRETURN(ticket, _("sl_open_file"));
1909}
1910
1911static
1912int check_fname_priv (const char * fname, int priv)
1913{
1914  SL_ENTER(_("check_fname_priv"));
1915  if (fname == NULL)
1916    SL_IRETURN(SL_ENULL, _("check_fname_priv"));
1917  if (priv != SL_YESPRIV && priv != SL_NOPRIV)
1918    SL_IRETURN(SL_EINTERNAL, _("check_fname_priv"));
1919  SL_IRETURN(SL_ENONE, _("check_fname_priv"));
1920}
1921 
1922SL_TICKET sl_open_write (const char * fname, int priv)
1923{
1924  long status;
1925  SL_ENTER(_("sl_open_write"));
1926
1927  if (SL_ENONE != (status = check_fname_priv (fname, priv)))
1928    SL_IRETURN(status, _("sl_open_write"));
1929
1930  status = sl_open_file(fname, SL_OPEN_FOR_WRITE, priv);
1931  SL_IRETURN(status, _("sl_open_write"));
1932}
1933
1934SL_TICKET sl_open_read (const char * fname, int priv)
1935{
1936  long status;
1937  SL_ENTER(_("sl_open_read"));
1938
1939  if (SL_ENONE != (status = check_fname_priv (fname, priv)))
1940    {
1941      TPT(( 0, FIL__, __LINE__, 
1942            _("msg=<Error in check_fname_priv.> status=<%ld>\n"), 
1943            status));
1944      SL_IRETURN(status, _("sl_open_read"));
1945    }
1946
1947  status = sl_open_file(fname, SL_OPEN_FOR_READ, priv);
1948  SL_IRETURN(status, _("sl_open_read"));
1949}
1950
1951SL_TICKET sl_open_fastread (const char * fname, int priv)
1952{
1953  long status;
1954  SL_ENTER(_("sl_open_fastread"));
1955
1956  if (SL_ENONE != (status = check_fname_priv (fname, priv)))
1957    SL_IRETURN(status, _("sl_open_read"));
1958
1959  status = sl_open_file(fname, SL_OPEN_FOR_FASTREAD, priv);
1960  SL_IRETURN(status, _("sl_open_fastread"));
1961}
1962
1963SL_TICKET sl_open_rdwr (const char * fname, int priv)
1964{
1965  long status;
1966  SL_ENTER(_("sl_open_rdwr"));
1967
1968  if (SL_ENONE != (status = check_fname_priv (fname, priv)))
1969    SL_IRETURN(status, _("sl_open_rdwr"));
1970
1971  status = sl_open_file(fname, SL_OPEN_FOR_RDWR, priv);
1972  SL_IRETURN(status, _("sl_open_rdwr"));
1973}
1974
1975SL_TICKET sl_open_safe_rdwr (const char * fname, int priv)
1976{
1977  long status;
1978  SL_ENTER(_("sl_open_safe_rdwr"));
1979
1980  if (SL_ENONE != (status = check_fname_priv (fname, priv)))
1981    SL_IRETURN(status, _("sl_open_safe_rdwr"));
1982
1983  status = sl_open_file(fname, SL_OPEN_SAFE_RDWR, priv);
1984  SL_IRETURN(status, _("sl_open_safe_rdwr"));
1985}
1986
1987SL_TICKET sl_open_write_trunc (const char * fname, int priv)
1988{
1989  long status;
1990  SL_ENTER(_("sl_open_write_trunc"));
1991
1992  if (SL_ENONE != (status = check_fname_priv (fname, priv)))
1993    SL_IRETURN(status, _("sl_open_write_trunc"));
1994
1995  status = sl_open_file(fname, SL_OPEN_FOR_WTRUNC, priv);
1996  SL_IRETURN(status, _("sl_open_write_trunc"));
1997}
1998
1999SL_TICKET sl_open_rdwr_trunc (const char * fname, int priv)
2000{
2001  long status;
2002  SL_ENTER(_("sl_open_rdwr_trunc"));
2003
2004  if (SL_ENONE != (status = check_fname_priv (fname, priv)))
2005    SL_IRETURN(status, _("sl_open_rdwr_trunc"));
2006
2007  status = sl_open_file(fname, SL_OPEN_FOR_RWTRUNC, priv);
2008  SL_IRETURN(status, _("sl_open_rdwr_trunc"));
2009}
2010
2011
2012int get_the_fd (SL_TICKET ticket)
2013{
2014  int fd;
2015
2016  if (SL_ISERROR(fd = sl_read_ticket(ticket)))
2017    return (fd);
2018
2019  if (ofiles[fd] == NULL || fd != ofiles[fd]->fd || fd < 0)
2020    return (SL_EINTERNAL);
2021  return (fd);
2022}
2023
2024int sl_init_content (SL_TICKET ticket, size_t size)
2025{
2026  int fd;
2027
2028  if (SL_ISERROR(fd = sl_read_ticket(ticket)))
2029    return (fd);
2030
2031  if (ofiles[fd] == NULL || fd != ofiles[fd]->fd || fd < 0)
2032    return (SL_EINTERNAL);
2033
2034  if (ofiles[fd]->content)
2035    sh_string_destroy(&(ofiles[fd]->content));
2036  ofiles[fd]->content = sh_string_new(size);
2037
2038  return SL_ENONE;
2039}
2040
2041sh_string * sl_get_content (SL_TICKET ticket)
2042{
2043  int fd;
2044
2045  if (SL_ISERROR(fd = sl_read_ticket(ticket)))
2046    return (NULL);
2047
2048  if (ofiles[fd] == NULL || fd != ofiles[fd]->fd || fd < 0)
2049    return (NULL);
2050
2051  return (ofiles[fd]->content);
2052}
2053
2054int sl_close (SL_TICKET ticket) 
2055{
2056  register int fd;
2057
2058  SL_ENTER(_("sl_close"));
2059
2060  if (SL_ISERROR(fd = get_the_fd (ticket)))
2061    SL_IRETURN(fd, _("sl_close"));
2062
2063  /* This may fail, but what to do then ?
2064   */
2065  if (0 != close(fd) && ofiles[fd] != NULL)
2066    {
2067      TPT((0, FIL__, __LINE__, 
2068           _("msg=<Error closing file.>, path=<%s>, fd=<%d>, err=<%s>\n"), 
2069           ofiles[fd]->path, fd, strerror(errno)));
2070    }
2071
2072  if (ofiles[fd] != NULL)
2073    {
2074      if (ofiles[fd]->content)
2075        sh_string_destroy(&(ofiles[fd]->content));
2076      (void) free(ofiles[fd]->path);
2077      (void) free(ofiles[fd]);
2078      ofiles[fd] = NULL;
2079    }
2080
2081  SL_IRETURN(SL_ENONE, _("sl_close")); 
2082}
2083
2084int sl_dropall(int fd, int except)
2085{
2086  while (fd < MAXFD)
2087    {
2088      if (ofiles[fd] != NULL && fd != except)
2089        {
2090          if (ofiles[fd]->content)
2091            sh_string_destroy(&(ofiles[fd]->content));
2092          if (ofiles[fd]->path != NULL)
2093            (void) free(ofiles[fd]->path);
2094          (void) free(ofiles[fd]);
2095          ofiles[fd] = NULL;
2096        }
2097      ++fd;
2098    }
2099  return 0;
2100}
2101
2102int sl_dropall_dirty(int fd, int except)
2103{
2104  while (fd < MAXFD)
2105    {
2106      if (ofiles[fd] != NULL && fd != except)
2107        {
2108          ofiles[fd] = NULL;
2109        }
2110      ++fd;
2111    }
2112  return 0;
2113}
2114
2115
2116int sl_unlink (SL_TICKET ticket) 
2117{
2118  register int fd;
2119
2120  SL_ENTER(_("sl_unlink"));
2121
2122  if (SL_ISERROR(fd = get_the_fd(ticket)))
2123    SL_IRETURN(fd, _("sl_unlink"));
2124
2125  if (retry_aud_unlink(FIL__, __LINE__, ofiles[fd]->path) < 0)
2126    SL_IRETURN(SL_EUNLINK, _("sl_unlink"));
2127
2128  SL_IRETURN(SL_ENONE, _("sl_unlink")); 
2129}
2130
2131 
2132int sl_seek (SL_TICKET ticket, off_t off_data) 
2133{
2134  register int fd;
2135
2136  SL_ENTER(_("sl_seek"));
2137
2138  if (SL_ISERROR(fd = get_the_fd(ticket)))
2139    SL_IRETURN(fd, _("sl_seek"));
2140
2141  if (lseek(fd, off_data, SEEK_SET) == (off_t)-1)
2142    SL_IRETURN(SL_EREWIND, _("sl_seek"));
2143
2144  SL_IRETURN(SL_ENONE, _("sl_seek")); 
2145}
2146   
2147int sl_rewind (SL_TICKET ticket) 
2148{
2149  register int fd;
2150
2151  SL_ENTER(_("sl_rewind"));
2152
2153  if (SL_ISERROR(fd = get_the_fd(ticket)))
2154    SL_IRETURN(fd, _("sl_rewind"));
2155
2156  if (lseek (fd, 0L, SEEK_SET) == (off_t)-1)
2157    SL_IRETURN(SL_EREWIND, _("sl_rewind"));
2158
2159  SL_IRETURN(SL_ENONE, _("sl_rewind")); 
2160}
2161
2162int sl_forward (SL_TICKET ticket) 
2163{
2164  register int fd;
2165
2166  SL_ENTER(_("sl_forward"));
2167
2168  if (SL_ISERROR(fd = get_the_fd(ticket)))
2169    SL_IRETURN(fd, _("sl_forward"));
2170
2171  if (lseek (fd, 0L, SEEK_END) == (off_t)-1)
2172    SL_IRETURN(SL_EFORWARD, _("sl_forward"));
2173
2174  SL_IRETURN(SL_ENONE, _("sl_forward")); 
2175}
2176
2177
2178int sl_sync (SL_TICKET ticket) 
2179{
2180  register int fd;
2181
2182  SL_ENTER(_("sl_sync"));
2183
2184  if (SL_ISERROR(fd = get_the_fd(ticket)))
2185    SL_IRETURN(fd, _("sl_sync"));
2186
2187  if (fsync (fd) == -1)
2188    SL_IRETURN(SL_ESYNC, _("sl_sync"));
2189
2190  SL_IRETURN(SL_ENONE, _("sl_sync")); 
2191}
2192
2193int sl_read_timeout_prep (SL_TICKET ticket)
2194{
2195  int fd;
2196  int sflags;
2197
2198  SL_ENTER(_("sl_read_timeout_prep"));
2199
2200  if (SL_ISERROR(fd = get_the_fd(ticket)))
2201    {
2202      TPT(( 0, FIL__, __LINE__, _("msg=<ticket error> errno=<%d>"), fd));
2203      SL_IRETURN(fd, _("sl_read_timeout_prep"));
2204    }
2205
2206  /* set to non-blocking mode
2207   */
2208  sflags = retry_fcntl(FIL__, __LINE__, fd, F_GETFL, 0);
2209  retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags | O_NONBLOCK);
2210
2211  SL_IRETURN(SL_ENONE, _("sl_read_timeout_prep"));
2212}
2213
2214
2215int sl_read_timeout_fd (int fd, void * buf_in, size_t count, 
2216                        int timeout, int is_nonblocking)
2217{
2218  int sflags = 0;
2219  fd_set readfds;
2220  struct timeval tv;
2221  /* int sflags; */
2222  int retval;
2223
2224  int    byteread = 0;
2225  int    bytes    = 0;
2226  char * buf;
2227
2228  time_t tnow;
2229  time_t tstart;
2230  time_t tdiff;
2231  extern volatile int sig_termfast;
2232 
2233  if (is_nonblocking == SL_FALSE)
2234    {
2235      /* set to non-blocking mode
2236       */
2237      sflags = retry_fcntl(FIL__, __LINE__, fd, F_GETFL, 0);
2238      retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags | O_NONBLOCK);
2239    }
2240
2241  buf = (char *) buf_in;
2242
2243  tstart = time(NULL);
2244  tdiff  = 0;
2245
2246  while (count > 0)
2247    {
2248      FD_ZERO(&readfds);
2249      FD_SET(fd, &readfds);
2250
2251      tv.tv_sec  = timeout - tdiff;
2252      tv.tv_usec = 0;
2253     
2254      retval = select (fd+1, &readfds, NULL, NULL, &tv);
2255     
2256      if (retval > 0)
2257        {
2258          byteread = read (fd, buf, count);
2259
2260          if (byteread > 0) 
2261            {
2262              bytes += byteread; count -= byteread;
2263              buf += byteread;
2264              if (count == 0)
2265                break;
2266            } 
2267          else if (byteread == 0)
2268            {
2269              break;
2270            }
2271          else
2272            {
2273              if (errno == EINTR || errno == EAGAIN)
2274                {
2275                  retry_msleep(1, 0);
2276                  tnow  = time(NULL);
2277                  tdiff = tnow - tstart;
2278                  continue;
2279                }
2280              else
2281                {
2282                  if (is_nonblocking == SL_FALSE)
2283                      retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags);
2284                  TPT(( 0, FIL__, __LINE__, _("msg=<read error>")));
2285                  return (SL_EREAD);
2286                }
2287            }
2288        }
2289      else if ((retval == -1) && (errno == EINTR || errno == EAGAIN))
2290        {
2291          retry_msleep(1, 0);
2292          tnow  = time(NULL);
2293          tdiff = tnow - tstart;
2294          continue;
2295        }
2296      else if (retval == 0)
2297        {
2298          if (is_nonblocking == SL_FALSE)
2299              retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags);
2300          TPT(( 0, FIL__, __LINE__, _("msg=<timeout>")));
2301          return (SL_TIMEOUT);
2302        }
2303      else
2304        {
2305          if (is_nonblocking == SL_FALSE)
2306              retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags);
2307          TPT(( 0, FIL__, __LINE__, _("msg=<timeout>")));
2308          return (SL_EREAD);
2309        }
2310
2311      if (sig_termfast == 1) 
2312        {
2313          if (is_nonblocking == SL_FALSE)
2314              retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags);
2315          TPT(( 0, FIL__, __LINE__, _("msg=<terminated>")));
2316          return (SL_EREAD);
2317        }
2318         
2319      tnow  = time(NULL);
2320      tdiff = tnow - tstart;
2321
2322      if (tdiff > timeout)
2323        {
2324          if (is_nonblocking == SL_FALSE)
2325              retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags);
2326          TPT(( 0, FIL__, __LINE__, _("msg=<timeout>")));
2327          return (SL_TIMEOUT);
2328        }
2329    }
2330
2331  if (is_nonblocking == SL_FALSE)
2332    retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags);
2333  return ((int) bytes);
2334}
2335
2336int sl_read_timeout (SL_TICKET ticket, void * buf_in, size_t count, 
2337                     int timeout, int is_nonblocking)
2338{
2339  int    fd, retval;
2340 
2341  SL_ENTER(_("sl_read_timeout"));
2342
2343  if (buf_in == NULL || SL_ISERROR(fd = get_the_fd(ticket)))
2344    {
2345      if (buf_in == NULL)
2346        {
2347          TPT(( 0, FIL__, __LINE__, _("msg=<null buffer>")));
2348          SL_IRETURN((SL_ENULL), _("sl_read_timeout"));
2349        }
2350      if (SL_ISERROR(fd = get_the_fd(ticket)))
2351        {
2352          TPT(( 0, FIL__, __LINE__, _("msg=<ticket error> errno=<%d>"), fd));
2353          SL_IRETURN((fd),  _("sl_read_timeout"));
2354        }
2355    }
2356
2357  retval = sl_read_timeout_fd (fd, buf_in, count, timeout, is_nonblocking);
2358  SL_IRETURN((retval), _("sl_read_timeout"));
2359}
2360
2361
2362int sl_read (SL_TICKET ticket, void * buf_in, size_t count)
2363{
2364  int fd;
2365  int byteread = 0;
2366  int bytes    = 0;
2367
2368  char * buf;
2369
2370  SL_ENTER(_("sl_read"));
2371
2372  if (count < 1)
2373    {
2374      TPT(( 0, FIL__, __LINE__, _("msg=<range error>")));
2375      SL_IRETURN((SL_ERANGE), _("sl_read"));
2376    }
2377  if (buf_in == NULL)
2378    {
2379      TPT(( 0, FIL__, __LINE__, _("msg=<null buffer>")));
2380      SL_IRETURN((SL_ENULL), _("sl_read"));
2381    }
2382
2383  if (SL_ISERROR(fd = get_the_fd(ticket)))
2384    {
2385      TPT(( 0, FIL__, __LINE__, _("msg=<ticket error> errno=<%d>"), fd));
2386      SL_IRETURN((fd), _("sl_read"));
2387    }
2388
2389  buf = (char *) buf_in;
2390
2391  do 
2392    {
2393      byteread = read (fd, buf, count);
2394      if (byteread > 0) 
2395        {
2396          bytes += byteread; count -= byteread;
2397          buf += byteread;
2398        } 
2399    } while ( byteread > 0 || 
2400              ( byteread == -1 && (errno == EINTR || errno == EAGAIN)) 
2401              );
2402
2403 
2404  if (byteread == (-1))
2405    {
2406      TPT(( 0, FIL__, __LINE__, _("msg=<read error> errno=<%d>\n"), errno));
2407      SL_IRETURN((SL_EREAD), _("sl_read"));
2408    }
2409  SL_IRETURN((bytes), _("sl_read"));
2410}
2411
2412int sl_read_fast (SL_TICKET ticket, void * buf_in, size_t count)
2413{
2414  int fd;
2415  int byteread = 0;
2416
2417  char * buf;
2418
2419  SL_ENTER(_("sl_read_fast"));
2420
2421  if (count < 1)
2422    {
2423      TPT(( 0, FIL__, __LINE__, _("msg=<range error>")));
2424      SL_IRETURN((SL_ERANGE), _("sl_read_fast"));
2425    }
2426  if (buf_in == NULL)
2427    {
2428      TPT(( 0, FIL__, __LINE__, _("msg=<null buffer>")));
2429      SL_IRETURN((SL_ENULL), _("sl_read_fast"));
2430    }
2431
2432  if (SL_ISERROR(fd = get_the_fd(ticket)))
2433    {
2434      TPT(( 0, FIL__, __LINE__, _("msg=<ticket error> errno=<%d>"), fd));
2435      SL_IRETURN((fd), _("sl_read_fast"));
2436    }
2437
2438  buf = (char *) buf_in;
2439
2440  do 
2441    {
2442      byteread = read (fd, buf, count);
2443      if (byteread >= 0) 
2444        {
2445          SL_IRETURN((byteread), _("sl_read_fast"));
2446        } 
2447    } while ( byteread == -1 && (errno == EINTR || errno == EAGAIN));
2448
2449 
2450  if (byteread == (-1))
2451    {
2452      TPT(( 0, FIL__, __LINE__, _("msg=<read error> errno=<%d>\n"), errno));
2453      SL_IRETURN((SL_EREAD), _("sl_read_fast"));
2454    }
2455  SL_IRETURN((0), _("sl_read_fast"));
2456}
2457
2458
2459int sl_write (SL_TICKET ticket, const void * msg_in, long nbytes)
2460{
2461  long bytewritten;
2462  long bytecount;
2463  int  fd;
2464
2465  const char * msg; 
2466
2467  SL_ENTER(_("sl_write"));
2468
2469  if (nbytes < 1)
2470    SL_IRETURN(SL_ERANGE, _("sl_write"));
2471  if (msg_in == NULL)
2472    SL_IRETURN(SL_ENULL, _("sl_write"));
2473  if (SL_ISERROR(fd = get_the_fd(ticket)))
2474    SL_IRETURN(fd, _("sl_write"));
2475
2476  msg = (const char *) msg_in;
2477
2478  /* write
2479   */
2480  bytecount    = 0;
2481  bytewritten  = 0;
2482  while (bytecount < nbytes) 
2483    {   
2484      if ((bytewritten = write (fd, msg, nbytes-bytecount)) > 0) 
2485        {
2486          bytecount += bytewritten;
2487          msg       += bytewritten;    /* move buffer pointer forward */
2488        }
2489      else if (bytewritten <= 0)
2490        {
2491          if ( errno == EINTR || errno == EAGAIN) /* try again */
2492              continue;
2493          else 
2494            SL_IRETURN(SL_EWRITE, _("sl_write"));
2495        }
2496    }
2497  SL_IRETURN(SL_ENONE, _("sl_write"));
2498}
2499
2500int sl_write_line (SL_TICKET ticket, const void * msg, long nbytes)
2501{
2502  int  status;
2503
2504  SL_ENTER(_("sl_write_line"));
2505
2506  status = sl_write(ticket,  msg, nbytes); 
2507  if (!SL_ISERROR(status))
2508    status = sl_write(ticket,  "\n", 1);
2509
2510  SL_IRETURN(status, _("sl_write_line"));
2511}
2512
2513int sl_write_line_fast (SL_TICKET ticket, void * msg, long nbytes)
2514{
2515  int  status;
2516  char * p = (char *) msg;
2517
2518  SL_ENTER(_("sl_write_line_fast"));
2519
2520  /* Here nbytes is strlen(msg), so p[nbytes] is the terminating '\0'
2521   * Overwrite the terminator, write out, then write back the terminator.
2522   */
2523  p[nbytes] = '\n';
2524  status = sl_write(ticket,  msg, nbytes+1);
2525  p[nbytes] = '\0';
2526
2527  SL_IRETURN(status, _("sl_write_line_fast"));
2528}
2529
2530
2531/* ----------------------------------------------------------------
2532 *
2533 *    Trustfile interface
2534 *
2535 * ---------------------------------------------------------------- */
2536
2537extern uid_t rootonly[];
2538extern int   EUIDSLOT;
2539extern int   ORIG_EUIDSLOT;
2540
2541extern char  tf_path[MAXFILENAME];      /* Error path for trust function. */
2542extern uid_t tf_euid;                   /* Space for EUID of process.     */
2543
2544char * sl_error_string(int errorcode)
2545{
2546  switch (errorcode)
2547    {
2548    case SL_EBOGUS: 
2549      return _("Bogus file. Modified during access.");
2550    case SL_EWRITE: 
2551      return _("Write error.");
2552    case SL_EREAD: 
2553      return _("Read error.");
2554    case SL_ESYNC: 
2555      return _("Error in fsync().");
2556    case SL_EFORWARD: 
2557      return _("Error in lseek().");
2558    case SL_EREWIND: 
2559      return _("Error in lseek().");
2560    case SL_EUNLINK: 
2561      return _("Error in unlink().");
2562    case SL_EMEM: 
2563      return _("Out of memory.");
2564    case SL_EINTERNAL: 
2565      return _("Internal error.");
2566    case SL_ETICKET:
2567      return _("Bad ticket.");
2568    case SL_EREPEAT: 
2569      return _("Illegal repeated use of function.");
2570    case SL_ERANGE: 
2571      return _("Argument out of range.");
2572    case SL_ENULL: 
2573      return _("Dereferenced NULL pointer.");
2574
2575    case SL_EBADUID: 
2576      return _("Owner not trustworthy.");
2577    case SL_EBADGID:
2578      return _("Group writeable and member not trustworthy.");
2579    case SL_EBADOTH:
2580      return _("World writeable.");
2581    case SL_EBADFILE:
2582      return _("File access error.");
2583    case SL_EBADNAME:
2584      return _("Invalid filename (prob. too long or null).");
2585
2586    case SL_ETRUNC:
2587      return _("Truncation occured.");
2588    case SL_ESTAT:
2589      return _("stat() failed.");
2590    default:
2591      return _("Unknown error.");
2592    }
2593}
2594
2595
2596
2597char * sl_trust_errfile(void)
2598{
2599  return &tf_path[0];
2600}
2601
2602extern uid_t tf_baduid;
2603uid_t   sl_trust_baduid(void)
2604{
2605  return tf_baduid;
2606}
2607
2608extern gid_t tf_badgid;
2609gid_t   sl_trust_badgid(void)
2610{
2611  return tf_badgid;
2612}
2613
2614
2615static int trust_count = 0;
2616
2617int  sl_trust_purge_user (void)
2618{
2619  int i;
2620
2621  EUIDSLOT = ORIG_EUIDSLOT;
2622  trust_count = 0;
2623
2624  for (i = EUIDSLOT; i < (EUIDSLOT + 15); ++i) 
2625    rootonly[i] = sh_uid_neg;
2626  return 0;
2627}
2628
2629int  sl_trust_add_user (uid_t pwid)
2630{
2631  SL_ENTER(_("sl_trust_add_user"));
2632
2633  if (trust_count == 15)
2634    SL_IRETURN(SL_ERANGE, _("sl_trust_add_user"));
2635 
2636  rootonly[EUIDSLOT] = pwid;
2637  ++EUIDSLOT;
2638  ++trust_count;
2639
2640  SL_IRETURN(SL_ENONE, _("sl_trust_add_user"));
2641}
2642
2643#include "sh_mem.h"
2644extern char * sh_util_strdup (const char * str);
2645
2646struct sl_trustfile_store {
2647  char * filename;
2648  uid_t  teuid;
2649  struct sl_trustfile_store * next;
2650};
2651
2652static struct sl_trustfile_store * sl_trusted_files = NULL;
2653
2654void sl_add_trusted_file(char * filename, uid_t teuid)
2655{
2656  struct sl_trustfile_store *new = SH_ALLOC(sizeof(struct sl_trustfile_store));
2657
2658  new->filename = sh_util_strdup (filename);
2659  new->teuid    = teuid;
2660  new->next     = sl_trusted_files;
2661
2662  sl_trusted_files = new;
2663  return;
2664}
2665
2666char * sl_check_trusted_file(char * filename, uid_t teuid)
2667{
2668  struct sl_trustfile_store *new = sl_trusted_files;
2669
2670  while (new)
2671    {
2672      if ((new->teuid == teuid) && (0 == strcmp(new->filename, filename)))
2673        return filename;
2674      new = new->next;
2675    }
2676
2677  return NULL;
2678}
2679
2680void sl_clear_trusted_file(struct sl_trustfile_store * file)
2681{
2682  if (file)
2683    {
2684      if (file->next != NULL)
2685        sl_clear_trusted_file(file->next);
2686      SH_FREE(file->filename);
2687      SH_FREE(file);
2688    }
2689  return;
2690}
2691
2692int sl_trustfile_euid(char * filename, uid_t teuid)
2693{
2694  long          status;
2695  static time_t old = 0;
2696  static time_t now;
2697
2698  SL_ENTER(_("sl_trustfile_euid"));
2699
2700  tf_path[0] = '\0';
2701  if (filename == NULL || filename[0] == '\0')
2702    SL_IRETURN(SL_EBADNAME, _("sl_trustfile_euid"));
2703
2704  now = time(NULL);
2705  if (now < (old + 300))
2706    {
2707      if (NULL != sl_check_trusted_file(filename, teuid))
2708        {
2709          sl_strlcpy(tf_path, filename, sizeof(tf_path));
2710          SL_IRETURN(SL_ENONE, _("sl_trustfile_euid"));
2711        }
2712    }
2713  else
2714    {
2715      sl_clear_trusted_file(sl_trusted_files);
2716      sl_trusted_files = NULL;
2717      old = now;
2718    }
2719
2720  tf_euid = teuid;
2721  status = sl_trustfile(filename, NULL, NULL);
2722  if (status == SL_ENONE)
2723    sl_add_trusted_file(filename, teuid);
2724  SL_IRETURN(status, _("sl_trustfile_euid"));
2725}
2726
2727/* ----------------------------------------------------------------
2728 *
2729 *    Overflow tests
2730 *
2731 * ---------------------------------------------------------------- */
2732
2733#ifndef SIZE_MAX
2734#define SIZE_MAX              (4294967295U)
2735#endif
2736
2737int sl_ok_muli (int a, int b) /* a*b */
2738{
2739  if ((b == 0) || (a >= (INT_MIN / b) && a <= (INT_MAX / b)))
2740    return SL_TRUE; /* no overflow */
2741  return SL_FALSE;
2742}
2743
2744int sl_ok_muls (size_t a, size_t b) /* a*b */
2745{
2746  if ((b == 0) || (a <= (SIZE_MAX / b)))
2747    return SL_TRUE; /* no overflow */
2748  return SL_FALSE;
2749}
2750
2751int sl_ok_divi (int a, int b) /* a/b */
2752{
2753  (void) a;
2754  if (b != 0)
2755    return SL_TRUE; /* no overflow */
2756  return SL_FALSE;
2757}
2758
2759int sl_ok_addi (int a, int b) /* a+b */
2760{
2761  if (a >= 0 && b >= 0)
2762    {
2763      if (a <= (INT_MAX - b))
2764        return SL_TRUE; /* no overflow */
2765      else
2766        return SL_FALSE;
2767    }
2768  else if (a < 0 && b < 0)
2769    {
2770      if (a >= (INT_MIN - b))
2771        return SL_TRUE; /* no overflow */
2772      else
2773        return SL_FALSE;
2774    }
2775  return SL_TRUE;
2776}
2777
2778int sl_ok_adds (size_t a, size_t b) /* a+b */
2779{
2780  if (a <= (SIZE_MAX - b))
2781    return SL_TRUE; /* no overflow */
2782  else
2783    return SL_FALSE;
2784}
2785
2786int sl_ok_subi (int a, int b) /* a-b */
2787{
2788  if (a >= 0 && b < 0)
2789    {
2790      if (a <= (INT_MAX + b))
2791        return SL_TRUE; /* no overflow */
2792      else
2793        return SL_FALSE;
2794    }
2795  else if (a < 0 && b >= 0)
2796    {
2797      if (a >= (INT_MIN + b))
2798        return SL_TRUE; /* no overflow */
2799      else
2800        return SL_FALSE;
2801    }
2802  return SL_TRUE;
2803}
Note: See TracBrowser for help on using the repository browser.