1/*
2  This software is available to you under a choice of one of two
3  licenses.  You may choose to be licensed under the terms of the GNU
4  General Public License (GPL) Version 2, available at
5  <http://www.fsf.org/copyleft/gpl.html>, or the OpenIB.org BSD
6  license, available in the LICENSE.TXT file accompanying this
7  software.  These details are also available at
8  <http://openib.org/license.html>.
9
10  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
11  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
13  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
14  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
15  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
16  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
17  SOFTWARE.
18
19  Copyright (c) 2004 Topspin Communications.  All rights reserved.
20  Copyright (c) 2006 Mellanox Technologies Ltd. All rights reserved.
21
22  $Id$
23*/
24
25/*
26 * system includes
27 */
28#if HAVE_CONFIG_H
29#  include <config.h>
30#endif /* HAVE_CONFIG_H */
31#include <unistd.h>
32#include <sys/types.h>
33#include <sys/stat.h>
34#include <errno.h>
35#include <stdio.h>
36#include <stdlib.h>
37#include <stdarg.h>
38#include <string.h>
39#include <syslog.h>
40#include <time.h>
41#include <limits.h>
42
43/*
44 * SDP specific includes
45 */
46#include "libsdp.h"
47
48extern char *program_invocation_short_name;
49
50typedef enum
51{
52	SDP_LOG_FILE,
53	SDP_LOG_SYSLOG,
54} __sdp_log_type_t;
55
56/* --------------------------------------------------------------------- */
57/* library static and global variables                                   */
58/* --------------------------------------------------------------------- */
59int __sdp_min_level = 9;
60static __sdp_log_type_t __sdp_log_type = SDP_LOG_FILE;
61static FILE *__sdp_log_file = NULL;
62
63void
64__sdp_log(
65	int level,
66	char *format,
67	... )
68{
69	va_list ap;
70	char extra_format[512];
71	time_t timeval;
72	char timestr[32];
73
74	if ( level < __sdp_min_level ) {
75		return;
76	}
77
78	va_start( ap, format );
79	switch ( __sdp_log_type ) {
80	case SDP_LOG_SYSLOG:
81		sprintf( extra_format, "%s[%d] libsdp %s ",
82					program_invocation_short_name, getpid(  ), format );
83		vsyslog( LOG_USER | LOG_NOTICE, extra_format, ap );
84		break;
85	case SDP_LOG_FILE:
86		timeval = time(NULL);
87#ifdef SOLARIS_BUILD
88		ctime_r(&timeval, timestr, sizeof timestr);
89#else
90                ctime_r(&timeval, timestr);
91#endif
92		timestr[strlen(timestr)-1] = '\0';
93		sprintf( extra_format, "%s %s[%d] libsdp %s ",
94					timestr, program_invocation_short_name,
95					getpid(  ), format );
96		if ( __sdp_log_file == NULL ) {
97			vfprintf( stderr, extra_format, ap );
98#if 0									  /* might slow everything too much? */
99			( void )fflush( stderr );
100#endif
101		} else {
102			vfprintf( __sdp_log_file, extra_format, ap );
103#if 0									  /* might slow everything too much? */
104			( void )fflush( __sdp_log_file );
105#endif
106		}
107		break;
108	}
109	va_end( ap );
110}
111
112int
113__sdp_log_get_level(
114	void )
115{
116	return ( __sdp_min_level );
117}
118
119void
120__sdp_log_set_min_level(
121	int level )
122{
123	__sdp_min_level = level;
124}
125
126static void
127__sdp_log_set_log_type(
128	__sdp_log_type_t type )
129{
130	if ( __sdp_log_file != NULL ) {
131		fclose( __sdp_log_file );
132		__sdp_log_file = NULL;
133	}
134
135	__sdp_log_type = type;
136}
137
138int
139__sdp_log_set_log_stderr(
140	void )
141{
142	__sdp_log_set_log_type( SDP_LOG_FILE );
143	/* NULL means stderr */
144
145	return 1;
146}
147
148int
149__sdp_log_set_log_syslog(
150	void )
151{
152	__sdp_log_set_log_type( SDP_LOG_SYSLOG );
153
154	return 1;
155}
156
157int
158__sdp_log_set_log_file(
159	char *filename )
160{
161	FILE *f;
162	uid_t uid;
163	struct stat lstat_res;
164	int status;
165
166	char *p, tfilename[PATH_MAX + 1];
167
168	/* Strip off any paths from the filename */
169	p = strrchr( filename, '/' );
170
171	/*
172		base on the active user ID we either use /var/log for root or
173		append the uid to the name
174	*/
175	uid = geteuid();
176	if (uid == 0) {
177		if ( p )
178			filename = p + 1;
179		snprintf( tfilename, sizeof(tfilename), "/var/log/%s", filename );
180	} else {
181		char tdir[PATH_MAX + 1];
182		/*
183			for regular user, allow log file to be placed in a user
184			requested path. If no path is requested the log file is
185			placed in /tmp/
186		*/
187		if ( p )
188			snprintf(tdir, sizeof(tdir), "%s.%d", filename, uid );
189		else
190			snprintf(tdir, sizeof(tdir ), "/tmp/%s.%d", filename, uid );
191
192		if (mkdir(tdir, 0700)) {
193			struct stat stat;
194
195			if (errno != EEXIST) {
196				__sdp_log( 9, "Couldn't create directory '%s' for logging (%m)\n", tdir );
197				return 0;
198			}
199
200			if (lstat(tdir, &stat)) {
201				__sdp_log(9, "Couldn't lstat directory %s\n", tdir);
202				return 0;
203			}
204
205			if (!S_ISDIR(stat.st_mode) || stat.st_uid != uid ||
206					(stat.st_mode & ~(S_IFMT | S_IRWXU))) {
207				__sdp_log( 9, "Cowardly refusing to log into directory:'%s'. "
208					  "Make sure it is not: (1) link, (2) other uid, (3) bad permissions."
209					  "thus is a security issue.\n", tdir );
210				return 0;
211			}
212		}
213
214		snprintf(tfilename, sizeof(tfilename), "%s/log", tdir);
215		printf("dir: %s file: %s\n", tdir, tfilename);
216	}
217
218	/* double check the file is not a link */
219	status = lstat(tfilename, &lstat_res);
220	if ( (status == 0) && S_ISLNK(lstat_res.st_mode) ) {
221		__sdp_log( 9, "Cowardly refusing to log into:'%s'. "
222					  "It is a link - thus is a security issue.\n", tfilename );
223		return 0;
224	}
225
226	f = fopen( tfilename, "a" );
227	if ( !f ) {
228		__sdp_log( 9, "Couldn't open '%s' for logging (%m)\n", tfilename );
229		return 0;
230	}
231
232	__sdp_log_set_log_type( SDP_LOG_FILE );
233	__sdp_log_file = f;
234
235	return 1;
236}
237