Mercurial > illumos > onarm
comparison usr/src/cmd/login/login_audit.c @ 0:c9caec207d52 b86
Initial porting based on b86
author | Koji Uno <koji.uno@sun.com> |
---|---|
date | Tue, 02 Jun 2009 18:56:50 +0900 |
parents | |
children | 1a15d5aaf794 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:c9caec207d52 |
---|---|
1 /* | |
2 * CDDL HEADER START | |
3 * | |
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. | |
7 * | |
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. | |
12 * | |
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] | |
18 * | |
19 * CDDL HEADER END | |
20 */ | |
21 /* | |
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. | |
23 * Use is subject to license terms. | |
24 */ | |
25 | |
26 #pragma ident "@(#)login_audit.c 1.4 06/11/02 SMI" | |
27 | |
28 #include <assert.h> | |
29 #include <priv.h> | |
30 #include <pwd.h> | |
31 #include <signal.h> | |
32 #include <stdlib.h> | |
33 #include <string.h> | |
34 #include <syslog.h> | |
35 #include <unistd.h> | |
36 #include <sys/wait.h> | |
37 | |
38 #include <bsm/adt.h> | |
39 #include <bsm/adt_event.h> | |
40 #include "login_audit.h" | |
41 | |
42 /* | |
43 * Key assumption: login is single threaded. | |
44 */ | |
45 static void audit_logout(adt_session_data_t *); | |
46 | |
47 /* | |
48 * if audit is not enabled, the adt_*() functions simply return without | |
49 * doing anything. In the success case, the credential has already been | |
50 * setup with audit data by PAM. | |
51 */ | |
52 | |
53 /* | |
54 * There is no information passed to login.c from rlogin or telnet | |
55 * about the terminal id. They both set the tid before they | |
56 * exec login; the value is picked up by adt_start_session() and is | |
57 * carefully *not* overwritten by adt_load_hostname(). | |
58 */ | |
59 | |
60 void | |
61 audit_success(uint_t event_id, struct passwd *pwd, char *optional_text) | |
62 { | |
63 adt_session_data_t *ah; | |
64 adt_event_data_t *event; | |
65 int rc; | |
66 | |
67 assert(pwd != NULL); | |
68 | |
69 if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA)) { | |
70 syslog(LOG_AUTH | LOG_ALERT, "login adt_start_session(): %m"); | |
71 return; | |
72 } | |
73 if (adt_set_user(ah, pwd->pw_uid, pwd->pw_gid, | |
74 pwd->pw_uid, pwd->pw_gid, NULL, ADT_USER)) { | |
75 syslog(LOG_AUTH | LOG_ALERT, "login adt_set_user(): %m"); | |
76 (void) adt_end_session(ah); | |
77 return; | |
78 } | |
79 event = adt_alloc_event(ah, event_id); | |
80 | |
81 if (event == NULL) | |
82 return; | |
83 | |
84 switch (event_id) { | |
85 case ADT_zlogin: | |
86 event->adt_zlogin.message = optional_text; | |
87 break; | |
88 default: | |
89 break; | |
90 } | |
91 rc = adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS); | |
92 | |
93 (void) adt_free_event(event); | |
94 if (rc) { | |
95 (void) adt_end_session(ah); | |
96 syslog(LOG_AUTH | LOG_ALERT, "login adt_put_event(): %m"); | |
97 return; | |
98 } | |
99 /* | |
100 * The code above executes whether or not audit is enabled. | |
101 * However audit_logout must only execute if audit is | |
102 * enabled so we don't fork unnecessarily. | |
103 */ | |
104 if (adt_audit_enabled()) { | |
105 switch (event_id) { | |
106 case ADT_login: | |
107 case ADT_rlogin: | |
108 case ADT_telnet: | |
109 case ADT_zlogin: | |
110 audit_logout(ah); /* fork to catch logout */ | |
111 break; | |
112 } | |
113 } | |
114 (void) adt_end_session(ah); | |
115 } | |
116 | |
117 /* | |
118 * errors are ignored since there is no action to take on error | |
119 */ | |
120 static void | |
121 audit_logout(adt_session_data_t *ah) | |
122 { | |
123 adt_event_data_t *logout; | |
124 int status; /* wait status */ | |
125 pid_t pid; | |
126 priv_set_t *priv; /* waiting process privs */ | |
127 | |
128 if ((logout = adt_alloc_event(ah, ADT_logout)) == NULL) { | |
129 syslog(LOG_AUTH | LOG_ALERT, | |
130 "adt_alloc_event(ADT_logout): %m"); | |
131 return; | |
132 } | |
133 if ((priv = priv_allocset()) == NULL) { | |
134 syslog(LOG_AUTH | LOG_ALERT, | |
135 "login audit_logout: could not alloc privs: %m"); | |
136 adt_free_event(logout); | |
137 return; | |
138 } | |
139 | |
140 /* | |
141 * The child returns and continues the login processing. | |
142 * The parent's sole job is to wait for child exit, write the | |
143 * logout audit record, and replay the child's exit code. | |
144 */ | |
145 | |
146 if ((pid = fork()) == 0) { | |
147 /* child */ | |
148 | |
149 adt_free_event(logout); | |
150 priv_freeset(priv); | |
151 return; | |
152 } | |
153 if (pid == -1) { | |
154 /* failure */ | |
155 | |
156 syslog(LOG_AUTH | LOG_ALERT, | |
157 "login audit_logout: could not fork: %m"); | |
158 adt_free_event(logout); | |
159 priv_freeset(priv); | |
160 return; | |
161 } | |
162 | |
163 /* parent process */ | |
164 | |
165 /* | |
166 * When this routine is called, the current working | |
167 * directory is the user's home directory and there are | |
168 * unknown open files. For the waiting process, change the | |
169 * current directory to root and close files so that the | |
170 * user's home directory and anything else can be unmounted | |
171 * if necessary. | |
172 */ | |
173 if (chdir("/") != 0) { | |
174 syslog(LOG_AUTH | LOG_ALERT, | |
175 "login audit_logut: could not chdir /: %m"); | |
176 } | |
177 /* | |
178 * Reduce privileges to just those needed. | |
179 */ | |
180 priv_emptyset(priv); | |
181 if ((priv_addset(priv, PRIV_PROC_AUDIT) != 0) || | |
182 (setppriv(PRIV_SET, PRIV_PERMITTED, priv) != 0)) { | |
183 syslog(LOG_AUTH | LOG_ALERT, | |
184 "login audit_logout: could not reduce privs: %m"); | |
185 } | |
186 closefrom(0); | |
187 priv_freeset(priv); | |
188 while (pid != waitpid(pid, &status, 0)) | |
189 continue; | |
190 | |
191 (void) adt_put_event(logout, ADT_SUCCESS, ADT_SUCCESS); | |
192 adt_free_event(logout); | |
193 (void) adt_end_session(ah); | |
194 exit(WEXITSTATUS(status)); | |
195 } | |
196 | |
197 /* | |
198 * errors are ignored since there is no action to take on error. | |
199 * | |
200 * If the user id is invalid, pwd is NULL. | |
201 */ | |
202 void | |
203 audit_failure(uint_t event_id, int failure_code, struct passwd *pwd, | |
204 const char *hostname, const char *ttyname, char *optional_text) | |
205 { | |
206 adt_session_data_t *ah; | |
207 adt_event_data_t *event; | |
208 uid_t uid; | |
209 gid_t gid; | |
210 adt_termid_t *p_tid; | |
211 | |
212 if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA)) | |
213 return; | |
214 | |
215 uid = ADT_NO_ATTRIB; | |
216 gid = ADT_NO_ATTRIB; | |
217 if (pwd != NULL) { | |
218 uid = pwd->pw_uid; | |
219 gid = pwd->pw_gid; | |
220 } | |
221 /* | |
222 * If this is a remote login, in.rlogind or in.telnetd has | |
223 * already set the terminal id, in which case | |
224 * adt_load_hostname() will use the preset terminal id and | |
225 * ignore hostname. (If no remote host and ttyname is NULL, | |
226 * let adt_load_ttyname() figure out what to do.) | |
227 */ | |
228 if (*hostname == '\0') | |
229 (void) adt_load_ttyname(ttyname, &p_tid); | |
230 else | |
231 (void) adt_load_hostname(hostname, &p_tid); | |
232 | |
233 if (adt_set_user(ah, uid, gid, uid, gid, p_tid, ADT_NEW)) { | |
234 (void) adt_end_session(ah); | |
235 if (p_tid != NULL) | |
236 free(p_tid); | |
237 return; | |
238 } | |
239 if (p_tid != NULL) | |
240 free(p_tid); | |
241 | |
242 event = adt_alloc_event(ah, event_id); | |
243 if (event == NULL) { | |
244 return; | |
245 } | |
246 switch (event_id) { | |
247 case ADT_zlogin: | |
248 event->adt_zlogin.message = optional_text; | |
249 break; | |
250 } | |
251 (void) adt_put_event(event, ADT_FAILURE, failure_code); | |
252 | |
253 adt_free_event(event); | |
254 (void) adt_end_session(ah); | |
255 } |