1cb5caa98Sdjl /*
2cb5caa98Sdjl * CDDL HEADER START
3cb5caa98Sdjl *
4cb5caa98Sdjl * The contents of this file are subject to the terms of the
5cb5caa98Sdjl * Common Development and Distribution License (the "License").
6cb5caa98Sdjl * You may not use this file except in compliance with the License.
7cb5caa98Sdjl *
8cb5caa98Sdjl * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9cb5caa98Sdjl * or http://www.opensolaris.org/os/licensing.
10cb5caa98Sdjl * See the License for the specific language governing permissions
11cb5caa98Sdjl * and limitations under the License.
12cb5caa98Sdjl *
13cb5caa98Sdjl * When distributing Covered Code, include this CDDL HEADER in each
14cb5caa98Sdjl * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15cb5caa98Sdjl * If applicable, add the following below this CDDL HEADER, with the
16cb5caa98Sdjl * fields enclosed by brackets "[]" replaced with your own identifying
17cb5caa98Sdjl * information: Portions Copyright [yyyy] [name of copyright owner]
18cb5caa98Sdjl *
19cb5caa98Sdjl * CDDL HEADER END
20cb5caa98Sdjl */
21cb5caa98Sdjl /*
22b57459abSJulian Pullen * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23cb5caa98Sdjl * Use is subject to license terms.
24*7d7551bcSMilan Jurik * Copyright 2012 Milan Jurik. All rights reserved.
25cb5caa98Sdjl */
26cb5caa98Sdjl
27cb5caa98Sdjl #include <stdlib.h>
28cb5caa98Sdjl #include <alloca.h>
29cb5caa98Sdjl #include <signal.h>
30cb5caa98Sdjl #include <sys/stat.h>
31cb5caa98Sdjl #include <unistd.h>
32cb5caa98Sdjl #include <pthread.h>
33cb5caa98Sdjl #include <time.h>
34cb5caa98Sdjl #include <errno.h>
35cb5caa98Sdjl #include <door.h>
36cb5caa98Sdjl #include <zone.h>
37cb5caa98Sdjl #include <resolv.h>
38cb5caa98Sdjl #include <sys/socket.h>
39cb5caa98Sdjl #include <net/route.h>
40cb5caa98Sdjl #include <string.h>
41cb5caa98Sdjl #include <net/if.h>
42cb5caa98Sdjl #include <sys/stat.h>
43cb5caa98Sdjl #include <fcntl.h>
44cb5caa98Sdjl #include "nscd_common.h"
45cb5caa98Sdjl #include "nscd_door.h"
46cb5caa98Sdjl #include "nscd_config.h"
47cb5caa98Sdjl #include "nscd_switch.h"
48cb5caa98Sdjl #include "nscd_log.h"
49cb5caa98Sdjl #include "nscd_selfcred.h"
50cb5caa98Sdjl #include "nscd_frontend.h"
51cb5caa98Sdjl #include "nscd_admin.h"
52cb5caa98Sdjl
53cb5caa98Sdjl static void rts_mon(void);
54cb5caa98Sdjl static void keep_open_dns_socket(void);
55cb5caa98Sdjl
56cb5caa98Sdjl extern nsc_ctx_t *cache_ctx_p[];
57cb5caa98Sdjl
58cb5caa98Sdjl /*
59cb5caa98Sdjl * Current active Configuration data for the frontend component
60cb5caa98Sdjl */
61cb5caa98Sdjl static nscd_cfg_global_frontend_t frontend_cfg_g;
62cb5caa98Sdjl static nscd_cfg_frontend_t *frontend_cfg;
63cb5caa98Sdjl
64cb5caa98Sdjl static int max_servers = 0;
65cb5caa98Sdjl static int max_servers_set = 0;
66cb5caa98Sdjl static int per_user_is_on = 1;
67cb5caa98Sdjl
68cb5caa98Sdjl static char *main_execname;
69cb5caa98Sdjl static char **main_argv;
70cb5caa98Sdjl extern int _whoami;
71cb5caa98Sdjl extern long activity;
72cb5caa98Sdjl extern mutex_t activity_lock;
73cb5caa98Sdjl
74cb5caa98Sdjl static sema_t common_sema;
75cb5caa98Sdjl
76cb5caa98Sdjl static thread_key_t lookup_state_key;
77cb5caa98Sdjl static mutex_t create_lock = DEFAULTMUTEX;
78cb5caa98Sdjl static int num_servers = 0;
79cb5caa98Sdjl static thread_key_t server_key;
80cb5caa98Sdjl
81cb5caa98Sdjl /*
82cb5caa98Sdjl * Bind a TSD value to a server thread. This enables the destructor to
83cb5caa98Sdjl * be called if/when this thread exits. This would be a programming
84cb5caa98Sdjl * error, but better safe than sorry.
85cb5caa98Sdjl */
86cb5caa98Sdjl /*ARGSUSED*/
87cb5caa98Sdjl static void *
server_tsd_bind(void * arg)88cb5caa98Sdjl server_tsd_bind(void *arg)
89cb5caa98Sdjl {
90cb5caa98Sdjl static void *value = 0;
91cb5caa98Sdjl
92cb5caa98Sdjl /* disable cancellation to avoid hangs if server threads disappear */
93cb5caa98Sdjl (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
94cb5caa98Sdjl (void) thr_setspecific(server_key, value);
95cb5caa98Sdjl (void) door_return(NULL, 0, NULL, 0);
96cb5caa98Sdjl
97cb5caa98Sdjl /* make lint happy */
98cb5caa98Sdjl return (NULL);
99cb5caa98Sdjl }
100cb5caa98Sdjl
101cb5caa98Sdjl /*
102cb5caa98Sdjl * Server threads are created here.
103cb5caa98Sdjl */
104cb5caa98Sdjl /*ARGSUSED*/
105cb5caa98Sdjl static void
server_create(door_info_t * dip)106cb5caa98Sdjl server_create(door_info_t *dip)
107cb5caa98Sdjl {
108cb5caa98Sdjl (void) mutex_lock(&create_lock);
109cb5caa98Sdjl if (++num_servers > max_servers) {
110cb5caa98Sdjl num_servers--;
111cb5caa98Sdjl (void) mutex_unlock(&create_lock);
112cb5caa98Sdjl return;
113cb5caa98Sdjl }
114cb5caa98Sdjl (void) mutex_unlock(&create_lock);
115cb5caa98Sdjl (void) thr_create(NULL, 0, server_tsd_bind, NULL,
116cb5caa98Sdjl THR_BOUND|THR_DETACHED, NULL);
117cb5caa98Sdjl }
118cb5caa98Sdjl
119cb5caa98Sdjl /*
120cb5caa98Sdjl * Server thread are destroyed here
121cb5caa98Sdjl */
122cb5caa98Sdjl /*ARGSUSED*/
123cb5caa98Sdjl static void
server_destroy(void * arg)124cb5caa98Sdjl server_destroy(void *arg)
125cb5caa98Sdjl {
126cb5caa98Sdjl (void) mutex_lock(&create_lock);
127cb5caa98Sdjl num_servers--;
128cb5caa98Sdjl (void) mutex_unlock(&create_lock);
129cb5caa98Sdjl }
130cb5caa98Sdjl
131cb5caa98Sdjl /*
132cb5caa98Sdjl * get clearance
133cb5caa98Sdjl */
134cb5caa98Sdjl int
_nscd_get_clearance(sema_t * sema)135cb5caa98Sdjl _nscd_get_clearance(sema_t *sema) {
136cb5caa98Sdjl if (sema_trywait(&common_sema) == 0) {
137cb5caa98Sdjl (void) thr_setspecific(lookup_state_key, NULL);
138cb5caa98Sdjl return (0);
139cb5caa98Sdjl }
140cb5caa98Sdjl
141cb5caa98Sdjl if (sema_trywait(sema) == 0) {
142cb5caa98Sdjl (void) thr_setspecific(lookup_state_key, (void*)1);
143cb5caa98Sdjl return (0);
144cb5caa98Sdjl }
145cb5caa98Sdjl
146cb5caa98Sdjl return (1);
147cb5caa98Sdjl }
148cb5caa98Sdjl
149cb5caa98Sdjl
150cb5caa98Sdjl /*
151cb5caa98Sdjl * release clearance
152cb5caa98Sdjl */
153cb5caa98Sdjl int
_nscd_release_clearance(sema_t * sema)154cb5caa98Sdjl _nscd_release_clearance(sema_t *sema) {
155cb5caa98Sdjl int which;
156cb5caa98Sdjl
157cb5caa98Sdjl (void) thr_getspecific(lookup_state_key, (void**)&which);
158cb5caa98Sdjl if (which == 0) /* from common pool */ {
159cb5caa98Sdjl (void) sema_post(&common_sema);
160cb5caa98Sdjl return (0);
161cb5caa98Sdjl }
162cb5caa98Sdjl
163cb5caa98Sdjl (void) sema_post(sema);
164cb5caa98Sdjl return (1);
165cb5caa98Sdjl }
166cb5caa98Sdjl
167cb5caa98Sdjl static void
dozip(void)168cb5caa98Sdjl dozip(void)
169cb5caa98Sdjl {
170cb5caa98Sdjl /* not much here */
171cb5caa98Sdjl }
172cb5caa98Sdjl
173940a40eaSsm26363 /*
174940a40eaSsm26363 * _nscd_restart_if_cfgfile_changed()
175940a40eaSsm26363 * Restart if modification times of nsswitch.conf or resolv.conf have changed.
176940a40eaSsm26363 *
177940a40eaSsm26363 * If nsswitch.conf has changed then it is possible that sources for
178940a40eaSsm26363 * various backends have changed and therefore the current cached
179940a40eaSsm26363 * data may not be consistent with the new data sources. By
180940a40eaSsm26363 * restarting the cache will be cleared and the new configuration will
181940a40eaSsm26363 * be used.
182940a40eaSsm26363 *
183940a40eaSsm26363 * The check for resolv.conf is made as only the first call to
184940a40eaSsm26363 * res_gethostbyname() or res_getaddrbyname() causes a call to
185940a40eaSsm26363 * res_ninit() to occur which in turn parses resolv.conf. Therefore
186940a40eaSsm26363 * to benefit from changes to resolv.conf nscd must be restarted when
187940a40eaSsm26363 * resolv.conf is updated, removed or created. If res_getXbyY calls
188940a40eaSsm26363 * are removed from NSS then this check could be removed.
189940a40eaSsm26363 *
190940a40eaSsm26363 */
19180b80bf0Smichen void
_nscd_restart_if_cfgfile_changed()19280b80bf0Smichen _nscd_restart_if_cfgfile_changed()
193cb5caa98Sdjl {
194cb5caa98Sdjl
195cb5caa98Sdjl static mutex_t nsswitch_lock = DEFAULTMUTEX;
19680b80bf0Smichen static timestruc_t last_nsswitch_check = { 0 };
19780b80bf0Smichen static timestruc_t last_nsswitch_modified = { 0 };
198940a40eaSsm26363 static timestruc_t last_resolv_modified = { -1, 0 };
19986f95553Smichen static mutex_t restarting_lock = DEFAULTMUTEX;
20086f95553Smichen static int restarting = 0;
20186f95553Smichen int restart = 0;
202cb5caa98Sdjl time_t now = time(NULL);
20380b80bf0Smichen char *me = "_nscd_restart_if_cfgfile_changed";
204cb5caa98Sdjl
205940a40eaSsm26363 #define FLAG_RESTART_REQUIRED if (restarting == 0) {\
206940a40eaSsm26363 (void) mutex_lock(&restarting_lock);\
207940a40eaSsm26363 if (restarting == 0) {\
208940a40eaSsm26363 restarting = 1;\
209940a40eaSsm26363 restart = 1;\
210940a40eaSsm26363 }\
211940a40eaSsm26363 (void) mutex_unlock(&restarting_lock);\
212940a40eaSsm26363 }
213940a40eaSsm26363
21486f95553Smichen if (restarting == 1)
21586f95553Smichen return;
21686f95553Smichen
21780b80bf0Smichen if (now - last_nsswitch_check.tv_sec < _NSC_FILE_CHECK_TIME)
218cb5caa98Sdjl return;
219cb5caa98Sdjl
220cb5caa98Sdjl (void) mutex_lock(&nsswitch_lock);
221cb5caa98Sdjl
22280b80bf0Smichen if (now - last_nsswitch_check.tv_sec >= _NSC_FILE_CHECK_TIME) {
223cb5caa98Sdjl struct stat nss_buf;
224cb5caa98Sdjl struct stat res_buf;
225cb5caa98Sdjl
22680b80bf0Smichen last_nsswitch_check.tv_sec = now;
22780b80bf0Smichen last_nsswitch_check.tv_nsec = 0;
228cb5caa98Sdjl
229cb5caa98Sdjl (void) mutex_unlock(&nsswitch_lock); /* let others continue */
230cb5caa98Sdjl
231cb5caa98Sdjl if (stat("/etc/nsswitch.conf", &nss_buf) < 0) {
23280b80bf0Smichen return;
23380b80bf0Smichen } else if (last_nsswitch_modified.tv_sec == 0) {
23480b80bf0Smichen last_nsswitch_modified = nss_buf.st_mtim;
23580b80bf0Smichen }
236cb5caa98Sdjl
23780b80bf0Smichen if (last_nsswitch_modified.tv_sec < nss_buf.st_mtim.tv_sec ||
23880b80bf0Smichen (last_nsswitch_modified.tv_sec == nss_buf.st_mtim.tv_sec &&
239940a40eaSsm26363 last_nsswitch_modified.tv_nsec < nss_buf.st_mtim.tv_nsec)) {
240940a40eaSsm26363 FLAG_RESTART_REQUIRED;
24186f95553Smichen }
242940a40eaSsm26363
243940a40eaSsm26363 if (restart == 0) {
244940a40eaSsm26363 if (stat("/etc/resolv.conf", &res_buf) < 0) {
245940a40eaSsm26363 /* Unable to stat file, were we previously? */
246940a40eaSsm26363 if (last_resolv_modified.tv_sec > 0) {
247940a40eaSsm26363 /* Yes, it must have been removed. */
248940a40eaSsm26363 FLAG_RESTART_REQUIRED;
249940a40eaSsm26363 } else if (last_resolv_modified.tv_sec == -1) {
250940a40eaSsm26363 /* No, then we've never seen it. */
251940a40eaSsm26363 last_resolv_modified.tv_sec = 0;
252940a40eaSsm26363 }
253940a40eaSsm26363 } else if (last_resolv_modified.tv_sec == -1) {
254940a40eaSsm26363 /* We've just started and file is present. */
255940a40eaSsm26363 last_resolv_modified = res_buf.st_mtim;
256940a40eaSsm26363 } else if (last_resolv_modified.tv_sec == 0) {
257940a40eaSsm26363 /* Wasn't there at start-up. */
258940a40eaSsm26363 FLAG_RESTART_REQUIRED;
259940a40eaSsm26363 } else if (last_resolv_modified.tv_sec <
260940a40eaSsm26363 res_buf.st_mtim.tv_sec ||
261940a40eaSsm26363 (last_resolv_modified.tv_sec ==
262940a40eaSsm26363 res_buf.st_mtim.tv_sec &&
263940a40eaSsm26363 last_resolv_modified.tv_nsec <
264940a40eaSsm26363 res_buf.st_mtim.tv_nsec)) {
265940a40eaSsm26363 FLAG_RESTART_REQUIRED;
26686f95553Smichen }
26786f95553Smichen }
26886f95553Smichen
26986f95553Smichen if (restart == 1) {
270cb5caa98Sdjl char *fmri;
271cb5caa98Sdjl
272cb5caa98Sdjl /*
273cb5caa98Sdjl * if in self cred mode, kill the forker and
274cb5caa98Sdjl * child nscds
275cb5caa98Sdjl */
276cb5caa98Sdjl if (_nscd_is_self_cred_on(0, NULL)) {
277cb5caa98Sdjl _nscd_kill_forker();
278cb5caa98Sdjl _nscd_kill_all_children();
279cb5caa98Sdjl }
280cb5caa98Sdjl
281cb5caa98Sdjl /*
282cb5caa98Sdjl * time for restart
283cb5caa98Sdjl */
284cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_INFO)
285cb5caa98Sdjl (me, "nscd restart due to %s or %s change\n",
286cb5caa98Sdjl "/etc/nsswitch.conf", "resolv.conf");
287cb5caa98Sdjl /*
288cb5caa98Sdjl * try to restart under smf
289cb5caa98Sdjl */
290cb5caa98Sdjl if ((fmri = getenv("SMF_FMRI")) == NULL) {
291cb5caa98Sdjl /* not running under smf - reexec */
292cb5caa98Sdjl (void) execv(main_execname, main_argv);
293cb5caa98Sdjl exit(1); /* just in case */
294cb5caa98Sdjl }
295cb5caa98Sdjl
296cb5caa98Sdjl if (smf_restart_instance(fmri) == 0)
297cb5caa98Sdjl (void) sleep(10); /* wait a bit */
298cb5caa98Sdjl exit(1); /* give up waiting for resurrection */
299cb5caa98Sdjl }
300cb5caa98Sdjl
301cb5caa98Sdjl } else
302cb5caa98Sdjl (void) mutex_unlock(&nsswitch_lock);
303cb5caa98Sdjl }
304cb5caa98Sdjl
305cb5caa98Sdjl uid_t
_nscd_get_client_euid()306cb5caa98Sdjl _nscd_get_client_euid()
307cb5caa98Sdjl {
308cb5caa98Sdjl ucred_t *uc = NULL;
309cb5caa98Sdjl uid_t id;
310cb5caa98Sdjl char *me = "get_client_euid";
311cb5caa98Sdjl
312cb5caa98Sdjl if (door_ucred(&uc) != 0) {
313cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
314cb5caa98Sdjl (me, "door_ucred: %s\n", strerror(errno));
315cb5caa98Sdjl return ((uid_t)-1);
316cb5caa98Sdjl }
317cb5caa98Sdjl
318cb5caa98Sdjl id = ucred_geteuid(uc);
319cb5caa98Sdjl ucred_free(uc);
320cb5caa98Sdjl return (id);
321cb5caa98Sdjl }
322cb5caa98Sdjl
323bf1e3beeSmichen /*
324b57459abSJulian Pullen * Check to see if the door client's euid is 0 or if it has required_priv
3256392794bSMichen Chang * privilege. Return 0 if yes, -1 otherwise.
326b57459abSJulian Pullen * Supported values for required_priv are:
327b57459abSJulian Pullen * - NSCD_ALL_PRIV: for all zones privileges
328b57459abSJulian Pullen * - NSCD_READ_PRIV: for PRIV_FILE_DAC_READ privilege
329bf1e3beeSmichen */
330bf1e3beeSmichen int
_nscd_check_client_priv(int required_priv)331b57459abSJulian Pullen _nscd_check_client_priv(int required_priv)
332bf1e3beeSmichen {
333bf1e3beeSmichen int rc = 0;
334bf1e3beeSmichen ucred_t *uc = NULL;
335bf1e3beeSmichen const priv_set_t *eset;
336bf1e3beeSmichen char *me = "_nscd_check_client_read_priv";
337b57459abSJulian Pullen priv_set_t *zs; /* zone */
338bf1e3beeSmichen
339bf1e3beeSmichen if (door_ucred(&uc) != 0) {
340bf1e3beeSmichen _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
341bf1e3beeSmichen (me, "door_ucred: %s\n", strerror(errno));
342bf1e3beeSmichen return (-1);
343bf1e3beeSmichen }
3446392794bSMichen Chang
3456392794bSMichen Chang if (ucred_geteuid(uc) == 0) {
3466392794bSMichen Chang ucred_free(uc);
3476392794bSMichen Chang return (0);
3486392794bSMichen Chang }
3496392794bSMichen Chang
350bf1e3beeSmichen eset = ucred_getprivset(uc, PRIV_EFFECTIVE);
351b57459abSJulian Pullen switch (required_priv) {
352b57459abSJulian Pullen case NSCD_ALL_PRIV:
353b57459abSJulian Pullen zs = priv_str_to_set("zone", ",", NULL);
354b57459abSJulian Pullen if (!priv_isequalset(eset, zs)) {
355b57459abSJulian Pullen _NSCD_LOG(NSCD_LOG_FRONT_END,
356b57459abSJulian Pullen NSCD_LOG_LEVEL_ERROR)
357b57459abSJulian Pullen (me, "missing all zones privileges\n");
358b57459abSJulian Pullen rc = -1;
359b57459abSJulian Pullen }
360b57459abSJulian Pullen priv_freeset(zs);
361b57459abSJulian Pullen break;
362b57459abSJulian Pullen case NSCD_READ_PRIV:
363bf1e3beeSmichen if (!priv_ismember(eset, PRIV_FILE_DAC_READ))
364bf1e3beeSmichen rc = -1;
365b57459abSJulian Pullen break;
366b57459abSJulian Pullen default:
367b57459abSJulian Pullen _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
368b57459abSJulian Pullen (me, "unknown required_priv: %d\n", required_priv);
369b57459abSJulian Pullen rc = -1;
370b57459abSJulian Pullen break;
371b57459abSJulian Pullen }
372bf1e3beeSmichen ucred_free(uc);
373bf1e3beeSmichen return (rc);
374bf1e3beeSmichen }
375bf1e3beeSmichen
376cb5caa98Sdjl static void
N2N_check_priv(void * buf,char * dc_str)377cb5caa98Sdjl N2N_check_priv(
378cb5caa98Sdjl void *buf,
379cb5caa98Sdjl char *dc_str)
380cb5caa98Sdjl {
381cb5caa98Sdjl nss_pheader_t *phdr = (nss_pheader_t *)buf;
382cb5caa98Sdjl ucred_t *uc = NULL;
383cb5caa98Sdjl const priv_set_t *eset;
384cb5caa98Sdjl zoneid_t zoneid;
385cb5caa98Sdjl int errnum;
386cb5caa98Sdjl char *me = "N2N_check_priv";
387cb5caa98Sdjl
388cb5caa98Sdjl if (door_ucred(&uc) != 0) {
389cb5caa98Sdjl errnum = errno;
390cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
391cb5caa98Sdjl (me, "door_ucred: %s\n", strerror(errno));
392cb5caa98Sdjl
393*7d7551bcSMilan Jurik NSCD_SET_STATUS(phdr, NSS_ERROR, errnum);
394*7d7551bcSMilan Jurik return;
395cb5caa98Sdjl }
396cb5caa98Sdjl
397cb5caa98Sdjl eset = ucred_getprivset(uc, PRIV_EFFECTIVE);
398cb5caa98Sdjl zoneid = ucred_getzoneid(uc);
399cb5caa98Sdjl
400cb5caa98Sdjl if ((zoneid != GLOBAL_ZONEID && zoneid != getzoneid()) ||
401cb5caa98Sdjl eset != NULL ? !priv_ismember(eset, PRIV_SYS_ADMIN) :
402cb5caa98Sdjl ucred_geteuid(uc) != 0) {
403cb5caa98Sdjl
404cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ALERT)
405cb5caa98Sdjl (me, "%s call failed(cred): caller pid %d, uid %d, "
406cb5caa98Sdjl "euid %d, zoneid %d\n", dc_str, ucred_getpid(uc),
407cb5caa98Sdjl ucred_getruid(uc), ucred_geteuid(uc), zoneid);
408cb5caa98Sdjl ucred_free(uc);
409cb5caa98Sdjl
410*7d7551bcSMilan Jurik NSCD_SET_STATUS(phdr, NSS_ERROR, EACCES);
411*7d7551bcSMilan Jurik return;
412cb5caa98Sdjl }
413cb5caa98Sdjl
414cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
415cb5caa98Sdjl (me, "nscd received %s cmd from pid %d, uid %d, "
416cb5caa98Sdjl "euid %d, zoneid %d\n", dc_str, ucred_getpid(uc),
417cb5caa98Sdjl ucred_getruid(uc), ucred_geteuid(uc), zoneid);
418cb5caa98Sdjl
419cb5caa98Sdjl ucred_free(uc);
420cb5caa98Sdjl
421*7d7551bcSMilan Jurik NSCD_SET_STATUS_SUCCESS(phdr);
422cb5caa98Sdjl }
423cb5caa98Sdjl
424e37190e5Smichen void
_nscd_APP_check_cred(void * buf,pid_t * pidp,char * dc_str,int log_comp,int log_level)425e37190e5Smichen _nscd_APP_check_cred(
426cb5caa98Sdjl void *buf,
427cb5caa98Sdjl pid_t *pidp,
428e37190e5Smichen char *dc_str,
429e37190e5Smichen int log_comp,
430e37190e5Smichen int log_level)
431cb5caa98Sdjl {
432cb5caa98Sdjl nss_pheader_t *phdr = (nss_pheader_t *)buf;
433cb5caa98Sdjl ucred_t *uc = NULL;
434cb5caa98Sdjl uid_t ruid;
435cb5caa98Sdjl uid_t euid;
436e37190e5Smichen pid_t pid;
437cb5caa98Sdjl int errnum;
438e37190e5Smichen char *me = "_nscd_APP_check_cred";
439cb5caa98Sdjl
440cb5caa98Sdjl if (door_ucred(&uc) != 0) {
441cb5caa98Sdjl errnum = errno;
442e37190e5Smichen _NSCD_LOG(log_comp, NSCD_LOG_LEVEL_ERROR)
443cb5caa98Sdjl (me, "door_ucred: %s\n", strerror(errno));
444cb5caa98Sdjl
445*7d7551bcSMilan Jurik NSCD_SET_STATUS(phdr, NSS_ERROR, errnum);
446*7d7551bcSMilan Jurik return;
447cb5caa98Sdjl }
448cb5caa98Sdjl
449e37190e5Smichen NSCD_SET_STATUS_SUCCESS(phdr);
450e37190e5Smichen pid = ucred_getpid(uc);
451cb5caa98Sdjl if (NSS_PACKED_CRED_CHECK(buf, ruid = ucred_getruid(uc),
452cb5caa98Sdjl euid = ucred_geteuid(uc))) {
453e37190e5Smichen if (pidp != NULL) {
454e37190e5Smichen if (*pidp == (pid_t)-1)
455e37190e5Smichen *pidp = pid;
456e37190e5Smichen else if (*pidp != pid) {
457e37190e5Smichen NSCD_SET_STATUS(phdr, NSS_ERROR, EACCES);
458e37190e5Smichen }
459e37190e5Smichen }
460e37190e5Smichen } else {
461e37190e5Smichen NSCD_SET_STATUS(phdr, NSS_ERROR, EACCES);
462cb5caa98Sdjl }
463cb5caa98Sdjl
464cb5caa98Sdjl ucred_free(uc);
465cb5caa98Sdjl
466e37190e5Smichen if (NSCD_STATUS_IS_NOT_OK(phdr)) {
467e37190e5Smichen _NSCD_LOG(log_comp, log_level)
468e37190e5Smichen (me, "%s call failed: caller pid %d (input pid = %d), ruid %d, "
469e37190e5Smichen "euid %d, header ruid %d, header euid %d\n", dc_str,
470e37190e5Smichen pid, (pidp != NULL) ? *pidp : -1, ruid, euid,
471e37190e5Smichen ((nss_pheader_t *)(buf))->p_ruid,
472e37190e5Smichen ((nss_pheader_t *)(buf))->p_euid);
473e37190e5Smichen }
474cb5caa98Sdjl }
475cb5caa98Sdjl
476606f6aa3Smichen /* log error and return -1 when an invalid packed buffer header is found */
477606f6aa3Smichen static int
pheader_error(nss_pheader_t * phdr,uint32_t call_number)478606f6aa3Smichen pheader_error(nss_pheader_t *phdr, uint32_t call_number)
479606f6aa3Smichen {
480606f6aa3Smichen char *call_num_str;
481606f6aa3Smichen
482606f6aa3Smichen switch (call_number) {
483606f6aa3Smichen case NSCD_SEARCH:
484606f6aa3Smichen call_num_str = "NSCD_SEARCH";
485606f6aa3Smichen break;
486606f6aa3Smichen case NSCD_SETENT:
487606f6aa3Smichen call_num_str = "NSCD_SETENT";
488606f6aa3Smichen break;
489606f6aa3Smichen case NSCD_GETENT:
490606f6aa3Smichen call_num_str = "NSCD_GETENT";
491606f6aa3Smichen break;
492606f6aa3Smichen case NSCD_ENDENT:
493606f6aa3Smichen call_num_str = "NSCD_ENDENT";
494606f6aa3Smichen break;
495606f6aa3Smichen case NSCD_PUT:
496606f6aa3Smichen call_num_str = "NSCD_PUT";
497606f6aa3Smichen break;
498606f6aa3Smichen case NSCD_GETHINTS:
499606f6aa3Smichen call_num_str = "NSCD_GETHINTS";
500606f6aa3Smichen break;
501606f6aa3Smichen default:
502606f6aa3Smichen call_num_str = "UNKNOWN";
503606f6aa3Smichen break;
504606f6aa3Smichen }
505606f6aa3Smichen
506606f6aa3Smichen _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ALERT)
507606f6aa3Smichen ("pheader_error", "call number %s: invalid packed buffer header\n",
508606f6aa3Smichen call_num_str);
509606f6aa3Smichen
510606f6aa3Smichen NSCD_SET_STATUS(phdr, NSS_ERROR, EINVAL);
511606f6aa3Smichen return (-1);
512606f6aa3Smichen }
513606f6aa3Smichen
514606f6aa3Smichen /*
515606f6aa3Smichen * Validate the header of a getXbyY or setent/getent/endent request.
516606f6aa3Smichen * Return 0 if good, -1 otherwise.
517606f6aa3Smichen *
518606f6aa3Smichen * A valid header looks like the following (size is arg_size, does
519606f6aa3Smichen * not include the output area):
520606f6aa3Smichen * +----------------------------------+ --
521606f6aa3Smichen * | nss_pheader_t (header fixed part)| ^
522606f6aa3Smichen * | | |
523606f6aa3Smichen * | pbufsiz, dbd,off, key_off, | len = sizeof(nss_pheader_t)
524606f6aa3Smichen * | data_off .... | |
525606f6aa3Smichen * | | v
526606f6aa3Smichen * +----------------------------------+ <----- dbd_off
527606f6aa3Smichen * | dbd (database description) | ^
528606f6aa3Smichen * | nss_dbd_t + up to 3 strings | |
529606f6aa3Smichen * | length = sizeof(nss_dbd_t) + | len = key_off - dbd_off
530606f6aa3Smichen * | length of 3 strings + | |
531606f6aa3Smichen * | length of padding | |
532606f6aa3Smichen * | (total length in multiple of 4) | v
533606f6aa3Smichen * +----------------------------------+ <----- key_off
534606f6aa3Smichen * | lookup key | ^
535606f6aa3Smichen * | nss_XbyY_key_t, content varies, | |
536606f6aa3Smichen * | based on database and lookup op | len = data_off - key_off
537606f6aa3Smichen * | length = data_off - key_off | |
538606f6aa3Smichen * | including padding, multiple of 4 | v
539606f6aa3Smichen * +----------------------------------+ <----- data_off (= arg_size)
540606f6aa3Smichen * | | ^
541606f6aa3Smichen * | area to hold results | |
542606f6aa3Smichen * | | len = data_len (= pbufsiz -
543606f6aa3Smichen * | | | data_off)
544606f6aa3Smichen * | | v
545606f6aa3Smichen * +----------------------------------+ <----- pbufsiz
546606f6aa3Smichen */
547606f6aa3Smichen static int
validate_pheader(void * argp,size_t arg_size,uint32_t call_number)548606f6aa3Smichen validate_pheader(
549606f6aa3Smichen void *argp,
550606f6aa3Smichen size_t arg_size,
551606f6aa3Smichen uint32_t call_number)
552606f6aa3Smichen {
553606f6aa3Smichen nss_pheader_t *phdr = (nss_pheader_t *)(void *)argp;
554606f6aa3Smichen nssuint_t l1, l2;
555606f6aa3Smichen
556606f6aa3Smichen /*
557606f6aa3Smichen * current version is NSCD_HEADER_REV, length of the fixed part
558606f6aa3Smichen * of the header must match the size of nss_pheader_t
559606f6aa3Smichen */
560606f6aa3Smichen if (phdr->p_version != NSCD_HEADER_REV ||
561606f6aa3Smichen phdr->dbd_off != sizeof (nss_pheader_t))
562606f6aa3Smichen return (pheader_error(phdr, call_number));
563606f6aa3Smichen
564606f6aa3Smichen /*
565606f6aa3Smichen * buffer size and offsets must be in multiple of 4
566606f6aa3Smichen */
567606f6aa3Smichen if ((arg_size & 3) || (phdr->dbd_off & 3) || (phdr->key_off & 3) ||
568606f6aa3Smichen (phdr->data_off & 3))
569606f6aa3Smichen return (pheader_error(phdr, call_number));
570606f6aa3Smichen
571606f6aa3Smichen /*
572606f6aa3Smichen * the input arg_size is the length of the request header
573606f6aa3Smichen * and should be less than NSCD_PHDR_MAXLEN
574606f6aa3Smichen */
575606f6aa3Smichen if (phdr->data_off != arg_size || arg_size > NSCD_PHDR_MAXLEN)
576606f6aa3Smichen return (pheader_error(phdr, call_number));
577606f6aa3Smichen
578606f6aa3Smichen /* get length of the dbd area */
579606f6aa3Smichen l1 = phdr->key_off - phdr-> dbd_off;
580606f6aa3Smichen
581606f6aa3Smichen /*
582606f6aa3Smichen * dbd area may contain padding, so length of dbd should
583606f6aa3Smichen * not be less than the length of the actual data
584606f6aa3Smichen */
585606f6aa3Smichen if (l1 < phdr->dbd_len)
586606f6aa3Smichen return (pheader_error(phdr, call_number));
587606f6aa3Smichen
588606f6aa3Smichen /* get length of the key area */
589606f6aa3Smichen l2 = phdr->data_off - phdr->key_off;
590606f6aa3Smichen
591606f6aa3Smichen /*
592606f6aa3Smichen * key area may contain padding, so length of key area should
593606f6aa3Smichen * not be less than the length of the actual data
594606f6aa3Smichen */
595606f6aa3Smichen if (l2 < phdr->key_len)
596606f6aa3Smichen return (pheader_error(phdr, call_number));
597606f6aa3Smichen
598606f6aa3Smichen /*
599606f6aa3Smichen * length of fixed part + lengths of dbd and key area = length of
600606f6aa3Smichen * the request header
601606f6aa3Smichen */
602606f6aa3Smichen if (sizeof (nss_pheader_t) + l1 + l2 != phdr->data_off)
603606f6aa3Smichen return (pheader_error(phdr, call_number));
604606f6aa3Smichen
605606f6aa3Smichen /* header length + data length = buffer length */
606606f6aa3Smichen if (phdr->data_off + phdr->data_len != phdr->pbufsiz)
607606f6aa3Smichen return (pheader_error(phdr, call_number));
608606f6aa3Smichen
609606f6aa3Smichen return (0);
610606f6aa3Smichen }
611606f6aa3Smichen
612606f6aa3Smichen /* log error and return -1 when an invalid nscd to nscd buffer is found */
613606f6aa3Smichen static int
N2Nbuf_error(nss_pheader_t * phdr,uint32_t call_number)614606f6aa3Smichen N2Nbuf_error(nss_pheader_t *phdr, uint32_t call_number)
615606f6aa3Smichen {
616606f6aa3Smichen char *call_num_str;
617606f6aa3Smichen
618606f6aa3Smichen switch (call_number) {
619606f6aa3Smichen case NSCD_PING:
620606f6aa3Smichen call_num_str = "NSCD_PING";
621606f6aa3Smichen break;
622606f6aa3Smichen
623606f6aa3Smichen case NSCD_IMHERE:
624606f6aa3Smichen call_num_str = "NSCD_IMHERE";
625606f6aa3Smichen break;
626606f6aa3Smichen
627606f6aa3Smichen case NSCD_PULSE:
628606f6aa3Smichen call_num_str = "NSCD_PULSE";
629606f6aa3Smichen break;
630606f6aa3Smichen
631606f6aa3Smichen case NSCD_FORK:
632606f6aa3Smichen call_num_str = "NSCD_FORK";
633606f6aa3Smichen break;
634606f6aa3Smichen
635606f6aa3Smichen case NSCD_KILL:
636606f6aa3Smichen call_num_str = "NSCD_KILL";
637606f6aa3Smichen break;
638606f6aa3Smichen
639606f6aa3Smichen case NSCD_REFRESH:
640606f6aa3Smichen call_num_str = "NSCD_REFRESH";
641606f6aa3Smichen break;
642606f6aa3Smichen
643606f6aa3Smichen case NSCD_GETPUADMIN:
644606f6aa3Smichen call_num_str = "NSCD_GETPUADMIN";
645606f6aa3Smichen break;
646606f6aa3Smichen
647606f6aa3Smichen case NSCD_GETADMIN:
648606f6aa3Smichen call_num_str = "NSCD_GETADMIN";
649606f6aa3Smichen break;
650606f6aa3Smichen
651606f6aa3Smichen case NSCD_SETADMIN:
652606f6aa3Smichen call_num_str = "NSCD_SETADMIN";
653606f6aa3Smichen break;
654606f6aa3Smichen
655606f6aa3Smichen case NSCD_KILLSERVER:
656606f6aa3Smichen call_num_str = "NSCD_KILLSERVER";
657606f6aa3Smichen break;
658606f6aa3Smichen default:
659606f6aa3Smichen call_num_str = "UNKNOWN";
660606f6aa3Smichen break;
661606f6aa3Smichen }
662606f6aa3Smichen
663606f6aa3Smichen _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ALERT)
664bf1e3beeSmichen ("N2Nbuf_error", "call number %s: invalid N2N buffer\n", call_num_str);
665606f6aa3Smichen
666606f6aa3Smichen NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
667606f6aa3Smichen NSCD_DOOR_BUFFER_CHECK_FAILED);
668606f6aa3Smichen
669606f6aa3Smichen return (-1);
670606f6aa3Smichen }
671606f6aa3Smichen
672606f6aa3Smichen /*
673606f6aa3Smichen * Validate the buffer of an nscd to nscd request.
674606f6aa3Smichen * Return 0 if good, -1 otherwise.
675606f6aa3Smichen *
676606f6aa3Smichen * A valid buffer looks like the following (size is arg_size):
677606f6aa3Smichen * +----------------------------------+ --
678606f6aa3Smichen * | nss_pheader_t (header fixed part)| ^
679606f6aa3Smichen * | | |
680606f6aa3Smichen * | pbufsiz, dbd,off, key_off, | len = sizeof(nss_pheader_t)
681606f6aa3Smichen * | data_off .... | |
682606f6aa3Smichen * | | v
683606f6aa3Smichen * +----------------------------------+ <---dbd_off = key_off = data_off
684606f6aa3Smichen * | | ^
685606f6aa3Smichen * | input data/output data | |
686606f6aa3Smichen * | OR no data | len = data_len (= pbufsiz -
687606f6aa3Smichen * | | | data_off)
688606f6aa3Smichen * | | | len could be zero
689606f6aa3Smichen * | | v
690606f6aa3Smichen * +----------------------------------+ <--- pbufsiz
691606f6aa3Smichen */
692606f6aa3Smichen static int
validate_N2Nbuf(void * argp,size_t arg_size,uint32_t call_number)693606f6aa3Smichen validate_N2Nbuf(
694606f6aa3Smichen void *argp,
695606f6aa3Smichen size_t arg_size,
696606f6aa3Smichen uint32_t call_number)
697606f6aa3Smichen {
698606f6aa3Smichen nss_pheader_t *phdr = (nss_pheader_t *)(void *)argp;
699606f6aa3Smichen
700606f6aa3Smichen /*
701606f6aa3Smichen * current version is NSCD_HEADER_REV, length of the fixed part
702606f6aa3Smichen * of the header must match the size of nss_pheader_t
703606f6aa3Smichen */
704606f6aa3Smichen if (phdr->p_version != NSCD_HEADER_REV ||
705606f6aa3Smichen phdr->dbd_off != sizeof (nss_pheader_t))
706606f6aa3Smichen return (N2Nbuf_error(phdr, call_number));
707606f6aa3Smichen
708606f6aa3Smichen /*
709606f6aa3Smichen * There are no dbd and key data, so the dbd, key, data
710606f6aa3Smichen * offsets should be equal
711606f6aa3Smichen */
712606f6aa3Smichen if (phdr->dbd_off != phdr->key_off ||
713606f6aa3Smichen phdr->dbd_off != phdr->data_off)
714606f6aa3Smichen return (N2Nbuf_error(phdr, call_number));
715606f6aa3Smichen
716606f6aa3Smichen /*
717606f6aa3Smichen * the input arg_size is the buffer length and should
718606f6aa3Smichen * be less or equal than NSCD_N2NBUF_MAXLEN
719606f6aa3Smichen */
720606f6aa3Smichen if (phdr->pbufsiz != arg_size || arg_size > NSCD_N2NBUF_MAXLEN)
721606f6aa3Smichen return (N2Nbuf_error(phdr, call_number));
722606f6aa3Smichen
723606f6aa3Smichen /* header length + data length = buffer length */
724606f6aa3Smichen if (phdr->data_off + phdr->data_len != phdr->pbufsiz)
725606f6aa3Smichen return (N2Nbuf_error(phdr, call_number));
726606f6aa3Smichen
727606f6aa3Smichen return (0);
728606f6aa3Smichen }
729606f6aa3Smichen
730cb5caa98Sdjl static void
lookup(char * argp,size_t arg_size)731cb5caa98Sdjl lookup(char *argp, size_t arg_size)
732cb5caa98Sdjl {
733cb5caa98Sdjl nsc_lookup_args_t largs;
734cb5caa98Sdjl char space[NSCD_LOOKUP_BUFSIZE];
735cb5caa98Sdjl nss_pheader_t *phdr = (nss_pheader_t *)(void *)argp;
736cb5caa98Sdjl
737cb5caa98Sdjl NSCD_ALLOC_LOOKUP_BUFFER(argp, arg_size, phdr, space,
738cb5caa98Sdjl sizeof (space));
739cb5caa98Sdjl
740606f6aa3Smichen /*
741606f6aa3Smichen * make sure the first couple bytes of the data area is null,
742606f6aa3Smichen * so that bad strings in the packed header stop here
743606f6aa3Smichen */
744606f6aa3Smichen (void) memset((char *)phdr + phdr->data_off, 0, 16);
745606f6aa3Smichen
746cb5caa98Sdjl (void) memset(&largs, 0, sizeof (largs));
747cb5caa98Sdjl largs.buffer = argp;
748cb5caa98Sdjl largs.bufsize = arg_size;
749cb5caa98Sdjl nsc_lookup(&largs, 0);
750cb5caa98Sdjl
751cb5caa98Sdjl /*
752cb5caa98Sdjl * only the PUN needs to keep track of the
753cb5caa98Sdjl * activity count to determine when to
754cb5caa98Sdjl * terminate itself
755cb5caa98Sdjl */
756cb5caa98Sdjl if (_whoami == NSCD_CHILD) {
757cb5caa98Sdjl (void) mutex_lock(&activity_lock);
758cb5caa98Sdjl ++activity;
759cb5caa98Sdjl (void) mutex_unlock(&activity_lock);
760cb5caa98Sdjl }
761cb5caa98Sdjl
762cb5caa98Sdjl NSCD_SET_RETURN_ARG(phdr, arg_size);
763cb5caa98Sdjl (void) door_return(argp, arg_size, NULL, 0);
764cb5caa98Sdjl }
765cb5caa98Sdjl
766cb5caa98Sdjl static void
getent(char * argp,size_t arg_size)767cb5caa98Sdjl getent(char *argp, size_t arg_size)
768cb5caa98Sdjl {
769cb5caa98Sdjl char space[NSCD_LOOKUP_BUFSIZE];
770cb5caa98Sdjl nss_pheader_t *phdr = (nss_pheader_t *)(void *)argp;
771cb5caa98Sdjl
772bf1e3beeSmichen NSCD_ALLOC_LOOKUP_BUFFER(argp, arg_size, phdr, space, sizeof (space));
773cb5caa98Sdjl
774cb5caa98Sdjl nss_pgetent(argp, arg_size);
775cb5caa98Sdjl
776cb5caa98Sdjl NSCD_SET_RETURN_ARG(phdr, arg_size);
777cb5caa98Sdjl (void) door_return(argp, arg_size, NULL, 0);
778cb5caa98Sdjl }
779cb5caa98Sdjl
780cb5caa98Sdjl static int
is_db_per_user(void * buf,char * dblist)781cb5caa98Sdjl is_db_per_user(void *buf, char *dblist)
782cb5caa98Sdjl {
783cb5caa98Sdjl nss_pheader_t *phdr = (nss_pheader_t *)buf;
784cb5caa98Sdjl nss_dbd_t *pdbd;
785cb5caa98Sdjl char *dbname, *dbn;
786cb5caa98Sdjl int len;
787cb5caa98Sdjl
788cb5caa98Sdjl /* copy db name into a temp buffer */
789cb5caa98Sdjl pdbd = (nss_dbd_t *)((void *)((char *)buf + phdr->dbd_off));
790cb5caa98Sdjl dbname = (char *)pdbd + pdbd->o_name;
791cb5caa98Sdjl len = strlen(dbname);
792cb5caa98Sdjl dbn = alloca(len + 2);
793cb5caa98Sdjl (void) memcpy(dbn, dbname, len);
794cb5caa98Sdjl
795cb5caa98Sdjl /* check if <dbname> + ',' can be found in the dblist string */
796cb5caa98Sdjl dbn[len] = ',';
797cb5caa98Sdjl dbn[len + 1] = '\0';
798cb5caa98Sdjl if (strstr(dblist, dbn) != NULL)
799cb5caa98Sdjl return (1);
800cb5caa98Sdjl
801cb5caa98Sdjl /*
802cb5caa98Sdjl * check if <dbname> can be found in the last part
803cb5caa98Sdjl * of the dblist string
804cb5caa98Sdjl */
805cb5caa98Sdjl dbn[len] = '\0';
806cb5caa98Sdjl if (strstr(dblist, dbn) != NULL)
807cb5caa98Sdjl return (1);
808cb5caa98Sdjl
809cb5caa98Sdjl return (0);
810cb5caa98Sdjl }
811cb5caa98Sdjl
812cb5caa98Sdjl /*
813cb5caa98Sdjl * Check to see if all conditions are met for processing per-user
814cb5caa98Sdjl * requests. Returns 1 if yes, -1 if backend is not configured,
815cb5caa98Sdjl * 0 otherwise.
816cb5caa98Sdjl */
817cb5caa98Sdjl static int
need_per_user_door(void * buf,int whoami,uid_t uid,char ** dblist)818cb5caa98Sdjl need_per_user_door(void *buf, int whoami, uid_t uid, char **dblist)
819cb5caa98Sdjl {
820cb5caa98Sdjl nss_pheader_t *phdr = (nss_pheader_t *)buf;
821cb5caa98Sdjl
822cb5caa98Sdjl NSCD_SET_STATUS_SUCCESS(phdr);
823cb5caa98Sdjl
824cb5caa98Sdjl /* if already a per-user nscd, no need to get per-user door */
825cb5caa98Sdjl if (whoami == NSCD_CHILD)
826cb5caa98Sdjl return (0);
827cb5caa98Sdjl
828cb5caa98Sdjl /* forker shouldn't be asked */
829cb5caa98Sdjl if (whoami == NSCD_FORKER) {
830cb5caa98Sdjl NSCD_SET_STATUS(phdr, NSS_ERROR, ENOTSUP);
831cb5caa98Sdjl return (0);
832cb5caa98Sdjl }
833cb5caa98Sdjl
834cb5caa98Sdjl /* if door client is root, no need for a per-user door */
835cb5caa98Sdjl if (uid == 0)
836cb5caa98Sdjl return (0);
837cb5caa98Sdjl
838cb5caa98Sdjl /*
839cb5caa98Sdjl * if per-user lookup is not configured, no per-user
840cb5caa98Sdjl * door available
841cb5caa98Sdjl */
842cb5caa98Sdjl if (_nscd_is_self_cred_on(0, dblist) == 0)
843cb5caa98Sdjl return (-1);
844cb5caa98Sdjl
845cb5caa98Sdjl /*
846cb5caa98Sdjl * if per-user lookup is not configured for the db,
847cb5caa98Sdjl * don't bother
848cb5caa98Sdjl */
849cb5caa98Sdjl if (is_db_per_user(phdr, *dblist) == 0)
850cb5caa98Sdjl return (0);
851cb5caa98Sdjl
852cb5caa98Sdjl return (1);
853cb5caa98Sdjl }
854cb5caa98Sdjl
855cb5caa98Sdjl static void
if_selfcred_return_per_user_door(char * argp,size_t arg_size,door_desc_t * dp,int whoami)856cb5caa98Sdjl if_selfcred_return_per_user_door(char *argp, size_t arg_size,
857cb5caa98Sdjl door_desc_t *dp, int whoami)
858cb5caa98Sdjl {
859cb5caa98Sdjl nss_pheader_t *phdr = (nss_pheader_t *)((void *)argp);
860cb5caa98Sdjl char *dblist;
861cb5caa98Sdjl int door = -1;
862cb5caa98Sdjl int rc = 0;
863cb5caa98Sdjl door_desc_t desc;
864606f6aa3Smichen char *space;
865606f6aa3Smichen int len;
866cb5caa98Sdjl
867cb5caa98Sdjl /*
868cb5caa98Sdjl * check to see if self-cred is configured and
869cb5caa98Sdjl * need to return an alternate PUN door
870cb5caa98Sdjl */
871cb5caa98Sdjl if (per_user_is_on == 1) {
872cb5caa98Sdjl rc = need_per_user_door(argp, whoami,
873cb5caa98Sdjl _nscd_get_client_euid(), &dblist);
874cb5caa98Sdjl if (rc == -1)
875cb5caa98Sdjl per_user_is_on = 0;
876cb5caa98Sdjl }
877cb5caa98Sdjl if (rc <= 0) {
878cb5caa98Sdjl /*
879cb5caa98Sdjl * self-cred not configured, and no error detected,
880cb5caa98Sdjl * return to continue the door call processing
881cb5caa98Sdjl */
882cb5caa98Sdjl if (NSCD_STATUS_IS_OK(phdr))
883cb5caa98Sdjl return;
884cb5caa98Sdjl else
885cb5caa98Sdjl /*
886cb5caa98Sdjl * configured but error detected,
887cb5caa98Sdjl * stop the door call processing
888cb5caa98Sdjl */
889cb5caa98Sdjl (void) door_return(argp, phdr->data_off, NULL, 0);
890cb5caa98Sdjl }
891cb5caa98Sdjl
892cb5caa98Sdjl /* get the alternate PUN door */
893cb5caa98Sdjl _nscd_proc_alt_get(argp, &door);
894cb5caa98Sdjl if (NSCD_GET_STATUS(phdr) != NSS_ALTRETRY) {
895cb5caa98Sdjl (void) door_return(argp, phdr->data_off, NULL, 0);
896cb5caa98Sdjl }
897cb5caa98Sdjl
898cb5caa98Sdjl /* return the alternate door descriptor */
899606f6aa3Smichen len = strlen(dblist) + 1;
900606f6aa3Smichen space = alloca(arg_size + len);
901606f6aa3Smichen phdr->data_len = len;
902606f6aa3Smichen (void) memcpy(space, phdr, arg_size);
903606f6aa3Smichen (void) strncpy((char *)space + arg_size, dblist, len);
904cb5caa98Sdjl dp = &desc;
905cb5caa98Sdjl dp->d_attributes = DOOR_DESCRIPTOR;
906cb5caa98Sdjl dp->d_data.d_desc.d_descriptor = door;
907606f6aa3Smichen arg_size += len;
908606f6aa3Smichen (void) door_return(space, arg_size, dp, 1);
909cb5caa98Sdjl }
910cb5caa98Sdjl
911cb5caa98Sdjl /*ARGSUSED*/
912cb5caa98Sdjl static void
switcher(void * cookie,char * argp,size_t arg_size,door_desc_t * dp,uint_t n_desc)913cb5caa98Sdjl switcher(void *cookie, char *argp, size_t arg_size,
914cb5caa98Sdjl door_desc_t *dp, uint_t n_desc)
915cb5caa98Sdjl {
916cb5caa98Sdjl int iam;
917cb5caa98Sdjl pid_t ent_pid = -1;
918cb5caa98Sdjl nss_pheader_t *phdr = (nss_pheader_t *)((void *)argp);
919cb5caa98Sdjl void *uptr;
920606f6aa3Smichen int len;
921606f6aa3Smichen size_t buflen;
922cb5caa98Sdjl int callnum;
923cb5caa98Sdjl char *me = "switcher";
924cb5caa98Sdjl
925cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
926cb5caa98Sdjl (me, "switcher ...\n");
927cb5caa98Sdjl
928cb5caa98Sdjl if (argp == DOOR_UNREF_DATA) {
929cb5caa98Sdjl (void) printf("Door Slam... exiting\n");
930cb5caa98Sdjl exit(0);
931cb5caa98Sdjl }
932cb5caa98Sdjl
933cb5caa98Sdjl if (argp == NULL) { /* empty door call */
934cb5caa98Sdjl (void) door_return(NULL, 0, 0, 0); /* return the favor */
935cb5caa98Sdjl }
936cb5caa98Sdjl
937cb5caa98Sdjl /*
938cb5caa98Sdjl * need to restart if main nscd and config file(s) changed
939cb5caa98Sdjl */
940cb5caa98Sdjl if (_whoami == NSCD_MAIN)
94180b80bf0Smichen _nscd_restart_if_cfgfile_changed();
942cb5caa98Sdjl
943cb5caa98Sdjl if ((phdr->nsc_callnumber & NSCDV2CATMASK) == NSCD_CALLCAT_APP) {
944606f6aa3Smichen
945606f6aa3Smichen /* make sure the packed buffer header is good */
946606f6aa3Smichen if (validate_pheader(argp, arg_size,
947606f6aa3Smichen phdr->nsc_callnumber) == -1)
948606f6aa3Smichen (void) door_return(argp, arg_size, NULL, 0);
949606f6aa3Smichen
950cb5caa98Sdjl switch (phdr->nsc_callnumber) {
951606f6aa3Smichen
952cb5caa98Sdjl case NSCD_SEARCH:
953cb5caa98Sdjl
954cb5caa98Sdjl /* if a fallback to main nscd, skip per-user setup */
955cb5caa98Sdjl if (phdr->p_status != NSS_ALTRETRY)
956cb5caa98Sdjl if_selfcred_return_per_user_door(argp, arg_size,
957cb5caa98Sdjl dp, _whoami);
958cb5caa98Sdjl lookup(argp, arg_size);
959cb5caa98Sdjl
960cb5caa98Sdjl break;
961cb5caa98Sdjl
962cb5caa98Sdjl case NSCD_SETENT:
963cb5caa98Sdjl
964e37190e5Smichen _nscd_APP_check_cred(argp, &ent_pid, "NSCD_SETENT",
965e37190e5Smichen NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ALERT);
966cb5caa98Sdjl if (NSCD_STATUS_IS_OK(phdr)) {
967cb5caa98Sdjl if_selfcred_return_per_user_door(argp, arg_size,
968cb5caa98Sdjl dp, _whoami);
969cb5caa98Sdjl nss_psetent(argp, arg_size, ent_pid);
970cb5caa98Sdjl }
971cb5caa98Sdjl break;
972cb5caa98Sdjl
973cb5caa98Sdjl case NSCD_GETENT:
974cb5caa98Sdjl
975cb5caa98Sdjl getent(argp, arg_size);
976cb5caa98Sdjl break;
977cb5caa98Sdjl
978cb5caa98Sdjl case NSCD_ENDENT:
979cb5caa98Sdjl
980cb5caa98Sdjl nss_pendent(argp, arg_size);
981cb5caa98Sdjl break;
982cb5caa98Sdjl
983cb5caa98Sdjl case NSCD_PUT:
984cb5caa98Sdjl
985cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
986cb5caa98Sdjl (me, "door call NSCD_PUT not supported yet\n");
987cb5caa98Sdjl
988cb5caa98Sdjl NSCD_SET_STATUS(phdr, NSS_ERROR, ENOTSUP);
989cb5caa98Sdjl break;
990cb5caa98Sdjl
991cb5caa98Sdjl case NSCD_GETHINTS:
992cb5caa98Sdjl
993cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
994cb5caa98Sdjl (me, "door call NSCD_GETHINTS not supported yet\n");
995cb5caa98Sdjl
996cb5caa98Sdjl NSCD_SET_STATUS(phdr, NSS_ERROR, ENOTSUP);
997cb5caa98Sdjl break;
998cb5caa98Sdjl
999cb5caa98Sdjl default:
1000cb5caa98Sdjl
1001cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1002cb5caa98Sdjl (me, "Unknown name service door call op %x\n",
1003cb5caa98Sdjl phdr->nsc_callnumber);
1004cb5caa98Sdjl
1005cb5caa98Sdjl NSCD_SET_STATUS(phdr, NSS_ERROR, EINVAL);
1006cb5caa98Sdjl break;
1007cb5caa98Sdjl }
1008cb5caa98Sdjl
1009cb5caa98Sdjl (void) door_return(argp, arg_size, NULL, 0);
1010cb5caa98Sdjl }
1011cb5caa98Sdjl
1012cb5caa98Sdjl iam = NSCD_MAIN;
1013cb5caa98Sdjl callnum = phdr->nsc_callnumber & ~NSCD_WHOAMI;
1014cb5caa98Sdjl if (callnum == NSCD_IMHERE ||
1015cb5caa98Sdjl callnum == NSCD_PULSE || callnum == NSCD_FORK)
1016cb5caa98Sdjl iam = phdr->nsc_callnumber & NSCD_WHOAMI;
1017cb5caa98Sdjl else
1018cb5caa98Sdjl callnum = phdr->nsc_callnumber;
1019cb5caa98Sdjl
1020cb5caa98Sdjl /* nscd -> nscd v2 calls */
1021606f6aa3Smichen
1022606f6aa3Smichen /* make sure the buffer is good */
1023606f6aa3Smichen if (validate_N2Nbuf(argp, arg_size, callnum) == -1)
1024606f6aa3Smichen (void) door_return(argp, arg_size, NULL, 0);
1025606f6aa3Smichen
1026cb5caa98Sdjl switch (callnum) {
1027cb5caa98Sdjl
1028cb5caa98Sdjl case NSCD_PING:
1029cb5caa98Sdjl NSCD_SET_STATUS_SUCCESS(phdr);
1030cb5caa98Sdjl break;
1031cb5caa98Sdjl
1032cb5caa98Sdjl case NSCD_IMHERE:
1033cb5caa98Sdjl _nscd_proc_iamhere(argp, dp, n_desc, iam);
1034cb5caa98Sdjl break;
1035cb5caa98Sdjl
1036cb5caa98Sdjl case NSCD_PULSE:
1037cb5caa98Sdjl N2N_check_priv(argp, "NSCD_PULSE");
1038cb5caa98Sdjl if (NSCD_STATUS_IS_OK(phdr))
1039cb5caa98Sdjl _nscd_proc_pulse(argp, iam);
1040cb5caa98Sdjl break;
1041cb5caa98Sdjl
1042cb5caa98Sdjl case NSCD_FORK:
1043cb5caa98Sdjl N2N_check_priv(argp, "NSCD_FORK");
1044cb5caa98Sdjl if (NSCD_STATUS_IS_OK(phdr))
1045cb5caa98Sdjl _nscd_proc_fork(argp, iam);
1046cb5caa98Sdjl break;
1047cb5caa98Sdjl
1048cb5caa98Sdjl case NSCD_KILL:
1049cb5caa98Sdjl N2N_check_priv(argp, "NSCD_KILL");
1050cb5caa98Sdjl if (NSCD_STATUS_IS_OK(phdr))
1051cb5caa98Sdjl exit(0);
1052cb5caa98Sdjl break;
1053cb5caa98Sdjl
1054cb5caa98Sdjl case NSCD_REFRESH:
1055606f6aa3Smichen N2N_check_priv(argp, "NSCD_REFRESH");
1056606f6aa3Smichen if (NSCD_STATUS_IS_OK(phdr)) {
1057cb5caa98Sdjl if (_nscd_refresh() != NSCD_SUCCESS)
1058cb5caa98Sdjl exit(1);
1059cb5caa98Sdjl NSCD_SET_STATUS_SUCCESS(phdr);
1060606f6aa3Smichen }
1061cb5caa98Sdjl break;
1062cb5caa98Sdjl
1063cb5caa98Sdjl case NSCD_GETPUADMIN:
1064cb5caa98Sdjl
1065cb5caa98Sdjl if (_nscd_is_self_cred_on(0, NULL)) {
1066cb5caa98Sdjl _nscd_peruser_getadmin(argp, sizeof (nscd_admin_t));
1067cb5caa98Sdjl } else {
1068cb5caa98Sdjl NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
1069cb5caa98Sdjl NSCD_SELF_CRED_NOT_CONFIGURED);
1070cb5caa98Sdjl }
1071cb5caa98Sdjl break;
1072cb5caa98Sdjl
1073cb5caa98Sdjl case NSCD_GETADMIN:
1074cb5caa98Sdjl
1075cb5caa98Sdjl len = _nscd_door_getadmin((void *)argp);
1076cb5caa98Sdjl if (len == 0)
1077cb5caa98Sdjl break;
1078cb5caa98Sdjl
1079cb5caa98Sdjl /* size of door buffer not big enough, allocate one */
1080cb5caa98Sdjl NSCD_ALLOC_DOORBUF(NSCD_GETADMIN, len, uptr, buflen);
1081cb5caa98Sdjl
1082cb5caa98Sdjl /* copy packed header */
1083cb5caa98Sdjl *(nss_pheader_t *)uptr = *(nss_pheader_t *)((void *)argp);
1084cb5caa98Sdjl
1085cb5caa98Sdjl /* set new buffer size */
1086cb5caa98Sdjl ((nss_pheader_t *)uptr)->pbufsiz = buflen;
1087cb5caa98Sdjl
1088cb5caa98Sdjl /* try one more time */
1089cb5caa98Sdjl (void) _nscd_door_getadmin((void *)uptr);
1090cb5caa98Sdjl (void) door_return(uptr, buflen, NULL, 0);
1091cb5caa98Sdjl break;
1092cb5caa98Sdjl
1093cb5caa98Sdjl case NSCD_SETADMIN:
1094cb5caa98Sdjl N2N_check_priv(argp, "NSCD_SETADMIN");
1095cb5caa98Sdjl if (NSCD_STATUS_IS_OK(phdr))
1096cb5caa98Sdjl _nscd_door_setadmin(argp);
1097cb5caa98Sdjl break;
1098cb5caa98Sdjl
1099cb5caa98Sdjl case NSCD_KILLSERVER:
1100cb5caa98Sdjl N2N_check_priv(argp, "NSCD_KILLSERVER");
1101cb5caa98Sdjl if (NSCD_STATUS_IS_OK(phdr)) {
1102cb5caa98Sdjl /* also kill the forker nscd if one is running */
1103cb5caa98Sdjl _nscd_kill_forker();
1104cb5caa98Sdjl exit(0);
1105cb5caa98Sdjl }
1106cb5caa98Sdjl break;
1107cb5caa98Sdjl
1108cb5caa98Sdjl default:
1109cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1110cb5caa98Sdjl (me, "Unknown name service door call op %d\n",
1111cb5caa98Sdjl phdr->nsc_callnumber);
1112cb5caa98Sdjl
1113cb5caa98Sdjl NSCD_SET_STATUS(phdr, NSS_ERROR, EINVAL);
1114cb5caa98Sdjl
1115cb5caa98Sdjl (void) door_return(argp, arg_size, NULL, 0);
1116cb5caa98Sdjl break;
1117cb5caa98Sdjl
1118cb5caa98Sdjl }
1119cb5caa98Sdjl (void) door_return(argp, arg_size, NULL, 0);
1120cb5caa98Sdjl }
1121cb5caa98Sdjl
1122cb5caa98Sdjl int
_nscd_setup_server(char * execname,char ** argv)1123cb5caa98Sdjl _nscd_setup_server(char *execname, char **argv)
1124cb5caa98Sdjl {
1125cb5caa98Sdjl
1126cb5caa98Sdjl int fd;
1127cb5caa98Sdjl int errnum;
1128cb5caa98Sdjl int bind_failed = 0;
112980b80bf0Smichen mode_t old_mask;
1130cb5caa98Sdjl struct stat buf;
1131cb5caa98Sdjl sigset_t myset;
1132cb5caa98Sdjl struct sigaction action;
1133cb5caa98Sdjl char *me = "_nscd_setup_server";
1134cb5caa98Sdjl
1135cb5caa98Sdjl main_execname = execname;
1136cb5caa98Sdjl main_argv = argv;
1137cb5caa98Sdjl
113882714199Ssdussud /* Any nscd process is to ignore SIGPIPE */
113982714199Ssdussud if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
114082714199Ssdussud errnum = errno;
114182714199Ssdussud _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
114282714199Ssdussud (me, "signal (SIGPIPE): %s\n", strerror(errnum));
114382714199Ssdussud return (-1);
114482714199Ssdussud }
114582714199Ssdussud
1146cb5caa98Sdjl keep_open_dns_socket();
1147cb5caa98Sdjl
1148cb5caa98Sdjl /*
1149cb5caa98Sdjl * the max number of server threads should be fixed now, so
1150cb5caa98Sdjl * set flag to indicate that no in-flight change is allowed
1151cb5caa98Sdjl */
1152cb5caa98Sdjl max_servers_set = 1;
1153cb5caa98Sdjl
1154cb5caa98Sdjl (void) thr_keycreate(&lookup_state_key, NULL);
1155bf1e3beeSmichen (void) sema_init(&common_sema, frontend_cfg_g.common_worker_threads,
1156cb5caa98Sdjl USYNC_THREAD, 0);
1157cb5caa98Sdjl
1158cb5caa98Sdjl /* Establish server thread pool */
1159cb5caa98Sdjl (void) door_server_create(server_create);
1160cb5caa98Sdjl if (thr_keycreate(&server_key, server_destroy) != 0) {
1161cb5caa98Sdjl errnum = errno;
1162cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1163cb5caa98Sdjl (me, "thr_keycreate (server thread): %s\n",
1164cb5caa98Sdjl strerror(errnum));
1165cb5caa98Sdjl return (-1);
1166cb5caa98Sdjl }
1167cb5caa98Sdjl
1168cb5caa98Sdjl /* Create a door */
1169cb5caa98Sdjl if ((fd = door_create(switcher, NAME_SERVICE_DOOR_COOKIE,
1170cb5caa98Sdjl DOOR_UNREF | DOOR_NO_CANCEL)) < 0) {
1171cb5caa98Sdjl errnum = errno;
1172cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1173cb5caa98Sdjl (me, "door_create: %s\n", strerror(errnum));
1174cb5caa98Sdjl return (-1);
1175cb5caa98Sdjl }
1176cb5caa98Sdjl
1177cb5caa98Sdjl /* if not main nscd, no more setup to do */
1178cb5caa98Sdjl if (_whoami != NSCD_MAIN)
1179cb5caa98Sdjl return (fd);
1180cb5caa98Sdjl
1181cb5caa98Sdjl /* bind to file system */
1182bf1e3beeSmichen if (is_system_labeled() && (getzoneid() == GLOBAL_ZONEID)) {
1183cb5caa98Sdjl if (stat(TSOL_NAME_SERVICE_DOOR, &buf) < 0) {
1184cb5caa98Sdjl int newfd;
118580b80bf0Smichen
118680b80bf0Smichen /* make sure the door will be readable by all */
118780b80bf0Smichen old_mask = umask(0);
1188cb5caa98Sdjl if ((newfd = creat(TSOL_NAME_SERVICE_DOOR, 0444)) < 0) {
1189cb5caa98Sdjl errnum = errno;
1190cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_FRONT_END,
1191cb5caa98Sdjl NSCD_LOG_LEVEL_ERROR)
1192cb5caa98Sdjl (me, "Cannot create %s: %s\n",
1193cb5caa98Sdjl TSOL_NAME_SERVICE_DOOR,
1194cb5caa98Sdjl strerror(errnum));
1195cb5caa98Sdjl bind_failed = 1;
1196cb5caa98Sdjl }
119780b80bf0Smichen /* rstore the old file mode creation mask */
119880b80bf0Smichen (void) umask(old_mask);
1199cb5caa98Sdjl (void) close(newfd);
1200cb5caa98Sdjl }
1201cb5caa98Sdjl if (symlink(TSOL_NAME_SERVICE_DOOR, NAME_SERVICE_DOOR) != 0) {
1202cb5caa98Sdjl if (errno != EEXIST) {
1203cb5caa98Sdjl errnum = errno;
1204cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_FRONT_END,
1205cb5caa98Sdjl NSCD_LOG_LEVEL_ERROR)
1206cb5caa98Sdjl (me, "Cannot symlink %s: %s\n",
1207bf1e3beeSmichen NAME_SERVICE_DOOR, strerror(errnum));
1208cb5caa98Sdjl bind_failed = 1;
1209cb5caa98Sdjl }
1210cb5caa98Sdjl }
1211cb5caa98Sdjl } else if (stat(NAME_SERVICE_DOOR, &buf) < 0) {
1212cb5caa98Sdjl int newfd;
121380b80bf0Smichen
121480b80bf0Smichen /* make sure the door will be readable by all */
121580b80bf0Smichen old_mask = umask(0);
1216cb5caa98Sdjl if ((newfd = creat(NAME_SERVICE_DOOR, 0444)) < 0) {
1217cb5caa98Sdjl errnum = errno;
1218cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1219cb5caa98Sdjl (me, "Cannot create %s: %s\n", NAME_SERVICE_DOOR,
1220cb5caa98Sdjl strerror(errnum));
1221cb5caa98Sdjl bind_failed = 1;
1222cb5caa98Sdjl }
122380b80bf0Smichen /* rstore the old file mode creation mask */
122480b80bf0Smichen (void) umask(old_mask);
1225cb5caa98Sdjl (void) close(newfd);
1226cb5caa98Sdjl }
1227cb5caa98Sdjl
1228cb5caa98Sdjl if (bind_failed == 1) {
1229cb5caa98Sdjl (void) door_revoke(fd);
1230cb5caa98Sdjl return (-1);
1231cb5caa98Sdjl }
1232cb5caa98Sdjl
1233cb5caa98Sdjl if (fattach(fd, NAME_SERVICE_DOOR) < 0) {
1234cb5caa98Sdjl if ((errno != EBUSY) ||
1235cb5caa98Sdjl (fdetach(NAME_SERVICE_DOOR) < 0) ||
1236cb5caa98Sdjl (fattach(fd, NAME_SERVICE_DOOR) < 0)) {
1237cb5caa98Sdjl errnum = errno;
1238bf1e3beeSmichen _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1239cb5caa98Sdjl (me, "fattach: %s\n", strerror(errnum));
1240cb5caa98Sdjl (void) door_revoke(fd);
1241cb5caa98Sdjl return (-1);
1242cb5caa98Sdjl }
1243cb5caa98Sdjl }
1244cb5caa98Sdjl
1245cb5caa98Sdjl /*
1246cb5caa98Sdjl * kick off routing socket monitor thread
1247cb5caa98Sdjl */
1248cb5caa98Sdjl if (thr_create(NULL, NULL,
1249cb5caa98Sdjl (void *(*)(void *))rts_mon, 0, 0, NULL) != 0) {
1250cb5caa98Sdjl errnum = errno;
1251cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1252cb5caa98Sdjl (me, "thr_create (routing socket monitor): %s\n",
1253cb5caa98Sdjl strerror(errnum));
1254cb5caa98Sdjl
1255cb5caa98Sdjl (void) door_revoke(fd);
1256cb5caa98Sdjl return (-1);
1257cb5caa98Sdjl }
1258cb5caa98Sdjl
1259cb5caa98Sdjl /*
1260cb5caa98Sdjl * set up signal handler for SIGHUP
1261cb5caa98Sdjl */
1262cb5caa98Sdjl action.sa_handler = dozip;
1263cb5caa98Sdjl action.sa_flags = 0;
1264cb5caa98Sdjl (void) sigemptyset(&action.sa_mask);
1265cb5caa98Sdjl (void) sigemptyset(&myset);
1266cb5caa98Sdjl (void) sigaddset(&myset, SIGHUP);
1267cb5caa98Sdjl
1268cb5caa98Sdjl if (sigaction(SIGHUP, &action, NULL) < 0) {
1269cb5caa98Sdjl errnum = errno;
1270cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1271cb5caa98Sdjl (me, "sigaction (SIGHUP): %s\n", strerror(errnum));
1272cb5caa98Sdjl
1273cb5caa98Sdjl (void) door_revoke(fd);
1274cb5caa98Sdjl return (-1);
1275cb5caa98Sdjl }
1276cb5caa98Sdjl
1277cb5caa98Sdjl return (fd);
1278cb5caa98Sdjl }
1279cb5caa98Sdjl
1280cb5caa98Sdjl int
_nscd_setup_child_server(int did)1281cb5caa98Sdjl _nscd_setup_child_server(int did)
1282cb5caa98Sdjl {
1283cb5caa98Sdjl
1284cb5caa98Sdjl int errnum;
1285cb5caa98Sdjl int fd;
1286cb5caa98Sdjl nscd_rc_t rc;
1287cb5caa98Sdjl char *me = "_nscd_setup_child_server";
1288cb5caa98Sdjl
1289cb5caa98Sdjl /* Re-establish our own server thread pool */
1290cb5caa98Sdjl (void) door_server_create(server_create);
1291cb5caa98Sdjl if (thr_keycreate(&server_key, server_destroy) != 0) {
1292cb5caa98Sdjl errnum = errno;
1293cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
1294cb5caa98Sdjl (me, "thr_keycreate failed: %s", strerror(errnum));
1295cb5caa98Sdjl return (-1);
1296cb5caa98Sdjl }
1297cb5caa98Sdjl
1298cb5caa98Sdjl /*
1299cb5caa98Sdjl * Create a new door.
1300cb5caa98Sdjl * Keep DOOR_REFUSE_DESC (self-cred nscds don't fork)
1301cb5caa98Sdjl */
1302cb5caa98Sdjl (void) close(did);
1303bf1e3beeSmichen if ((fd = door_create(switcher, NAME_SERVICE_DOOR_COOKIE,
1304cb5caa98Sdjl DOOR_REFUSE_DESC|DOOR_UNREF|DOOR_NO_CANCEL)) < 0) {
1305cb5caa98Sdjl errnum = errno;
1306cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
1307cb5caa98Sdjl (me, "door_create failed: %s", strerror(errnum));
1308cb5caa98Sdjl return (-1);
1309cb5caa98Sdjl }
1310cb5caa98Sdjl
1311cb5caa98Sdjl /*
1312cb5caa98Sdjl * kick off routing socket monitor thread
1313cb5caa98Sdjl */
1314cb5caa98Sdjl if (thr_create(NULL, NULL,
1315cb5caa98Sdjl (void *(*)(void *))rts_mon, 0, 0, NULL) != 0) {
1316cb5caa98Sdjl errnum = errno;
1317cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1318cb5caa98Sdjl (me, "thr_create (routing socket monitor): %s\n",
1319cb5caa98Sdjl strerror(errnum));
1320cb5caa98Sdjl (void) door_revoke(fd);
1321cb5caa98Sdjl return (-1);
1322cb5caa98Sdjl }
1323cb5caa98Sdjl
1324cb5caa98Sdjl /*
1325cb5caa98Sdjl * start monitoring the states of the name service clients
1326cb5caa98Sdjl */
1327cb5caa98Sdjl rc = _nscd_init_smf_monitor();
1328cb5caa98Sdjl if (rc != NSCD_SUCCESS) {
1329cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1330cb5caa98Sdjl (me, "unable to start the SMF monitor (rc = %d)\n", rc);
1331cb5caa98Sdjl
1332cb5caa98Sdjl (void) door_revoke(fd);
1333cb5caa98Sdjl return (-1);
1334cb5caa98Sdjl }
1335cb5caa98Sdjl
1336cb5caa98Sdjl return (fd);
1337cb5caa98Sdjl }
1338cb5caa98Sdjl
1339cb5caa98Sdjl nscd_rc_t
_nscd_alloc_frontend_cfg()1340cb5caa98Sdjl _nscd_alloc_frontend_cfg()
1341cb5caa98Sdjl {
1342cb5caa98Sdjl frontend_cfg = calloc(NSCD_NUM_DB, sizeof (nscd_cfg_frontend_t));
1343cb5caa98Sdjl if (frontend_cfg == NULL)
1344cb5caa98Sdjl return (NSCD_NO_MEMORY);
1345cb5caa98Sdjl
1346cb5caa98Sdjl return (NSCD_SUCCESS);
1347cb5caa98Sdjl }
1348cb5caa98Sdjl
1349cb5caa98Sdjl
1350cb5caa98Sdjl /* ARGSUSED */
1351cb5caa98Sdjl nscd_rc_t
_nscd_cfg_frontend_notify(void * data,struct nscd_cfg_param_desc * pdesc,nscd_cfg_id_t * nswdb,nscd_cfg_flag_t dflag,nscd_cfg_error_t ** errorp,void * cookie)1352cb5caa98Sdjl _nscd_cfg_frontend_notify(
1353cb5caa98Sdjl void *data,
1354cb5caa98Sdjl struct nscd_cfg_param_desc *pdesc,
1355cb5caa98Sdjl nscd_cfg_id_t *nswdb,
1356cb5caa98Sdjl nscd_cfg_flag_t dflag,
1357cb5caa98Sdjl nscd_cfg_error_t **errorp,
1358cb5caa98Sdjl void *cookie)
1359cb5caa98Sdjl {
1360cb5caa98Sdjl void *dp;
1361cb5caa98Sdjl
1362cb5caa98Sdjl /*
1363cb5caa98Sdjl * At init time, the whole group of config params are received.
1364cb5caa98Sdjl * At update time, group or individual parameter value could
1365cb5caa98Sdjl * be received.
1366cb5caa98Sdjl */
1367cb5caa98Sdjl
1368cb5caa98Sdjl if (_nscd_cfg_flag_is_set(dflag, NSCD_CFG_DFLAG_INIT) ||
1369cb5caa98Sdjl _nscd_cfg_flag_is_set(dflag, NSCD_CFG_DFLAG_GROUP)) {
1370cb5caa98Sdjl /*
1371cb5caa98Sdjl * group data is received, copy in the
1372cb5caa98Sdjl * entire strcture
1373cb5caa98Sdjl */
1374bf1e3beeSmichen if (_nscd_cfg_flag_is_set(pdesc->pflag, NSCD_CFG_PFLAG_GLOBAL))
1375bf1e3beeSmichen frontend_cfg_g = *(nscd_cfg_global_frontend_t *)data;
1376cb5caa98Sdjl else
1377cb5caa98Sdjl frontend_cfg[nswdb->index] =
1378cb5caa98Sdjl *(nscd_cfg_frontend_t *)data;
1379cb5caa98Sdjl
1380cb5caa98Sdjl } else {
1381cb5caa98Sdjl /*
1382cb5caa98Sdjl * individual paramater is received: copy in the
1383cb5caa98Sdjl * parameter value.
1384cb5caa98Sdjl */
1385bf1e3beeSmichen if (_nscd_cfg_flag_is_set(pdesc->pflag, NSCD_CFG_PFLAG_GLOBAL))
1386cb5caa98Sdjl dp = (char *)&frontend_cfg_g + pdesc->p_offset;
1387cb5caa98Sdjl else
1388cb5caa98Sdjl dp = (char *)&frontend_cfg[nswdb->index] +
1389cb5caa98Sdjl pdesc->p_offset;
1390cb5caa98Sdjl (void) memcpy(dp, data, pdesc->p_size);
1391cb5caa98Sdjl }
1392cb5caa98Sdjl
1393cb5caa98Sdjl return (NSCD_SUCCESS);
1394cb5caa98Sdjl }
1395cb5caa98Sdjl
1396cb5caa98Sdjl /* ARGSUSED */
1397cb5caa98Sdjl nscd_rc_t
_nscd_cfg_frontend_verify(void * data,struct nscd_cfg_param_desc * pdesc,nscd_cfg_id_t * nswdb,nscd_cfg_flag_t dflag,nscd_cfg_error_t ** errorp,void ** cookie)1398cb5caa98Sdjl _nscd_cfg_frontend_verify(
1399cb5caa98Sdjl void *data,
1400cb5caa98Sdjl struct nscd_cfg_param_desc *pdesc,
1401cb5caa98Sdjl nscd_cfg_id_t *nswdb,
1402cb5caa98Sdjl nscd_cfg_flag_t dflag,
1403cb5caa98Sdjl nscd_cfg_error_t **errorp,
1404cb5caa98Sdjl void **cookie)
1405cb5caa98Sdjl {
1406cb5caa98Sdjl
1407cb5caa98Sdjl char *me = "_nscd_cfg_frontend_verify";
1408cb5caa98Sdjl
1409cb5caa98Sdjl /*
1410cb5caa98Sdjl * if max. number of server threads is set and in effect,
1411cb5caa98Sdjl * don't allow changing of the frontend configuration
1412cb5caa98Sdjl */
1413cb5caa98Sdjl if (max_servers_set) {
1414cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_INFO)
1415cb5caa98Sdjl (me, "changing of the frontend configuration not allowed now");
1416cb5caa98Sdjl
1417cb5caa98Sdjl return (NSCD_CFG_CHANGE_NOT_ALLOWED);
1418cb5caa98Sdjl }
1419cb5caa98Sdjl
1420cb5caa98Sdjl return (NSCD_SUCCESS);
1421cb5caa98Sdjl }
1422cb5caa98Sdjl
1423cb5caa98Sdjl /* ARGSUSED */
1424cb5caa98Sdjl nscd_rc_t
_nscd_cfg_frontend_get_stat(void ** stat,struct nscd_cfg_stat_desc * sdesc,nscd_cfg_id_t * nswdb,nscd_cfg_flag_t * dflag,void (** free_stat)(void * stat),nscd_cfg_error_t ** errorp)1425cb5caa98Sdjl _nscd_cfg_frontend_get_stat(
1426cb5caa98Sdjl void **stat,
1427cb5caa98Sdjl struct nscd_cfg_stat_desc *sdesc,
1428cb5caa98Sdjl nscd_cfg_id_t *nswdb,
1429cb5caa98Sdjl nscd_cfg_flag_t *dflag,
1430cb5caa98Sdjl void (**free_stat)(void *stat),
1431cb5caa98Sdjl nscd_cfg_error_t **errorp)
1432cb5caa98Sdjl {
1433cb5caa98Sdjl return (NSCD_SUCCESS);
1434cb5caa98Sdjl }
1435cb5caa98Sdjl
1436cb5caa98Sdjl void
_nscd_init_cache_sema(sema_t * sema,char * cache_name)1437cb5caa98Sdjl _nscd_init_cache_sema(sema_t *sema, char *cache_name)
1438cb5caa98Sdjl {
1439cb5caa98Sdjl int i, j;
1440cb5caa98Sdjl char *dbn;
1441cb5caa98Sdjl
1442cb5caa98Sdjl if (max_servers == 0)
1443cb5caa98Sdjl max_servers = frontend_cfg_g.common_worker_threads +
1444cb5caa98Sdjl frontend_cfg_g.cache_hit_threads;
1445cb5caa98Sdjl
1446cb5caa98Sdjl for (i = 0; i < NSCD_NUM_DB; i++) {
1447cb5caa98Sdjl
1448cb5caa98Sdjl dbn = NSCD_NSW_DB_NAME(i);
1449cb5caa98Sdjl if (strcasecmp(dbn, cache_name) == 0) {
1450cb5caa98Sdjl j = frontend_cfg[i].worker_thread_per_nsw_db;
1451cb5caa98Sdjl (void) sema_init(sema, j, USYNC_THREAD, 0);
1452cb5caa98Sdjl max_servers += j;
1453cb5caa98Sdjl break;
1454cb5caa98Sdjl }
1455cb5caa98Sdjl }
1456cb5caa98Sdjl }
1457cb5caa98Sdjl
1458cb5caa98Sdjl /*
1459cb5caa98Sdjl * Monitor the routing socket. Address lists stored in the ipnodes
1460cb5caa98Sdjl * cache are sorted based on destination address selection rules,
1461cb5caa98Sdjl * so when things change that could affect that sorting (interfaces
1462cb5caa98Sdjl * go up or down, flags change, etc.), we clear that cache so the
1463cb5caa98Sdjl * list will be re-ordered the next time the hostname is resolved.
1464cb5caa98Sdjl */
1465cb5caa98Sdjl static void
rts_mon(void)1466cb5caa98Sdjl rts_mon(void)
1467cb5caa98Sdjl {
1468cb5caa98Sdjl int rt_sock, rdlen, idx;
1469cb5caa98Sdjl union {
1470cb5caa98Sdjl struct {
1471cb5caa98Sdjl struct rt_msghdr rtm;
1472cb5caa98Sdjl struct sockaddr_storage addrs[RTA_NUMBITS];
1473cb5caa98Sdjl } r;
1474cb5caa98Sdjl struct if_msghdr ifm;
1475cb5caa98Sdjl struct ifa_msghdr ifam;
1476cb5caa98Sdjl } mbuf;
1477cb5caa98Sdjl struct ifa_msghdr *ifam = &mbuf.ifam;
1478cb5caa98Sdjl char *me = "rts_mon";
1479cb5caa98Sdjl
1480cb5caa98Sdjl rt_sock = socket(PF_ROUTE, SOCK_RAW, 0);
1481cb5caa98Sdjl if (rt_sock < 0) {
1482cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1483cb5caa98Sdjl (me, "Failed to open routing socket: %s\n", strerror(errno));
1484cb5caa98Sdjl thr_exit(0);
1485cb5caa98Sdjl }
1486cb5caa98Sdjl
1487cb5caa98Sdjl for (;;) {
1488cb5caa98Sdjl rdlen = read(rt_sock, &mbuf, sizeof (mbuf));
1489cb5caa98Sdjl if (rdlen <= 0) {
1490cb5caa98Sdjl if (rdlen == 0 || (errno != EINTR && errno != EAGAIN)) {
1491cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_FRONT_END,
1492cb5caa98Sdjl NSCD_LOG_LEVEL_ERROR)
1493cb5caa98Sdjl (me, "routing socket read: %s\n",
1494cb5caa98Sdjl strerror(errno));
1495cb5caa98Sdjl thr_exit(0);
1496cb5caa98Sdjl }
1497cb5caa98Sdjl continue;
1498cb5caa98Sdjl }
1499cb5caa98Sdjl if (ifam->ifam_version != RTM_VERSION) {
1500cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_FRONT_END,
1501cb5caa98Sdjl NSCD_LOG_LEVEL_ERROR)
1502cb5caa98Sdjl (me, "rx unknown version (%d) on "
1503cb5caa98Sdjl "routing socket.\n",
1504cb5caa98Sdjl ifam->ifam_version);
1505cb5caa98Sdjl continue;
1506cb5caa98Sdjl }
1507cb5caa98Sdjl switch (ifam->ifam_type) {
1508cb5caa98Sdjl case RTM_NEWADDR:
1509cb5caa98Sdjl case RTM_DELADDR:
1510cb5caa98Sdjl /* if no ipnodes cache, then nothing to do */
1511cb5caa98Sdjl idx = get_cache_idx("ipnodes");
1512cb5caa98Sdjl if (cache_ctx_p[idx] == NULL ||
1513cb5caa98Sdjl cache_ctx_p[idx]->reaper_on != nscd_true)
1514cb5caa98Sdjl break;
1515cb5caa98Sdjl nsc_invalidate(cache_ctx_p[idx], NULL, NULL);
1516cb5caa98Sdjl break;
1517cb5caa98Sdjl case RTM_ADD:
1518cb5caa98Sdjl case RTM_DELETE:
1519cb5caa98Sdjl case RTM_CHANGE:
1520cb5caa98Sdjl case RTM_GET:
1521cb5caa98Sdjl case RTM_LOSING:
1522cb5caa98Sdjl case RTM_REDIRECT:
1523cb5caa98Sdjl case RTM_MISS:
1524cb5caa98Sdjl case RTM_LOCK:
1525cb5caa98Sdjl case RTM_OLDADD:
1526cb5caa98Sdjl case RTM_OLDDEL:
1527cb5caa98Sdjl case RTM_RESOLVE:
1528cb5caa98Sdjl case RTM_IFINFO:
15291cb875aeSCathy Zhou case RTM_CHGADDR:
15301cb875aeSCathy Zhou case RTM_FREEADDR:
1531cb5caa98Sdjl break;
1532cb5caa98Sdjl default:
1533cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1534cb5caa98Sdjl (me, "rx unknown msg type (%d) on routing socket.\n",
1535cb5caa98Sdjl ifam->ifam_type);
1536cb5caa98Sdjl break;
1537cb5caa98Sdjl }
1538cb5caa98Sdjl }
1539cb5caa98Sdjl }
1540cb5caa98Sdjl
1541cb5caa98Sdjl static void
keep_open_dns_socket(void)1542cb5caa98Sdjl keep_open_dns_socket(void)
1543cb5caa98Sdjl {
1544cb5caa98Sdjl _res.options |= RES_STAYOPEN; /* just keep this udp socket open */
1545cb5caa98Sdjl }
1546