source: trunk/src/slib.c@ 535

Last change on this file since 535 was 529, checked in by katerina, 7 years ago

Fix for ticket #427 (_BSD_SOURCE)

File size: 71.3 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;
1779 SL_IRETURN(SL_EMEM, _("sl_make_ticket"));
1780 }
1781
1782 /* Get a ticket.
1783 */
1784 ticket = sl_create_ticket((unsigned int)fd);
1785
1786 if (SL_ISERROR(ticket))
1787 {
1788 (void) free (ofiles[fd]->path);
1789 (void) free (ofiles[fd]);
[247]1790 ofiles[fd] = NULL;
[1]1791 SL_IRETURN(ticket, _("sl_make_ticket"));
1792 }
1793
[22]1794 sl_strlcpy (ofiles[fd]->path, filename, len);
[167]1795 ofiles[fd]->ticket = ticket;
1796 ofiles[fd]->fd = fd;
1797 ofiles[fd]->content = NULL;
[252]1798 ofiles[fd]->stream = stream;
[481]1799 ofiles[fd]->flush = S_FALSE;
[1]1800
[248]1801 sl_strlcpy(ofiles[fd]->ofile, ofile, SL_OFILE_SIZE);
1802 ofiles[fd]->oline = oline;
1803
[1]1804 SL_IRETURN(ticket, _("sl_make_ticket"));
1805}
1806
1807#define SL_OPEN_MIN 113
1808#define SL_OPEN_FOR_READ 113
1809#define SL_OPEN_FOR_WRITE 114
1810#define SL_OPEN_FOR_RDWR 115
1811#define SL_OPEN_FOR_WTRUNC 116
1812#define SL_OPEN_FOR_RWTRUNC 117
1813#define SL_OPEN_SAFE_RDWR 118
1814#define SL_OPEN_FOR_FASTREAD 119
1815#define SL_OPEN_MAX 119
1816
1817#if !defined(O_NOATIME)
[395]1818#if defined(__linux__) && (defined(__i386__) || defined(__x86_64__) || defined(__PPC__))
[1]1819#define O_NOATIME 01000000
1820#else
1821 /*
1822 * bitwise 'or' with zero does not modify any bit
1823 */
1824#define O_NOATIME 0
1825#endif
1826#endif
1827
1828static int o_noatime = O_NOATIME;
1829static mode_t open_mode = (S_IWUSR|S_IRUSR|S_IRGRP);
1830
1831
1832static
[248]1833int sl_open_file (const char * ofile, int oline,
1834 const char *filename, int mode, int priv)
[1]1835{
1836 struct stat lbuf;
1837 struct stat buf;
[192]1838 int errval = 0;
[1]1839 int lstat_return;
1840 int stat_return;
1841 int fd;
1842 int sflags;
[22]1843 size_t len;
[1]1844 SL_TICKET ticket;
1845
1846#if !defined(O_NONBLOCK)
1847#if defined(O_NDELAY)
1848#define O_NONBLOCK O_NDELAY
1849#else
1850#define O_NONBLOCK 0
1851#endif
1852#endif
1853
1854 SL_ENTER(_("sl_open_file"));
1855
1856 if (filename == NULL)
1857 SL_IRETURN(SL_ENULL, _("sl_open_file"));
1858 if (mode < SL_OPEN_MIN || mode > SL_OPEN_MAX)
[243]1859 SL_IRETURN(SL_EINTERNAL07, _("sl_open_file"));
[1]1860
1861 /* "This system call always succeeds and the previous value of
1862 * the mask is returned."
1863 */
[252]1864 (void) umask (0);
[1]1865
1866 if (mode == SL_OPEN_FOR_FASTREAD)
1867 {
1868 fd = aud_open_noatime (FIL__, __LINE__, priv, filename,
1869 O_RDONLY|O_NONBLOCK, 0, &o_noatime);
[8]1870 /*
[1]1871 if (fd >= 0) {
1872 sflags = retry_fcntl(FIL__, __LINE__, fd, F_GETFL, 0);
1873 retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags & ~O_NONBLOCK);
1874 }
[8]1875 */
[1]1876 if (fd < 0)
1877 SL_IRETURN(SL_EBADFILE, _("sl_open_file"));
1878 goto createTicket;
1879 }
1880
1881#ifdef USE_SUID
1882 if (priv == SL_YESPRIV)
1883 sl_set_suid();
1884#endif
1885 if (mode == SL_OPEN_FOR_READ)
1886 lstat_return = retry_stat (FIL__, __LINE__, filename, &lbuf);
1887 else
1888 lstat_return = retry_lstat(FIL__, __LINE__, filename, &lbuf);
[192]1889 errval = errno;
[1]1890#ifdef USE_SUID
1891 if (priv == SL_YESPRIV)
1892 sl_unset_suid();
1893#endif
1894
1895 if (lstat_return == -1)
1896 {
1897 lstat_return = ENOENT;
1898 if ( (mode == SL_OPEN_FOR_READ && lstat_return == ENOENT) ||
[192]1899 (errval != ENOENT))
[1]1900 {
1901 TPT(( 0, FIL__, __LINE__, _("msg=<lstat: %s> errno=<%d>\n"),
[192]1902 filename, errval));
1903 errno = errval;
1904 SL_IRETURN(SL_ESTAT, _("sl_open_file"));
[1]1905 }
1906 }
1907
1908 if ( (mode != SL_OPEN_FOR_READ) && (lstat_return != ENOENT) &&
1909 ( S_ISDIR(lbuf.st_mode) || (S_IWOTH & lbuf.st_mode) )
1910 )
[192]1911 {
1912 int retval = S_ISDIR(lbuf.st_mode) ? SL_EISDIR : SL_EBADOTH;
1913 errno = 0;
1914 SL_IRETURN(retval, _("sl_open_file"));
1915 }
[1]1916
1917 /* O_NOATIME has an effect for read(). But write() ?.
1918 */
1919 switch (mode)
1920 {
1921 case SL_OPEN_FOR_READ:
1922 fd = aud_open_noatime (FIL__, __LINE__, priv, filename,
1923 O_RDONLY|O_NONBLOCK, 0, &o_noatime);
[192]1924 errval = errno;
[1]1925 if (fd >= 0) {
1926 sflags = retry_fcntl(FIL__, __LINE__, fd, F_GETFL, 0);
1927 retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags & ~O_NONBLOCK);
1928 }
1929 break;
1930 case SL_OPEN_FOR_WRITE:
1931 if (lstat_return == ENOENT)
1932 fd = aud_open (FIL__, __LINE__, priv, filename,
1933 O_WRONLY|O_CREAT|O_EXCL, open_mode);
1934 else
1935 fd = aud_open (FIL__, __LINE__, priv, filename,
1936 O_WRONLY, open_mode);
[192]1937 errval = errno;
[1]1938 break;
1939 case SL_OPEN_SAFE_RDWR:
1940 if (lstat_return == ENOENT)
[192]1941 {
1942 fd = aud_open (FIL__, __LINE__, priv, filename,
1943 O_RDWR|O_CREAT|O_EXCL, open_mode);
1944 errval = errno;
1945 }
[1]1946 else
[192]1947 {
1948 errno = errval;
1949 SL_IRETURN(SL_EBADFILE, _("sl_open_file"));
1950 }
[1]1951 break;
1952 case SL_OPEN_FOR_RDWR:
1953 if (lstat_return == ENOENT)
[192]1954 fd = aud_open (FIL__, __LINE__, priv, filename,
1955 O_RDWR|O_CREAT|O_EXCL, open_mode);
[1]1956 else
1957 fd = aud_open (FIL__, __LINE__, priv, filename,
1958 O_RDWR, open_mode);
[192]1959 errval = errno;
[1]1960 break;
1961 case SL_OPEN_FOR_WTRUNC:
1962 if (lstat_return == ENOENT)
1963 fd = aud_open (FIL__, __LINE__, priv, filename,
1964 O_WRONLY|O_CREAT|O_EXCL, open_mode);
1965 else
1966 fd = aud_open (FIL__, __LINE__, priv, filename,
1967 O_WRONLY|O_TRUNC, open_mode);
[192]1968 errval = errno;
[1]1969 break;
1970 case SL_OPEN_FOR_RWTRUNC:
1971 if (lstat_return == ENOENT)
1972 fd = aud_open (FIL__, __LINE__, priv, filename,
1973 O_RDWR|O_CREAT|O_EXCL, open_mode);
1974 else
1975 fd = aud_open (FIL__, __LINE__, priv, filename,
1976 O_RDWR|O_TRUNC, open_mode);
[192]1977 errval = errno;
[1]1978 break;
1979 default:
[192]1980 errno = 0;
[243]1981 SL_IRETURN(SL_EINTERNAL08, _("sl_open_file"));
[1]1982 }
1983
1984 if (fd < 0)
1985 {
1986 TPT(( 0, FIL__, __LINE__, _("msg=<Error opening: %s> errno=<%d>\n"),
[192]1987 filename, errval));
1988 errno = errval;
[1]1989 SL_IRETURN(SL_EBADFILE, _("sl_open_file"));
1990 }
1991
1992#ifdef USE_SUID
1993 if (priv == SL_YESPRIV)
1994 sl_set_suid();
1995#endif
1996 stat_return = retry_fstat(FIL__, __LINE__, fd, &buf);
[192]1997 errval = errno;
[1]1998#ifdef USE_SUID
1999 if (priv == SL_YESPRIV)
2000 sl_unset_suid();
2001#endif
2002
2003 if (stat_return < 0)
2004 {
[252]2005 sl_close_fd (FIL__, __LINE__, fd);
[192]2006 errno = errval;
2007 SL_IRETURN(SL_EFSTAT, _("sl_open_file"));
[1]2008 }
2009
[192]2010 errno = 0;
2011
[1]2012 if (lstat_return != ENOENT && buf.st_ino != lbuf.st_ino)
2013 {
[252]2014 sl_close_fd (FIL__, __LINE__, fd);
[1]2015 SL_IRETURN(SL_EBOGUS, _("sl_open_file"));
2016 }
2017
2018 createTicket:
2019
2020 /* Make entry.
2021 */
[473]2022 /* cppcheck-suppress arrayIndexOutOfBoundsCond */
[1]2023 if (fd >= MAXFD)
2024 {
[252]2025 sl_close_fd(FIL__, __LINE__, fd);
[1]2026 SL_IRETURN(SL_TOOMANY, _("sl_open_file"));
2027 }
2028
[248]2029 if (ofiles[fd] != NULL) /* stale entry */
[1]2030 {
[248]2031 /*
[252]2032 sl_close_fd(FIL__, __LINE__, fd);
[243]2033 SL_IRETURN(SL_EINTERNAL09, _("sl_open_file"));
[248]2034 */
2035 sl_strlcpy(stale_orig_file, ofiles[fd]->ofile, sizeof(stale_orig_file));
2036 stale_orig_line = ofiles[fd]->oline;
2037
2038 if (ofiles[fd]->content)
2039 sh_string_destroy(&(ofiles[fd]->content));
2040 (void) free (ofiles[fd]->path);
2041 (void) free (ofiles[fd]);
2042 ofiles[fd] = NULL;
[1]2043 }
2044
[454]2045 if ( (ofiles[fd] = calloc(1,sizeof(SL_OFILE))) == NULL)
[1]2046 {
[252]2047 sl_close_fd(FIL__, __LINE__, fd);
[1]2048 SL_IRETURN(SL_EMEM, _("sl_open_file"));
2049 }
2050
[22]2051 len = sl_strlen(filename)+1;
2052
[454]2053 if ( (ofiles[fd]->path = calloc(1,len) ) == NULL)
[1]2054 {
[247]2055 free (ofiles[fd]);
[1]2056 ofiles[fd] = NULL;
[252]2057 sl_close_fd(FIL__, __LINE__, fd);
[1]2058 SL_IRETURN(SL_EMEM, _("sl_open_file"));
2059 }
2060
2061 /* Get a ticket.
2062 */
2063 ticket = sl_create_ticket(fd);
2064
2065 if (SL_ISERROR(ticket))
2066 {
2067 (void) free (ofiles[fd]->path);
2068 (void) free (ofiles[fd]);
[247]2069 ofiles[fd] = NULL;
[252]2070 sl_close_fd(FIL__, __LINE__, fd);
[1]2071 SL_IRETURN(ticket, _("sl_open_file"));
2072 }
2073
[22]2074 sl_strlcpy (ofiles[fd]->path, filename, len);
[167]2075 ofiles[fd]->ticket = ticket;
2076 ofiles[fd]->fd = fd;
2077 ofiles[fd]->content = NULL;
[252]2078 ofiles[fd]->stream = NULL;
[481]2079 ofiles[fd]->flush = S_FALSE;
[1]2080
[248]2081 sl_strlcpy(ofiles[fd]->ofile, ofile, SL_OFILE_SIZE);
2082 ofiles[fd]->oline = oline;
2083
[1]2084 SL_IRETURN(ticket, _("sl_open_file"));
2085}
2086
[252]2087FILE * sl_stream (SL_TICKET ticket, char * mode)
2088{
2089 int fd;
2090
2091 if (SL_ISERROR(fd = sl_read_ticket(ticket)))
2092 return (NULL);
2093
2094 if (ofiles[fd] == NULL || fd != ofiles[fd]->fd ||
2095 ticket != ofiles[fd]->ticket || fd < 0)
2096 return (NULL);
2097
2098 if (!ofiles[fd]->stream)
2099 ofiles[fd]->stream = fdopen(fd, mode);
2100
2101 return ofiles[fd]->stream;
2102}
2103
[196]2104int get_the_fd (SL_TICKET ticket)
2105{
2106 int fd;
2107
2108 if (SL_ISERROR(fd = sl_read_ticket(ticket)))
2109 return (fd);
2110
[248]2111 if (ofiles[fd] == NULL || fd != ofiles[fd]->fd ||
2112 ticket != ofiles[fd]->ticket || fd < 0)
[243]2113 return (SL_EINTERNAL10);
[248]2114
[196]2115 return (fd);
2116}
2117
[1]2118static
[20]2119int check_fname_priv (const char * fname, int priv)
[1]2120{
2121 SL_ENTER(_("check_fname_priv"));
2122 if (fname == NULL)
2123 SL_IRETURN(SL_ENULL, _("check_fname_priv"));
2124 if (priv != SL_YESPRIV && priv != SL_NOPRIV)
[243]2125 SL_IRETURN(SL_EINTERNAL11, _("check_fname_priv"));
[1]2126 SL_IRETURN(SL_ENONE, _("check_fname_priv"));
2127}
2128
[248]2129SL_TICKET sl_open_write (const char * ofile, int oline,
2130 const char * fname, int priv)
[1]2131{
2132 long status;
2133 SL_ENTER(_("sl_open_write"));
2134
2135 if (SL_ENONE != (status = check_fname_priv (fname, priv)))
2136 SL_IRETURN(status, _("sl_open_write"));
2137
[248]2138 status = sl_open_file(ofile, oline, fname, SL_OPEN_FOR_WRITE, priv);
[1]2139 SL_IRETURN(status, _("sl_open_write"));
2140}
2141
[248]2142SL_TICKET sl_open_read (const char * ofile, int oline,
2143 const char * fname, int priv)
[1]2144{
2145 long status;
2146 SL_ENTER(_("sl_open_read"));
2147
2148 if (SL_ENONE != (status = check_fname_priv (fname, priv)))
2149 {
2150 TPT(( 0, FIL__, __LINE__,
2151 _("msg=<Error in check_fname_priv.> status=<%ld>\n"),
2152 status));
2153 SL_IRETURN(status, _("sl_open_read"));
2154 }
2155
[248]2156 status = sl_open_file(ofile, oline, fname, SL_OPEN_FOR_READ, priv);
[1]2157 SL_IRETURN(status, _("sl_open_read"));
2158}
2159
[196]2160#if defined(HAVE_POSIX_FADVISE) && defined(HAVE_MINCORE) && defined(POSIX_FADV_DONTNEED)
2161static int sl_check_mincore(int fd)
2162{
2163 /* Idea from Tobias Oetiker (http://insights.oetiker.ch/linux/fadvise.html)
2164 */
2165 struct stat fbuf;
2166 int retval = -1;
2167
2168 if (0 == fstat(fd, &fbuf))
2169 {
2170 void *f_map;
2171
2172 f_map = mmap((void *)0, fbuf.st_size, PROT_NONE, MAP_SHARED, fd, 0);
2173 if (MAP_FAILED != f_map)
2174 {
2175 extern int sh_unix_pagesize(void);
2176 size_t i;
2177 size_t page_size = sh_unix_pagesize();
2178 size_t vec_size = (fbuf.st_size+page_size-1)/page_size;
2179 unsigned char * vec = calloc(1, vec_size);
2180
2181 if (vec)
2182 {
2183 mincore(f_map, fbuf.st_size, vec);
[237]2184 /* imax = fbuf.st_size/page_size; */
[196]2185 for (i = 0; i <= vec_size; ++i)
2186 {
2187 if (vec[i]&1)
2188 {
2189 goto incore;
2190 }
2191 }
2192 retval = 0;
2193 incore:
2194 free(vec);
2195 }
2196 munmap(f_map, fbuf.st_size);
2197 }
2198 }
2199 return retval;
2200}
2201#endif
2202
[481]2203static int sl_drop_cache = S_FALSE;
[196]2204
2205int sl_set_drop_cache(const char * str)
2206{
2207 extern int sh_util_flagval(const char * c, int * fval);
2208 return sh_util_flagval(str, &sl_drop_cache);
2209}
2210
[248]2211SL_TICKET sl_open_fastread (const char * ofile, int oline,
2212 const char * fname, int priv)
[1]2213{
2214 long status;
2215 SL_ENTER(_("sl_open_fastread"));
2216
2217 if (SL_ENONE != (status = check_fname_priv (fname, priv)))
2218 SL_IRETURN(status, _("sl_open_read"));
2219
[248]2220 status = sl_open_file(ofile, oline, fname, SL_OPEN_FOR_FASTREAD, priv);
[196]2221
2222#if defined(HAVE_POSIX_FADVISE) && defined(HAVE_MINCORE) && defined(POSIX_FADV_DONTNEED)
2223
[481]2224 if (S_FALSE != sl_drop_cache && !SL_ISERROR(status))
[196]2225 {
2226 int fd = get_the_fd(status);
2227 if (fd >= 0)
2228 {
2229 if (0 == sl_check_mincore(fd))
[481]2230 ofiles[fd]->flush = S_TRUE;
[196]2231 }
2232 }
2233
2234#endif
2235
[1]2236 SL_IRETURN(status, _("sl_open_fastread"));
2237}
2238
[248]2239SL_TICKET sl_open_rdwr (const char * ofile, int oline,
2240 const char * fname, int priv)
[1]2241{
2242 long status;
2243 SL_ENTER(_("sl_open_rdwr"));
2244
2245 if (SL_ENONE != (status = check_fname_priv (fname, priv)))
2246 SL_IRETURN(status, _("sl_open_rdwr"));
2247
[248]2248 status = sl_open_file(ofile, oline, fname, SL_OPEN_FOR_RDWR, priv);
[1]2249 SL_IRETURN(status, _("sl_open_rdwr"));
2250}
2251
[248]2252SL_TICKET sl_open_safe_rdwr (const char * ofile, int oline,
2253 const char * fname, int priv)
[1]2254{
2255 long status;
2256 SL_ENTER(_("sl_open_safe_rdwr"));
2257
2258 if (SL_ENONE != (status = check_fname_priv (fname, priv)))
2259 SL_IRETURN(status, _("sl_open_safe_rdwr"));
2260
[248]2261 status = sl_open_file(ofile, oline, fname, SL_OPEN_SAFE_RDWR, priv);
[1]2262 SL_IRETURN(status, _("sl_open_safe_rdwr"));
2263}
2264
[248]2265SL_TICKET sl_open_write_trunc (const char * ofile, int oline,
2266 const char * fname, int priv)
[1]2267{
2268 long status;
2269 SL_ENTER(_("sl_open_write_trunc"));
2270
2271 if (SL_ENONE != (status = check_fname_priv (fname, priv)))
2272 SL_IRETURN(status, _("sl_open_write_trunc"));
2273
[248]2274 status = sl_open_file(ofile, oline, fname, SL_OPEN_FOR_WTRUNC, priv);
[1]2275 SL_IRETURN(status, _("sl_open_write_trunc"));
2276}
2277
[248]2278SL_TICKET sl_open_rdwr_trunc (const char * ofile, int oline,
2279 const char * fname, int priv)
[1]2280{
2281 long status;
2282 SL_ENTER(_("sl_open_rdwr_trunc"));
2283
2284 if (SL_ENONE != (status = check_fname_priv (fname, priv)))
2285 SL_IRETURN(status, _("sl_open_rdwr_trunc"));
2286
[248]2287 status = sl_open_file(ofile, oline, fname, SL_OPEN_FOR_RWTRUNC, priv);
[1]2288 SL_IRETURN(status, _("sl_open_rdwr_trunc"));
2289}
2290
2291
[167]2292int sl_init_content (SL_TICKET ticket, size_t size)
2293{
2294 int fd;
2295
2296 if (SL_ISERROR(fd = sl_read_ticket(ticket)))
2297 return (fd);
2298
[248]2299 if (ofiles[fd] == NULL || fd != ofiles[fd]->fd ||
2300 ticket != ofiles[fd]->ticket || fd < 0)
[243]2301 return (SL_EINTERNAL12);
[167]2302
2303 if (ofiles[fd]->content)
2304 sh_string_destroy(&(ofiles[fd]->content));
2305 ofiles[fd]->content = sh_string_new(size);
2306
2307 return SL_ENONE;
2308}
2309
2310sh_string * sl_get_content (SL_TICKET ticket)
2311{
2312 int fd;
2313
2314 if (SL_ISERROR(fd = sl_read_ticket(ticket)))
2315 return (NULL);
2316
[248]2317 if (ofiles[fd] == NULL || fd != ofiles[fd]->fd ||
2318 ticket != ofiles[fd]->ticket || fd < 0)
[167]2319 return (NULL);
2320
2321 return (ofiles[fd]->content);
2322}
2323
[212]2324int sl_lock (SL_TICKET ticket)
2325{
2326 int fd;
2327 struct flock lock;
2328 int retval;
2329
2330 SL_ENTER(_("sl_lock"));
2331
2332 if (SL_ISERROR(fd = get_the_fd (ticket)))
2333 SL_IRETURN(fd, _("sl_lock"));
2334
2335 lock.l_type = F_WRLCK;
2336 lock.l_whence = SEEK_SET;
2337 lock.l_start = 0;
2338 lock.l_len = 0;
2339
2340 /* F_SETLK returns if the lock cannot be obtained */
2341 do {
2342 retval = fcntl(fd, F_SETLK, &lock);
2343 } while (retval < 0 && errno == EINTR);
2344
2345 if (retval < 0 && errno == EBADF)
2346 SL_IRETURN(SL_ETICKET, _("sl_lock"));
2347 else if (retval < 0)
2348 SL_IRETURN(SL_EBADFILE, _("sl_lock"));
2349 else
2350 SL_IRETURN(SL_ENONE, _("sl_lock"));
2351 }
2352
[1]2353int sl_close (SL_TICKET ticket)
2354{
2355 register int fd;
[252]2356 FILE * fp = NULL;
[1]2357
2358 SL_ENTER(_("sl_close"));
2359
2360 if (SL_ISERROR(fd = get_the_fd (ticket)))
2361 SL_IRETURN(fd, _("sl_close"));
2362
[247]2363 if (ofiles[fd] != NULL)
2364 {
[196]2365#if defined(HAVE_POSIX_FADVISE) && defined(HAVE_MINCORE) && defined(POSIX_FADV_DONTNEED)
[481]2366 if (ofiles[fd]->flush == S_TRUE)
[247]2367 {
2368 posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED);
2369 }
2370#endif
2371 if (ofiles[fd]->content)
2372 sh_string_destroy(&(ofiles[fd]->content));
2373 (void) free (ofiles[fd]->path);
[252]2374 fp = ofiles[fd]->stream;
[247]2375 (void) free (ofiles[fd]);
2376 ofiles[fd] = NULL;
[196]2377 }
2378
[1]2379 /* This may fail, but what to do then ?
2380 */
[252]2381 if (fp)
[1]2382 {
[252]2383 if (0 != fclose (fp)) /* within sl_close */
2384 {
2385 TPT((0, FIL__, __LINE__,
2386 _("msg=<Error fclosing file.>, fd=<%d>, err=<%s>\n"),
2387 fd, strerror(errno)));
[525]2388 SL_IRETURN(SL_ECLOSE, _("sl_close"));
[252]2389 }
[1]2390 }
[252]2391 else
2392 {
2393 if (0 != close(fd)) /* within sl_close */
2394 {
2395 TPT((0, FIL__, __LINE__,
2396 _("msg=<Error closing file.>, fd=<%d>, err=<%s>\n"),
2397 fd, strerror(errno)));
[525]2398 SL_IRETURN(SL_ECLOSE, _("sl_close"));
[252]2399 }
2400 }
[1]2401
2402 SL_IRETURN(SL_ENONE, _("sl_close"));
2403}
2404
[252]2405int sl_close_fd (const char * file, int line, int fd)
2406{
2407 int ret = -1;
2408
2409 SL_ENTER(_("sl_close_fd"));
2410
2411 if (fd >= 0 && fd < MAXFD && ofiles[fd] != NULL) /* stale ofiles[fd] handle */
2412 {
2413 sl_strlcpy(badfd_orig_file, file, sizeof(badfd_orig_file));
2414 badfd_orig_line = line;
2415 }
2416
2417 ret = close(fd); /* within sl_close_fd wrapper */
2418
2419 SL_IRETURN(ret, _("sl_close_fd"));
2420}
2421
2422int sl_fclose (const char * file, int line, FILE * fp)
2423{
2424 int ret = -1;
2425 int fd;
2426
2427 SL_ENTER(_("sl_fclose"));
2428
2429 fd = fileno(fp);
2430
2431 if (fd >= 0 && fd < MAXFD && ofiles[fd] != NULL) /* stale ofiles[fd] handle */
2432 {
2433 sl_strlcpy(badfd_orig_file, file, sizeof(badfd_orig_file));
2434 badfd_orig_line = line;
2435 }
2436
2437 ret = fclose(fp); /* within sl_fclose wrapper */
2438
2439 SL_IRETURN(ret, _("sl_fclose"));
2440}
2441
[1]2442int sl_dropall(int fd, int except)
2443{
2444 while (fd < MAXFD)
2445 {
2446 if (ofiles[fd] != NULL && fd != except)
2447 {
[167]2448 if (ofiles[fd]->content)
2449 sh_string_destroy(&(ofiles[fd]->content));
[1]2450 if (ofiles[fd]->path != NULL)
[247]2451 (void) free (ofiles[fd]->path);
2452 (void) free (ofiles[fd]);
[1]2453 ofiles[fd] = NULL;
2454 }
2455 ++fd;
2456 }
2457 return 0;
2458}
2459
[174]2460int sl_dropall_dirty(int fd, int except)
2461{
2462 while (fd < MAXFD)
2463 {
2464 if (ofiles[fd] != NULL && fd != except)
2465 {
2466 ofiles[fd] = NULL;
2467 }
2468 ++fd;
2469 }
2470 return 0;
2471}
[1]2472
[174]2473
[1]2474int sl_unlink (SL_TICKET ticket)
2475{
2476 register int fd;
2477
2478 SL_ENTER(_("sl_unlink"));
2479
2480 if (SL_ISERROR(fd = get_the_fd(ticket)))
2481 SL_IRETURN(fd, _("sl_unlink"));
2482
2483 if (retry_aud_unlink(FIL__, __LINE__, ofiles[fd]->path) < 0)
2484 SL_IRETURN(SL_EUNLINK, _("sl_unlink"));
2485
2486 SL_IRETURN(SL_ENONE, _("sl_unlink"));
2487}
2488
2489
2490int sl_seek (SL_TICKET ticket, off_t off_data)
2491{
2492 register int fd;
2493
2494 SL_ENTER(_("sl_seek"));
2495
2496 if (SL_ISERROR(fd = get_the_fd(ticket)))
2497 SL_IRETURN(fd, _("sl_seek"));
2498
2499 if (lseek(fd, off_data, SEEK_SET) == (off_t)-1)
2500 SL_IRETURN(SL_EREWIND, _("sl_seek"));
2501
2502 SL_IRETURN(SL_ENONE, _("sl_seek"));
2503}
2504
2505int sl_rewind (SL_TICKET ticket)
2506{
2507 register int fd;
2508
2509 SL_ENTER(_("sl_rewind"));
2510
2511 if (SL_ISERROR(fd = get_the_fd(ticket)))
2512 SL_IRETURN(fd, _("sl_rewind"));
2513
2514 if (lseek (fd, 0L, SEEK_SET) == (off_t)-1)
2515 SL_IRETURN(SL_EREWIND, _("sl_rewind"));
2516
2517 SL_IRETURN(SL_ENONE, _("sl_rewind"));
2518}
2519
2520int sl_forward (SL_TICKET ticket)
2521{
2522 register int fd;
2523
2524 SL_ENTER(_("sl_forward"));
2525
2526 if (SL_ISERROR(fd = get_the_fd(ticket)))
2527 SL_IRETURN(fd, _("sl_forward"));
2528
2529 if (lseek (fd, 0L, SEEK_END) == (off_t)-1)
2530 SL_IRETURN(SL_EFORWARD, _("sl_forward"));
2531
2532 SL_IRETURN(SL_ENONE, _("sl_forward"));
2533}
2534
2535
2536int sl_sync (SL_TICKET ticket)
2537{
2538 register int fd;
2539
2540 SL_ENTER(_("sl_sync"));
2541
2542 if (SL_ISERROR(fd = get_the_fd(ticket)))
2543 SL_IRETURN(fd, _("sl_sync"));
2544
2545 if (fsync (fd) == -1)
2546 SL_IRETURN(SL_ESYNC, _("sl_sync"));
2547
2548 SL_IRETURN(SL_ENONE, _("sl_sync"));
2549}
2550
[8]2551int sl_read_timeout_prep (SL_TICKET ticket)
2552{
2553 int fd;
2554 int sflags;
[1]2555
[8]2556 SL_ENTER(_("sl_read_timeout_prep"));
2557
2558 if (SL_ISERROR(fd = get_the_fd(ticket)))
2559 {
2560 TPT(( 0, FIL__, __LINE__, _("msg=<ticket error> errno=<%d>"), fd));
2561 SL_IRETURN(fd, _("sl_read_timeout_prep"));
2562 }
2563
2564 /* set to non-blocking mode
2565 */
2566 sflags = retry_fcntl(FIL__, __LINE__, fd, F_GETFL, 0);
2567 retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags | O_NONBLOCK);
2568
2569 SL_IRETURN(SL_ENONE, _("sl_read_timeout_prep"));
2570}
2571
[131]2572
2573int sl_read_timeout_fd (int fd, void * buf_in, size_t count,
2574 int timeout, int is_nonblocking)
[1]2575{
[137]2576 int sflags = 0;
[1]2577 fd_set readfds;
2578 struct timeval tv;
[8]2579 /* int sflags; */
[1]2580 int retval;
[192]2581 int error;
[1]2582
2583 int byteread = 0;
2584 int bytes = 0;
2585 char * buf;
2586
2587 time_t tnow;
2588 time_t tstart;
2589 time_t tdiff;
2590 extern volatile int sig_termfast;
2591
[481]2592 if (is_nonblocking == S_FALSE)
[1]2593 {
[131]2594 /* set to non-blocking mode
2595 */
2596 sflags = retry_fcntl(FIL__, __LINE__, fd, F_GETFL, 0);
2597 retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags | O_NONBLOCK);
[1]2598 }
2599
2600 buf = (char *) buf_in;
2601
2602 tstart = time(NULL);
2603 tdiff = 0;
2604
2605 while (count > 0)
2606 {
2607 FD_ZERO(&readfds);
2608 FD_SET(fd, &readfds);
2609
2610 tv.tv_sec = timeout - tdiff;
2611 tv.tv_usec = 0;
2612
2613 retval = select (fd+1, &readfds, NULL, NULL, &tv);
2614
2615 if (retval > 0)
2616 {
2617 byteread = read (fd, buf, count);
[8]2618
2619 if (byteread > 0)
[1]2620 {
2621 bytes += byteread; count -= byteread;
2622 buf += byteread;
2623 if (count == 0)
2624 break;
2625 }
2626 else if (byteread == 0)
2627 {
[371]2628 /* zero indicates end of file */
[1]2629 break;
2630 }
2631 else
2632 {
2633 if (errno == EINTR || errno == EAGAIN)
2634 {
2635 retry_msleep(1, 0);
2636 tnow = time(NULL);
2637 tdiff = tnow - tstart;
2638 continue;
2639 }
2640 else
2641 {
[192]2642 error = errno;
[481]2643 if (is_nonblocking == S_FALSE)
[131]2644 retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags);
[169]2645 TPT(( 0, FIL__, __LINE__, _("msg=<read error>")));
[192]2646 errno = error;
[1]2647 return (SL_EREAD);
2648 }
2649 }
2650 }
2651 else if ((retval == -1) && (errno == EINTR || errno == EAGAIN))
2652 {
2653 retry_msleep(1, 0);
2654 tnow = time(NULL);
2655 tdiff = tnow - tstart;
2656 continue;
2657 }
2658 else if (retval == 0)
2659 {
[481]2660 if (is_nonblocking == S_FALSE)
[131]2661 retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags);
[169]2662 TPT(( 0, FIL__, __LINE__, _("msg=<timeout>")));
[192]2663 errno = 0;
[371]2664 if (bytes > 0)
2665 return ((int) bytes);
[1]2666 return (SL_TIMEOUT);
2667 }
2668 else
2669 {
[192]2670 error = errno;
[481]2671 if (is_nonblocking == S_FALSE)
[131]2672 retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags);
[169]2673 TPT(( 0, FIL__, __LINE__, _("msg=<timeout>")));
[192]2674 errno = error;
[1]2675 return (SL_EREAD);
2676 }
[8]2677
2678 if (sig_termfast == 1)
2679 {
[481]2680 if (is_nonblocking == S_FALSE)
[131]2681 retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags);
[169]2682 TPT(( 0, FIL__, __LINE__, _("msg=<terminated>")));
[192]2683 errno = 0;
[8]2684 return (SL_EREAD);
2685 }
2686
[1]2687 tnow = time(NULL);
2688 tdiff = tnow - tstart;
[8]2689
2690 if (tdiff > timeout)
2691 {
[481]2692 if (is_nonblocking == S_FALSE)
[131]2693 retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags);
[169]2694 TPT(( 0, FIL__, __LINE__, _("msg=<timeout>")));
[192]2695 errno = 0;
[371]2696 if (bytes > 0)
2697 return ((int) bytes);
[8]2698 return (SL_TIMEOUT);
2699 }
[1]2700 }
2701
[481]2702 if (is_nonblocking == S_FALSE)
[131]2703 retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags);
[1]2704 return ((int) bytes);
2705}
2706
[131]2707int sl_read_timeout (SL_TICKET ticket, void * buf_in, size_t count,
2708 int timeout, int is_nonblocking)
2709{
[169]2710 int fd, retval;
[131]2711
[169]2712 SL_ENTER(_("sl_read_timeout"));
2713
[131]2714 if (buf_in == NULL || SL_ISERROR(fd = get_the_fd(ticket)))
2715 {
2716 if (buf_in == NULL)
2717 {
2718 TPT(( 0, FIL__, __LINE__, _("msg=<null buffer>")));
[169]2719 SL_IRETURN((SL_ENULL), _("sl_read_timeout"));
[131]2720 }
2721 if (SL_ISERROR(fd = get_the_fd(ticket)))
2722 {
2723 TPT(( 0, FIL__, __LINE__, _("msg=<ticket error> errno=<%d>"), fd));
[169]2724 SL_IRETURN((fd), _("sl_read_timeout"));
[131]2725 }
2726 }
[1]2727
[169]2728 retval = sl_read_timeout_fd (fd, buf_in, count, timeout, is_nonblocking);
2729 SL_IRETURN((retval), _("sl_read_timeout"));
[131]2730}
2731
2732
[1]2733int sl_read (SL_TICKET ticket, void * buf_in, size_t count)
2734{
2735 int fd;
2736 int byteread = 0;
2737 int bytes = 0;
2738
2739 char * buf;
2740
[169]2741 SL_ENTER(_("sl_read"));
2742
[1]2743 if (count < 1)
2744 {
2745 TPT(( 0, FIL__, __LINE__, _("msg=<range error>")));
[169]2746 SL_IRETURN((SL_ERANGE), _("sl_read"));
[1]2747 }
2748 if (buf_in == NULL)
2749 {
2750 TPT(( 0, FIL__, __LINE__, _("msg=<null buffer>")));
[169]2751 SL_IRETURN((SL_ENULL), _("sl_read"));
[1]2752 }
2753
2754 if (SL_ISERROR(fd = get_the_fd(ticket)))
2755 {
2756 TPT(( 0, FIL__, __LINE__, _("msg=<ticket error> errno=<%d>"), fd));
[169]2757 SL_IRETURN((fd), _("sl_read"));
[1]2758 }
2759
2760 buf = (char *) buf_in;
2761
2762 do
2763 {
2764 byteread = read (fd, buf, count);
2765 if (byteread > 0)
2766 {
2767 bytes += byteread; count -= byteread;
2768 buf += byteread;
2769 }
2770 } while ( byteread > 0 ||
[5]2771 ( byteread == -1 && (errno == EINTR || errno == EAGAIN))
[1]2772 );
2773
2774
2775 if (byteread == (-1))
2776 {
2777 TPT(( 0, FIL__, __LINE__, _("msg=<read error> errno=<%d>\n"), errno));
[169]2778 SL_IRETURN((SL_EREAD), _("sl_read"));
[1]2779 }
[169]2780 SL_IRETURN((bytes), _("sl_read"));
[1]2781}
2782
2783int sl_read_fast (SL_TICKET ticket, void * buf_in, size_t count)
2784{
2785 int fd;
2786 int byteread = 0;
2787
2788 char * buf;
2789
[169]2790 SL_ENTER(_("sl_read_fast"));
2791
[1]2792 if (count < 1)
2793 {
2794 TPT(( 0, FIL__, __LINE__, _("msg=<range error>")));
[169]2795 SL_IRETURN((SL_ERANGE), _("sl_read_fast"));
[1]2796 }
2797 if (buf_in == NULL)
2798 {
2799 TPT(( 0, FIL__, __LINE__, _("msg=<null buffer>")));
[169]2800 SL_IRETURN((SL_ENULL), _("sl_read_fast"));
[1]2801 }
2802
2803 if (SL_ISERROR(fd = get_the_fd(ticket)))
2804 {
2805 TPT(( 0, FIL__, __LINE__, _("msg=<ticket error> errno=<%d>"), fd));
[169]2806 SL_IRETURN((fd), _("sl_read_fast"));
[1]2807 }
2808
2809 buf = (char *) buf_in;
2810
2811 do
2812 {
2813 byteread = read (fd, buf, count);
2814 if (byteread >= 0)
2815 {
[169]2816 SL_IRETURN((byteread), _("sl_read_fast"));
[1]2817 }
[5]2818 } while ( byteread == -1 && (errno == EINTR || errno == EAGAIN));
[1]2819
2820
2821 if (byteread == (-1))
2822 {
2823 TPT(( 0, FIL__, __LINE__, _("msg=<read error> errno=<%d>\n"), errno));
[169]2824 SL_IRETURN((SL_EREAD), _("sl_read_fast"));
[1]2825 }
[169]2826 SL_IRETURN((0), _("sl_read_fast"));
[1]2827}
2828
2829
[170]2830int sl_write (SL_TICKET ticket, const void * msg_in, long nbytes)
[1]2831{
2832 long bytewritten;
2833 long bytecount;
2834 int fd;
2835
[170]2836 const char * msg;
[1]2837
2838 SL_ENTER(_("sl_write"));
2839
2840 if (nbytes < 1)
2841 SL_IRETURN(SL_ERANGE, _("sl_write"));
2842 if (msg_in == NULL)
2843 SL_IRETURN(SL_ENULL, _("sl_write"));
2844 if (SL_ISERROR(fd = get_the_fd(ticket)))
2845 SL_IRETURN(fd, _("sl_write"));
2846
[170]2847 msg = (const char *) msg_in;
[1]2848
2849 /* write
2850 */
2851 bytecount = 0;
[383]2852
[1]2853 while (bytecount < nbytes)
2854 {
[383]2855 bytewritten = write (fd, msg, nbytes-bytecount);
2856
2857 if (bytewritten > 0)
[1]2858 {
2859 bytecount += bytewritten;
2860 msg += bytewritten; /* move buffer pointer forward */
2861 }
2862 else if (bytewritten <= 0)
2863 {
2864 if ( errno == EINTR || errno == EAGAIN) /* try again */
2865 continue;
2866 else
2867 SL_IRETURN(SL_EWRITE, _("sl_write"));
2868 }
2869 }
2870 SL_IRETURN(SL_ENONE, _("sl_write"));
2871}
2872
[170]2873int sl_write_line (SL_TICKET ticket, const void * msg, long nbytes)
[1]2874{
2875 int status;
2876
2877 SL_ENTER(_("sl_write_line"));
2878
2879 status = sl_write(ticket, msg, nbytes);
2880 if (!SL_ISERROR(status))
2881 status = sl_write(ticket, "\n", 1);
2882
2883 SL_IRETURN(status, _("sl_write_line"));
2884}
2885
[76]2886int sl_write_line_fast (SL_TICKET ticket, void * msg, long nbytes)
2887{
2888 int status;
2889 char * p = (char *) msg;
[1]2890
[76]2891 SL_ENTER(_("sl_write_line_fast"));
2892
2893 /* Here nbytes is strlen(msg), so p[nbytes] is the terminating '\0'
2894 * Overwrite the terminator, write out, then write back the terminator.
2895 */
2896 p[nbytes] = '\n';
2897 status = sl_write(ticket, msg, nbytes+1);
2898 p[nbytes] = '\0';
2899
2900 SL_IRETURN(status, _("sl_write_line_fast"));
2901}
2902
2903
[1]2904/* ----------------------------------------------------------------
2905 *
2906 * Trustfile interface
2907 *
2908 * ---------------------------------------------------------------- */
2909
2910extern uid_t rootonly[];
[481]2911extern unsigned int EUIDSLOT;
2912extern unsigned int ORIG_EUIDSLOT;
[1]2913
2914extern char tf_path[MAXFILENAME]; /* Error path for trust function. */
2915extern uid_t tf_euid; /* Space for EUID of process. */
2916
2917char * sl_error_string(int errorcode)
2918{
[192]2919
[1]2920 switch (errorcode)
2921 {
2922 case SL_EBOGUS:
[214]2923 return _("Bogus file, modified during access");
[1]2924 case SL_EWRITE:
[200]2925 return _("Write error");
[1]2926 case SL_EREAD:
[200]2927 return _("Read error");
[1]2928 case SL_ESYNC:
[200]2929 return _("Error in fsync()");
[1]2930 case SL_EFORWARD:
[200]2931 return _("Error in lseek()");
[1]2932 case SL_EREWIND:
[200]2933 return _("Error in lseek()");
[1]2934 case SL_EUNLINK:
[200]2935 return _("Error in unlink()");
[1]2936 case SL_EMEM:
[200]2937 return _("Out of memory");
[1]2938 case SL_EINTERNAL:
[200]2939 return _("Internal error");
[243]2940 case SL_EINTERNAL01:
2941 return _("Internal error 01");
2942 case SL_EINTERNAL02:
2943 return _("Internal error 02");
2944 case SL_EINTERNAL03:
2945 return _("Internal error 03");
2946 case SL_EINTERNAL04:
2947 return _("Internal error 04");
2948 case SL_EINTERNAL05:
2949 return _("Internal error 05");
2950 case SL_EINTERNAL06:
2951 return _("Internal error 06");
2952 case SL_EINTERNAL07:
2953 return _("Internal error 07");
2954 case SL_EINTERNAL08:
2955 return _("Internal error 08");
2956 case SL_EINTERNAL09:
2957 return _("Internal error 09");
2958 case SL_EINTERNAL10:
2959 return _("Internal error 10");
2960 case SL_EINTERNAL11:
2961 return _("Internal error 11");
2962 case SL_EINTERNAL12:
2963 return _("Internal error 12");
[1]2964 case SL_ETICKET:
[200]2965 return _("Bad ticket");
[1]2966 case SL_EREPEAT:
[200]2967 return _("Illegal repeated use of function");
[1]2968 case SL_ERANGE:
[200]2969 return _("Argument out of range");
[1]2970 case SL_ENULL:
[200]2971 return _("Dereferenced NULL pointer");
[1]2972
2973 case SL_EBADUID:
[200]2974 return _("Owner not trustworthy");
[1]2975 case SL_EBADGID:
[200]2976 return _("Group writeable and member not trustworthy");
[1]2977 case SL_EBADOTH:
[200]2978 return _("World writeable");
[192]2979 case SL_EISDIR:
[200]2980 return _("Is a directory");
[1]2981 case SL_EBADFILE:
[200]2982 return _("File access error");
[1]2983 case SL_EBADNAME:
[200]2984 return _("Invalid filename (prob. too long or null)");
[1]2985
2986 case SL_ETRUNC:
[200]2987 return _("Truncation occured");
[1]2988 case SL_ESTAT:
[200]2989 return _("stat() failed");
[192]2990 case SL_EFSTAT:
[200]2991 return _("fstat() failed");
[1]2992 default:
[200]2993 return _("Unknown error");
[1]2994 }
2995}
2996
2997
2998
[170]2999char * sl_trust_errfile(void)
[1]3000{
3001 return &tf_path[0];
3002}
3003
3004extern uid_t tf_baduid;
[170]3005uid_t sl_trust_baduid(void)
[1]3006{
3007 return tf_baduid;
3008}
3009
3010extern gid_t tf_badgid;
[170]3011gid_t sl_trust_badgid(void)
[1]3012{
3013 return tf_badgid;
3014}
3015
3016
3017static int trust_count = 0;
3018
[170]3019int sl_trust_purge_user (void)
[1]3020{
[481]3021 unsigned int i;
[1]3022
3023 EUIDSLOT = ORIG_EUIDSLOT;
3024 trust_count = 0;
3025
3026 for (i = EUIDSLOT; i < (EUIDSLOT + 15); ++i)
3027 rootonly[i] = sh_uid_neg;
3028 return 0;
3029}
3030
3031int sl_trust_add_user (uid_t pwid)
3032{
3033 SL_ENTER(_("sl_trust_add_user"));
3034
3035 if (trust_count == 15)
3036 SL_IRETURN(SL_ERANGE, _("sl_trust_add_user"));
3037
3038 rootonly[EUIDSLOT] = pwid;
3039 ++EUIDSLOT;
3040 ++trust_count;
3041
3042 SL_IRETURN(SL_ENONE, _("sl_trust_add_user"));
3043}
3044
[76]3045#include "sh_mem.h"
3046extern char * sh_util_strdup (const char * str);
3047
3048struct sl_trustfile_store {
3049 char * filename;
3050 uid_t teuid;
3051 struct sl_trustfile_store * next;
3052};
3053
3054static struct sl_trustfile_store * sl_trusted_files = NULL;
3055
[183]3056static void sl_add_trusted_file(const char * filename, uid_t teuid)
[76]3057{
3058 struct sl_trustfile_store *new = SH_ALLOC(sizeof(struct sl_trustfile_store));
3059
3060 new->filename = sh_util_strdup (filename);
3061 new->teuid = teuid;
3062 new->next = sl_trusted_files;
3063
3064 sl_trusted_files = new;
3065 return;
3066}
3067
[183]3068static const char * sl_check_trusted_file(const char * filename, uid_t teuid)
[76]3069{
3070 struct sl_trustfile_store *new = sl_trusted_files;
3071
3072 while (new)
3073 {
3074 if ((new->teuid == teuid) && (0 == strcmp(new->filename, filename)))
3075 return filename;
3076 new = new->next;
3077 }
3078
3079 return NULL;
3080}
3081
[183]3082static void sl_clear_trusted_file(struct sl_trustfile_store * file)
[76]3083{
3084 if (file)
3085 {
3086 if (file->next != NULL)
3087 sl_clear_trusted_file(file->next);
3088 SH_FREE(file->filename);
3089 SH_FREE(file);
3090 }
3091 return;
3092}
3093
[183]3094int sl_trustfile_euid(const char * filename, uid_t teuid)
[1]3095{
[76]3096 long status;
[481]3097 static size_t old = 0;
3098 static size_t now;
[76]3099
[1]3100 SL_ENTER(_("sl_trustfile_euid"));
3101
3102 tf_path[0] = '\0';
3103 if (filename == NULL || filename[0] == '\0')
3104 SL_IRETURN(SL_EBADNAME, _("sl_trustfile_euid"));
3105
[76]3106 now = time(NULL);
[481]3107
[76]3108 if (now < (old + 300))
3109 {
3110 if (NULL != sl_check_trusted_file(filename, teuid))
3111 {
3112 sl_strlcpy(tf_path, filename, sizeof(tf_path));
3113 SL_IRETURN(SL_ENONE, _("sl_trustfile_euid"));
3114 }
3115 }
3116 else
3117 {
3118 sl_clear_trusted_file(sl_trusted_files);
3119 sl_trusted_files = NULL;
3120 old = now;
3121 }
3122
[1]3123 tf_euid = teuid;
3124 status = sl_trustfile(filename, NULL, NULL);
[76]3125 if (status == SL_ENONE)
3126 sl_add_trusted_file(filename, teuid);
[1]3127 SL_IRETURN(status, _("sl_trustfile_euid"));
3128}
3129
[20]3130/* ----------------------------------------------------------------
3131 *
3132 * Overflow tests
3133 *
3134 * ---------------------------------------------------------------- */
[1]3135
[34]3136#ifndef SIZE_MAX
3137#define SIZE_MAX (4294967295U)
3138#endif
3139
[20]3140int sl_ok_muli (int a, int b) /* a*b */
3141{
[34]3142 if ((b == 0) || (a >= (INT_MIN / b) && a <= (INT_MAX / b)))
[481]3143 return S_TRUE; /* no overflow */
3144 return S_FALSE;
[20]3145}
3146
[34]3147int sl_ok_muls (size_t a, size_t b) /* a*b */
3148{
3149 if ((b == 0) || (a <= (SIZE_MAX / b)))
[481]3150 return S_TRUE; /* no overflow */
3151 return S_FALSE;
[34]3152}
3153
[20]3154int sl_ok_divi (int a, int b) /* a/b */
3155{
3156 (void) a;
3157 if (b != 0)
[481]3158 return S_TRUE; /* no overflow */
3159 return S_FALSE;
[20]3160}
3161
3162int sl_ok_addi (int a, int b) /* a+b */
3163{
3164 if (a >= 0 && b >= 0)
3165 {
3166 if (a <= (INT_MAX - b))
[481]3167 return S_TRUE; /* no overflow */
[20]3168 else
[481]3169 return S_FALSE;
[20]3170 }
3171 else if (a < 0 && b < 0)
3172 {
3173 if (a >= (INT_MIN - b))
[481]3174 return S_TRUE; /* no overflow */
[20]3175 else
[481]3176 return S_FALSE;
[20]3177 }
[481]3178 return S_TRUE;
[20]3179}
3180
[34]3181int sl_ok_adds (size_t a, size_t b) /* a+b */
3182{
3183 if (a <= (SIZE_MAX - b))
[481]3184 return S_TRUE; /* no overflow */
[34]3185 else
[481]3186 return S_FALSE;
[34]3187}
3188
[20]3189int sl_ok_subi (int a, int b) /* a-b */
3190{
3191 if (a >= 0 && b < 0)
3192 {
3193 if (a <= (INT_MAX + b))
[481]3194 return S_TRUE; /* no overflow */
[20]3195 else
[481]3196 return S_FALSE;
[20]3197 }
3198 else if (a < 0 && b >= 0)
3199 {
3200 if (a >= (INT_MIN + b))
[481]3201 return S_TRUE; /* no overflow */
[20]3202 else
[481]3203 return S_FALSE;
[20]3204 }
[481]3205 return S_TRUE;
[20]3206}
Note: See TracBrowser for help on using the repository browser.