source: trunk/src/slib.c@ 543

Last change on this file since 543 was 539, checked in by katerina, 6 years ago

Fixes for tickets #431 (OpenBSD compatibility) and #432 (compiler warnings).

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