source: trunk/src/slib.c@ 194

Last change on this file since 194 was 192, checked in by katerina, 16 years ago

Fixes for cygwin, and improved error diagnostics (tickets #126, #127, #128).

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