1219820Sjeff/*
2219820Sjeff  This software is available to you under a choice of one of two
3219820Sjeff  licenses.  You may choose to be licensed under the terms of the GNU
4219820Sjeff  General Public License (GPL) Version 2, available at
5219820Sjeff  <http://www.fsf.org/copyleft/gpl.html>, or the OpenIB.org BSD
6219820Sjeff  license, available in the LICENSE.TXT file accompanying this
7219820Sjeff  software.  These details are also available at
8219820Sjeff  <http://openib.org/license.html>.
9219820Sjeff
10219820Sjeff  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
11219820Sjeff  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12219820Sjeff  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
13219820Sjeff  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
14219820Sjeff  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
15219820Sjeff  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
16219820Sjeff  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
17219820Sjeff  SOFTWARE.
18219820Sjeff
19219820Sjeff  Copyright (c) 2004 Topspin Communications.  All rights reserved.
20219820Sjeff  Copyright (c) 2006 Mellanox Technologies Ltd. All rights reserved.
21219820Sjeff
22219820Sjeff  $Id$
23219820Sjeff*/
24219820Sjeff
25219820Sjeff/*
26219820Sjeff * system includes
27219820Sjeff */
28219820Sjeff#if HAVE_CONFIG_H
29219820Sjeff#  include <config.h>
30219820Sjeff#endif /* HAVE_CONFIG_H */
31219820Sjeff#include <unistd.h>
32219820Sjeff#include <sys/types.h>
33219820Sjeff#include <sys/stat.h>
34219820Sjeff#include <errno.h>
35219820Sjeff#include <stdio.h>
36219820Sjeff#include <stdlib.h>
37219820Sjeff#include <stdarg.h>
38219820Sjeff#include <string.h>
39219820Sjeff#include <syslog.h>
40219820Sjeff#include <time.h>
41219820Sjeff#include <limits.h>
42219820Sjeff
43219820Sjeff/*
44219820Sjeff * SDP specific includes
45219820Sjeff */
46219820Sjeff#include "libsdp.h"
47219820Sjeff
48219820Sjeffextern char *program_invocation_short_name;
49219820Sjeff
50219820Sjefftypedef enum
51219820Sjeff{
52219820Sjeff	SDP_LOG_FILE,
53219820Sjeff	SDP_LOG_SYSLOG,
54219820Sjeff} __sdp_log_type_t;
55219820Sjeff
56219820Sjeff/* --------------------------------------------------------------------- */
57219820Sjeff/* library static and global variables                                   */
58219820Sjeff/* --------------------------------------------------------------------- */
59219820Sjeffint __sdp_min_level = 9;
60219820Sjeffstatic __sdp_log_type_t __sdp_log_type = SDP_LOG_FILE;
61219820Sjeffstatic FILE *__sdp_log_file = NULL;
62219820Sjeff
63219820Sjeffvoid
64219820Sjeff__sdp_log(
65219820Sjeff	int level,
66219820Sjeff	char *format,
67219820Sjeff	... )
68219820Sjeff{
69219820Sjeff	va_list ap;
70219820Sjeff	char extra_format[512];
71219820Sjeff	time_t timeval;
72219820Sjeff	char timestr[32];
73219820Sjeff
74219820Sjeff	if ( level < __sdp_min_level ) {
75219820Sjeff		return;
76219820Sjeff	}
77219820Sjeff
78219820Sjeff	va_start( ap, format );
79219820Sjeff	switch ( __sdp_log_type ) {
80219820Sjeff	case SDP_LOG_SYSLOG:
81219820Sjeff		sprintf( extra_format, "%s[%d] libsdp %s ",
82219820Sjeff					program_invocation_short_name, getpid(  ), format );
83219820Sjeff		vsyslog( LOG_USER | LOG_NOTICE, extra_format, ap );
84219820Sjeff		break;
85219820Sjeff	case SDP_LOG_FILE:
86219820Sjeff		timeval = time(NULL);
87219820Sjeff#ifdef SOLARIS_BUILD
88219820Sjeff		ctime_r(&timeval, timestr, sizeof timestr);
89219820Sjeff#else
90219820Sjeff                ctime_r(&timeval, timestr);
91219820Sjeff#endif
92219820Sjeff		timestr[strlen(timestr)-1] = '\0';
93219820Sjeff		sprintf( extra_format, "%s %s[%d] libsdp %s ",
94219820Sjeff					timestr, program_invocation_short_name,
95219820Sjeff					getpid(  ), format );
96219820Sjeff		if ( __sdp_log_file == NULL ) {
97219820Sjeff			vfprintf( stderr, extra_format, ap );
98219820Sjeff#if 0									  /* might slow everything too much? */
99219820Sjeff			( void )fflush( stderr );
100219820Sjeff#endif
101219820Sjeff		} else {
102219820Sjeff			vfprintf( __sdp_log_file, extra_format, ap );
103219820Sjeff#if 0									  /* might slow everything too much? */
104219820Sjeff			( void )fflush( __sdp_log_file );
105219820Sjeff#endif
106219820Sjeff		}
107219820Sjeff		break;
108219820Sjeff	}
109219820Sjeff	va_end( ap );
110219820Sjeff}
111219820Sjeff
112219820Sjeffint
113219820Sjeff__sdp_log_get_level(
114219820Sjeff	void )
115219820Sjeff{
116219820Sjeff	return ( __sdp_min_level );
117219820Sjeff}
118219820Sjeff
119219820Sjeffvoid
120219820Sjeff__sdp_log_set_min_level(
121219820Sjeff	int level )
122219820Sjeff{
123219820Sjeff	__sdp_min_level = level;
124219820Sjeff}
125219820Sjeff
126219820Sjeffstatic void
127219820Sjeff__sdp_log_set_log_type(
128219820Sjeff	__sdp_log_type_t type )
129219820Sjeff{
130219820Sjeff	if ( __sdp_log_file != NULL ) {
131219820Sjeff		fclose( __sdp_log_file );
132219820Sjeff		__sdp_log_file = NULL;
133219820Sjeff	}
134219820Sjeff
135219820Sjeff	__sdp_log_type = type;
136219820Sjeff}
137219820Sjeff
138219820Sjeffint
139219820Sjeff__sdp_log_set_log_stderr(
140219820Sjeff	void )
141219820Sjeff{
142219820Sjeff	__sdp_log_set_log_type( SDP_LOG_FILE );
143219820Sjeff	/* NULL means stderr */
144219820Sjeff
145219820Sjeff	return 1;
146219820Sjeff}
147219820Sjeff
148219820Sjeffint
149219820Sjeff__sdp_log_set_log_syslog(
150219820Sjeff	void )
151219820Sjeff{
152219820Sjeff	__sdp_log_set_log_type( SDP_LOG_SYSLOG );
153219820Sjeff
154219820Sjeff	return 1;
155219820Sjeff}
156219820Sjeff
157219820Sjeffint
158219820Sjeff__sdp_log_set_log_file(
159219820Sjeff	char *filename )
160219820Sjeff{
161219820Sjeff	FILE *f;
162219820Sjeff	uid_t uid;
163219820Sjeff	struct stat lstat_res;
164219820Sjeff	int status;
165219820Sjeff
166219820Sjeff	char *p, tfilename[PATH_MAX + 1];
167219820Sjeff
168219820Sjeff	/* Strip off any paths from the filename */
169219820Sjeff	p = strrchr( filename, '/' );
170219820Sjeff
171219820Sjeff	/*
172219820Sjeff		base on the active user ID we either use /var/log for root or
173219820Sjeff		append the uid to the name
174219820Sjeff	*/
175219820Sjeff	uid = geteuid();
176219820Sjeff	if (uid == 0) {
177219820Sjeff		if ( p )
178219820Sjeff			filename = p + 1;
179219820Sjeff		snprintf( tfilename, sizeof(tfilename), "/var/log/%s", filename );
180219820Sjeff	} else {
181219820Sjeff		char tdir[PATH_MAX + 1];
182219820Sjeff		/*
183219820Sjeff			for regular user, allow log file to be placed in a user
184219820Sjeff			requested path. If no path is requested the log file is
185219820Sjeff			placed in /tmp/
186219820Sjeff		*/
187219820Sjeff		if ( p )
188219820Sjeff			snprintf(tdir, sizeof(tdir), "%s.%d", filename, uid );
189219820Sjeff		else
190219820Sjeff			snprintf(tdir, sizeof(tdir ), "/tmp/%s.%d", filename, uid );
191219820Sjeff
192219820Sjeff		if (mkdir(tdir, 0700)) {
193219820Sjeff			struct stat stat;
194219820Sjeff
195219820Sjeff			if (errno != EEXIST) {
196219820Sjeff				__sdp_log( 9, "Couldn't create directory '%s' for logging (%m)\n", tdir );
197219820Sjeff				return 0;
198219820Sjeff			}
199219820Sjeff
200219820Sjeff			if (lstat(tdir, &stat)) {
201219820Sjeff				__sdp_log(9, "Couldn't lstat directory %s\n", tdir);
202219820Sjeff				return 0;
203219820Sjeff			}
204219820Sjeff
205219820Sjeff			if (!S_ISDIR(stat.st_mode) || stat.st_uid != uid ||
206219820Sjeff					(stat.st_mode & ~(S_IFMT | S_IRWXU))) {
207219820Sjeff				__sdp_log( 9, "Cowardly refusing to log into directory:'%s'. "
208219820Sjeff					  "Make sure it is not: (1) link, (2) other uid, (3) bad permissions."
209219820Sjeff					  "thus is a security issue.\n", tdir );
210219820Sjeff				return 0;
211219820Sjeff			}
212219820Sjeff		}
213219820Sjeff
214219820Sjeff		snprintf(tfilename, sizeof(tfilename), "%s/log", tdir);
215219820Sjeff		printf("dir: %s file: %s\n", tdir, tfilename);
216219820Sjeff	}
217219820Sjeff
218219820Sjeff	/* double check the file is not a link */
219219820Sjeff	status = lstat(tfilename, &lstat_res);
220219820Sjeff	if ( (status == 0) && S_ISLNK(lstat_res.st_mode) ) {
221219820Sjeff		__sdp_log( 9, "Cowardly refusing to log into:'%s'. "
222219820Sjeff					  "It is a link - thus is a security issue.\n", tfilename );
223219820Sjeff		return 0;
224219820Sjeff	}
225219820Sjeff
226219820Sjeff	f = fopen( tfilename, "a" );
227219820Sjeff	if ( !f ) {
228219820Sjeff		__sdp_log( 9, "Couldn't open '%s' for logging (%m)\n", tfilename );
229219820Sjeff		return 0;
230219820Sjeff	}
231219820Sjeff
232219820Sjeff	__sdp_log_set_log_type( SDP_LOG_FILE );
233219820Sjeff	__sdp_log_file = f;
234219820Sjeff
235219820Sjeff	return 1;
236219820Sjeff}
237