4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <sys/types.h>
27 #include <sys/systeminfo.h>
28 #include <bsm/audit.h>
29 #include <bsm/libbsm.h>
30 #include <bsm/audit_uevents.h>
31 #include <bsm/audit_private.h>
41 #include <sys/socket.h>
42 #include <netinet/in.h>
43 #include <arpa/inet.h>
50 #define F_SMASK "%x\n"
51 #define F_FMASK "%x\n"
52 #define F_PORT "%lx\n"
54 #define F_MACH "%x %x %x %x\n"
57 #define AU_SUFFIX ".au"
59 #define ANC_BAD_FILE -1
60 #define ANC_BAD_FORMAT -2
62 #define AUDIT_CRON_TEXTBUF 256
63 static char textbuf
[AUDIT_CRON_TEXTBUF
];
68 return (!cannot_audit(0));
72 audit_cron_syslog(const char *message
) {
73 static int is_open
= 0;
76 openlog("Solaris_Audit", LOG_ODELAY
, LOG_CRON
);
79 syslog(LOG_WARNING
, "%s", message
);
83 * audit_cron_getinfo returns the audit characteristics from the relevant
84 * auxiliary file, it if exists. If not, it creates them from the crontab
89 audit_cron_getinfo(char *fname
, char *fname_aux
, struct auditinfo_addr
*info
)
97 "Used defaults instead of ancilary audit file";
99 if ((fd
= open(fname_aux
, O_RDONLY
)) == -1) {
100 /* no syslog here; common case */
103 if (fstat(fd
, &st
) == -1) {
104 /* no syslog here either; common case */
108 if (read(fd
, textbuf
, st
.st_size
) != st
.st_size
) {
109 audit_cron_syslog(msg
);
122 &(info
->ai_mask
.am_success
),
123 &(info
->ai_mask
.am_failure
),
124 &(info
->ai_termid
.at_port
),
125 &(info
->ai_termid
.at_type
),
126 &(info
->ai_termid
.at_addr
[0]),
127 &(info
->ai_termid
.at_addr
[1]),
128 &(info
->ai_termid
.at_addr
[2]),
129 &(info
->ai_termid
.at_addr
[3]),
130 &(info
->ai_asid
)) != 10) {
131 audit_cron_syslog(msg
);
139 if (unlink(fname_aux
)) {
142 "Failed to remove invalid ancilary audit file");
144 /* intentionally falls through */
147 if (stat(fname
, &st
))
150 /* port and IP are zero */
151 (void) memset(&(info
->ai_termid
), 0, sizeof (au_tid_addr_t
));
152 info
->ai_termid
.at_type
= AU_IPv4
;
154 /* the caller is the child of cron which will run the job. */
155 info
->ai_asid
= getpid();
157 info
->ai_mask
.am_success
= 0; /* cover error case */
158 info
->ai_mask
.am_failure
= 0;
160 if (strstr(fname
, "crontabs") != NULL
) {
161 if (getpwnam_r(basename(fname
), &pwd
, pwd_buff
,
162 sizeof (pwd_buff
)) == NULL
)
163 return (-1); /* getpwnam_r sets errno */
165 if (getpwuid_r(st
.st_uid
, &pwd
, pwd_buff
, sizeof (pwd_buff
)) ==
167 return (-1); /* getpwuid_r sets errno */
170 info
->ai_auid
= pwd
.pw_uid
;
172 if (au_user_mask(pwd
.pw_name
, &mask
)) {
173 errno
= EINVAL
; /* pw_name lookup failed */
176 info
->ai_mask
.am_success
= mask
.am_success
;
177 info
->ai_mask
.am_failure
= mask
.am_failure
;
183 audit_cron_setinfo(char *fname
, struct auditinfo_addr
*info
)
188 r
= chmod(fname
, 0200);
189 if (r
== -1 && errno
!= ENOENT
)
192 if ((fd
= open(fname
, O_CREAT
|O_WRONLY
|O_TRUNC
, 0200)) == -1)
195 len
= sprintf(textbuf
,
204 info
->ai_mask
.am_success
,
205 info
->ai_mask
.am_failure
,
206 info
->ai_termid
.at_port
,
207 info
->ai_termid
.at_type
,
208 info
->ai_termid
.at_addr
[0],
209 info
->ai_termid
.at_addr
[1],
210 info
->ai_termid
.at_addr
[2],
211 info
->ai_termid
.at_addr
[3],
214 if (write(fd
, textbuf
, len
) != len
)
215 goto audit_setinfo_clean
;
217 if (fchmod(fd
, 0400) == -1)
218 goto audit_setinfo_clean
;
226 (void) unlink(fname
);
232 audit_cron_make_anc_name(char *fname
)
236 anc_name
= (char *)malloc(strlen(fname
) + strlen(AU_SUFFIX
) + 1);
237 if (anc_name
== NULL
)
240 (void) strcpy(anc_name
, fname
);
241 (void) strcat(anc_name
, AU_SUFFIX
);
246 audit_cron_is_anc_name(char *name
)
250 pos
= strlen(name
) - strlen(AU_SUFFIX
);
254 if (strcmp(name
+ pos
, AU_SUFFIX
) == 0)
261 audit_cron_session_failure(char *name
, int type
, char *err_str
)
266 mess
= dgettext(bsm_dom
,
267 "at-job session for user %s failed: ancillary file: %s");
269 mess
= dgettext(bsm_dom
,
270 "crontab job session for user %s failed: ancillary file: %s");
272 (void) snprintf(textbuf
, sizeof (textbuf
), mess
, name
, err_str
);
274 aug_save_event(AUE_cron_invoke
);
276 aug_save_text(textbuf
);
289 struct auditinfo_addr info
;
291 char *anc_file
, *fname
;
293 char full_path
[PATH_MAX
];
295 if (cannot_audit(0)) {
299 /* get auditinfo from ancillary file */
300 if (at_jobname
== NULL
) {
302 * this is a cron-event, so we can get
303 * filename from "name" arg
307 if (strlen(path
) + strlen(fname
) + 2 > PATH_MAX
) {
308 errno
= ENAMETOOLONG
;
311 (void) strcat(strcat(strcpy(full_path
, path
), "/"),
316 /* this is an at-event, use "at_jobname" */
321 anc_file
= audit_cron_make_anc_name(fname
);
322 if (anc_file
== NULL
) {
325 r
= audit_cron_getinfo(fname
, anc_file
, &info
);
332 if (r
== ANC_BAD_FORMAT
)
333 err_str
= dgettext(bsm_dom
, "bad format");
335 err_str
= strerror(errno
);
337 audit_cron_session_failure(name
,
340 if (anc_file
!= NULL
)
348 /* get current audit masks */
349 if (au_user_mask(name
, &mask
) == 0) {
350 info
.ai_mask
.am_success
|= mask
.am_success
;
351 info
.ai_mask
.am_failure
|= mask
.am_failure
;
354 /* save audit attributes for further use in current process */
355 aug_save_auid(info
.ai_auid
);
356 aug_save_asid(info
.ai_asid
);
357 aug_save_tid_ex(info
.ai_termid
.at_port
, info
.ai_termid
.at_addr
,
358 info
.ai_termid
.at_type
);
359 aug_save_pid(getpid());
365 /* set mixed audit masks */
366 return (setaudit_addr(&info
, sizeof (info
)));
370 * audit_cron_new_job - create audit record with an information
371 * about new job started by cron.
373 * cmd - command being run by cron daemon.
374 * type - type of job (0 - at-job, 1 - crontab job).
375 * event - not used. pointer to cron event structure.
379 audit_cron_new_job(char *cmd
, int type
, void *event
)
385 (void) snprintf(textbuf
, sizeof (textbuf
),
386 dgettext(bsm_dom
, "at-job"));
387 } else if (type
== 1) {
388 (void) snprintf(textbuf
, sizeof (textbuf
),
389 dgettext(bsm_dom
, "batch-job"));
390 } else if (type
== 2) {
391 (void) snprintf(textbuf
, sizeof (textbuf
),
392 dgettext(bsm_dom
, "crontab-job"));
393 } else if ((type
> 2) && (type
<= 25)) { /* 25 from cron.h */
394 (void) snprintf(textbuf
, sizeof (textbuf
),
395 dgettext(bsm_dom
, "queue-job (%c)"), (type
+'a'));
397 (void) snprintf(textbuf
, sizeof (textbuf
),
398 dgettext(bsm_dom
, "unknown job type (%d)"), type
);
401 aug_save_event(AUE_cron_invoke
);
403 aug_save_text(textbuf
);
409 audit_cron_bad_user(char *name
)
414 (void) snprintf(textbuf
, sizeof (textbuf
),
415 dgettext(bsm_dom
, "bad user %s"), name
);
417 aug_save_event(AUE_cron_invoke
);
419 aug_save_text(textbuf
);
424 audit_cron_user_acct_expired(char *name
)
429 (void) snprintf(textbuf
, sizeof (textbuf
),
431 "user %s account expired"), name
);
433 aug_save_event(AUE_cron_invoke
);
435 aug_save_text(textbuf
);
440 audit_cron_create_anc_file(char *name
, char *path
, char *uname
, uid_t uid
)
446 char full_path
[PATH_MAX
];
455 if (strlen(path
) + strlen(name
) + 2 > PATH_MAX
)
457 (void) strcat(strcat(strcpy(full_path
, path
), "/"), name
);
460 anc_name
= audit_cron_make_anc_name(name
);
462 if (access(anc_name
, F_OK
) != 0) {
463 if (au_user_mask(uname
, &msk
) != 0) {
470 ai
.ai_termid
.at_port
= 0;
471 ai
.ai_termid
.at_type
= AU_IPv4
;
472 ai
.ai_termid
.at_addr
[0] = 0;
473 ai
.ai_termid
.at_addr
[1] = 0;
474 ai
.ai_termid
.at_addr
[2] = 0;
475 ai
.ai_termid
.at_addr
[3] = 0;
476 /* generate new pid to use it as asid */
486 * we need to clear status of children for
487 * wait() call in "cron"
491 (void) waitpid(pid
, &lock
, 0);
494 if (audit_cron_setinfo(anc_name
, &ai
) != 0) {
505 audit_cron_delete_anc_file(char *name
, char *path
)
508 char full_path
[PATH_MAX
];
515 if (strlen(path
) + strlen(name
) + 2 > PATH_MAX
)
517 (void) strcat(strcat(strcpy(full_path
, path
), "/"), name
);
520 anc_name
= audit_cron_make_anc_name(name
);
521 r
= unlink(anc_name
);