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 /*
23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26 /*
27 * The ipmgmtd daemon is started by ip-interface-management SMF service. This
28 * daemon is used to manage, mapping of 'address object' to 'interface name' and
29 * 'logical interface number', on which the address is created. It also provides
30 * a means to update the ipadm persistent data-store.
31 *
32 * The daemon tracks the <addrobj, lifname> mapping in-memory using a linked
33 * list `aobjmap'. Access to this list is synchronized using a readers-writers
34 * lock. The active <addrobj, lifname> mapping is kept in
35 * /etc/svc/volatile/ipadm/aobjmap.conf cache file, so that the mapping can be
36 * recovered when ipmgmtd exits for some reason (e.g., when ipmgmtd is restarted
37 * using svcadm or accidentally killed).
38 *
39 * Today, the persistent configuration of interfaces, addresses and protocol
40 * properties is kept in /etc/ipadm/ipadm.conf. The access to the persistent
41 * data store is synchronized using reader-writers lock `ipmgmt_dbconf_lock'.
42 *
43 * The communication between the library, libipadm.so and the daemon, is through
88 static int ipmgmt_init();
89 static int ipmgmt_init_privileges();
90 static void ipmgmt_ngz_persist_if();
91
92 static ipadm_handle_t iph;
93 typedef struct ipmgmt_pif_s {
94 struct ipmgmt_pif_s *pif_next;
95 char pif_ifname[LIFNAMSIZ];
96 boolean_t pif_v4;
97 boolean_t pif_v6;
98 } ipmgmt_pif_t;
99
100 static ipmgmt_pif_t *ngz_pifs;
101
102 static int
103 ipmgmt_db_init()
104 {
105 int fd, err, scferr;
106 scf_resources_t res;
107 boolean_t upgrade = B_TRUE;
108
109 /*
110 * Check to see if we need to upgrade the data-store. We need to
111 * upgrade, if the version of the data-store does not match with
112 * IPADM_DB_VERSION. Further, if we cannot determine the current
113 * version of the data-store, we always err on the side of caution
114 * and upgrade the data-store to current version.
115 */
116 if ((scferr = ipmgmt_create_scf_resources(IPMGMTD_FMRI, &res)) == 0)
117 upgrade = ipmgmt_needs_upgrade(&res);
118 if (upgrade) {
119 err = ipmgmt_db_walk(ipmgmt_db_upgrade, NULL, IPADM_DB_WRITE);
120 if (err != 0) {
121 ipmgmt_log(LOG_ERR, "could not upgrade the "
122 "ipadm data-store: %s", strerror(err));
123 err = 0;
124 } else {
125 /*
126 * upgrade was success, let's update SCF with the
127 * current data-store version number.
128 */
129 if (scferr == 0)
130 ipmgmt_update_dbver(&res);
131 }
132 }
133 if (scferr == 0)
134 ipmgmt_release_scf_resources(&res);
135
136 /* creates the address object data store, if it doesn't exist */
137 if ((fd = open(ADDROBJ_MAPPING_DB_FILE, O_CREAT|O_RDONLY,
138 IPADM_FILE_MODE)) == -1) {
139 err = errno;
140 ipmgmt_log(LOG_ERR, "could not open %s: %s",
141 ADDROBJ_MAPPING_DB_FILE, strerror(err));
142 return (err);
143 }
144 (void) close(fd);
145
146 aobjmap.aobjmap_head = NULL;
147 (void) pthread_rwlock_init(&aobjmap.aobjmap_rwlock, NULL);
148
149 /*
150 * If the daemon is recovering from a crash or restart, read the
151 * address object to logical interface mapping and build an in-memory
152 * representation of the mapping. That is, build `aobjmap' structure
153 * from address object data store.
154 */
155 if ((err = ipadm_rw_db(ipmgmt_aobjmap_init, NULL,
156 ADDROBJ_MAPPING_DB_FILE, 0, IPADM_DB_READ)) != 0) {
157 /* if there was nothing to initialize, it's fine */
158 if (err != ENOENT)
159 return (err);
160 err = 0;
161 }
162
163 ipmgmt_ngz_persist_if(); /* create persistent interface info for NGZ */
164
165 return (err);
166 }
167
168 static int
169 ipmgmt_door_init()
170 {
171 int fd;
172 int err;
173
174 /* create the door file for ipmgmtd */
175 if ((fd = open(IPMGMT_DOOR, O_CREAT|O_RDONLY, IPADM_FILE_MODE)) == -1) {
176 err = errno;
177 ipmgmt_log(LOG_ERR, "could not open %s: %s",
178 IPMGMT_DOOR, strerror(err));
179 return (err);
180 }
181 (void) close(fd);
182
183 if ((ipmgmt_door_fd = door_create(ipmgmt_handler, NULL,
184 DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) {
185 err = errno;
186 ipmgmt_log(LOG_ERR, "failed to create door: %s", strerror(err));
187 return (err);
188 }
189 /*
190 * fdetach first in case a previous daemon instance exited
191 * ungracefully.
192 */
193 (void) fdetach(IPMGMT_DOOR);
194 if (fattach(ipmgmt_door_fd, IPMGMT_DOOR) != 0) {
195 err = errno;
196 ipmgmt_log(LOG_ERR, "failed to attach door to %s: %s",
197 IPMGMT_DOOR, strerror(err));
198 goto fail;
199 }
200 return (0);
201 fail:
202 (void) door_revoke(ipmgmt_door_fd);
203 ipmgmt_door_fd = -1;
204 return (err);
205 }
206
207 static void
208 ipmgmt_door_fini()
209 {
210 if (ipmgmt_door_fd == -1)
211 return;
212
213 (void) fdetach(IPMGMT_DOOR);
214 if (door_revoke(ipmgmt_door_fd) == -1) {
215 ipmgmt_log(LOG_ERR, "failed to revoke access to door %s: %s",
216 IPMGMT_DOOR, strerror(errno));
217 }
218 }
219
220 static int
221 ipmgmt_init()
222 {
223 int err;
224
225 if (signal(SIGTERM, ipmgmt_exit) == SIG_ERR ||
226 signal(SIGINT, ipmgmt_exit) == SIG_ERR) {
227 err = errno;
228 ipmgmt_log(LOG_ERR, "signal() for SIGTERM/INT failed: %s",
229 strerror(err));
230 return (err);
231 }
232 if ((err = ipmgmt_db_init()) != 0 || (err = ipmgmt_door_init()) != 0)
233 return (err);
234 return (0);
235 }
236
333 * for NATIVE (ipkg) zones.
334 */
335 (void) ipadm_init_net_from_gz(iph, NULL,
336 (s10c ? NULL : ipmgmt_persist_if_cb));
337 ipadm_close(iph);
338 }
339 }
340
341 /*
342 * Set the uid of this daemon to the "netadm" user. Finish the following
343 * operations before setuid() because they need root privileges:
344 *
345 * - create the /etc/svc/volatile/ipadm directory;
346 * - change its uid/gid to "netadm"/"netadm";
347 */
348 static int
349 ipmgmt_init_privileges()
350 {
351 struct stat statbuf;
352 int err;
353
354 /* create the IPADM_TMPFS_DIR directory */
355 if (stat(IPADM_TMPFS_DIR, &statbuf) < 0) {
356 if (mkdir(IPADM_TMPFS_DIR, (mode_t)0755) < 0) {
357 err = errno;
358 goto fail;
359 }
360 } else {
361 if ((statbuf.st_mode & S_IFMT) != S_IFDIR) {
362 err = ENOTDIR;
363 goto fail;
364 }
365 }
366
367 if ((chmod(IPADM_TMPFS_DIR, 0755) < 0) ||
368 (chown(IPADM_TMPFS_DIR, UID_NETADM, GID_NETADM) < 0)) {
369 err = errno;
370 goto fail;
371 }
372
373 /*
374 * initialize any NGZ specific network information before dropping
375 * privileges. We need these privileges to plumb IP interfaces handed
376 * down from the GZ (for dlpi_open() etc.) and also to configure the
377 * address itself (for any IPI_PRIV ioctls like SLIFADDR)
378 */
379 ipmgmt_ngz_init();
380
381 /*
382 * Apply all protocol module properties. We need to apply all protocol
383 * properties before we drop root privileges.
384 */
385 ipmgmt_init_prop();
386
387 /*
388 * limit the privileges of this daemon and set the uid of this
|
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 /*
23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2015 Joyent, Inc.
25 */
26
27 /*
28 * The ipmgmtd daemon is started by ip-interface-management SMF service. This
29 * daemon is used to manage, mapping of 'address object' to 'interface name' and
30 * 'logical interface number', on which the address is created. It also provides
31 * a means to update the ipadm persistent data-store.
32 *
33 * The daemon tracks the <addrobj, lifname> mapping in-memory using a linked
34 * list `aobjmap'. Access to this list is synchronized using a readers-writers
35 * lock. The active <addrobj, lifname> mapping is kept in
36 * /etc/svc/volatile/ipadm/aobjmap.conf cache file, so that the mapping can be
37 * recovered when ipmgmtd exits for some reason (e.g., when ipmgmtd is restarted
38 * using svcadm or accidentally killed).
39 *
40 * Today, the persistent configuration of interfaces, addresses and protocol
41 * properties is kept in /etc/ipadm/ipadm.conf. The access to the persistent
42 * data store is synchronized using reader-writers lock `ipmgmt_dbconf_lock'.
43 *
44 * The communication between the library, libipadm.so and the daemon, is through
89 static int ipmgmt_init();
90 static int ipmgmt_init_privileges();
91 static void ipmgmt_ngz_persist_if();
92
93 static ipadm_handle_t iph;
94 typedef struct ipmgmt_pif_s {
95 struct ipmgmt_pif_s *pif_next;
96 char pif_ifname[LIFNAMSIZ];
97 boolean_t pif_v4;
98 boolean_t pif_v6;
99 } ipmgmt_pif_t;
100
101 static ipmgmt_pif_t *ngz_pifs;
102
103 static int
104 ipmgmt_db_init()
105 {
106 int fd, err, scferr;
107 scf_resources_t res;
108 boolean_t upgrade = B_TRUE;
109 char aobjpath[MAXPATHLEN];
110
111 /*
112 * Check to see if we need to upgrade the data-store. We need to
113 * upgrade, if the version of the data-store does not match with
114 * IPADM_DB_VERSION. Further, if we cannot determine the current
115 * version of the data-store, we always err on the side of caution
116 * and upgrade the data-store to current version.
117 */
118 if ((scferr = ipmgmt_create_scf_resources(IPMGMTD_FMRI, &res)) == 0)
119 upgrade = ipmgmt_needs_upgrade(&res);
120 if (upgrade) {
121 err = ipmgmt_db_walk(ipmgmt_db_upgrade, NULL, IPADM_DB_WRITE);
122 if (err != 0) {
123 ipmgmt_log(LOG_ERR, "could not upgrade the "
124 "ipadm data-store: %s", strerror(err));
125 err = 0;
126 } else {
127 /*
128 * upgrade was success, let's update SCF with the
129 * current data-store version number.
130 */
131 if (scferr == 0)
132 ipmgmt_update_dbver(&res);
133 }
134 }
135 if (scferr == 0)
136 ipmgmt_release_scf_resources(&res);
137
138 /* creates the address object data store, if it doesn't exist */
139 ipmgmt_path(IPADM_PATH_ADDROBJ_MAP_DB, aobjpath, sizeof (aobjpath));
140 if ((fd = open(aobjpath, O_CREAT|O_RDONLY, IPADM_FILE_MODE)) == -1) {
141 err = errno;
142 ipmgmt_log(LOG_ERR, "could not open %s: %s", aobjpath,
143 strerror(err));
144 return (err);
145 }
146 (void) close(fd);
147
148 aobjmap.aobjmap_head = NULL;
149 (void) pthread_rwlock_init(&aobjmap.aobjmap_rwlock, NULL);
150
151 /*
152 * If the daemon is recovering from a crash or restart, read the
153 * address object to logical interface mapping and build an in-memory
154 * representation of the mapping. That is, build `aobjmap' structure
155 * from address object data store.
156 */
157 if ((err = ipadm_rw_db(ipmgmt_aobjmap_init, NULL, aobjpath, 0,
158 IPADM_DB_READ)) != 0) {
159 /* if there was nothing to initialize, it's fine */
160 if (err != ENOENT)
161 return (err);
162 err = 0;
163 }
164
165 ipmgmt_ngz_persist_if(); /* create persistent interface info for NGZ */
166
167 return (err);
168 }
169
170 static const char *
171 ipmgmt_door_path()
172 {
173 static char door[MAXPATHLEN];
174 static boolean_t init_done = B_FALSE;
175
176 if (!init_done) {
177 const char *zroot = zone_get_nroot();
178
179 /*
180 * If this is a branded zone, make sure we use the "/native"
181 * prefix for the door path:
182 */
183 (void) snprintf(door, sizeof (door), "%s%s", zroot != NULL ?
184 zroot : "", IPMGMT_DOOR);
185
186 init_done = B_TRUE;
187 }
188
189 return (door);
190 }
191
192 static int
193 ipmgmt_door_init()
194 {
195 int fd;
196 int err;
197 const char *door = ipmgmt_door_path();
198
199 /*
200 * Create the door file for ipmgmtd.
201 */
202 if ((fd = open(door, O_CREAT | O_RDONLY, IPADM_FILE_MODE)) == -1) {
203 err = errno;
204 ipmgmt_log(LOG_ERR, "could not open %s: %s", door,
205 strerror(err));
206 return (err);
207 }
208 (void) close(fd);
209
210 if ((ipmgmt_door_fd = door_create(ipmgmt_handler, NULL,
211 DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) {
212 err = errno;
213 ipmgmt_log(LOG_ERR, "failed to create door: %s", strerror(err));
214 return (err);
215 }
216
217 /*
218 * fdetach first in case a previous daemon instance exited
219 * ungracefully.
220 */
221 (void) fdetach(door);
222 if (fattach(ipmgmt_door_fd, door) != 0) {
223 err = errno;
224 ipmgmt_log(LOG_ERR, "failed to attach door to %s: %s", door,
225 strerror(err));
226 goto fail;
227 }
228 return (0);
229 fail:
230 (void) door_revoke(ipmgmt_door_fd);
231 ipmgmt_door_fd = -1;
232 return (err);
233 }
234
235 static void
236 ipmgmt_door_fini()
237 {
238 const char *door = ipmgmt_door_path();
239
240 if (ipmgmt_door_fd == -1)
241 return;
242
243 (void) fdetach(door);
244 if (door_revoke(ipmgmt_door_fd) == -1) {
245 ipmgmt_log(LOG_ERR, "failed to revoke access to door %s: %s",
246 door, strerror(errno));
247 }
248 }
249
250 static int
251 ipmgmt_init()
252 {
253 int err;
254
255 if (signal(SIGTERM, ipmgmt_exit) == SIG_ERR ||
256 signal(SIGINT, ipmgmt_exit) == SIG_ERR) {
257 err = errno;
258 ipmgmt_log(LOG_ERR, "signal() for SIGTERM/INT failed: %s",
259 strerror(err));
260 return (err);
261 }
262 if ((err = ipmgmt_db_init()) != 0 || (err = ipmgmt_door_init()) != 0)
263 return (err);
264 return (0);
265 }
266
363 * for NATIVE (ipkg) zones.
364 */
365 (void) ipadm_init_net_from_gz(iph, NULL,
366 (s10c ? NULL : ipmgmt_persist_if_cb));
367 ipadm_close(iph);
368 }
369 }
370
371 /*
372 * Set the uid of this daemon to the "netadm" user. Finish the following
373 * operations before setuid() because they need root privileges:
374 *
375 * - create the /etc/svc/volatile/ipadm directory;
376 * - change its uid/gid to "netadm"/"netadm";
377 */
378 static int
379 ipmgmt_init_privileges()
380 {
381 struct stat statbuf;
382 int err;
383 char tmpfsdir[MAXPATHLEN];
384
385 /*
386 * Create the volatile storage directory:
387 */
388 ipmgmt_path(IPADM_PATH_TMPFS_DIR, tmpfsdir, sizeof (tmpfsdir));
389 if (stat(tmpfsdir, &statbuf) < 0) {
390 if (mkdir(tmpfsdir, (mode_t)0755) < 0) {
391 err = errno;
392 goto fail;
393 }
394 } else {
395 if ((statbuf.st_mode & S_IFMT) != S_IFDIR) {
396 err = ENOTDIR;
397 goto fail;
398 }
399 }
400
401 if ((chmod(tmpfsdir, 0755) < 0) ||
402 (chown(tmpfsdir, UID_NETADM, GID_NETADM) < 0)) {
403 err = errno;
404 goto fail;
405 }
406
407 /*
408 * initialize any NGZ specific network information before dropping
409 * privileges. We need these privileges to plumb IP interfaces handed
410 * down from the GZ (for dlpi_open() etc.) and also to configure the
411 * address itself (for any IPI_PRIV ioctls like SLIFADDR)
412 */
413 ipmgmt_ngz_init();
414
415 /*
416 * Apply all protocol module properties. We need to apply all protocol
417 * properties before we drop root privileges.
418 */
419 ipmgmt_init_prop();
420
421 /*
422 * limit the privileges of this daemon and set the uid of this
|