~ubuntu-branches/ubuntu/lucid/rsyslog/lucid-updates

1 by Michael Biebl
Import upstream version 1.19.10
1
/* omusrmsg.c
2
 * This is the implementation of the build-in output module for sending
3
 * user messages.
4
 *
5
 * NOTE: read comments in module-template.h to understand how this file
6
 *       works!
7
 *
8
 * File begun on 2007-07-20 by RGerhards (extracted from syslogd.c)
9
 * This file is under development and has not yet arrived at being fully
10
 * self-contained and a real object. So far, it is mostly an excerpt
11
 * of the "old" message code without any modifications. However, it
12
 * helps to have things at the right place one we go to the meat of it.
13
 *
14
 * Copyright 2007 Rainer Gerhards and Adiscon GmbH.
15
 *
1.1.2 by Michael Biebl
Import upstream version 3.14.2
16
 * This file is part of rsyslog.
17
 *
18
 * Rsyslog is free software: you can redistribute it and/or modify
19
 * it under the terms of the GNU General Public License as published by
20
 * the Free Software Foundation, either version 3 of the License, or
21
 * (at your option) any later version.
22
 *
23
 * Rsyslog is distributed in the hope that it will be useful,
1 by Michael Biebl
Import upstream version 1.19.10
24
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26
 * GNU General Public License for more details.
27
 *
28
 * You should have received a copy of the GNU General Public License
1.1.2 by Michael Biebl
Import upstream version 3.14.2
29
 * along with Rsyslog.  If not, see <http://www.gnu.org/licenses/>.
1 by Michael Biebl
Import upstream version 1.19.10
30
 *
31
 * A copy of the GPL can be found in the file "COPYING" in this distribution.
32
 */
33
#include "config.h"
34
#include "rsyslog.h"
35
#include <stdio.h>
36
#include <stdarg.h>
37
#include <stdlib.h>
38
#include <string.h>
39
#include <assert.h>
40
#include <signal.h>
41
#include <sys/param.h>
42
#include <utmp.h>
43
#include <unistd.h>
44
#include <sys/uio.h>
45
#include <sys/stat.h>
46
#include <setjmp.h>
47
#if HAVE_FCNTL_H
48
#include <fcntl.h>
49
#else
50
#include <sys/msgbuf.h>
51
#endif
1.1.2 by Michael Biebl
Import upstream version 3.14.2
52
#if HAVE_PATHS_H
53
#include <paths.h>
54
#endif
1 by Michael Biebl
Import upstream version 1.19.10
55
#include "srUtils.h"
56
#include "stringbuf.h"
57
#include "syslogd-types.h"
58
#include "syslogd.h"
59
#include "omusrmsg.h"
60
#include "module-template.h"
1.1.2 by Michael Biebl
Import upstream version 3.14.2
61
#include "errmsg.h"
62
63
64
/* portability: */
65
#ifndef _PATH_DEV
66
#	define _PATH_DEV	"/dev/"
67
#endif
68
69
70
MODULE_TYPE_OUTPUT
1 by Michael Biebl
Import upstream version 1.19.10
71
72
/* internal structures
73
 */
74
DEF_OMOD_STATIC_DATA
1.1.2 by Michael Biebl
Import upstream version 3.14.2
75
DEFobjCurrIf(errmsg)
1 by Michael Biebl
Import upstream version 1.19.10
76
77
typedef struct _instanceData {
78
	int bIsWall; /* 1- is wall, 0 - individual users */
79
	char uname[MAXUNAMES][UNAMESZ+1];
80
} instanceData;
81
82
83
BEGINcreateInstance
84
CODESTARTcreateInstance
85
ENDcreateInstance
86
87
88
BEGINisCompatibleWithFeature
89
CODESTARTisCompatibleWithFeature
90
	if(eFeat == sFEATURERepeatedMsgReduction)
91
		iRet = RS_RET_OK;
92
ENDisCompatibleWithFeature
93
94
95
BEGINfreeInstance
96
CODESTARTfreeInstance
97
	/* TODO: free the instance pointer (currently a leak, will go away) */
98
ENDfreeInstance
99
100
101
BEGINdbgPrintInstInfo
102
	register int i;
103
CODESTARTdbgPrintInstInfo
104
	for (i = 0; i < MAXUNAMES && *pData->uname[i]; i++)
1.1.2 by Michael Biebl
Import upstream version 3.14.2
105
		dbgprintf("%s, ", pData->uname[i]);
1 by Michael Biebl
Import upstream version 1.19.10
106
ENDdbgPrintInstInfo
107
108
109
static jmp_buf ttybuf;
110
111
static void endtty()
112
{
113
	longjmp(ttybuf, 1);
114
}
115
116
/**
117
 * BSD setutent/getutent() replacement routines
118
 * The following routines emulate setutent() and getutent() under
119
 * BSD because they are not available there. We only emulate what we actually
120
 * need! rgerhards 2005-03-18
121
 */
