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]
23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 #include <auth_attr.h>
29 #include <auth_list.h>
31 #include <bsm/adt_event.h>
39 #include <sys/param.h>
40 #include <sys/types.h>
46 #include "libnwam_impl.h"
47 #include <libnwam_priv.h>
51 * Communicate with and implement library backend (running in netcfgd) to
52 * retrieve or change NWAM configuration.
55 static int backend_door_client_fd
= -1;
58 * Check if uid has proper auths. flags is used to check auths for
59 * enable/disable of profiles and manipulation of Known WLANs.
62 nwam_check_auths(uid_t uid
, boolean_t write
, uint64_t flags
)
65 nwam_error_t err
= NWAM_SUCCESS
;
67 if ((pwd
= getpwuid(uid
)) == NULL
) {
69 return (NWAM_PERMISSION_DENIED
);
72 if (flags
& NWAM_FLAG_ENTITY_ENABLE
) {
73 /* Enabling/disabling profile - need SELECT auth */
74 if (chkauthattr(AUTOCONF_SELECT_AUTH
, pwd
->pw_name
) == 0)
75 err
= NWAM_PERMISSION_DENIED
;
77 } else if (flags
& NWAM_FLAG_ENTITY_KNOWN_WLAN
) {
78 /* Known WLAN activity - need WLAN auth */
79 if (chkauthattr(AUTOCONF_WLAN_AUTH
, pwd
->pw_name
) == 0)
80 err
= NWAM_PERMISSION_DENIED
;
84 * First, check for WRITE, since it implies READ. If this
85 * auth is not present, and write is true, fail, otherwise
88 if (chkauthattr(AUTOCONF_WRITE_AUTH
, pwd
->pw_name
) == 0) {
90 err
= NWAM_PERMISSION_DENIED
;
92 if (chkauthattr(AUTOCONF_READ_AUTH
,
94 err
= NWAM_PERMISSION_DENIED
;
104 nwam_create_backend_door_arg(nwam_backend_door_cmd_t cmd
,
105 const char *dbname
, const char *objname
, uint64_t flags
,
106 void *obj
, nwam_backend_door_arg_t
*arg
)
113 case NWAM_BACKEND_DOOR_CMD_READ_REQ
:
115 * For a read request, we want the full buffer to be
116 * available for the backend door to write to.
118 datalen
= NWAM_BACKEND_DOOR_ARG_SIZE
;
121 case NWAM_BACKEND_DOOR_CMD_UPDATE_REQ
:
123 * An update request may either specify an object list
124 * (which we pack into the buffer immediately after the
125 * backend door request) or may not specify an object
126 * (signifying a request to create the container of the
133 /* Data immediately follows the descriptor */
134 dataptr
= (caddr_t
)arg
+ sizeof (nwam_backend_door_arg_t
);
135 datalen
= NWAM_BACKEND_DOOR_ARG_SIZE
;
136 /* pack object list for update request, adjusting datalen */
137 if ((err
= nwam_pack_object_list(obj
, (char **)&dataptr
,
138 &datalen
)) != NWAM_SUCCESS
)
142 case NWAM_BACKEND_DOOR_CMD_REMOVE_REQ
:
143 /* A remove request has no associated object list. */
148 return (NWAM_INVALID_ARG
);
151 arg
->nwbda_cmd
= cmd
;
152 arg
->nwbda_flags
= flags
;
153 arg
->nwbda_datalen
= datalen
;
154 arg
->nwbda_result
= NWAM_SUCCESS
;
157 (void) strlcpy(arg
->nwbda_dbname
, dbname
, MAXPATHLEN
);
159 arg
->nwbda_dbname
[0] = '\0';
162 (void) strlcpy(arg
->nwbda_object
, objname
, NWAM_MAX_NAME_LEN
);
164 arg
->nwbda_object
[0] = '\0';
166 return (NWAM_SUCCESS
);
170 * If the arg datalen is non-zero, unpack the object list associated with
171 * the backend door argument.
174 nwam_read_object_from_backend_door_arg(nwam_backend_door_arg_t
*arg
,
175 char *dbname
, char *name
, void *objp
)
178 caddr_t dataptr
= (caddr_t
)arg
+ sizeof (nwam_backend_door_arg_t
);
180 if (arg
->nwbda_result
!= NWAM_SUCCESS
)
181 return (arg
->nwbda_result
);
183 if (arg
->nwbda_datalen
> 0) {
184 if ((err
= nwam_unpack_object_list((char *)dataptr
,
185 arg
->nwbda_datalen
, objp
)) != NWAM_SUCCESS
)
188 *((char **)objp
) = NULL
;
192 * If "dbname" and "name" are non-NULL, copy in the actual dbname
193 * and name values from the door arg since both may have been changed
194 * from case-insensitive to case-sensitive matches. They will be the
195 * same length as they only differ in case.
197 if (dbname
!= NULL
&& strcmp(dbname
, arg
->nwbda_dbname
) != 0)
198 (void) strlcpy(dbname
, arg
->nwbda_dbname
, strlen(dbname
) + 1);
199 if (name
!= NULL
&& strcmp(name
, arg
->nwbda_object
) != 0)
200 (void) strlcpy(name
, arg
->nwbda_object
, strlen(name
) + 1);
202 return (NWAM_SUCCESS
);
207 nwam_backend_door_server(void *cookie
, char *arg
, size_t arg_size
,
208 door_desc_t
*dp
, uint_t ndesc
)
210 /* LINTED: alignment */
211 nwam_backend_door_arg_t
*req
= (nwam_backend_door_arg_t
*)arg
;
213 void *obj
, *newobj
= NULL
;
216 boolean_t write
= B_TRUE
;
219 if (arg_size
< sizeof (nwam_backend_door_arg_t
)) {
220 req
->nwbda_result
= NWAM_INVALID_ARG
;
221 (void) door_return((char *)req
,
222 sizeof (nwam_backend_door_arg_t
), NULL
, 0);
225 if (door_ucred(&ucr
) != 0) {
226 req
->nwbda_result
= NWAM_ERROR_INTERNAL
;
227 (void) door_return((char *)req
, arg_size
, NULL
, 0);
231 uid
= ucred_getruid(ucr
);
233 if (req
->nwbda_cmd
== NWAM_BACKEND_DOOR_CMD_READ_REQ
)
235 if ((err
= nwam_check_auths(uid
, write
, req
->nwbda_flags
))
238 nwam_record_audit_event(ucr
,
239 req
->nwbda_cmd
== NWAM_BACKEND_DOOR_CMD_UPDATE_REQ
?
240 ADT_netcfg_update
: ADT_netcfg_remove
,
241 (char *)req
->nwbda_object
,
242 (char *)req
->nwbda_dbname
, ADT_FAILURE
,
243 ADT_FAIL_VALUE_AUTH
);
245 req
->nwbda_result
= err
;
249 switch (req
->nwbda_cmd
) {
250 case NWAM_BACKEND_DOOR_CMD_READ_REQ
:
251 if ((req
->nwbda_result
= nwam_read_object_from_files_backend
252 (strlen(req
->nwbda_dbname
) > 0 ? req
->nwbda_dbname
: NULL
,
253 strlen(req
->nwbda_object
) > 0 ? req
->nwbda_object
: NULL
,
254 req
->nwbda_flags
, &newobj
)) != NWAM_SUCCESS
) {
257 if (newobj
!= NULL
) {
258 size_t datalen
= arg_size
-
259 sizeof (nwam_backend_door_arg_t
);
260 caddr_t dataptr
= (caddr_t
)req
+
261 sizeof (nwam_backend_door_arg_t
);
263 if ((req
->nwbda_result
= nwam_pack_object_list(newobj
,
264 (char **)&dataptr
, &datalen
)) != NWAM_SUCCESS
)
265 req
->nwbda_datalen
= 0;
267 req
->nwbda_datalen
= datalen
;
268 nwam_free_object_list(newobj
);
270 req
->nwbda_datalen
= 0;
274 case NWAM_BACKEND_DOOR_CMD_UPDATE_REQ
:
275 if (req
->nwbda_datalen
== 0) {
278 if ((req
->nwbda_result
=
279 nwam_read_object_from_backend_door_arg
280 (req
, NULL
, NULL
, &obj
)) != NWAM_SUCCESS
)
283 req
->nwbda_result
= nwam_update_object_in_files_backend(
284 req
->nwbda_dbname
[0] == 0 ? NULL
: req
->nwbda_dbname
,
285 req
->nwbda_object
[0] == 0 ? NULL
: req
->nwbda_object
,
286 req
->nwbda_flags
, obj
);
287 nwam_free_object_list(obj
);
288 if (req
->nwbda_result
== NWAM_SUCCESS
) {
289 req
->nwbda_datalen
= 0;
290 nwam_record_audit_event(ucr
, ADT_netcfg_update
,
291 (char *)req
->nwbda_object
,
292 (char *)req
->nwbda_dbname
, ADT_SUCCESS
,
297 case NWAM_BACKEND_DOOR_CMD_REMOVE_REQ
:
298 req
->nwbda_result
= nwam_remove_object_from_files_backend
299 (strlen(req
->nwbda_dbname
) > 0 ? req
->nwbda_dbname
: NULL
,
300 strlen(req
->nwbda_object
) > 0 ? req
->nwbda_object
: NULL
,
302 if (req
->nwbda_result
== NWAM_SUCCESS
) {
303 nwam_record_audit_event(ucr
, ADT_netcfg_update
,
304 (char *)req
->nwbda_object
,
305 (char *)req
->nwbda_dbname
, ADT_SUCCESS
,
311 req
->nwbda_result
= NWAM_INVALID_ARG
;
318 (void) door_return((char *)req
, arg_size
, NULL
, 0);
321 static int backend_door_fd
= -1;
324 nwam_backend_fini(void)
326 if (backend_door_fd
!= -1) {
327 (void) door_revoke(backend_door_fd
);
328 backend_door_fd
= -1;
330 (void) unlink(NWAM_BACKEND_DOOR_FILE
);
334 nwam_backend_init(void)
339 /* Create the door directory if it doesn't already exist */
340 if (stat(NWAM_DOOR_DIR
, &statbuf
) < 0) {
341 if (mkdir(NWAM_DOOR_DIR
, (mode_t
)0755) < 0)
342 return (NWAM_ERROR_BACKEND_INIT
);
344 if ((statbuf
.st_mode
& S_IFMT
) != S_IFDIR
)
345 return (NWAM_ERROR_BACKEND_INIT
);
348 if (chmod(NWAM_DOOR_DIR
, 0755) < 0 ||
349 chown(NWAM_DOOR_DIR
, UID_NETADM
, GID_NETADM
) < 0)
350 return (NWAM_ERROR_BACKEND_INIT
);
352 /* Do a low-overhead "touch" on the file that will be the door node. */
353 did
= open(NWAM_BACKEND_DOOR_FILE
,
354 O_RDWR
| O_CREAT
| O_EXCL
| O_NOFOLLOW
| O_NONBLOCK
,
355 S_IRUSR
| S_IRGRP
| S_IROTH
);
359 else if (errno
!= EEXIST
)
360 return (NWAM_ERROR_BACKEND_INIT
);
362 /* Create the door. */
363 backend_door_fd
= door_create(nwam_backend_door_server
, NULL
,
365 if (backend_door_fd
== -1)
366 return (NWAM_ERROR_BACKEND_INIT
);
368 /* Attach the door to the file. */
369 (void) fdetach(NWAM_BACKEND_DOOR_FILE
);
370 if (fattach(backend_door_fd
, NWAM_BACKEND_DOOR_FILE
) == -1) {
371 (void) door_revoke(backend_door_fd
);
372 return (NWAM_ERROR_BACKEND_INIT
);
375 return (NWAM_SUCCESS
);
379 nwam_backend_door_call(nwam_backend_door_cmd_t cmd
, char *dbname
,
380 char *objname
, uint64_t flags
, void *obj
)
382 uchar_t reqbuf
[NWAM_BACKEND_DOOR_ARG_SIZE
];
383 /* LINTED: alignment */
384 nwam_backend_door_arg_t
*req
= (nwam_backend_door_arg_t
*)&reqbuf
;
385 nwam_error_t err
, reserr
;
387 if ((err
= nwam_create_backend_door_arg(cmd
, dbname
, objname
, flags
,
388 obj
, req
)) != NWAM_SUCCESS
)
391 if (nwam_make_door_call(NWAM_BACKEND_DOOR_FILE
, &backend_door_client_fd
,
392 req
, sizeof (reqbuf
)) != 0)
393 return (NWAM_ERROR_BIND
);
395 reserr
= req
->nwbda_result
;
397 if (cmd
== NWAM_BACKEND_DOOR_CMD_READ_REQ
) {
398 err
= nwam_read_object_from_backend_door_arg(req
, dbname
,
402 return (err
== NWAM_SUCCESS
? reserr
: err
);
406 * Read object specified by objname from backend dbname, retrieving an object
407 * list representation.
409 * If dbname is NULL, obj is a list of string arrays consisting of the list
410 * of backend dbnames.
412 * If objname is NULL, read all objects in the specified dbname and create
413 * an object list containing a string array which represents each object.
415 * Otherwise obj will point to a list of the properties for the object
416 * specified by objname in the backend dbname.
420 nwam_read_object_from_backend(char *dbname
, char *objname
,
421 uint64_t flags
, void *obj
)
423 nwam_error_t err
= nwam_check_auths(getuid(), B_FALSE
, flags
);
425 if (err
!= NWAM_SUCCESS
)
428 return (nwam_backend_door_call(NWAM_BACKEND_DOOR_CMD_READ_REQ
,
429 dbname
, objname
, flags
, obj
));
433 * Read in all objects from backend dbname and update object corresponding
434 * to objname with properties recorded in proplist, writing the results to
435 * the backend dbname.
438 nwam_update_object_in_backend(char *dbname
, char *objname
,
439 uint64_t flags
, void *obj
)
441 nwam_error_t err
= nwam_check_auths(getuid(), B_TRUE
, flags
);
443 if (err
!= NWAM_SUCCESS
)
446 return (nwam_backend_door_call(NWAM_BACKEND_DOOR_CMD_UPDATE_REQ
,
447 dbname
, objname
, flags
, obj
));
451 * Remove specified object from backend by reading in the list of objects,
452 * removing objname and writing the remainder.
454 * If objname is NULL, remove the backend dbname.
457 nwam_remove_object_from_backend(char *dbname
, char *objname
, uint64_t flags
)
459 nwam_error_t err
= nwam_check_auths(getuid(), B_TRUE
, flags
);
461 if (err
!= NWAM_SUCCESS
)
464 return (nwam_backend_door_call(NWAM_BACKEND_DOOR_CMD_REMOVE_REQ
,
465 dbname
, objname
, flags
, NULL
));