4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 * Copyright (c) 2016 by Delphix. All rights reserved.
27 #pragma ident "%Z%%M% %I% %E% SMI"
29 #include <sys/types.h>
31 #include <sys/systeminfo.h>
32 #include <bsm/audit.h>
33 #include <bsm/libbsm.h>
34 #include <bsm/audit_uevents.h>
35 #include <bsm/audit_private.h>
44 #define AUDIT_GET_DIFFS_NO_CRONTAB 1
45 #define AUDIT_GET_DIFFS_CRONTAB 0
46 #define AUDIT_GET_DIFFS_ERR -1
47 #define AUDIT_GET_DIFFS_NO_DIFFS -2
49 static int audit_crontab_get_diffs(char *cf
, char *tmp_name
,
53 audit_crontab_modify(char *path
, char *tmp_path
, int sorf
)
58 if (cannot_audit(0)) {
65 if (getaudit_addr(&ai
, sizeof (ai
))) {
69 r
= audit_crontab_get_diffs(path
, tmp_path
, &diffs
);
71 if (r
== AUDIT_GET_DIFFS_NO_DIFFS
) {
74 if (diffs
!= NULL
&& r
!= AUDIT_GET_DIFFS_ERR
) {
79 if (r
== AUDIT_GET_DIFFS_NO_CRONTAB
) {
86 * create an ancilary file if audit characteristics exist
87 * else delete an ancilary if if one exists
90 anc_name
= audit_cron_make_anc_name(path
);
93 else if (audit_crontab_process_not_audited()) {
94 (void) unlink(anc_name
);
97 r
= audit_cron_setinfo(anc_name
, &ai
);
101 aug_save_auid(ai
.ai_auid
);
102 aug_save_euid(geteuid());
103 aug_save_egid(getegid());
104 aug_save_uid(getuid());
105 aug_save_gid(getgid());
106 aug_save_pid(getpid());
107 aug_save_asid(ai
.ai_asid
);
108 aug_save_tid_ex(ai
.ai_termid
.at_port
, ai
.ai_termid
.at_addr
,
109 ai
.ai_termid
.at_type
);
113 event
= (create
) ? AUE_crontab_create
: AUE_crontab_mod
;
114 aug_save_event(event
);
117 if (aug_audit() != 0)
124 audit_crontab_delete(char *path
, int sorf
)
128 if (cannot_audit(0)) {
132 anc_name
= audit_cron_make_anc_name(path
);
133 if (anc_name
!= NULL
) {
134 r
= unlink(anc_name
);
140 (void) aug_save_me();
143 aug_save_event(AUE_crontab_delete
);
145 if (aug_audit() != 0)
152 * gets differences between old and new crontab files.
154 * cf - name of crontab file
155 * tmp_name - name of new crontab file
156 * bufptr - pointer to an array of characters with
157 * either an error message or an output of "diff" command.
160 * AUDIT_GET_DIFFS_ERR - errors;
161 * file not exists (do not free *bufptr in this case)
162 * AUDIT_GET_DIFFS_NO_DIFFS - errors;
163 * file exists (do not free *bufptr in this case)
164 * AUDIT_GET_DIFFS_CRONTAB - OK, old crontab file exists.
165 * AUDIT_GET_DIFFS_NO_CRONTAB - OK. there is no crontab file.
168 audit_crontab_get_diffs(char *cf
, char *tmp_name
, char **bufptr
)
170 struct stat st
, st_tmp
;
172 int len
, r
= AUDIT_GET_DIFFS_CRONTAB
;
173 char *buf
= NULL
, err_buf
[128];
175 (void) memset(err_buf
, 0, 128);
177 if (seteuid(0) == -1) {
178 r
= AUDIT_GET_DIFFS_ERR
;
179 (void) snprintf(err_buf
, sizeof (err_buf
),
180 "crontab: seteuid: %s\n", strerror(errno
));
183 if (stat(cf
, &st
) == -1) {
184 if (errno
== ENOENT
) {
185 r
= AUDIT_GET_DIFFS_NO_CRONTAB
;
187 r
= AUDIT_GET_DIFFS_ERR
;
188 (void) snprintf(err_buf
, sizeof (err_buf
),
189 "crontab: %s: stat: %s\n",
190 cf
, strerror(errno
));
197 if (stat(tmp_name
, &st_tmp
) == -1) {
198 r
= AUDIT_GET_DIFFS_ERR
;
199 (void) snprintf(err_buf
, sizeof (err_buf
),
200 "crontab: %s: stat: %s\n",
201 tmp_name
, strerror(errno
));
205 if (st_tmp
.st_size
== 0 && len
== 0) {
206 /* there is no difference */
207 r
= AUDIT_GET_DIFFS_NO_DIFFS
;
213 /* return information on create or update crontab */
214 (void) seteuid(euid
);
216 case AUDIT_GET_DIFFS_ERR
:
221 case AUDIT_GET_DIFFS_NO_DIFFS
:
226 case AUDIT_GET_DIFFS_CRONTAB
:
228 if (strlen(buf
) != 0) {
231 r
= AUDIT_GET_DIFFS_NO_DIFFS
;
236 case AUDIT_GET_DIFFS_NO_CRONTAB
:
238 if (strlen(buf
) != 0) {
252 * audit_crontab_not_allowed determines if we have a case that should be audited
253 * but we can't. If auditing is enabled but the current process is not
254 * audited, then the ruid of the user doing the editing must be the owner
255 * id of the file to be edited.
257 * When audit_crontab_not_allowed is called, ruid is for the crontab file
258 * to be modified or created.
261 #define PWD_BUFFER_SIZE 512
264 audit_crontab_not_allowed(uid_t ruid
, char *user
) {
266 char buffer
[PWD_BUFFER_SIZE
];
267 int rc
= 0; /* 0 == allow */
269 if (!cannot_audit(0)) { /* allow access if audit off */
270 if (getpwnam_r(user
, &pwd
, buffer
, PWD_BUFFER_SIZE
) == NULL
) {
271 rc
= 1; /* deny access if invalid */
272 } else if (ruid
== pwd
.pw_uid
)
273 rc
= 0; /* editing their own crontab */
275 rc
= audit_crontab_process_not_audited();
281 audit_crontab_process_not_audited() {
282 struct auditpinfo_addr info
;
285 info
.ap_pid
= getpid();
286 if (auditon(A_GETPINFO_ADDR
, (caddr_t
)&info
, sizeof (info
)) != 0)
287 rc
= 0; /* audit failure: not enabled */
289 rc
= (info
.ap_auid
== AU_NOAUDITID
);