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
)
96 struct passwd
*result
;
99 "Used defaults instead of ancilary audit file";
101 if ((fd
= open(fname_aux
, O_RDONLY
)) == -1) {
102 /* no syslog here; common case */
105 if (fstat(fd
, &st
) == -1) {
106 /* no syslog here either; common case */
110 if (read(fd
, textbuf
, st
.st_size
) != st
.st_size
) {
111 audit_cron_syslog(msg
);
124 &(info
->ai_mask
.am_success
),
125 &(info
->ai_mask
.am_failure
),
126 &(info
->ai_termid
.at_port
),
127 &(info
->ai_termid
.at_type
),
128 &(info
->ai_termid
.at_addr
[0]),
129 &(info
->ai_termid
.at_addr
[1]),
130 &(info
->ai_termid
.at_addr
[2]),
131 &(info
->ai_termid
.at_addr
[3]),
132 &(info
->ai_asid
)) != 10) {
133 audit_cron_syslog(msg
);
141 if (unlink(fname_aux
)) {
144 "Failed to remove invalid ancilary audit file");
146 /* intentionally falls through */
149 if (stat(fname
, &st
))
152 /* port and IP are zero */
153 (void) memset(&(info
->ai_termid
), 0, sizeof (au_tid_addr_t
));
154 info
->ai_termid
.at_type
= AU_IPv4
;
156 /* the caller is the child of cron which will run the job. */
157 info
->ai_asid
= getpid();
159 info
->ai_mask
.am_success
= 0; /* cover error case */
160 info
->ai_mask
.am_failure
= 0;
162 if (strstr(fname
, "crontabs") != NULL
) {
163 ret
= getpwnam_r(basename(fname
), &pwd
, pwd_buff
, sizeof
164 (pwd_buff
), &result
);
168 ret
= getpwuid_r(st
.st_uid
, &pwd
, pwd_buff
, sizeof (pwd_buff
),
174 info
->ai_auid
= pwd
.pw_uid
;
176 if (au_user_mask(pwd
.pw_name
, &mask
)) {
177 errno
= EINVAL
; /* pw_name lookup failed */
180 info
->ai_mask
.am_success
= mask
.am_success
;
181 info
->ai_mask
.am_failure
= mask
.am_failure
;
187 audit_cron_setinfo(char *fname
, struct auditinfo_addr
*info
)
192 r
= chmod(fname
, 0200);
193 if (r
== -1 && errno
!= ENOENT
)
196 if ((fd
= open(fname
, O_CREAT
|O_WRONLY
|O_TRUNC
, 0200)) == -1)
199 len
= sprintf(textbuf
,
208 info
->ai_mask
.am_success
,
209 info
->ai_mask
.am_failure
,
210 info
->ai_termid
.at_port
,
211 info
->ai_termid
.at_type
,
212 info
->ai_termid
.at_addr
[0],
213 info
->ai_termid
.at_addr
[1],
214 info
->ai_termid
.at_addr
[2],
215 info
->ai_termid
.at_addr
[3],
218 if (write(fd
, textbuf
, len
) != len
)
219 goto audit_setinfo_clean
;
221 if (fchmod(fd
, 0400) == -1)
222 goto audit_setinfo_clean
;
230 (void) unlink(fname
);
236 audit_cron_make_anc_name(char *fname
)
240 anc_name
= (char *)malloc(strlen(fname
) + strlen(AU_SUFFIX
) + 1);
241 if (anc_name
== NULL
)
244 (void) strcpy(anc_name
, fname
);
245 (void) strcat(anc_name
, AU_SUFFIX
);
250 audit_cron_is_anc_name(char *name
)
254 pos
= strlen(name
) - strlen(AU_SUFFIX
);
258 if (strcmp(name
+ pos
, AU_SUFFIX
) == 0)
265 audit_cron_session_failure(char *name
, int type
, char *err_str
)
270 mess
= dgettext(bsm_dom
,
271 "at-job session for user %s failed: ancillary file: %s");
273 mess
= dgettext(bsm_dom
,
274 "crontab job session for user %s failed: ancillary file: %s");
276 (void) snprintf(textbuf
, sizeof (textbuf
), mess
, name
, err_str
);
278 aug_save_event(AUE_cron_invoke
);
280 aug_save_text(textbuf
);
293 struct auditinfo_addr info
;
295 char *anc_file
, *fname
;
297 char full_path
[PATH_MAX
];
299 if (cannot_audit(0)) {
303 /* get auditinfo from ancillary file */
304 if (at_jobname
== NULL
) {
306 * this is a cron-event, so we can get
307 * filename from "name" arg
311 if (strlen(path
) + strlen(fname
) + 2 > PATH_MAX
) {
312 errno
= ENAMETOOLONG
;
315 (void) strcat(strcat(strcpy(full_path
, path
), "/"),
320 /* this is an at-event, use "at_jobname" */
325 anc_file
= audit_cron_make_anc_name(fname
);
326 if (anc_file
== NULL
) {
329 r
= audit_cron_getinfo(fname
, anc_file
, &info
);
336 if (r
== ANC_BAD_FORMAT
)
337 err_str
= dgettext(bsm_dom
, "bad format");
339 err_str
= strerror(errno
);
341 audit_cron_session_failure(name
,
351 /* get current audit masks */
352 if (au_user_mask(name
, &mask
) == 0) {
353 info
.ai_mask
.am_success
|= mask
.am_success
;
354 info
.ai_mask
.am_failure
|= mask
.am_failure
;
357 /* save audit attributes for further use in current process */
358 aug_save_auid(info
.ai_auid
);
359 aug_save_asid(info
.ai_asid
);
360 aug_save_tid_ex(info
.ai_termid
.at_port
, info
.ai_termid
.at_addr
,
361 info
.ai_termid
.at_type
);
362 aug_save_pid(getpid());
368 /* set mixed audit masks */
369 return (setaudit_addr(&info
, sizeof (info
)));
373 * audit_cron_new_job - create audit record with an information
374 * about new job started by cron.
376 * cmd - command being run by cron daemon.
377 * type - type of job (0 - at-job, 1 - crontab job).
378 * event - not used. pointer to cron event structure.
382 audit_cron_new_job(char *cmd
, int type
, void *event
)
388 (void) snprintf(textbuf
, sizeof (textbuf
),
389 dgettext(bsm_dom
, "at-job"));
390 } else if (type
== 1) {
391 (void) snprintf(textbuf
, sizeof (textbuf
),
392 dgettext(bsm_dom
, "batch-job"));
393 } else if (type
== 2) {
394 (void) snprintf(textbuf
, sizeof (textbuf
),
395 dgettext(bsm_dom
, "crontab-job"));
396 } else if ((type
> 2) && (type
<= 25)) { /* 25 from cron.h */
397 (void) snprintf(textbuf
, sizeof (textbuf
),
398 dgettext(bsm_dom
, "queue-job (%c)"), (type
+'a'));
400 (void) snprintf(textbuf
, sizeof (textbuf
),
401 dgettext(bsm_dom
, "unknown job type (%d)"), type
);
404 aug_save_event(AUE_cron_invoke
);
406 aug_save_text(textbuf
);
412 audit_cron_bad_user(char *name
)
417 (void) snprintf(textbuf
, sizeof (textbuf
),
418 dgettext(bsm_dom
, "bad user %s"), name
);
420 aug_save_event(AUE_cron_invoke
);
422 aug_save_text(textbuf
);
427 audit_cron_user_acct_expired(char *name
)
432 (void) snprintf(textbuf
, sizeof (textbuf
),
434 "user %s account expired"), name
);
436 aug_save_event(AUE_cron_invoke
);
438 aug_save_text(textbuf
);
443 audit_cron_create_anc_file(char *name
, char *path
, char *uname
, uid_t uid
)
449 char full_path
[PATH_MAX
];
458 if (strlen(path
) + strlen(name
) + 2 > PATH_MAX
)
460 (void) strcat(strcat(strcpy(full_path
, path
), "/"), name
);
463 anc_name
= audit_cron_make_anc_name(name
);
465 if (access(anc_name
, F_OK
) != 0) {
466 if (au_user_mask(uname
, &msk
) != 0) {
473 ai
.ai_termid
.at_port
= 0;
474 ai
.ai_termid
.at_type
= AU_IPv4
;
475 ai
.ai_termid
.at_addr
[0] = 0;
476 ai
.ai_termid
.at_addr
[1] = 0;
477 ai
.ai_termid
.at_addr
[2] = 0;
478 ai
.ai_termid
.at_addr
[3] = 0;
479 /* generate new pid to use it as asid */
489 * we need to clear status of children for
490 * wait() call in "cron"
494 (void) waitpid(pid
, &lock
, 0);
497 if (audit_cron_setinfo(anc_name
, &ai
) != 0) {
508 audit_cron_delete_anc_file(char *name
, char *path
)
511 char full_path
[PATH_MAX
];
518 if (strlen(path
) + strlen(name
) + 2 > PATH_MAX
)
520 (void) strcat(strcat(strcpy(full_path
, path
), "/"), name
);
523 anc_name
= audit_cron_make_anc_name(name
);
524 r
= unlink(anc_name
);