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