@@ -224,7 +224,7 @@ size_t syslog_parse_identifier(const char **buf, char **identifier, char **pid)
224224 return e ;
225225}
226226
227- static void syslog_skip_date ( char * * buf ) {
227+ static int syslog_skip_timestamp ( const char * * buf ) {
228228 enum {
229229 LETTER ,
230230 SPACE ,
@@ -244,24 +244,21 @@ static void syslog_skip_date(char **buf) {
244244 SPACE
245245 };
246246
247- char * p ;
247+ const char * p , * t ;
248248 unsigned i ;
249249
250250 assert (buf );
251251 assert (* buf );
252252
253- p = * buf ;
254-
255- for (i = 0 ; i < ELEMENTSOF (sequence ); i ++ , p ++ ) {
256-
253+ for (i = 0 , p = * buf ; i < ELEMENTSOF (sequence ); i ++ , p ++ ) {
257254 if (!* p )
258- return ;
255+ return 0 ;
259256
260257 switch (sequence [i ]) {
261258
262259 case SPACE :
263260 if (* p != ' ' )
264- return ;
261+ return 0 ;
265262 break ;
266263
267264 case SPACE_OR_NUMBER :
@@ -271,75 +268,99 @@ static void syslog_skip_date(char **buf) {
271268 _fallthrough_ ;
272269 case NUMBER :
273270 if (* p < '0' || * p > '9' )
274- return ;
271+ return 0 ;
275272
276273 break ;
277274
278275 case LETTER :
279276 if (!(* p >= 'A' && * p <= 'Z' ) &&
280277 !(* p >= 'a' && * p <= 'z' ))
281- return ;
278+ return 0 ;
282279
283280 break ;
284281
285282 case COLON :
286283 if (* p != ':' )
287- return ;
284+ return 0 ;
288285 break ;
289286
290287 }
291288 }
292289
290+ t = * buf ;
293291 * buf = p ;
292+ return p - t ;
294293}
295294
296295void server_process_syslog_message (
297296 Server * s ,
298297 const char * buf ,
299- size_t buf_len ,
298+ size_t raw_len ,
300299 const struct ucred * ucred ,
301300 const struct timeval * tv ,
302301 const char * label ,
303302 size_t label_len ) {
304303
305- char syslog_priority [sizeof ("PRIORITY=" ) + DECIMAL_STR_MAX (int )],
306- syslog_facility [sizeof ("SYSLOG_FACILITY=" ) + DECIMAL_STR_MAX (int )], * msg ;
307- const char * message = NULL , * syslog_identifier = NULL , * syslog_pid = NULL ;
304+ char * t , syslog_priority [sizeof ("PRIORITY=" ) + DECIMAL_STR_MAX (int )],
305+ syslog_facility [sizeof ("SYSLOG_FACILITY=" ) + DECIMAL_STR_MAX (int )];
306+ const char * msg , * syslog_ts , * a ;
308307 _cleanup_free_ char * identifier = NULL , * pid = NULL ;
309308 int priority = LOG_USER | LOG_INFO , r ;
310309 ClientContext * context = NULL ;
311310 struct iovec * iovec ;
312- size_t n = 0 , m , i ;
311+ size_t n = 0 , m , i , leading_ws , syslog_ts_len ;
312+ bool store_raw ;
313313
314314 assert (s );
315315 assert (buf );
316+ /* The message cannot be empty. */
317+ assert (raw_len > 0 );
318+ /* The buffer NUL-terminated and can be used a string. raw_len is the length
319+ * without the terminating NUL byte, the buffer is actually one bigger. */
320+ assert (buf [raw_len ] == '\0' );
316321
317322 if (ucred && pid_is_valid (ucred -> pid )) {
318323 r = client_context_get (s , ucred -> pid , ucred , label , label_len , NULL , & context );
319324 if (r < 0 )
320325 log_warning_errno (r , "Failed to retrieve credentials for PID " PID_FMT ", ignoring: %m" , ucred -> pid );
321326 }
322327
323- /* We are creating copy of the message because we want to forward original message verbatim to the legacy
324- syslog implementation */
325- for (i = buf_len ; i > 0 ; i -- )
328+ /* We are creating a copy of the message because we want to forward the original message
329+ verbatim to the legacy syslog implementation */
330+ for (i = raw_len ; i > 0 ; i -- )
326331 if (!strchr (WHITESPACE , buf [i - 1 ]))
327332 break ;
328333
329- msg = newa (char , i + 1 );
330- * ((char * ) mempcpy (msg , buf , i )) = 0 ;
331- msg = skip_leading_chars (msg , WHITESPACE );
334+ leading_ws = strspn (buf , WHITESPACE );
332335
333- syslog_parse_priority ((const char * * )& msg , & priority , true);
336+ if (i == raw_len )
337+ /* Nice! No need to strip anything on the end, let's optimize this a bit */
338+ msg = buf + leading_ws ;
339+ else {
340+ msg = t = newa (char , i - leading_ws + 1 );
341+ memcpy (t , buf + leading_ws , i - leading_ws );
342+ t [i - leading_ws ] = 0 ;
343+ }
344+
345+ /* We will add the SYSLOG_RAW= field when we stripped anything
346+ * _or_ if the input message contained NUL bytes. */
347+ store_raw = msg != buf || strlen (msg ) != raw_len ;
348+
349+ syslog_parse_priority (& msg , & priority , true);
334350
335351 if (!client_context_test_priority (context , priority ))
336352 return ;
337353
338- if (s -> forward_to_syslog )
339- forward_syslog_raw (s , priority , buf , buf_len , ucred , tv );
354+ syslog_ts = msg ;
355+ syslog_ts_len = syslog_skip_timestamp (& msg );
356+ if (syslog_ts_len == 0 )
357+ /* We failed to parse the full timestamp, store the raw message too */
358+ store_raw = true;
359+
360+ syslog_parse_identifier (& msg , & identifier , & pid );
340361
341- syslog_skip_date ( & msg );
342- syslog_parse_identifier (( const char * * ) & msg , & identifier , & pid );
362+ if ( s -> forward_to_syslog )
363+ forward_syslog_raw ( s , priority , buf , raw_len , ucred , tv );
343364
344365 if (s -> forward_to_kmsg )
345366 server_forward_kmsg (s , priority , identifier , msg , ucred );
@@ -350,7 +371,7 @@ void server_process_syslog_message(
350371 if (s -> forward_to_wall )
351372 server_forward_wall (s , priority , identifier , msg , ucred );
352373
353- m = N_IOVEC_META_FIELDS + 6 + client_context_extra_fields_n_iovec (context );
374+ m = N_IOVEC_META_FIELDS + 8 + client_context_extra_fields_n_iovec (context );
354375 iovec = newa (struct iovec , m );
355376
356377 iovec [n ++ ] = IOVEC_MAKE_STRING ("_TRANSPORT=syslog" );
@@ -364,18 +385,37 @@ void server_process_syslog_message(
364385 }
365386
366387 if (identifier ) {
367- syslog_identifier = strjoina ("SYSLOG_IDENTIFIER=" , identifier );
368- iovec [n ++ ] = IOVEC_MAKE_STRING (syslog_identifier );
388+ a = strjoina ("SYSLOG_IDENTIFIER=" , identifier );
389+ iovec [n ++ ] = IOVEC_MAKE_STRING (a );
369390 }
370391
371392 if (pid ) {
372- syslog_pid = strjoina ("SYSLOG_PID=" , pid );
373- iovec [n ++ ] = IOVEC_MAKE_STRING (syslog_pid );
393+ a = strjoina ("SYSLOG_PID=" , pid );
394+ iovec [n ++ ] = IOVEC_MAKE_STRING (a );
395+ }
396+
397+ if (syslog_ts_len > 0 ) {
398+ const size_t hlen = strlen ("SYSLOG_TIMESTAMP=" );
399+
400+ t = newa (char , hlen + raw_len );
401+ memcpy (t , "SYSLOG_TIMESTAMP=" , hlen );
402+ memcpy (t + hlen , syslog_ts , syslog_ts_len );
403+
404+ iovec [n ++ ] = IOVEC_MAKE (t , hlen + syslog_ts_len );
374405 }
375406
376- message = strjoina ("MESSAGE=" , msg );
377- if (message )
378- iovec [n ++ ] = IOVEC_MAKE_STRING (message );
407+ a = strjoina ("MESSAGE=" , msg );
408+ iovec [n ++ ] = IOVEC_MAKE_STRING (a );
409+
410+ if (store_raw ) {
411+ const size_t hlen = strlen ("SYSLOG_RAW=" );
412+
413+ t = newa (char , hlen + raw_len );
414+ memcpy (t , "SYSLOG_RAW=" , hlen );
415+ memcpy (t + hlen , buf , raw_len );
416+
417+ iovec [n ++ ] = IOVEC_MAKE (t , hlen + raw_len );
418+ }
379419
380420 server_dispatch_message (s , iovec , n , m , context , tv , priority , 0 );
381421}
0 commit comments