Merge remote-tracking branch 'origin/master'
[unleashed/lotheac.git] / usr / src / lib / libnwam / common / libnwam_backend.c
blobe96b95da9500a39c066d740b539ab317ef2a7aad
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
23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #include <assert.h>
28 #include <auth_attr.h>
29 #include <auth_list.h>
30 #include <ctype.h>
31 #include <door.h>
32 #include <errno.h>
33 #include <fcntl.h>
34 #include <libgen.h>
35 #include <pwd.h>
36 #include <secdb.h>
37 #include <stdlib.h>
38 #include <sys/param.h>
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <stdio.h>
42 #include <strings.h>
43 #include <unistd.h>
45 #include "libnwam_impl.h"
46 #include <libnwam_priv.h>
47 #include <libnwam.h>
50 * Communicate with and implement library backend (running in netcfgd) to
51 * retrieve or change NWAM configuration.
54 static int backend_door_client_fd = -1;
57 * Check if uid has proper auths. flags is used to check auths for
58 * enable/disable of profiles and manipulation of Known WLANs.
60 static nwam_error_t
61 nwam_check_auths(uid_t uid, boolean_t write, uint64_t flags)
63 struct passwd *pwd;
64 nwam_error_t err = NWAM_SUCCESS;
66 if ((pwd = getpwuid(uid)) == NULL) {
67 endpwent();
68 return (NWAM_PERMISSION_DENIED);
71 if (flags & NWAM_FLAG_ENTITY_ENABLE) {
72 /* Enabling/disabling profile - need SELECT auth */
73 if (chkauthattr(AUTOCONF_SELECT_AUTH, pwd->pw_name) == 0)
74 err = NWAM_PERMISSION_DENIED;
76 } else if (flags & NWAM_FLAG_ENTITY_KNOWN_WLAN) {
77 /* Known WLAN activity - need WLAN auth */
78 if (chkauthattr(AUTOCONF_WLAN_AUTH, pwd->pw_name) == 0)
79 err = NWAM_PERMISSION_DENIED;
81 } else {
83 * First, check for WRITE, since it implies READ. If this
84 * auth is not present, and write is true, fail, otherwise
85 * check for READ.
87 if (chkauthattr(AUTOCONF_WRITE_AUTH, pwd->pw_name) == 0) {
88 if (write) {
89 err = NWAM_PERMISSION_DENIED;
90 } else {
91 if (chkauthattr(AUTOCONF_READ_AUTH,
92 pwd->pw_name) == 0)
93 err = NWAM_PERMISSION_DENIED;
98 endpwent();
99 return (err);
102 static nwam_error_t
103 nwam_create_backend_door_arg(nwam_backend_door_cmd_t cmd,
104 const char *dbname, const char *objname, uint64_t flags,
105 void *obj, nwam_backend_door_arg_t *arg)
107 nwam_error_t err;
108 size_t datalen = 0;
109 caddr_t dataptr;
111 switch (cmd) {
112 case NWAM_BACKEND_DOOR_CMD_READ_REQ:
114 * For a read request, we want the full buffer to be
115 * available for the backend door to write to.
117 datalen = NWAM_BACKEND_DOOR_ARG_SIZE;
118 break;
120 case NWAM_BACKEND_DOOR_CMD_UPDATE_REQ:
122 * An update request may either specify an object list
123 * (which we pack into the buffer immediately after the
124 * backend door request) or may not specify an object
125 * (signifying a request to create the container of the
126 * object).
128 if (obj == NULL) {
129 datalen = 0;
130 break;
132 /* Data immediately follows the descriptor */
133 dataptr = (caddr_t)arg + sizeof (nwam_backend_door_arg_t);
134 datalen = NWAM_BACKEND_DOOR_ARG_SIZE;
135 /* pack object list for update request, adjusting datalen */
136 if ((err = nwam_pack_object_list(obj, (char **)&dataptr,
137 &datalen)) != NWAM_SUCCESS)
138 return (err);
139 break;
141 case NWAM_BACKEND_DOOR_CMD_REMOVE_REQ:
142 /* A remove request has no associated object list. */
143 datalen = 0;
144 break;
146 default:
147 return (NWAM_INVALID_ARG);
150 arg->nwbda_cmd = cmd;
151 arg->nwbda_flags = flags;
152 arg->nwbda_datalen = datalen;
153 arg->nwbda_result = NWAM_SUCCESS;
155 if (dbname != NULL)
156 (void) strlcpy(arg->nwbda_dbname, dbname, MAXPATHLEN);
157 else
158 arg->nwbda_dbname[0] = '\0';
160 if (objname != NULL)
161 (void) strlcpy(arg->nwbda_object, objname, NWAM_MAX_NAME_LEN);
162 else
163 arg->nwbda_object[0] = '\0';
165 return (NWAM_SUCCESS);
169 * If the arg datalen is non-zero, unpack the object list associated with
170 * the backend door argument.
172 static nwam_error_t
173 nwam_read_object_from_backend_door_arg(nwam_backend_door_arg_t *arg,
174 char *dbname, char *name, void *objp)
176 nwam_error_t err;
177 caddr_t dataptr = (caddr_t)arg + sizeof (nwam_backend_door_arg_t);
179 if (arg->nwbda_result != NWAM_SUCCESS)
180 return (arg->nwbda_result);
182 if (arg->nwbda_datalen > 0) {
183 if ((err = nwam_unpack_object_list((char *)dataptr,
184 arg->nwbda_datalen, objp)) != NWAM_SUCCESS)
185 return (err);
186 } else {
187 *((char **)objp) = NULL;
191 * If "dbname" and "name" are non-NULL, copy in the actual dbname
192 * and name values from the door arg since both may have been changed
193 * from case-insensitive to case-sensitive matches. They will be the
194 * same length as they only differ in case.
196 if (dbname != NULL && strcmp(dbname, arg->nwbda_dbname) != 0)
197 (void) strlcpy(dbname, arg->nwbda_dbname, strlen(dbname) + 1);
198 if (name != NULL && strcmp(name, arg->nwbda_object) != 0)
199 (void) strlcpy(name, arg->nwbda_object, strlen(name) + 1);
201 return (NWAM_SUCCESS);
204 /* ARGSUSED */
205 void
206 nwam_backend_door_server(void *cookie, char *arg, size_t arg_size,
207 door_desc_t *dp, uint_t ndesc)
209 /* LINTED: alignment */
210 nwam_backend_door_arg_t *req = (nwam_backend_door_arg_t *)arg;
211 nwam_error_t err;
212 void *obj, *newobj = NULL;
213 ucred_t *ucr = NULL;
214 uid_t uid;
215 boolean_t write = B_TRUE;
217 /* Check arg size */
218 if (arg_size < sizeof (nwam_backend_door_arg_t)) {
219 req->nwbda_result = NWAM_INVALID_ARG;
220 (void) door_return((char *)req,
221 sizeof (nwam_backend_door_arg_t), NULL, 0);
224 if (door_ucred(&ucr) != 0) {
225 req->nwbda_result = NWAM_ERROR_INTERNAL;
226 (void) door_return((char *)req, arg_size, NULL, 0);
229 /* Check auths */
230 uid = ucred_getruid(ucr);
232 if (req->nwbda_cmd == NWAM_BACKEND_DOOR_CMD_READ_REQ)
233 write = B_FALSE;
234 if ((err = nwam_check_auths(uid, write, req->nwbda_flags))
235 != NWAM_SUCCESS) {
236 req->nwbda_result = err;
237 goto door_return;
240 switch (req->nwbda_cmd) {
241 case NWAM_BACKEND_DOOR_CMD_READ_REQ:
242 if ((req->nwbda_result = nwam_read_object_from_files_backend
243 (strlen(req->nwbda_dbname) > 0 ? req->nwbda_dbname : NULL,
244 strlen(req->nwbda_object) > 0 ? req->nwbda_object : NULL,
245 req->nwbda_flags, &newobj)) != NWAM_SUCCESS) {
246 break;
248 if (newobj != NULL) {
249 size_t datalen = arg_size -
250 sizeof (nwam_backend_door_arg_t);
251 caddr_t dataptr = (caddr_t)req +
252 sizeof (nwam_backend_door_arg_t);
254 if ((req->nwbda_result = nwam_pack_object_list(newobj,
255 (char **)&dataptr, &datalen)) != NWAM_SUCCESS)
256 req->nwbda_datalen = 0;
257 else
258 req->nwbda_datalen = datalen;
259 nwam_free_object_list(newobj);
260 } else {
261 req->nwbda_datalen = 0;
263 break;
265 case NWAM_BACKEND_DOOR_CMD_UPDATE_REQ:
266 if (req->nwbda_datalen == 0) {
267 obj = NULL;
268 } else {
269 if ((req->nwbda_result =
270 nwam_read_object_from_backend_door_arg
271 (req, NULL, NULL, &obj)) != NWAM_SUCCESS)
272 break;
274 req->nwbda_result = nwam_update_object_in_files_backend(
275 req->nwbda_dbname[0] == 0 ? NULL : req->nwbda_dbname,
276 req->nwbda_object[0] == 0 ? NULL : req->nwbda_object,
277 req->nwbda_flags, obj);
278 nwam_free_object_list(obj);
279 if (req->nwbda_result == NWAM_SUCCESS) {
280 req->nwbda_datalen = 0;
282 break;
284 case NWAM_BACKEND_DOOR_CMD_REMOVE_REQ:
285 req->nwbda_result = nwam_remove_object_from_files_backend
286 (strlen(req->nwbda_dbname) > 0 ? req->nwbda_dbname : NULL,
287 strlen(req->nwbda_object) > 0 ? req->nwbda_object : NULL,
288 req->nwbda_flags);
289 break;
291 default:
292 req->nwbda_result = NWAM_INVALID_ARG;
293 break;
296 door_return:
297 ucred_free(ucr);
299 (void) door_return((char *)req, arg_size, NULL, 0);
302 static int backend_door_fd = -1;
304 void
305 nwam_backend_fini(void)
307 if (backend_door_fd != -1) {
308 (void) door_revoke(backend_door_fd);
309 backend_door_fd = -1;
311 (void) unlink(NWAM_BACKEND_DOOR_FILE);
314 nwam_error_t
315 nwam_backend_init(void)
317 int did;
318 struct stat statbuf;
320 /* Create the door directory if it doesn't already exist */
321 if (stat(NWAM_DOOR_DIR, &statbuf) < 0) {
322 if (mkdir(NWAM_DOOR_DIR, (mode_t)0755) < 0)
323 return (NWAM_ERROR_BACKEND_INIT);
324 } else {
325 if ((statbuf.st_mode & S_IFMT) != S_IFDIR)
326 return (NWAM_ERROR_BACKEND_INIT);
329 if (chmod(NWAM_DOOR_DIR, 0755) < 0 ||
330 chown(NWAM_DOOR_DIR, UID_NETADM, GID_NETADM) < 0)
331 return (NWAM_ERROR_BACKEND_INIT);
333 /* Do a low-overhead "touch" on the file that will be the door node. */
334 did = open(NWAM_BACKEND_DOOR_FILE,
335 O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW | O_NONBLOCK,
336 S_IRUSR | S_IRGRP | S_IROTH);
338 if (did != -1)
339 (void) close(did);
340 else if (errno != EEXIST)
341 return (NWAM_ERROR_BACKEND_INIT);
343 /* Create the door. */
344 backend_door_fd = door_create(nwam_backend_door_server, NULL,
345 DOOR_REFUSE_DESC);
346 if (backend_door_fd == -1)
347 return (NWAM_ERROR_BACKEND_INIT);
349 /* Attach the door to the file. */
350 (void) fdetach(NWAM_BACKEND_DOOR_FILE);
351 if (fattach(backend_door_fd, NWAM_BACKEND_DOOR_FILE) == -1) {
352 (void) door_revoke(backend_door_fd);
353 return (NWAM_ERROR_BACKEND_INIT);
356 return (NWAM_SUCCESS);
359 static nwam_error_t
360 nwam_backend_door_call(nwam_backend_door_cmd_t cmd, char *dbname,
361 char *objname, uint64_t flags, void *obj)
363 uchar_t reqbuf[NWAM_BACKEND_DOOR_ARG_SIZE];
364 /* LINTED: alignment */
365 nwam_backend_door_arg_t *req = (nwam_backend_door_arg_t *)&reqbuf;
366 nwam_error_t err, reserr;
368 if ((err = nwam_create_backend_door_arg(cmd, dbname, objname, flags,
369 obj, req)) != NWAM_SUCCESS)
370 return (err);
372 if (nwam_make_door_call(NWAM_BACKEND_DOOR_FILE, &backend_door_client_fd,
373 req, sizeof (reqbuf)) != 0)
374 return (NWAM_ERROR_BIND);
376 reserr = req->nwbda_result;
378 if (cmd == NWAM_BACKEND_DOOR_CMD_READ_REQ) {
379 err = nwam_read_object_from_backend_door_arg(req, dbname,
380 objname, obj);
383 return (err == NWAM_SUCCESS ? reserr : err);
387 * Read object specified by objname from backend dbname, retrieving an object
388 * list representation.
390 * If dbname is NULL, obj is a list of string arrays consisting of the list
391 * of backend dbnames.
393 * If objname is NULL, read all objects in the specified dbname and create
394 * an object list containing a string array which represents each object.
396 * Otherwise obj will point to a list of the properties for the object
397 * specified by objname in the backend dbname.
399 /* ARGSUSED2 */
400 nwam_error_t
401 nwam_read_object_from_backend(char *dbname, char *objname,
402 uint64_t flags, void *obj)
404 nwam_error_t err = nwam_check_auths(getuid(), B_FALSE, flags);
406 if (err != NWAM_SUCCESS)
407 return (err);
409 return (nwam_backend_door_call(NWAM_BACKEND_DOOR_CMD_READ_REQ,
410 dbname, objname, flags, obj));
414 * Read in all objects from backend dbname and update object corresponding
415 * to objname with properties recorded in proplist, writing the results to
416 * the backend dbname.
418 nwam_error_t
419 nwam_update_object_in_backend(char *dbname, char *objname,
420 uint64_t flags, void *obj)
422 nwam_error_t err = nwam_check_auths(getuid(), B_TRUE, flags);
424 if (err != NWAM_SUCCESS)
425 return (err);
427 return (nwam_backend_door_call(NWAM_BACKEND_DOOR_CMD_UPDATE_REQ,
428 dbname, objname, flags, obj));
432 * Remove specified object from backend by reading in the list of objects,
433 * removing objname and writing the remainder.
435 * If objname is NULL, remove the backend dbname.
437 nwam_error_t
438 nwam_remove_object_from_backend(char *dbname, char *objname, uint64_t flags)
440 nwam_error_t err = nwam_check_auths(getuid(), B_TRUE, flags);
442 if (err != NWAM_SUCCESS)
443 return (err);
445 return (nwam_backend_door_call(NWAM_BACKEND_DOOR_CMD_REMOVE_REQ,
446 dbname, objname, flags, NULL));