8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / lib / libbsm / common / audit_cron.c
blob106e28a9466f338962c7a63c22ec3ce31f2e3143
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
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>
32 #include <unistd.h>
33 #include <wait.h>
34 #include <fcntl.h>
35 #include <pwd.h>
36 #include <string.h>
37 #include <stdlib.h>
38 #include <errno.h>
39 #include <syslog.h>
40 #include <sys/stat.h>
41 #include <sys/socket.h>
42 #include <netinet/in.h>
43 #include <arpa/inet.h>
44 #include <libgen.h>
46 #include <locale.h>
47 #include "generic.h"
49 #define F_AUID "%u\n"
50 #define F_SMASK "%x\n"
51 #define F_FMASK "%x\n"
52 #define F_PORT "%lx\n"
53 #define F_TYPE "%x\n"
54 #define F_MACH "%x %x %x %x\n"
55 #define F_ASID "%u\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];
65 int
66 audit_cron_mode()
68 return (!cannot_audit(0));
71 static void
72 audit_cron_syslog(const char *message) {
73 static int is_open = 0;
75 if (!is_open) {
76 openlog("Solaris_Audit", LOG_ODELAY, LOG_CRON);
77 is_open = 1;
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
85 * or atjob uid.
88 static int
89 audit_cron_getinfo(char *fname, char *fname_aux, struct auditinfo_addr *info)
91 int fd;
92 struct stat st;
93 au_mask_t mask;
94 struct passwd pwd;
95 char pwd_buff[1024];
96 static char *msg =
97 "Used defaults instead of ancilary audit file";
99 if ((fd = open(fname_aux, O_RDONLY)) == -1) {
100 /* no syslog here; common case */
101 goto make_it_up;
103 if (fstat(fd, &st) == -1) {
104 /* no syslog here either; common case */
105 goto delete_first;
108 if (read(fd, textbuf, st.st_size) != st.st_size) {
109 audit_cron_syslog(msg);
110 goto delete_first;
113 if (sscanf(textbuf,
114 F_AUID
115 F_SMASK
116 F_FMASK
117 F_PORT
118 F_TYPE
119 F_MACH
120 F_ASID,
121 &(info->ai_auid),
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);
132 goto delete_first;
134 (void) close(fd);
135 return (0);
137 delete_first:
138 (void) close(fd);
139 if (unlink(fname_aux)) {
140 if (errno != ENOENT)
141 audit_cron_syslog(
142 "Failed to remove invalid ancilary audit file");
144 /* intentionally falls through */
146 make_it_up:
147 if (stat(fname, &st))
148 return (-1);
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 */
164 } else {
165 if (getpwuid_r(st.st_uid, &pwd, pwd_buff, sizeof (pwd_buff)) ==
166 NULL)
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 */
174 return (-1);
176 info->ai_mask.am_success = mask.am_success;
177 info->ai_mask.am_failure = mask.am_failure;
179 return (0);
183 audit_cron_setinfo(char *fname, struct auditinfo_addr *info)
185 int fd, len, r;
186 int save_err;
188 r = chmod(fname, 0200);
189 if (r == -1 && errno != ENOENT)
190 return (-1);
192 if ((fd = open(fname, O_CREAT|O_WRONLY|O_TRUNC, 0200)) == -1)
193 return (-1);
195 len = sprintf(textbuf,
196 F_AUID
197 F_SMASK
198 F_FMASK
199 F_PORT
200 F_TYPE
201 F_MACH
202 F_ASID,
203 info->ai_auid,
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],
212 info->ai_asid);
214 if (write(fd, textbuf, len) != len)
215 goto audit_setinfo_clean;
217 if (fchmod(fd, 0400) == -1)
218 goto audit_setinfo_clean;
220 (void) close(fd);
221 return (0);
223 audit_setinfo_clean:
224 save_err = errno;
225 (void) close(fd);
226 (void) unlink(fname);
227 errno = save_err;
228 return (-1);
231 char *
232 audit_cron_make_anc_name(char *fname)
234 char *anc_name;
236 anc_name = (char *)malloc(strlen(fname) + strlen(AU_SUFFIX) + 1);
237 if (anc_name == NULL)
238 return (NULL);
240 (void) strcpy(anc_name, fname);
241 (void) strcat(anc_name, AU_SUFFIX);
242 return (anc_name);
246 audit_cron_is_anc_name(char *name)
248 int pos;
250 pos = strlen(name) - strlen(AU_SUFFIX);
251 if (pos <= 0)
252 return (0);
254 if (strcmp(name + pos, AU_SUFFIX) == 0)
255 return (1);
257 return (0);
260 static void
261 audit_cron_session_failure(char *name, int type, char *err_str)
263 const char *mess;
265 if (type == 0)
266 mess = dgettext(bsm_dom,
267 "at-job session for user %s failed: ancillary file: %s");
268 else
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);
275 aug_save_sorf(4);
276 aug_save_text(textbuf);
277 (void) aug_audit();
282 audit_cron_session(
283 char *name,
284 char *path,
285 uid_t uid,
286 gid_t gid,
287 char *at_jobname)
289 struct auditinfo_addr info;
290 au_mask_t mask;
291 char *anc_file, *fname;
292 int r = 0;
293 char full_path[PATH_MAX];
295 if (cannot_audit(0)) {
296 return (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
305 fname = name;
306 if (path != NULL) {
307 if (strlen(path) + strlen(fname) + 2 > PATH_MAX) {
308 errno = ENAMETOOLONG;
309 r = -1;
311 (void) strcat(strcat(strcpy(full_path, path), "/"),
312 fname);
313 fname = full_path;
315 } else {
316 /* this is an at-event, use "at_jobname" */
317 fname = at_jobname;
320 if (r == 0) {
321 anc_file = audit_cron_make_anc_name(fname);
322 if (anc_file == NULL) {
323 r = -1;
324 } else {
325 r = audit_cron_getinfo(fname, anc_file, &info);
329 if (r != 0) {
330 char *err_str;
332 if (r == ANC_BAD_FORMAT)
333 err_str = dgettext(bsm_dom, "bad format");
334 else
335 err_str = strerror(errno);
337 audit_cron_session_failure(name,
338 at_jobname == NULL,
339 err_str);
340 if (anc_file != NULL)
341 free(anc_file);
342 return (r);
345 free(anc_file);
346 aug_init();
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());
360 aug_save_uid(uid);
361 aug_save_gid(gid);
362 aug_save_euid(uid);
363 aug_save_egid(gid);
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.
372 * args:
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.
377 /*ARGSUSED*/
378 void
379 audit_cron_new_job(char *cmd, int type, void *event)
381 if (cannot_audit(0))
382 return;
384 if (type == 0) {
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'));
396 } else {
397 (void) snprintf(textbuf, sizeof (textbuf),
398 dgettext(bsm_dom, "unknown job type (%d)"), type);
401 aug_save_event(AUE_cron_invoke);
402 aug_save_sorf(0);
403 aug_save_text(textbuf);
404 aug_save_text1(cmd);
405 (void) aug_audit();
408 void
409 audit_cron_bad_user(char *name)
411 if (cannot_audit(0))
412 return;
414 (void) snprintf(textbuf, sizeof (textbuf),
415 dgettext(bsm_dom, "bad user %s"), name);
417 aug_save_event(AUE_cron_invoke);
418 aug_save_sorf(2);
419 aug_save_text(textbuf);
420 (void) aug_audit();
423 void
424 audit_cron_user_acct_expired(char *name)
426 if (cannot_audit(0))
427 return;
429 (void) snprintf(textbuf, sizeof (textbuf),
430 dgettext(bsm_dom,
431 "user %s account expired"), name);
433 aug_save_event(AUE_cron_invoke);
434 aug_save_sorf(3);
435 aug_save_text(textbuf);
436 (void) aug_audit();
440 audit_cron_create_anc_file(char *name, char *path, char *uname, uid_t uid)
442 au_mask_t msk;
443 auditinfo_addr_t ai;
444 int pid;
445 char *anc_name;
446 char full_path[PATH_MAX];
448 if (cannot_audit(0))
449 return (0);
451 if (name == NULL)
452 return (0);
454 if (path != NULL) {
455 if (strlen(path) + strlen(name) + 2 > PATH_MAX)
456 return (-1);
457 (void) strcat(strcat(strcpy(full_path, path), "/"), name);
458 name = full_path;
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) {
464 free(anc_name);
465 return (-1);
468 ai.ai_mask = msk;
469 ai.ai_auid = uid;
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 */
477 pid = vfork();
478 if (pid == -1) {
479 free(anc_name);
480 return (-1);
482 if (pid == 0)
483 exit(0);
484 else {
486 * we need to clear status of children for
487 * wait() call in "cron"
489 int lock;
491 (void) waitpid(pid, &lock, 0);
493 ai.ai_asid = pid;
494 if (audit_cron_setinfo(anc_name, &ai) != 0) {
495 free(anc_name);
496 return (-1);
500 free(anc_name);
501 return (0);
505 audit_cron_delete_anc_file(char *name, char *path)
507 char *anc_name;
508 char full_path[PATH_MAX];
509 int r;
511 if (name == NULL)
512 return (0);
514 if (path != NULL) {
515 if (strlen(path) + strlen(name) + 2 > PATH_MAX)
516 return (-1);
517 (void) strcat(strcat(strcpy(full_path, path), "/"), name);
518 name = full_path;
520 anc_name = audit_cron_make_anc_name(name);
521 r = unlink(anc_name);
522 free(anc_name);
523 return (r);