/* * $Id: com-misc.c,v 1.9.2.1 2003/05/07 11:15:05 mt Exp $ * * Common miscellaneous functions * * Author(s): Jens-Gero Boehm * Pieter Hollants * Marius Tomaschewski * Volker Wiegand * * This file is part of the SuSE Proxy Suite * See also http://proxy-suite.suse.de/ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * * A history log can be found at the end of this file. */ #ifndef lint static char rcsid[] = "$Id: com-misc.c,v 1.9.2.1 2003/05/07 11:15:05 mt Exp $"; #endif #include #if defined(STDC_HEADERS) # include # include # include # include # include #endif #include #if defined(HAVE_UNISTD_H) # include #endif #if TIME_WITH_SYS_TIME # include # include #else # if HAVE_SYS_TIME_H # include # else # include # endif #endif #if defined(HAVE_FCNTL_H) # include #elif defined(HAVE_SYS_FCNTL_H) # include #endif #include "com-config.h" #include "com-debug.h" #include "com-misc.h" #include "com-syslog.h" /* ------------------------------------------------------------ */ static void misc_cleanup(void); /* ------------------------------------------------------------ */ static int initflag = 0; /* Have we been initialized? */ static char p_name[512] = "[unknown name]"; static char p_vers[512] = "[unknown version]"; static char p_date[512] = "[unknown date]"; static char **use_ptr = NULL; /* Usage information array */ static char *pid_name = NULL; /* Name of ProcID file */ /* ------------------------------------------------------------ ** ** ** Function......: misc_cleanup ** ** Parameters....: (none) ** ** Return........: (none) ** ** Purpose.......: Clean up at program exit. ** ** ------------------------------------------------------------ */ static void misc_cleanup(void) { if (pid_name != NULL) { void *tmp = (void *) pid_name; unlink(pid_name); pid_name = NULL; misc_free(FL, tmp); } } /* ------------------------------------------------------------ ** ** ** Function......: misc_forget ** ** Parameters....: (none) ** ** Return........: (none) ** ** Purpose.......: Forget cleanup's (for forked children). ** ** ------------------------------------------------------------ */ void misc_forget(void) { if (pid_name != NULL) { void *tmp = (void *) pid_name; pid_name = NULL; misc_free(FL, tmp); } } /* ------------------------------------------------------------ ** ** ** Function......: misc_setprog / misc_getprog ** ** Parameters....: prog_str Program name ** usage_arr Usage info string array ** ** Return........: Program basename ** ** Purpose.......: Makes the prog-name known to logging, ** provides a short name without path. ** ** ------------------------------------------------------------ */ char *misc_setprog(char *prog_str, char *usage_arr[]) { char *p; if (prog_str == NULL) p = "[unknown name]"; else if ((p = strrchr(prog_str, '/')) != NULL) p++; else p = prog_str; misc_strncpy(p_name, p, sizeof(p_name)); if (usage_arr != NULL) use_ptr = usage_arr; return p_name; } char *misc_getprog(void) { return p_name; } /* ------------------------------------------------------------ ** ** ** Function......: misc_setvers / misc_getvers ** misc_setdate / misc_getdate ** misc_getvsdt ** ** Parameters....: version Program version ** ** Return........: Program version ** ** Purpose.......: Sets and retrieves the program version ** and program compilation date and time. ** And a "standard version + date" thing. ** ** ------------------------------------------------------------ */ void misc_setvers(char *vers_str) { if (vers_str == NULL) vers_str = "[unknown version]"; misc_strncpy(p_vers, vers_str, sizeof(p_vers)); } char *misc_getvers(void) { return p_vers; } void misc_setdate(char *date_str) { if (date_str == NULL) date_str = "[unknown date]"; misc_strncpy(p_date, date_str, sizeof(p_date)); } char *misc_getdate(void) { return p_date; } char *misc_getvsdt(void) { static char str[MAX_PATH_SIZE * 2]; #if defined(HAVE_SNPRINTF) snprintf(str, sizeof(str), "Version %s - %s", p_vers, p_date); #else sprintf(str, "Version %s - %s", p_vers, p_date); #endif return str; } /* ------------------------------------------------------------ ** ** ** Function......: misc_alloc ** ** Parameters....: file Filename of requestor ** line Line number of requestor ** len Number of bytes requested ** ** Return........: Pointer to memory ** ** Purpose.......: Allocate memory with malloc. The program ** dies if no memory is available. ** The memory is automatically zero'ed. ** ** ------------------------------------------------------------ */ void *misc_alloc(char *file, int line, size_t len) { void *ptr; if (file == NULL) /* Sanity check */ file = "[unknown file]"; if (len == 0) /* Another check ... */ misc_die(file, line, "misc_alloc: ?len?"); if ((ptr = malloc(len)) == NULL) misc_die(file, line, "out of memory"); #if defined(COMPILE_DEBUG) debug(4, "alloc %u (%.*s:%d): %p", (unsigned) len, MAX_PATH_SIZE, file, line, ptr); #endif memset(ptr, 0, len); return ptr; } /* ------------------------------------------------------------ ** ** ** Function......: misc_strdup ** ** Parameters....: file Filename of requestor ** line Line number of requestor ** str Pointer to original string ** ** Return........: Pointer to allocated string ** ** Purpose.......: Allocate memory for a copy of the given ** string with misc_alloc and copy the ** string in place. ** ** ------------------------------------------------------------ */ char *misc_strdup(char *file, int line, char *str) { char *ptr; int len; /* Basic sanity check */ if (str == NULL) misc_die(file, line, "misc_strdup: ?str?"); len = strlen(str); ptr = (char *) misc_alloc(file, line, len + 1); strncpy(ptr, str, len); return ptr; } /* ------------------------------------------------------------ ** ** ** Function......: misc_free ** ** Parameters....: file Filename of requestor ** line Line number of requestor ** ptr Memory area to be freed ** ** Return........: (none) ** ** Purpose.......: Free memory allocated with misc_alloc. ** ** ------------------------------------------------------------ */ void misc_free(char *file, int line, void *ptr) { if (file == NULL) /* Sanity check */ file = "[unknown file]"; #if defined(COMPILE_DEBUG) debug(4, "free %p (%.*s:%d)", ptr, MAX_PATH_SIZE, file, line); #else line = line; /* Calm down picky compilers... */ #endif if (ptr != NULL) free(ptr); } /* ------------------------------------------------------------ ** ** ** Function......: misc_usage ** ** Parameters....: fmt Printf-string with usage ** ** Return........: (none) ** ** Purpose.......: Print a usage info and terminate. ** ** ------------------------------------------------------------ */ void misc_usage(char *fmt, ...) { va_list aptr; int i; if (use_ptr != NULL) { for (i = 0; use_ptr[i] != NULL; i++) fprintf(stderr, "%s\n", use_ptr[i]); } if (fmt != NULL && *fmt != '\0') { fprintf(stderr, "%s Error: ", p_name); va_start(aptr, fmt); vfprintf(stderr, fmt, aptr); va_end(aptr); fprintf(stderr, "\n\n"); } exit(EXIT_FAILURE); } /* ------------------------------------------------------------ ** ** ** Function......: misc_die ** ** Parameters....: fmt Printf-string with message ** ** Return........: (none) ** ** Purpose.......: Print an error message and terminate. ** ** ------------------------------------------------------------ */ void misc_die(char *file, int line, char *fmt, ...) { int tmperr = errno; /* Save errno for later */ char str[MAX_PATH_SIZE * 4]; va_list aptr; size_t len; if (file == NULL) /* Sanity check */ file = "[unknown file]"; memset(str, 0, sizeof(str)); #if defined(HAVE_SNPRINTF) snprintf(str, sizeof(str), "%s (%.*s:%d): ", p_name, MAX_PATH_SIZE, file, line); #else sprintf(str, "%s (%.*s:%d): ", p_name, MAX_PATH_SIZE, file, line); #endif len = strlen(str); if (fmt != NULL && *fmt != '\0') { va_start(aptr, fmt); #if defined(HAVE_VSNPRINTF) vsnprintf(str + len, sizeof(str)-len, fmt, aptr); #else vsprintf(str + len, fmt, aptr); #endif va_end(aptr); len = strlen(str); } if (tmperr) { #if defined(HAVE_SNPRINTF) snprintf(str + len, sizeof(str)-len, " (errno=%d [%.256s])", tmperr, strerror(tmperr)); #else sprintf(str + len, " (errno=%d [%.256s])", tmperr, strerror(tmperr)); #endif } fprintf(stderr, "%s\n", str); syslog_write(T_FTL, "%s", str); errno = tmperr; /* Restore errno */ exit(EXIT_FAILURE); } /* ------------------------------------------------------------ ** ** ** Function......: misc_pidfile ** ** Parameters....: name Desired PID-file name ** ** Return........: (none) ** ** Purpose.......: Create a file with the Process-ID. ** ** ------------------------------------------------------------ */ void misc_pidfile(char *name) { FILE *fp; int fd; if (initflag == 0) { atexit(misc_cleanup); initflag = 1; } /* ** Do some housekeeping (maybe it's just a close) */ if (misc_strequ(name, pid_name)) return; if (pid_name != NULL) { void *tmp = (void *) pid_name; unlink(pid_name); pid_name = NULL; misc_free(FL, tmp); } /* ** Do we have a real filename now? */ if (name != NULL) { if (unlink(name) < 0 && errno != ENOENT) { syslog_error("can't remove pidfile '%.*s'", MAX_PATH_SIZE, name); exit(EXIT_FAILURE); } if ((fd = open(name, O_RDWR | O_CREAT | O_EXCL, 0644)) < 0) { syslog_error("can't open pidfile '%.*s'", MAX_PATH_SIZE, name); exit(EXIT_FAILURE); } if ((fp = fdopen(fd, "w")) == NULL) { syslog_error("can't open pidfile '%.*s'", MAX_PATH_SIZE, name); exit(EXIT_FAILURE); } fprintf(fp, "%d\n", (int) getpid()); fclose(fp); pid_name = misc_strdup(FL, name); } #if defined(COMPILE_DEBUG) debug(2, "pid-file: '%s'", NIL(pid_name)); #endif } /* ------------------------------------------------------------ ** ** ** Function......: misc_strtrim ** ** Parameters....: s String to be trimmed ** ** Return........: String without leading or trailing space ** ** Purpose.......: Trims white space at the beginning and end ** of a given string (this is done in-place). ** ** ------------------------------------------------------------ */ char *misc_strtrim(char *s) { char *p; if (s == NULL) return NULL; while (*s == ' ' || *s == '\t') s++; p = s + strlen(s); while (p > s && (p[-1] == ' ' || p[-1] == '\t' || p[-1] == '\n' || p[-1] == '\r')) *--p = '\0'; return s; } /* ------------------------------------------------------------ ** ** ** Function......: misc_strequ / misc_strcaseequ ** ** Parameters....: s1 First string to compare ** s2 Second string to compare ** ** Return........: 1=strings are equal, 0=strings differ ** ** Purpose.......: Check if two strings are equal. The ** strings could well be NULL pointers. ** And strcasecmp ignores upper/lower case. ** ** ------------------------------------------------------------ */ int misc_strequ(const char *s1, const char *s2) { if (s1 == NULL && s2 == NULL) return 1; if (s1 == NULL && s2 != NULL) return 0; if (s1 != NULL && s2 == NULL) return 0; return (strcmp(s1, s2) == 0); } int misc_strcaseequ(const char *s1, const char *s2) { if (s1 == NULL && s2 == NULL) return 1; if (s1 == NULL && s2 != NULL) return 0; if (s1 != NULL && s2 == NULL) return 0; return (strcasecmp(s1, s2) == 0); } /* ------------------------------------------------------------ ** ** ** Function......: misc_strnequ / misc_strncaseequ ** ** Parameters....: s1 First string to compare ** s2 Second string to compare ** n number of characters in ** in s1 to compare ** ** Return........: 1=strings are equal, 0=strings differ ** ** Purpose.......: Check if two strings are equal. The ** strings could well be NULL pointers. ** strncasecmp ignores upper/lower case. ** ** ------------------------------------------------------------ */ int misc_strnequ(const char *s1, const char *s2, size_t n) { if (s1 == NULL && s2 == NULL) return 1; if (s1 == NULL && s2 != NULL) return 0; if (s1 != NULL && s2 == NULL) return 0; return (strncmp(s1, s2, n) == 0); } int misc_strncaseequ(const char *s1, const char *s2, size_t n) { if (s1 == NULL && s2 == NULL) return 1; if (s1 == NULL && s2 != NULL) return 0; if (s1 != NULL && s2 == NULL) return 0; return (strncasecmp(s1, s2, n) == 0); } /* ------------------------------------------------------------ ** ** ** Function......: misc_strncpy ** ** Parameters....: s1 Destination pointer ** s2 Source pointer ** len Size of Destination buffer ** ** Return........: Destination pointer ** ** Purpose.......: Copies at most (len - 1) bytes from source ** to destination and fills the residual space ** of the destination buffer with null bytes. ** ** ------------------------------------------------------------ */ char *misc_strncpy(char *s1, const char *s2, size_t len) { size_t cnt; /* ** Prepare the destination buffer */ if (s1 == NULL) return NULL; memset(s1, 0, len); /* ** Check the source and get its size */ if (s2 == NULL || (cnt = strlen(s2)) == 0) return s1; /* ** Copy at most (len - 1) bytes */ if (cnt >= len) cnt = len - 1; memcpy(s1, s2, cnt); /* ** Done -- return destination pointer */ return s1; } /* ------------------------------------------------------------ ** ** ** Function......: misc_chroot ** ** Parameters....: dir chroot directory ** ** Return........: 0 on success, -1 if dir argument ** was emtpy; exits program on error ** ** Purpose.......: change root into specified directory ** ** ------------------------------------------------------------ */ int misc_chroot (char *dir) { if(dir && *dir) { chdir("/"); if (chroot(dir)) { syslog_error("can't chroot to '%.1024s'", dir); exit(EXIT_FAILURE); } chdir("/"); return 0; } return -1; } /* ------------------------------------------------------------ ** ** ** Function......: misc_uidgid ** ** Parameters....: uid UID (-1 -> use config_uid) ** gid GID (-1 -> use config_gid) ** ** Return........: (none), exits program on error ** ** Purpose.......: Set the UID and GID for the current process. ** If the parameters are -1, use the config ** file's "User" and "Group" variables. ** ** ------------------------------------------------------------ */ void misc_uidgid(uid_t uid, gid_t gid) { #if defined(COMPILE_DEBUG) debug(2, "uid-gid desired: uid=%d gid=%d", (int) uid, (int) gid); #endif if (gid == CONFIG_GID) { if(config_str(NULL, "Group", NULL)) { /* ** if config defines a group, use it ** or complain (not found in system) */ gid = config_gid(NULL, "Group", CONFIG_GID); } else { gid = getgid(); } } if (gid == CONFIG_GID) { syslog_error("can't determine Group-ID to use"); exit(EXIT_FAILURE); } if (setgid(gid) < 0) { syslog_error("can't set Group-ID to %d", (int) gid); exit(EXIT_FAILURE); } if (getegid() != gid) { syslog_error("can't set Group-ID to %d", (int) gid); exit(EXIT_FAILURE); } if (uid == CONFIG_UID) { if(config_str(NULL, "User", NULL)) { /* ** if config defines a user, use it ** or complain (not found in system) */ uid = config_uid(NULL, "User", CONFIG_UID); } else { uid = getuid(); } } if (uid == CONFIG_UID) { syslog_error("can't determine User-ID to use"); exit(EXIT_FAILURE); } if (setuid(uid) < 0) { syslog_error("can't set User-ID to %d", (int) uid); exit(EXIT_FAILURE); } if (geteuid() != uid) { syslog_error("can't set User-ID to %d", (int) uid); exit(EXIT_FAILURE); } #if defined(COMPILE_DEBUG) debug(2, "uid-gid adopted: uid=%d gid=%d", (int) getuid(), (int) getgid()); #endif } /* ------------------------------------------------------------ ** ** ** Function......: misc_rand ** ** Parameters....: lower range mark ** upper range mark ** ** Return........: random number between lower and upper mark ** ** Purpose.......: generates a random number in specified range. ** ** ------------------------------------------------------------ */ int misc_rand (int lrng, int urng) { struct timeval t; if (lrng == urng) return lrng; if (lrng > urng) { /* swap values */ lrng ^= urng; urng ^= lrng; lrng ^= urng; } gettimeofday (&t, NULL); srand (t.tv_usec); return (lrng + (rand () % (urng - lrng + 1))); } /* ------------------------------------------------------------ * $Log: com-misc.c,v $ * Revision 1.9.2.1 2003/05/07 11:15:05 mt * misc_strdup: changed to allow empty strings * misc_rand: removed sequence in lrng/urng swapping * * Revision 1.9 2002/05/02 12:59:00 mt * merged with v1.8.2.2 * * Revision 1.8.2.1 2002/01/28 01:53:07 mt * implemented misc_strnequ misc_strncaseequ wrappers * * Revision 1.8 2002/01/14 18:18:50 mt * implemented misc_chroot wrapper function * added checks in misc_uidgid if User/Group are set in config * added snprintf usage if supported, replaced all strcpy with strncpy * * Revision 1.7 2001/11/06 23:04:43 mt * applied / merged with transparent proxy patches v8 * see ftp-proxy/NEWS for more detailed release news * * Revision 1.6 1999/09/30 09:49:45 wiegand * updated string trim function to trim also newlines * * Revision 1.5 1999/09/26 13:25:05 wiegand * protection of debug/pid/log files against attacks * * Revision 1.4 1999/09/21 05:42:28 wiegand * syslog / abort review * * Revision 1.3 1999/09/17 06:32:28 wiegand * buffer length and overflow protection review * * Revision 1.2 1999/09/16 14:26:33 wiegand * minor code review and cleanup * * Revision 1.1 1999/09/15 14:05:38 wiegand * initial checkin * * ------------------------------------------------------------ */