dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / libbsm / common / audit_cron.c
blob50258abb70420f4997c21a1989bf08050650c064
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 struct passwd *result;
97 int ret;
98 static char *msg =
99 "Used defaults instead of ancilary audit file";
101 if ((fd = open(fname_aux, O_RDONLY)) == -1) {
102 /* no syslog here; common case */
103 goto make_it_up;
105 if (fstat(fd, &st) == -1) {
106 /* no syslog here either; common case */
107 goto delete_first;
110 if (read(fd, textbuf, st.st_size) != st.st_size) {
111 audit_cron_syslog(msg);
112 goto delete_first;
115 if (sscanf(textbuf,
116 F_AUID
117 F_SMASK
118 F_FMASK
119 F_PORT
120 F_TYPE
121 F_MACH
122 F_ASID,
123 &(info->ai_auid),
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);
134 goto delete_first;
136 (void) close(fd);
137 return (0);
139 delete_first:
140 (void) close(fd);
141 if (unlink(fname_aux)) {
142 if (errno != ENOENT)
143 audit_cron_syslog(
144 "Failed to remove invalid ancilary audit file");
146 /* intentionally falls through */
148 make_it_up:
149 if (stat(fname, &st))
150 return (-1);
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);
165 if (!result)
166 return (ret);
167 } else {
168 ret = getpwuid_r(st.st_uid, &pwd, pwd_buff, sizeof (pwd_buff),
169 &result);
170 if (!result)
171 return (ret);
174 info->ai_auid = pwd.pw_uid;
176 if (au_user_mask(pwd.pw_name, &mask)) {
177 errno = EINVAL; /* pw_name lookup failed */
178 return (-1);
180 info->ai_mask.am_success = mask.am_success;
181 info->ai_mask.am_failure = mask.am_failure;
183 return (0);
187 audit_cron_setinfo(char *fname, struct auditinfo_addr *info)
189 int fd, len, r;
190 int save_err;
192 r = chmod(fname, 0200);
193 if (r == -1 && errno != ENOENT)
194 return (-1);
196 if ((fd = open(fname, O_CREAT|O_WRONLY|O_TRUNC, 0200)) == -1)
197 return (-1);
199 len = sprintf(textbuf,
200 F_AUID
201 F_SMASK
202 F_FMASK
203 F_PORT
204 F_TYPE
205 F_MACH
206 F_ASID,
207 info->ai_auid,
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],
216 info->ai_asid);
218 if (write(fd, textbuf, len) != len)
219 goto audit_setinfo_clean;
221 if (fchmod(fd, 0400) == -1)
222 goto audit_setinfo_clean;
224 (void) close(fd);
225 return (0);
227 audit_setinfo_clean:
228 save_err = errno;
229 (void) close(fd);
230 (void) unlink(fname);
231 errno = save_err;
232 return (-1);
235 char *
236 audit_cron_make_anc_name(char *fname)
238 char *anc_name;
240 anc_name = (char *)malloc(strlen(fname) + strlen(AU_SUFFIX) + 1);
241 if (anc_name == NULL)
242 return (NULL);
244 (void) strcpy(anc_name, fname);
245 (void) strcat(anc_name, AU_SUFFIX);
246 return (anc_name);
250 audit_cron_is_anc_name(char *name)
252 int pos;
254 pos = strlen(name) - strlen(AU_SUFFIX);
255 if (pos <= 0)
256 return (0);
258 if (strcmp(name + pos, AU_SUFFIX) == 0)
259 return (1);
261 return (0);
264 static void
265 audit_cron_session_failure(char *name, int type, char *err_str)
267 const char *mess;
269 if (type == 0)
270 mess = dgettext(bsm_dom,
271 "at-job session for user %s failed: ancillary file: %s");
272 else
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);
279 aug_save_sorf(4);
280 aug_save_text(textbuf);
281 (void) aug_audit();
286 audit_cron_session(
287 char *name,
288 char *path,
289 uid_t uid,
290 gid_t gid,
291 char *at_jobname)
293 struct auditinfo_addr info;
294 au_mask_t mask;
295 char *anc_file, *fname;
296 int r = 0;
297 char full_path[PATH_MAX];
299 if (cannot_audit(0)) {
300 return (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
309 fname = name;
310 if (path != NULL) {
311 if (strlen(path) + strlen(fname) + 2 > PATH_MAX) {
312 errno = ENAMETOOLONG;
313 r = -1;
315 (void) strcat(strcat(strcpy(full_path, path), "/"),
316 fname);
317 fname = full_path;
319 } else {
320 /* this is an at-event, use "at_jobname" */
321 fname = at_jobname;
324 if (r == 0) {
325 anc_file = audit_cron_make_anc_name(fname);
326 if (anc_file == NULL) {
327 r = -1;
328 } else {
329 r = audit_cron_getinfo(fname, anc_file, &info);
333 if (r != 0) {
334 char *err_str;
336 if (r == ANC_BAD_FORMAT)
337 err_str = dgettext(bsm_dom, "bad format");
338 else
339 err_str = strerror(errno);
341 audit_cron_session_failure(name,
342 at_jobname == NULL,
343 err_str);
344 free(anc_file);
345 return (r);
348 free(anc_file);
349 aug_init();
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());
363 aug_save_uid(uid);
364 aug_save_gid(gid);
365 aug_save_euid(uid);
366 aug_save_egid(gid);
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.
375 * args:
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.
380 /*ARGSUSED*/
381 void
382 audit_cron_new_job(char *cmd, int type, void *event)
384 if (cannot_audit(0))
385 return;
387 if (type == 0) {
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'));
399 } else {
400 (void) snprintf(textbuf, sizeof (textbuf),
401 dgettext(bsm_dom, "unknown job type (%d)"), type);
404 aug_save_event(AUE_cron_invoke);
405 aug_save_sorf(0);
406 aug_save_text(textbuf);
407 aug_save_text1(cmd);
408 (void) aug_audit();
411 void
412 audit_cron_bad_user(char *name)
414 if (cannot_audit(0))
415 return;
417 (void) snprintf(textbuf, sizeof (textbuf),
418 dgettext(bsm_dom, "bad user %s"), name);
420 aug_save_event(AUE_cron_invoke);
421 aug_save_sorf(2);
422 aug_save_text(textbuf);
423 (void) aug_audit();
426 void
427 audit_cron_user_acct_expired(char *name)
429 if (cannot_audit(0))
430 return;
432 (void) snprintf(textbuf, sizeof (textbuf),
433 dgettext(bsm_dom,
434 "user %s account expired"), name);
436 aug_save_event(AUE_cron_invoke);
437 aug_save_sorf(3);
438 aug_save_text(textbuf);
439 (void) aug_audit();
443 audit_cron_create_anc_file(char *name, char *path, char *uname, uid_t uid)
445 au_mask_t msk;
446 auditinfo_addr_t ai;
447 int pid;
448 char *anc_name;
449 char full_path[PATH_MAX];
451 if (cannot_audit(0))
452 return (0);
454 if (name == NULL)
455 return (0);
457 if (path != NULL) {
458 if (strlen(path) + strlen(name) + 2 > PATH_MAX)
459 return (-1);
460 (void) strcat(strcat(strcpy(full_path, path), "/"), name);
461 name = full_path;
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) {
467 free(anc_name);
468 return (-1);
471 ai.ai_mask = msk;
472 ai.ai_auid = uid;
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 */
480 pid = vfork();
481 if (pid == -1) {
482 free(anc_name);
483 return (-1);
485 if (pid == 0)
486 exit(0);
487 else {
489 * we need to clear status of children for
490 * wait() call in "cron"
492 int lock;
494 (void) waitpid(pid, &lock, 0);
496 ai.ai_asid = pid;
497 if (audit_cron_setinfo(anc_name, &ai) != 0) {
498 free(anc_name);
499 return (-1);
503 free(anc_name);
504 return (0);
508 audit_cron_delete_anc_file(char *name, char *path)
510 char *anc_name;
511 char full_path[PATH_MAX];
512 int r;
514 if (name == NULL)
515 return (0);
517 if (path != NULL) {
518 if (strlen(path) + strlen(name) + 2 > PATH_MAX)
519 return (-1);
520 (void) strcat(strcat(strcpy(full_path, path), "/"), name);
521 name = full_path;
523 anc_name = audit_cron_make_anc_name(name);
524 r = unlink(anc_name);
525 free(anc_name);
526 return (r);