1.1.5 by Michael Biebl
Import upstream version 3.18.1
122
#ifdef OS_BSD
1 by Michael Biebl
Import upstream version 1.19.10
123
static FILE *BSD_uf = NULL;
124
void setutent(void)
125
{
126
	assert(BSD_uf == NULL);
127
	if ((BSD_uf = fopen(_PATH_UTMP, "r")) == NULL) {
1.1.2 by Michael Biebl
Import upstream version 3.14.2
128
		errmsg.LogError(NO_ERRCODE, "%s", _PATH_UTMP);
1 by Michael Biebl
Import upstream version 1.19.10
129
		return;
130
	}
131
}
132
133
struct utmp* getutent(void)
134
{
135
	static struct utmp st_utmp;
136
137
	if(fread((char *)&st_utmp, sizeof(st_utmp), 1, BSD_uf) != 1)
138
		return NULL;
139
140
	return(&st_utmp);
141
}
142
143
void endutent(void)
144
{
145
	fclose(BSD_uf);
146
	BSD_uf = NULL;
147
}
1.1.5 by Michael Biebl
Import upstream version 3.18.1
148
#endif  /* #ifdef OS_BSD */
1 by Michael Biebl
Import upstream version 1.19.10
149
150
151
/*
152
 *  WALLMSG -- Write a message to the world at large
153
 *
154
 *	Write the specified message to either the entire
155
 *	world, or a list of approved users.
156
 *
157
 * rgerhards, 2005-10-19: applying the following sysklogd patch:
158
 * Tue May  4 16:52:01 CEST 2004: Solar Designer <solar@openwall.com>
159
 *	Adjust the size of a variable to prevent a buffer overflow
160
 *	should _PATH_DEV ever contain something different than "/dev/".
161
 */
162
static rsRetVal wallmsg(uchar* pMsg, instanceData *pData)
163
{
164
  
165
	char p[sizeof(_PATH_DEV) + UNAMESZ];
166
	register int i;
167
	int ttyf;
168
	static int reenter = 0;
169
	struct utmp ut;
170
	struct utmp *uptr;
171
	struct sigaction sigAct;
172
173
	assert(pMsg != NULL);
174
175
	if (reenter++)
176
		return RS_RET_OK;
177
178
	/* open the user login file */
179
	setutent();
180
181
	/*
182
	 * Might as well fork instead of using nonblocking I/O
183
	 * and doing notty().
184
	 */
185
	if (fork() == 0) {
186
		memset(&sigAct, 0, sizeof(sigAct));
187
		sigemptyset(&sigAct.sa_mask);
188
		sigAct.sa_handler = SIG_DFL;
189
		sigaction(SIGTERM, &sigAct, NULL);
190
		alarm(0);
191
192
#		ifdef		SIGTTOU
193
		sigAct.sa_handler = SIG_DFL;
194
		sigaction(SIGTERM, &sigAct, NULL);
195
#		endif
196
		/* It is save to call sigprocmask here, as we are now executing the child (no threads) */
197
		sigprocmask(SIG_SETMASK, &sigAct.sa_mask, NULL);
198
	/* TODO: find a way to limit the max size of the message. hint: this
199
	 * should go into the template!
200
	 */
201
	
202
	/* rgerhards 2005-10-24: HINT: this code might be run in a seperate thread
203
	 * instead of a seperate process once we have multithreading...
204
	 */
205
206
		/* scan the user login file */
207
		while ((uptr = getutent())) {
208
			memcpy(&ut, uptr, sizeof(ut));
209
			/* is this slot used? */
210
			if (ut.ut_name[0] == '\0')
211
				continue;
1.1.5 by Michael Biebl
Import upstream version 3.18.1
212
#ifndef OS_BSD
1 by Michael Biebl
Import upstream version 1.19.10
213
			if (ut.ut_type != USER_PROCESS)
214
			        continue;
215
#endif
216
			if (!(strncmp (ut.ut_name,"LOGIN", 6))) /* paranoia */
217
			        continue;
218
219
			/* should we send the message to this user? */
220
			if (pData->bIsWall == 0) {
221
				for (i = 0; i < MAXUNAMES; i++) {
222
					if (!pData->uname[i][0]) {
223
						i = MAXUNAMES;
224
						break;
225
					}
226
					if (strncmp(pData->uname[i],
227
					    ut.ut_name, UNAMESZ) == 0)
228
						break;
229
				}
230
				if (i >= MAXUNAMES)
231
					continue;
232
			}
233
234
			/* compute the device name */
235
			strcpy(p, _PATH_DEV);
236
			strncat(p, ut.ut_line, UNAMESZ);
237
238
			if (setjmp(ttybuf) == 0) {
239
				sigAct.sa_handler = endtty;
240
				sigaction(SIGALRM, &sigAct, NULL);
241
				(void) alarm(15);
242
				/* open the terminal */
243
				ttyf = open(p, O_WRONLY|O_NOCTTY);
244
				if (ttyf >= 0) {
245
					struct stat statb;
246
247
					if (fstat(ttyf, &statb) == 0 &&
248
					    (statb.st_mode & S_IWRITE)) {
249
						(void) write(ttyf, pMsg, strlen((char*)pMsg));
250
					}
251
					close(ttyf);
252
					ttyf = -1;
253
				}
254
			}
255
			(void) alarm(0);
256
		}
257
		exit(0); /* "good" exit - this terminates the child forked just for message delivery */
258
	}
259
	/* close the user login file */
260
	endutent();
261
	reenter = 0;
262
	return RS_RET_OK;
263
}
264
265
266
BEGINtryResume
267
CODESTARTtryResume
268
ENDtryResume
269
270
BEGINdoAction
271
CODESTARTdoAction
272
	dbgprintf("\n");
