source: trunk/src/slib.c@ 592

Last change on this file since 592 was 592, checked in by katerina, 7 days ago

Fixes for compiler warnings.

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