Imported Upstream version 2.4.3
[platform/upstream/audit.git] / lib / audit_logging.c
1 /* audit_logging.c -- 
2  * Copyright 2005-2008,2010,2011,2013 Red Hat Inc., Durham, North Carolina.
3  * All Rights Reserved.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  * Authors:
20  *      Steve Grubb <sgrubb@redhat.com>
21  */
22
23 #include "config.h"
24 #include <stdio.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <sys/stat.h>
29 #include <errno.h>
30 #include <netinet/in.h> // inet6 addrlen
31 #include <netdb.h>      // gethostbyname
32 #include <arpa/inet.h>  // inet_ntop
33 #include <utmp.h>
34 #include <limits.h>     // PATH_MAX
35
36 #include "libaudit.h"
37 #include "private.h"
38
39 #define TTY_PATH        32
40 #define MAX_USER        (UT_NAMESIZE * 2) + 8
41
42 // NOTE: The kernel fills in pid, uid, and loginuid of sender. Therefore,
43 // these routines do not need to send them.
44
45 /*
46  * resolve's the hostname - caller must pass a INET6_ADDRSTRLEN byte buffer
47  * Returns string w/ numerical address, or "?" on failure
48  */
49 static void _resolve_addr(char buf[], const char *host)
50 {
51         struct addrinfo *ai;
52         struct addrinfo hints;
53         int e;
54
55         buf[0] = '?';
56         buf[1] = 0;
57         /* Short circuit this lookup if NULL, or empty */
58         if (host == NULL || *host == 0)
59                 return;
60
61         memset(&hints, 0, sizeof(hints));
62         hints.ai_flags = AI_ADDRCONFIG;
63         hints.ai_socktype = SOCK_STREAM;
64
65         e = getaddrinfo(host, NULL, &hints, &ai);
66         if (e != 0) {
67                 audit_msg(LOG_ERR, 
68                         "resolve_addr: cannot resolve hostname %s (%s)",
69                         host, gai_strerror(e));
70                 return;
71         }
72         // What to do if more than 1 addr?
73         inet_ntop(ai->ai_family, ai->ai_family == AF_INET ?
74                 (void *) &((struct sockaddr_in *)ai->ai_addr)->sin_addr :
75                 (void *) &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr,
76                 buf, INET6_ADDRSTRLEN);
77         freeaddrinfo(ai);
78 }
79
80 /*
81  * This function checks a string to see if it needs encoding. It
82  * return 1 if needed and 0 if not
83  */
84 int audit_value_needs_encoding(const char *str, unsigned int size)
85 {
86         unsigned int i;
87
88         if (str == NULL)
89                 return 0;
90
91         for (i=0; i<size; i++) {
92                 // we don't test for > 0x7f because str[] is signed.
93                 if (str[i] == '"' || str[i] < 0x21 || str[i] == 0x7F)
94                         return 1;
95         }
96         return 0;
97 }
98
99 /*
100  * This function does encoding of "untrusted" names just like the kernel
101  */
102 char *audit_encode_value(char *final, const char *buf, unsigned int size)
103 {
104         unsigned int i;
105         char *ptr = final;
106         const char *hex = "0123456789ABCDEF";
107
108         if (final == NULL)
109                 return NULL;
110
111         if (buf == NULL) {
112                 *final = 0;
113                 return final;
114         }
115
116         for (i=0; i<size; i++) {
117                 *ptr++ = hex[(buf[i] & 0xF0)>>4]; /* Upper nibble */
118                 *ptr++ = hex[buf[i] & 0x0F];      /* Lower nibble */
119         }
120         *ptr = 0;
121         return final;
122 }
123
124 char *audit_encode_nv_string(const char *name, const char *value,
125                 unsigned int vlen)
126 {
127         char *str;
128
129         if (vlen == 0 && value)
130                 vlen = strlen(value);
131
132         if (value && audit_value_needs_encoding(value, vlen)) {
133                 char *tmp = malloc(2*vlen + 1);
134                 if (tmp) {
135                         audit_encode_value(tmp, value, vlen);
136                         if (asprintf(&str, "%s=%s", name, tmp) < 0)
137                                 str = NULL;
138                         free(tmp);
139                 } else
140                         str = NULL;
141         } else
142                 if (asprintf(&str, "%s=\"%s\"", name, value ? value : "?") < 0)
143                         str = NULL;
144         return str;
145 }
146
147 /*
148  * Get the executable's name 
149  */
150 static char *_get_exename(char *exename, int size)
151 {
152         int res;
153         char tmp[PATH_MAX+1];
154
155         /* get the name of the current executable */
156         if ((res = readlink("/proc/self/exe", tmp, PATH_MAX)) == -1) {
157                 strcpy(exename, "\"?\"");
158                 audit_msg(LOG_ERR, "get_exename: cannot determine executable");
159         } else {
160                 tmp[res] = '\0';
161                 if (audit_value_needs_encoding(tmp, res))
162                         return audit_encode_value(exename, tmp, res);
163                 snprintf(exename, size, "\"%s\"", tmp);
164         }
165         return exename;
166 }
167
168 /*
169  * Get the command line name 
170  * NOTE: at the moment, this only escapes what the user sent
171  */
172 static char *_get_commname(const char *comm, char *commname, unsigned int size)
173 {
174         unsigned int len;
175         
176         if (comm == NULL) {
177                 strcpy(commname, "\"?\"");
178                 return commname;
179         }
180
181         len = strlen(comm);
182         if (audit_value_needs_encoding(comm, len))
183                 audit_encode_value(commname, comm, len);
184         else
185                 snprintf(commname, size, "\"%s\"", comm);
186
187         return commname;
188 }
189
190 static int check_ttyname(const char *ttyn)
191 {
192         struct stat statbuf;
193
194         if (lstat(ttyn, &statbuf)
195                 || !S_ISCHR(statbuf.st_mode)
196                 || (statbuf.st_nlink > 1 && strncmp(ttyn, "/dev/", 5))) {
197                 audit_msg(LOG_ERR, "FATAL: bad tty %s", ttyn);
198                 return 1;
199         }
200         return 0;
201 }
202
203 static const char *_get_tty(char *tname, int size)
204 {
205         int rc, i, found = 0;
206
207         for (i=0; i<3 && !found; i++) {
208                 rc = ttyname_r(i, tname, size);
209                 if (rc == 0 && tname[0] != '\0')
210                         found = 1;
211         }
212
213         if (!found)
214                 return NULL;
215         
216         if (check_ttyname(tname)) 
217                 return NULL;
218
219         if (strncmp(tname, "/dev/", 5) == 0)
220                 return &tname[5];
221
222         return tname;
223 }
224
225 /*
226  * This function will log a message to the audit system using a predefined
227  * message format. This function should be used by all console apps that do
228  * not manipulate accounts or groups.
229  *
230  * audit_fd - The fd returned by audit_open
231  * type - type of message, ex: AUDIT_USER, AUDIT_USYS_CONFIG, AUDIT_USER_LOGIN
232  * message - the message being sent
233  * hostname - the hostname if known
234  * addr - The network address of the user
235  * tty - The tty of the user
236  * result - 1 is "success" and 0 is "failed"
237  *
238  * It returns the sequence number which is > 0 on success or <= 0 on error.
239  */
240 int audit_log_user_message(int audit_fd, int type, const char *message,
241         const char *hostname, const char *addr, const char *tty, int result)
242 {
243         char buf[MAX_AUDIT_MESSAGE_LENGTH];
244         char addrbuf[INET6_ADDRSTRLEN];
245         static char exename[PATH_MAX*2]="";
246         char ttyname[TTY_PATH];
247         const char *success;
248         int ret;
249
250         if (audit_fd < 0)
251                 return 0;
252
253         if (result)
254                 success = "success";
255         else
256                 success = "failed";
257
258         /* If hostname is empty string, make it NULL ptr */
259         if (hostname && *hostname == 0)
260                 hostname = NULL;
261         addrbuf[0] = 0;
262         if (addr == NULL || strlen(addr) == 0)
263                 _resolve_addr(addrbuf, hostname);
264         else
265                 strncat(addrbuf, addr, sizeof(addrbuf)-1);
266
267         if (exename[0] == 0)
268                 _get_exename(exename, sizeof(exename));
269         if (tty == NULL) 
270                 tty = _get_tty(ttyname, TTY_PATH);
271         else if (*tty == 0)
272                 tty = NULL;
273
274         snprintf(buf, sizeof(buf),
275                 "%s exe=%s hostname=%s addr=%s terminal=%s res=%s",
276                 message, exename,
277                 hostname ? hostname : "?",
278                 addrbuf,
279                 tty ? tty : "?",
280                 success
281                 );
282
283         errno = 0;
284         ret = audit_send_user_message( audit_fd, type, HIDE_IT, buf );
285         if ((ret < 1) && errno == 0)
286                 errno = ret;
287         return ret;
288 }
289
290 /*
291  * This function will log a message to the audit system using a predefined
292  * message format. This function should be used by all console apps that do
293  * not manipulate accounts or groups and are executing a script. An example
294  * would be python or crond wanting to say what they are executing.
295  *
296  * audit_fd - The fd returned by audit_open
297  * type - type of message, ex: AUDIT_USER, AUDIT_USYS_CONFIG, AUDIT_USER_LOGIN
298  * message - the message being sent
299  * comm - the program command line name
300  * hostname - the hostname if known
301  * addr - The network address of the user
302  * tty - The tty of the user
303  * result - 1 is "success" and 0 is "failed"
304  *
305  * It returns the sequence number which is > 0 on success or <= 0 on error.
306  */
307 int audit_log_user_comm_message(int audit_fd, int type, const char *message,
308         const char *comm, const char *hostname, const char *addr,
309         const char *tty, int result)
310 {
311         char buf[MAX_AUDIT_MESSAGE_LENGTH];
312         char addrbuf[INET6_ADDRSTRLEN];
313         static char exename[PATH_MAX*2]="";
314         char commname[PATH_MAX*2];
315         char ttyname[TTY_PATH];
316         const char *success;
317         int ret;
318
319         if (audit_fd < 0)
320                 return 0;
321
322         if (result)
323                 success = "success";
324         else
325                 success = "failed";
326
327         /* If hostname is empty string, make it NULL ptr */
328         if (hostname && *hostname == 0)
329                 hostname = NULL;
330         addrbuf[0] = 0;
331         if (addr == NULL || strlen(addr) == 0)
332                 _resolve_addr(addrbuf, hostname);
333         else
334                 strncat(addrbuf, addr, sizeof(addrbuf)-1);
335         if (exename[0] == 0)
336                 _get_exename(exename, sizeof(exename));
337         if (tty == NULL) 
338                 tty = _get_tty(ttyname, TTY_PATH);
339         else if (*tty == 0)
340                 tty = NULL;
341
342         _get_commname(comm, commname, sizeof(commname));
343
344         snprintf(buf, sizeof(buf),
345                 "%s comm=%s exe=%s hostname=%s addr=%s terminal=%s res=%s",
346                 message, commname, exename,
347                 hostname ? hostname : "?",
348                 addrbuf,
349                 tty ? tty : "?",
350                 success
351                 );
352
353         errno = 0;
354         ret = audit_send_user_message( audit_fd, type, HIDE_IT, buf );
355         if ((ret < 1) && errno == 0)
356                 errno = ret;
357         return ret;
358 }
359
360
361 /*
362  * This function will log a message to the audit system using a predefined
363  * message format. It should be used for all account manipulation operations.
364  * Parameter usage is as follows:
365  *
366  * audit_fd - The fd returned by audit_open
367  * type - type of message: AUDIT_USER_CHAUTHTOK for changing any account
368  *        attributes.
369  * pgname - program's name
370  * op  -  operation. "adding user", "changing finger info", "deleting group"
371  * name - user's account or group name. If not available use NULL.
372  * id  -  uid or gid that the operation is being performed on. This is used
373  *        only when user is NULL.
374  * host - The hostname if known
375  * addr - The network address of the user
376  * tty  - The tty of the user
377  * result - 1 is "success" and 0 is "failed"
378  *
379  * It returns the sequence number which is > 0 on success or <= 0 on error.
380  */
381 int audit_log_acct_message(int audit_fd, int type, const char *pgname,
382         const char *op, const char *name, unsigned int id, 
383         const char *host, const char *addr, const char *tty, int result)
384 {
385         const char *success;
386         char buf[MAX_AUDIT_MESSAGE_LENGTH];
387         char addrbuf[INET6_ADDRSTRLEN];
388         static char exename[PATH_MAX*2] = "";
389         char ttyname[TTY_PATH];
390         int ret;
391
392         if (audit_fd < 0)
393                 return 0;
394
395         if (result)
396                 success = "success";
397         else
398                 success = "failed";
399
400         /* If hostname is empty string, make it NULL ptr */
401         if (host && *host == 0)
402                 host = NULL;
403         addrbuf[0] = 0;
404         if (addr == NULL || strlen(addr) == 0)
405                 _resolve_addr(addrbuf, host);
406         else
407                 strncat(addrbuf, addr, sizeof(addrbuf)-1);
408
409         if (pgname == NULL) {
410                 if (exename[0] == 0)
411                         _get_exename(exename, sizeof(exename));
412         } else if (pgname[0] != '"')
413                 snprintf(exename, sizeof(exename), "\"%s\"", pgname);
414         else
415                 snprintf(exename, sizeof(exename), "%s", pgname);
416
417         if (tty == NULL) 
418                 tty = _get_tty(ttyname, TTY_PATH);
419         else if (*tty == 0)
420                 tty = NULL;
421
422         if (name && id == -1) {
423                 char user[MAX_USER];
424                 const char *format;
425                 size_t len;
426
427                 user[0] = 0;
428                 strncat(user, name, MAX_USER-1);
429                 len = strnlen(user, UT_NAMESIZE);
430                 user[len] = 0;
431                 if (audit_value_needs_encoding(name, len)) {
432                         audit_encode_value(user, name, len);
433                         format = 
434              "op=%s acct=%s exe=%s hostname=%s addr=%s terminal=%s res=%s";
435                 } else
436                         format = 
437          "op=%s acct=\"%s\" exe=%s hostname=%s addr=%s terminal=%s res=%s";
438
439                 snprintf(buf, sizeof(buf), format,
440                         op, user, exename,
441                         host ? host : "?",
442                         addrbuf,
443                         tty ? tty : "?",
444                         success
445                         );
446         } else
447                 snprintf(buf, sizeof(buf),
448                 "op=%s id=%u exe=%s hostname=%s addr=%s terminal=%s res=%s",
449                         op, id, exename,
450                         host ? host : "?",
451                         addrbuf,
452                         tty ? tty : "?",
453                         success
454                         );
455
456         errno = 0;
457         ret = audit_send_user_message(audit_fd, type, REAL_ERR, buf);
458         if ((ret < 1) && errno == 0)
459                 errno = ret;
460         return ret;
461 }
462
463 /*
464  * This function will log a message to the audit system using a predefined
465  * message format. This function should be used by all apps that are SE Linux
466  * object managers.
467  *
468  * audit_fd - The fd returned by audit_open
469  * type - type of message, ex: AUDIT_USER, AUDIT_USYS_CONFIG, AUDIT_USER_LOGIN
470  * message - the message being sent
471  * hostname - the hostname if known
472  * addr - The network address of the user
473  * tty - The tty of the user
474  * uid - The auid of the person related to the avc message
475  *
476  * It returns the sequence number which is > 0 on success or <= 0 on error.
477  */
478 int audit_log_user_avc_message(int audit_fd, int type, const char *message,
479         const char *hostname, const char *addr, const char *tty, uid_t uid)
480 {
481         char buf[MAX_AUDIT_MESSAGE_LENGTH];
482         char addrbuf[INET6_ADDRSTRLEN];
483         static char exename[PATH_MAX*2] = "";
484         char ttyname[TTY_PATH];
485         int retval;
486
487         if (audit_fd < 0)
488                 return 0;
489
490         /* If hostname is empty string, make it NULL ptr */
491         if (hostname && *hostname == 0)
492                 hostname = NULL;
493         addrbuf[0] = 0;
494         if (addr == NULL || strlen(addr) == 0)
495                 _resolve_addr(addrbuf, hostname);
496         else
497                 strncat(addrbuf, addr, sizeof(addrbuf)-1);
498         if (exename[0] == 0)
499                 _get_exename(exename, sizeof(exename));
500         if (tty == NULL) 
501                 tty = _get_tty(ttyname, TTY_PATH);
502         else if (*tty == 0)
503                 tty = NULL;
504
505         snprintf(buf, sizeof(buf),
506             "%s exe=%s sauid=%d hostname=%s addr=%s terminal=%s",
507                 message, exename, uid,
508                 hostname ? hostname : "?",
509                 addrbuf,
510                 tty ? tty : "?"
511                 );
512
513         errno = 0;
514         retval = audit_send_user_message( audit_fd, type, REAL_ERR, buf );
515         if (retval == -EPERM && getuid() != 0) {
516                 syslog(LOG_ERR, "Can't send to audit system: %s %s",
517                         audit_msg_type_to_name(type), buf);
518                 return 0;
519         }
520         if ((retval < 1) && errno == 0)
521                 errno = retval;
522         return retval;
523 }
524
525 /*
526  * This function will log a message to the audit system using a predefined
527  * message format. It should be used for all SE linux user and role 
528  * manipulation operations.
529  * Parameter usage is as follows:
530  *
531  * type - type of message: AUDIT_ROLE_ASSIGN/REMOVE for changing any SE Linux
532  *        user or role attributes.
533  * pgname - program's name
534  * op  -  operation. "adding-user", "adding-role", "deleting-user", "deleting-role"
535  * name - user's account. If not available use NULL.
536  * id  -  uid that the operation is being performed on. This is used
537  *        only when name is NULL.
538  * new_seuser - the new seuser that the login user is getting
539  * new_role - the new_role that the login user is getting
540  * new_range - the new mls range that the login user is getting
541  * old_seuser - the old seuser that the login usr had
542  * old_role - the old role that the login user had
543  * old_range - the old mls range that the login usr had
544  * host - The hostname if known
545  * addr - The network address of the user
546  * tty  - The tty of the user
547  * result - 1 is "success" and 0 is "failed"
548  *
549  * It returns the sequence number which is > 0 on success or <= 0 on error.
550  */
551 int audit_log_semanage_message(int audit_fd, int type, const char *pgname,
552         const char *op, const char *name, unsigned int id, 
553         const char *new_seuser, const char *new_role, const char *new_range,
554         const char *old_seuser, const char *old_role, const char *old_range,
555         const char *host, const char *addr,
556         const char *tty, int result)
557 {
558         const char *success;
559         char buf[MAX_AUDIT_MESSAGE_LENGTH];
560         char addrbuf[INET6_ADDRSTRLEN];
561         static char exename[PATH_MAX*2] = "";
562         char ttyname[TTY_PATH];
563         int ret;
564
565         if (audit_fd < 0)
566                 return 0;
567
568         if (result)
569                 success = "success";
570         else
571                 success = "failed";
572
573         /* If hostname is empty string, make it NULL ptr */
574         if (host && *host == 0)
575                 host = NULL;
576         addrbuf[0] = 0;
577         if (addr == NULL || strlen(addr) == 0)
578                 _resolve_addr(addrbuf, host);
579         else
580                 strncat(addrbuf, addr, sizeof(addrbuf)-1);
581
582         if (pgname == NULL || strlen(pgname) == 0) {
583                 if (exename[0] == 0)
584                         _get_exename(exename, sizeof(exename));
585                 pgname = exename;
586         }
587         if (tty == NULL || strlen(tty) == 0) 
588                 tty = _get_tty(ttyname, TTY_PATH);
589         else if (*tty == 0)
590                 tty = NULL;
591
592         if (name && strlen(name) > 0) {
593                 size_t len;
594                 const char *format;
595                 char user[MAX_USER];
596
597                 user[0] = 0;
598                 strncat(user, name, MAX_USER-1);
599                 len = strnlen(user, UT_NAMESIZE);
600                 user[len] = 0;
601                 if (audit_value_needs_encoding(name, len)) {
602                         audit_encode_value(user, name, len);
603                         format = "op=%s acct=%s old-seuser=%s old-role=%s old-range=%s new-seuser=%s new-role=%s new-range=%s exe=%s hostname=%s addr=%s terminal=%s res=%s";
604                 } else
605                         format = "op=%s acct=\"%s\" old-seuser=%s old-role=%s old-range=%s new-seuser=%s new-role=%s new-range=%s exe=%s hostname=%s addr=%s terminal=%s res=%s";
606                 snprintf(buf, sizeof(buf), format, op, user, 
607                         old_seuser && strlen(old_seuser) ? old_seuser : "?",
608                         old_role && strlen(old_role) ? old_role : "?",
609                         old_range && strlen(old_range) ? old_range : "?",
610                         new_seuser && strlen(new_seuser) ? new_seuser : "?",
611                         new_role && strlen(new_role) ? new_role : "?",
612                         new_range && strlen(new_range) ? new_range : "?",
613                         pgname,
614                         host && strlen(host) ? host : "?",
615                         addrbuf,
616                         tty && strlen(tty) ? tty : "?",
617                         success
618                         );
619         } else
620                 snprintf(buf, sizeof(buf),
621                 "op=%s id=%u old-seuser=%s old-role=%s old-range=%s new-seuser=%s new-role=%s new-range=%s exe=%s hostname=%s addr=%s terminal=%s res=%s",
622                         op, id,
623                         old_seuser && strlen(old_seuser) ? old_seuser : "?",
624                         old_role && strlen(old_role) ? old_role : "?",
625                         old_range && strlen(old_range) ? old_range : "?",
626                         new_seuser && strlen(new_seuser) ? new_seuser : "?",
627                         new_role && strlen(new_role) ? new_role : "?",
628                         new_range && strlen(new_range) ? new_range : "?",
629                         pgname,
630                         host && strlen(host) ? host : "?",
631                         addrbuf,
632                         tty && strlen(tty) ? tty : "?",
633                         success
634                         );
635
636         errno = 0;
637         ret = audit_send_user_message(audit_fd, type, REAL_ERR, buf);
638         if ((ret < 1) && errno == 0)
639                 errno = ret;
640         return ret;
641 }
642
643 /*
644  * This function will log a message to the audit system using a predefined
645  * message format. This function should be used by all console apps that do
646  * not manipulate accounts or groups.
647  *
648  * audit_fd - The fd returned by audit_open
649  * type - type of message, ex: AUDIT_USER_CMD
650  * command - the command line being logged
651  * tty - The tty of the user
652  * result - 1 is "success" and 0 is "failed"
653  *
654  * It returns the sequence number which is > 0 on success or <= 0 on error.
655  */
656 int audit_log_user_command(int audit_fd, int type, const char *command,
657         const char *tty, int result)
658 {
659         char *p;
660         char buf[MAX_AUDIT_MESSAGE_LENGTH];
661         char commname[PATH_MAX*2];
662         char cwdname[PATH_MAX*2];
663         char ttyname[TTY_PATH];
664         char format[64];
665         const char *success;
666         char *cmd;
667         int ret, cwdenc=0, cmdenc=0;
668         unsigned int len;
669
670         if (audit_fd < 0)
671                 return 0;
672
673         if (result)
674                 success = "success";
675         else
676                 success = "failed";
677
678         if (tty == NULL) 
679                 tty = _get_tty(ttyname, TTY_PATH);
680         else if (*tty == 0)
681                 tty = NULL;
682
683         /* Trim leading spaces */
684         while (*command == ' ')
685                 command++;
686
687         cmd = strdup(command);
688         if (cmd == NULL)
689                 return -1;
690
691         // We borrow the commname buffer
692         if (getcwd(commname, PATH_MAX) == NULL)
693                 strcpy(commname, "?");
694         len = strlen(commname);
695         if (audit_value_needs_encoding(commname, len)) {
696                 audit_encode_value(cwdname, commname, len);
697                 cwdenc = 1;
698         } else
699                 strcpy(cwdname, commname);
700
701         len = strlen(cmd);
702         // Trim the trailing carriage return and spaces
703         while (len && (cmd[len-1] == 0x0A || cmd[len-1] == ' ')) {
704                 cmd[len-1] = 0;
705                 len--;
706         }
707
708         if (len >= PATH_MAX) {
709                 cmd[PATH_MAX] = 0;
710                 len = PATH_MAX-1;
711         }
712         if (audit_value_needs_encoding(cmd, len)) {
713                 audit_encode_value(commname, cmd, len);
714                 cmdenc = 1;
715         }
716         if (cmdenc == 0)
717                 strcpy(commname, cmd);
718         free(cmd);
719
720         // Make the format string
721         if (cwdenc)
722                 p=stpcpy(format, "cwd=%s ");
723         else
724                 p=stpcpy(format, "cwd=\"%s\" ");
725
726         if (cmdenc)
727                 p = stpcpy(p, "cmd=%s ");
728         else
729                 p = stpcpy(p, "cmd=\"%s\" ");
730
731         strcpy(p, "terminal=%s res=%s");
732
733         // now use the format string to make the event
734         snprintf(buf, sizeof(buf), format,
735                         cwdname, commname,
736                         tty ? tty : "?",
737                         success
738                 );
739
740         errno = 0;
741         ret = audit_send_user_message( audit_fd, type, HIDE_IT, buf );
742         if ((ret < 1) && errno == 0)
743                 errno = ret;
744         return ret;
745 }
746