273
	iRet = wallmsg(ppString[0], pData);
274
ENDdoAction
275
276
277
BEGINparseSelectorAct
278
	uchar *q;
279
	int i;
280
CODESTARTparseSelectorAct
281
CODE_STD_STRING_REQUESTparseSelectorAct(1)
282
283
       /* User names must begin with a gnu e-regex:
284
        *   [a-zA-Z0-9_.]
285
	* plus '*' for wall
286
        */
287
       if (!*p || !((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z')
288
                    || (*p >= '0' && *p <= '9') || *p == '_' || *p == '.' || *p == '*'))
289
	       ABORT_FINALIZE(RS_RET_CONFLINE_UNPROCESSED);
290
291
	if((iRet = createInstance(&pData)) != RS_RET_OK)
292
		goto finalize_it;
293
294
295
	if(*p == '*') { /* wall */
296
		dbgprintf("write-all");
297
		++p; /* eat '*' */
298
		pData->bIsWall = 1; /* write to all users */
299
		if((iRet = cflineParseTemplateName(&p, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS, (uchar*) " WallFmt"))
300
		    != RS_RET_OK)
301
			goto finalize_it;
302
	} else {
303
                /* everything else beginning with the regex above
304
                 * is currently treated as a user name
305
                 * TODO: is this portable?
306
		 */
307
		dbgprintf("users: %s\n", p);	/* ASP */
308
		pData->bIsWall = 0; /* write to individual users */
309
		for (i = 0; i < MAXUNAMES && *p && *p != ';'; i++) {
310
			for (q = p; *q && *q != ',' && *q != ';'; )
311
				q++;
312
			(void) strncpy((char*) pData->uname[i], (char*) p, UNAMESZ);
313
			if ((q - p) > UNAMESZ)
314
				pData->uname[i][UNAMESZ] = '\0';
315
			else
316
				pData->uname[i][q - p] = '\0';
317
			while (*q == ',' || *q == ' ')
318
				q++;
319
			p = q;
320
		}
321
		/* done, on to the template
322
		 * TODO: we need to handle the case where i >= MAXUNAME!
323
		 */
324
		if((iRet = cflineParseTemplateName(&p, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS, (uchar*)" StdUsrMsgFmt"))
325
		    != RS_RET_OK)
326
			goto finalize_it;
327
	}
328
CODE_STD_FINALIZERparseSelectorAct
329
ENDparseSelectorAct
330
331
1.1.2 by Michael Biebl
Import upstream version 3.14.2
332
BEGINmodExit
333
CODESTARTmodExit
334
ENDmodExit
1 by Michael Biebl
Import upstream version 1.19.10
335
336
337
BEGINqueryEtryPt
338
CODESTARTqueryEtryPt
339
CODEqueryEtryPt_STD_OMOD_QUERIES
340
ENDqueryEtryPt
341
342
343
BEGINmodInit(UsrMsg)
344
CODESTARTmodInit
1.1.2 by Michael Biebl
Import upstream version 3.14.2
345
	*ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
1 by Michael Biebl
Import upstream version 1.19.10
346
CODEmodInit_QueryRegCFSLineHdlr
1.1.2 by Michael Biebl
Import upstream version 3.14.2
347
	CHKiRet(objUse(errmsg, CORE_COMPONENT));
1 by Michael Biebl
Import upstream version 1.19.10
348
ENDmodInit
349
350
/*
351
 * vi:set ai:
352
 */