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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * Simple doors ldap cache daemon
50 #include <sys/types.h>
52 #include <locale.h> /* LC_ALL */
56 #include <stddef.h> /* offsetof */
59 #include "getxby_door.h"
62 static void detachfromtty();
63 admin_t current_admin
;
64 static int will_become_server
;
66 static void switcher(void *cookie
, char *argp
, size_t arg_size
,
67 door_desc_t
*dp
, uint_t n_desc
);
68 static void usage(char *s
);
69 static int cachemgr_set_lf(admin_t
*ptr
, char *logfile
);
70 static int client_getadmin(admin_t
*ptr
);
71 static int setadmin(ldap_call_t
*ptr
);
72 static int client_setadmin(admin_t
*ptr
);
73 static int client_showstats(admin_t
*ptr
);
74 static int is_root(int free_uc
, char *dc_str
, ucred_t
**uc
);
75 int is_root_or_all_privs(char *dc_str
, ucred_t
**ucp
);
76 static void admin_modify(LineBuf
*config_info
, ldap_call_t
*in
);
80 static unsigned int refresh
= 10800; /* dynamic discovery interval */
86 static const char *caches
[1] = {"ldap"};
88 if (strncmp(caches
[0], s
, strlen(caches
[0])) == 0)
89 return (¤t_admin
.ldap_stat
);
97 while (*s
&& *s
!= ',')
99 return ((*s
== ',') ? (s
+ 1) : NULL
);
103 * This is here to prevent the ldap_cachemgr becomes
104 * daemonlized to early to soon during boot time.
105 * This causes problems during boot when automounter
106 * and others try to use libsldap before ldap_cachemgr
107 * finishes walking the server list.
110 sig_ok_to_exit(int signo
)
112 if (signo
== SIGUSR1
) {
113 logit("sig_ok_to_exit(): parent exiting...\n");
116 logit("sig_ok_to_exit(): invalid signal(%d) received.\n",
118 syslog(LOG_ERR
, gettext("ldap_cachemgr: "
119 "invalid signal(%d) received."), signo
);
123 #define LDAP_TABLES 1 /* ldap */
124 #define TABLE_THREADS 10
125 #define COMMON_THREADS 20
126 #define CACHE_MISS_THREADS (COMMON_THREADS + LDAP_TABLES * TABLE_THREADS)
127 #define CACHE_HIT_THREADS 20
129 * There is only one thread handling GETSTATUSCHANGE START from main nscd
130 * most of time. But it could happen that a main nscd is restarted, old main
131 * nscd's handling thread is still alive when new main nscd starts and sends
132 * START, or old main dies. STOP is not sent in both cases.
133 * The main nscd requires 2 threads to handle START and STOP. So max number
134 * of change threads is set to 4.
136 #define MAX_CHG_THREADS 4
137 #define MAX_SERVER_THREADS (CACHE_HIT_THREADS + CACHE_MISS_THREADS + \
140 static sema_t common_sema
;
141 static sema_t ldap_sema
;
142 static thread_key_t lookup_state_key
;
143 static int chg_threads_num
= 0;
144 static mutex_t chg_threads_num_lock
= DEFAULTMUTEX
;
147 initialize_lookup_clearance()
149 (void) thr_keycreate(&lookup_state_key
, NULL
);
150 (void) sema_init(&common_sema
, COMMON_THREADS
, USYNC_THREAD
, 0);
151 (void) sema_init(&ldap_sema
, TABLE_THREADS
, USYNC_THREAD
, 0);
155 get_clearance(int callnumber
)
157 sema_t
*table_sema
= NULL
;
160 if (sema_trywait(&common_sema
) == 0) {
161 (void) thr_setspecific(lookup_state_key
, NULL
);
165 switch (callnumber
) {
168 table_sema
= &ldap_sema
;
171 logit("Internal Error: get_clearance\n");
175 if (sema_trywait(table_sema
) == 0) {
176 (void) thr_setspecific(lookup_state_key
, (void*)1);
180 if (current_admin
.debug_level
>= DBG_CANT_FIND
) {
181 logit("get_clearance: throttling load for %s table\n", tab
);
188 release_clearance(int callnumber
)
191 sema_t
*table_sema
= NULL
;
193 (void) thr_getspecific(lookup_state_key
, (void**)&which
);
194 if (which
== 0) /* from common pool */ {
195 (void) sema_post(&common_sema
);
199 switch (callnumber
) {
201 table_sema
= &ldap_sema
;
204 logit("Internal Error: release_clearance\n");
207 (void) sema_post(table_sema
);
213 static mutex_t create_lock
;
214 static int num_servers
= 0;
215 static thread_key_t server_key
;
219 * Bind a TSD value to a server thread. This enables the destructor to
220 * be called if/when this thread exits. This would be a programming error,
221 * but better safe than sorry.
226 server_tsd_bind(void *arg
)
228 static void *value
= 0;
231 * disable cancellation to prevent hangs when server
235 (void) thr_setspecific(server_key
, value
);
236 (void) door_return(NULL
, 0, NULL
, 0);
242 * Server threads are created here.
247 server_create(door_info_t
*dip
)
249 (void) mutex_lock(&create_lock
);
250 if (++num_servers
> MAX_SERVER_THREADS
) {
252 (void) mutex_unlock(&create_lock
);
255 (void) mutex_unlock(&create_lock
);
256 (void) thr_create(NULL
, 0, server_tsd_bind
, NULL
,
257 THR_BOUND
|THR_DETACHED
, NULL
);
261 * Server thread are destroyed here
266 server_destroy(void *arg
)
268 (void) mutex_lock(&create_lock
);
270 (void) mutex_unlock(&create_lock
);
273 static void client_killserver();
276 main(int argc
, char ** argv
)
286 struct sigaction sighupaction
;
289 /* setup for localization */
290 (void) setlocale(LC_ALL
, "");
291 (void) textdomain(TEXT_DOMAIN
);
293 openlog("ldap_cachemgr", LOG_PID
, LOG_DAEMON
);
295 if (chdir(NSLDAPDIRECTORY
) < 0) {
296 (void) fprintf(stderr
, gettext("chdir(\"%s\") failed: %s\n"),
297 NSLDAPDIRECTORY
, strerror(errno
));
302 * Correctly set file mode creation mask, so to make the new files
303 * created for door calls being readable by all.
308 * Special case non-root user here - he/she/they/it can just print
313 if (argc
!= 2 || strcmp(argv
[1], "-g")) {
314 (void) fprintf(stderr
,
315 gettext("Must be root to use any option "
316 "other than -g.\n\n"));
320 if ((__ns_ldap_cache_ping() != NS_CACHE_SUCCESS
) ||
321 (client_getadmin(¤t_admin
) != 0)) {
322 (void) fprintf(stderr
,
323 gettext("%s doesn't appear to be running.\n"),
327 (void) client_showstats(¤t_admin
);
334 * Determine if there is already a daemon running
337 will_become_server
= (__ns_ldap_cache_ping() != NS_CACHE_SUCCESS
);
340 * load normal config file
343 if (will_become_server
) {
344 static const ldap_stat_t defaults
= {
346 DEFAULTTTL
}; /* ttl */
348 current_admin
.ldap_stat
= defaults
;
349 (void) strcpy(current_admin
.logfile
, LOGFILE
);
351 if (client_getadmin(¤t_admin
)) {
352 (void) fprintf(stderr
, gettext("Cannot contact %s "
353 "properly(?)\n"), argv
[0]);
359 while ((opt
= getopt(argc
, argv
, "fKgl:r:d:")) != EOF
) {
361 while ((opt
= getopt(argc
, argv
, "fKgs:l:r:d:")) != EOF
) {
378 cache
= getcacheptr("ldap");
383 cache
->ldap_ttl
= atoi(optarg
);
387 (void) strlcpy(current_admin
.logfile
,
388 optarg
, sizeof (current_admin
.logfile
));
392 debug_level
= atoi(optarg
);
395 case 's': /* undocumented: use dynamic (SLP) config */
409 * will not show statistics if no daemon running
411 if (will_become_server
&& showstats
) {
412 (void) fprintf(stderr
,
413 gettext("%s doesn't appear to be running.\n"),
418 if (!will_become_server
) {
420 (void) client_showstats(¤t_admin
);
423 current_admin
.debug_level
= debug_level
;
424 if (client_setadmin(¤t_admin
) < 0) {
425 (void) fprintf(stderr
,
426 gettext("Error during admin call\n"));
430 if (!showstats
&& !doset
) {
431 (void) fprintf(stderr
,
432 gettext("%s already running....use '%s "
433 "-K' to stop\n"), argv
[0], argv
[0]);
439 * daemon from here on
446 if (strlen(current_admin
.logfile
) == 0)
448 * no specified log file
450 (void) strcpy(current_admin
.logfile
, LOGFILE
);
452 (void) cachemgr_set_lf(¤t_admin
,
453 current_admin
.logfile
);
455 * validate the range of debug level number
456 * and set the number to current_admin.debug_level
458 if (cachemgr_set_dl(¤t_admin
, debug_level
) < 0) {
460 * print error messages to the screen
461 * cachemgr_set_dl prints msgs to cachemgr.log
464 (void) fprintf(stderr
,
465 gettext("Incorrect Debug Level: %d\n"
466 "It should be between %d and %d\n"),
467 debug_level
, DBG_OFF
, MAXDEBUG
);
471 if (strlen(current_admin
.logfile
) == 0)
472 (void) strcpy(current_admin
.logfile
, "/dev/null");
473 (void) cachemgr_set_lf(¤t_admin
,
474 current_admin
.logfile
);
478 detachfromtty(argv
[0]);
481 * perform some initialization
484 initialize_lookup_clearance();
486 if (getldap_init() != 0)
490 * Establish our own server thread pool
493 (void) door_server_create(server_create
);
494 if (thr_keycreate(&server_key
, server_destroy
) != 0) {
495 logit("thr_keycreate() call failed\n");
497 gettext("ldap_cachemgr: thr_keycreate() call failed"));
498 perror("thr_keycreate");
506 if ((did
= door_create(switcher
, LDAP_CACHE_DOOR_COOKIE
,
507 DOOR_UNREF
| DOOR_REFUSE_DESC
| DOOR_NO_CANCEL
)) < 0) {
508 logit("door_create() call failed\n");
509 syslog(LOG_ERR
, gettext(
510 "ldap_cachemgr: door_create() call failed"));
511 perror("door_create");
516 * bind to file system
519 if (stat(LDAP_CACHE_DOOR
, &buf
) < 0) {
522 if ((newfd
= creat(LDAP_CACHE_DOOR
, 0444)) < 0) {
523 logit("Cannot create %s:%s\n",
531 if (fattach(did
, LDAP_CACHE_DOOR
) < 0) {
532 if ((errno
!= EBUSY
) ||
533 (fdetach(LDAP_CACHE_DOOR
) < 0) ||
534 (fattach(did
, LDAP_CACHE_DOOR
) < 0)) {
535 logit("fattach() call failed\n");
536 syslog(LOG_ERR
, gettext(
537 "ldap_cachemgr: fattach() call failed"));
543 /* catch SIGHUP revalid signals */
544 sighupaction
.sa_handler
= getldap_revalidate
;
545 sighupaction
.sa_flags
= 0;
546 (void) sigemptyset(&sighupaction
.sa_mask
);
547 (void) sigemptyset(&myset
);
548 (void) sigaddset(&myset
, SIGHUP
);
550 if (sigaction(SIGHUP
, &sighupaction
, NULL
) < 0) {
551 logit("sigaction() call failed\n");
553 gettext("ldap_cachemgr: sigaction() call failed"));
558 if (thr_sigsetmask(SIG_BLOCK
, &myset
, NULL
) < 0) {
559 logit("thr_sigsetmask() call failed\n");
561 gettext("ldap_cachemgr: thr_sigsetmask() call failed"));
562 perror("thr_sigsetmask");
567 * kick off revalidate threads only if ttl != 0
570 if (thr_create(NULL
, 0, (void *(*)(void*))getldap_refresh
,
571 NULL
, 0, NULL
) != 0) {
572 logit("thr_create() call failed\n");
574 gettext("ldap_cachemgr: thr_create() call failed"));
575 perror("thr_create");
580 * kick off the thread which refreshes the server info
583 if (thr_create(NULL
, 0, (void *(*)(void*))getldap_serverInfo_refresh
,
584 NULL
, 0, NULL
) != 0) {
585 logit("thr_create() call failed\n");
587 gettext("ldap_cachemgr: thr_create() call failed"));
588 perror("thr_create");
593 * kick off the thread which cleans up waiting threads for
597 if (thr_create(NULL
, 0, chg_cleanup_waiting_threads
,
598 NULL
, 0, NULL
) != 0) {
599 logit("thr_create() chg_cleanup_waiting_threads call failed\n");
601 gettext("ldap_cachemgr: thr_create() "
602 "chg_cleanup_waiting_threads call failed"));
608 /* kick off SLP discovery thread */
609 if (thr_create(NULL
, 0, (void *(*)(void *))discover
,
610 (void *)&refresh
, 0, NULL
) != 0) {
611 logit("thr_create() call failed\n");
612 syslog(LOG_ERR
, gettext("ldap_cachemgr: thr_create() "
614 perror("thr_create");
620 if (thr_sigsetmask(SIG_UNBLOCK
, &myset
, NULL
) < 0) {
621 logit("thr_sigsetmask() call failed\n");
623 gettext("ldap_cachemgr: the_sigsetmask() call failed"));
624 perror("thr_sigsetmask");
633 /*LINTED E_FUNC_HAS_NO_RETURN_STMT*/
638 * Before calling the alloca() function we have to be sure that we won't get
639 * beyond the stack. Since we don't know the precise layout of the stack,
640 * the address of an automatic of the function gives us a rough idea, plus/minus
641 * a bit. We also need a bit more of stackspace after the call to be able
642 * to call further functions. Even something as simple as making a system call
643 * from within this function can take ~100 Bytes of stackspace.
645 #define SAFETY_BUFFER 32 * 1024 /* 32KB */
649 get_data_size(LineBuf
*config_info
, int *err_code
)
651 size_t configSize
= sizeof (ldap_return_t
);
652 dataunion
*buf
= NULL
; /* For the 'sizeof' purpose */
654 if (config_info
->str
!= NULL
&&
655 config_info
->len
>= sizeof (buf
->data
.ldap_ret
.ldap_u
.config
)) {
656 configSize
= sizeof (buf
->space
) +
658 sizeof (buf
->data
.ldap_ret
.ldap_u
.config
);
660 if (!stack_inbounds((char *)&buf
-
661 (configSize
+ SAFETY_BUFFER
))) {
663 * We do not have enough space on the stack
664 * to accomodate the whole DUAProfile
666 logit("The DUAProfile is too big. There is not enough "
667 "space to process it. Ignoring it.\n");
668 syslog(LOG_ERR
, gettext("ldap_cachemgr: The DUAProfile "
669 "is too big. There is not enough space "
670 "to process it. Ignoring it."));
672 *err_code
= NS_CACHE_SERVERERROR
;
674 free(config_info
->str
);
675 config_info
->str
= NULL
;
676 config_info
->len
= 0;
677 configSize
= sizeof (ldap_return_t
);
686 switcher(void *cookie
, char *argp
, size_t arg_size
,
687 door_desc_t
*dp
, uint_t n_desc
)
690 #define ALLOCATE 1001
692 ldap_call_t
*ptr
= (ldap_call_t
*)argp
;
696 dataunion
*buf
= NULL
;
699 * By default the size of a buffer to be passed down to a client
700 * is equal to the size of the ldap_return_t structure. We need
701 * a bigger buffer in a few cases.
703 size_t configSize
= sizeof (ldap_return_t
);
704 int ldapErrno
= 0, state
, callnumber
;
711 if (argp
== DOOR_UNREF_DATA
) {
712 logit("Door Slam... invalid door param\n");
713 syslog(LOG_ERR
, gettext("ldap_cachemgr: Door Slam... "
714 "invalid door param"));
715 (void) printf(gettext("Door Slam... invalid door param\n"));
719 if (ptr
== NULL
) { /* empty door call */
720 (void) door_return(NULL
, 0, 0, 0); /* return the favor */
723 bzero(&dataSource
, sizeof (dataSource
));
726 * We presume that sizeof (ldap_return_t) bytes are always available
729 callnumber
= ptr
->ldap_callnumber
;
731 switch (callnumber
) {
734 * Just a 'ping'. Use the default size
735 * of the buffer and set the
742 * Get the current LDAP configuration.
743 * Since this is dynamic data and its size can exceed
744 * the size of ldap_return_t, the next step will
745 * calculate how much space exactly is required.
747 getldap_lookup(&configInfo
, ptr
);
753 * Get the current Admin Credentials (DN and password).
754 * Since this is dynamic data and its size can exceed
755 * the size of ldap_return_t, the next step will
756 * calculate how much space exactly is required.
758 getldap_admincred(&configInfo
, ptr
);
764 * Get the root DSE for a next server in the list.
765 * Since this is dynamic data and its size can exceed
766 * the size of ldap_return_t, the next step will
767 * calculate how much space exactly is required.
769 getldap_getserver(&configInfo
, ptr
);
775 * Get the cache stattistics.
776 * Since this is dynamic data and its size can exceed
777 * the size of ldap_return_t, the next step will
778 * calculate how much space exactly is required.
780 getldap_get_cacheStat(&configInfo
);
786 * Get current configuration and statistics.
787 * The size of the statistics structure is less then
788 * sizeof (ldap_return_t). So specify the source
789 * where to take the info and proceed with the memory
794 if (ldapErrno
== 0) {
795 dataSource
.begin
= ¤t_admin
;
796 dataSource
.size
= sizeof (current_admin
);
797 dataSource
.destroy
= 0;
802 * Process the request and proceed with the default
805 if (is_root(1, "KILLSERVER", &uc
))
813 * Process the request and proceed with the default
816 if (is_root(1, "SETADMIN", &uc
))
817 ldapErrno
= setadmin(ptr
);
825 * Get the cache stattistics.
826 * Since this is dynamic data and its size can exceed
827 * the size of ldap_return_t, the next step will
828 * calculate how much space exactly is required.
830 getldap_get_cacheData(&configInfo
, ptr
);
836 * Process the request and proceed with the default
839 if (is_root(0, "SETCACHE", &uc
) &&
840 is_called_from_nscd(ucred_getpid(uc
))) {
841 ldapErrno
= getldap_set_cacheData(ptr
);
842 current_admin
.ldap_stat
.ldap_numbercalls
++;
851 admin_modify(&configInfo
, ptr
);
855 case GETSTATUSCHANGE
:
857 * Process the request and proceed with the default
860 (void) mutex_lock(&chg_threads_num_lock
);
862 if (chg_threads_num
> MAX_CHG_THREADS
) {
864 (void) mutex_unlock(&chg_threads_num_lock
);
865 ldapErrno
= CHG_EXCEED_MAX_THREADS
;
869 (void) mutex_unlock(&chg_threads_num_lock
);
871 if (is_root(0, "GETSTATUSCHANGE", &uc
) &&
872 is_called_from_nscd(ucred_getpid(uc
))) {
873 ldapErrno
= chg_get_statusChange(
874 &configInfo
, ptr
, ucred_getpid(uc
));
883 (void) mutex_lock(&chg_threads_num_lock
);
885 (void) mutex_unlock(&chg_threads_num_lock
);
889 * This means an unknown request type. Proceed with
890 * the default buffer allocation.
892 logit("Unknown ldap service door call op %d\n",
893 ptr
->ldap_callnumber
);
903 * This stage calculates how much data will be
904 * passed down to the client, checks if there is
905 * enough space on the stack to accommodate the data,
906 * increases the value of the configSize variable
907 * if necessary and specifies the data source.
908 * In case of any error occurred ldapErrno will be set
911 if (configInfo
.str
== NULL
) {
915 configSize
= get_data_size(&configInfo
, &ldapErrno
);
917 if (ldapErrno
== 0) {
918 dataSource
.begin
= configInfo
.str
;
919 dataSource
.size
= configInfo
.len
;
920 dataSource
.destroy
= 1;
923 current_admin
.ldap_stat
.ldap_numbercalls
++;
927 * Allocate a buffer of the calculated (or default) size
928 * and proceed with populating it with data.
930 buf
= (dataunion
*) alloca(configSize
);
933 * Set a return code and, if a data source is specified,
934 * copy data from the source to the buffer.
936 buf
->data
.ldap_ret
.ldap_errno
= ldapErrno
;
937 buf
->data
.ldap_ret
.ldap_return_code
= ldapErrno
;
938 buf
->data
.ldap_ret
.ldap_bufferbytesused
= configSize
;
940 if (dataSource
.begin
!= NULL
) {
941 (void) memcpy(buf
->data
.ldap_ret
.ldap_u
.config
,
944 if (dataSource
.destroy
) {
945 free(dataSource
.begin
);
950 (void) door_return((char *)&buf
->data
,
951 buf
->data
.ldap_ret
.ldap_bufferbytesused
,
961 (void) fprintf(stderr
,
962 gettext("Usage: %s [-d debug_level] [-l logfilename]\n"), s
);
963 (void) fprintf(stderr
, gettext(" [-K] "
964 "[-r revalidate_interval] "));
966 (void) fprintf(stderr
, gettext(" [-g]\n"));
968 (void) fprintf(stderr
, gettext(" [-g] [-s]\n"));
974 static int logfd
= -1;
977 cachemgr_set_lf(admin_t
*ptr
, char *logfile
)
982 * we don't really want to try and open the log file
983 * /dev/null since that will fail w/ our security fixes
986 if (logfile
== NULL
|| *logfile
== 0) {
988 } else if (strcmp(logfile
, "/dev/null") == 0) {
989 (void) strcpy(current_admin
.logfile
, "/dev/null");
994 open(logfile
, O_EXCL
|O_WRONLY
|O_CREAT
, 0644)) < 0) {
996 * File already exists... now we need to get cute
997 * since opening a file in a world-writeable directory
998 * safely is hard = it could be a hard link or a
999 * symbolic link to a system file.
1004 if (lstat(logfile
, &before
) < 0) {
1005 logit("Cannot open new logfile \"%s\": %sn",
1006 logfile
, strerror(errno
));
1009 if (S_ISREG(before
.st_mode
) && /* no symbolic links */
1010 (before
.st_nlink
== 1) && /* no hard links */
1011 (before
.st_uid
== 0)) { /* owned by root */
1014 O_APPEND
|O_WRONLY
, 0644)) < 0) {
1015 logit("Cannot open new logfile "
1017 logfile
, strerror(errno
));
1021 logit("Cannot use specified logfile "
1022 "\"%s\": file is/has links or isn't "
1023 "owned by root\n", logfile
);
1027 (void) strlcpy(ptr
->logfile
, logfile
, sizeof (ptr
->logfile
));
1028 (void) close(logfd
);
1030 logit("Starting ldap_cachemgr, logfile %s\n", logfile
);
1037 logit(char *format
, ...)
1039 static mutex_t loglock
;
1041 char buffer
[BUFSIZ
];
1044 va_start(ap
, format
);
1049 (void) gettimeofday(&tv
, NULL
);
1050 (void) ctime_r(&tv
.tv_sec
, buffer
, BUFSIZ
);
1051 (void) snprintf(buffer
+19, BUFSIZE
, ".%.4ld ",
1053 safechars
= sizeof (buffer
) - 30;
1054 if (vsnprintf(buffer
+25, safechars
, format
, ap
) > safechars
)
1055 (void) strcat(buffer
, "...\n");
1056 (void) mutex_lock(&loglock
);
1057 (void) write(logfd
, buffer
, strlen(buffer
));
1058 (void) mutex_unlock(&loglock
);
1065 client_getadmin(admin_t
*ptr
)
1072 u
.data
.ldap_call
.ldap_callnumber
= GETADMIN
;
1074 adata
= sizeof (u
.data
);
1077 if (__ns_ldap_trydoorcall(&dptr
, &ndata
, &adata
) != NS_CACHE_SUCCESS
) {
1080 (void) memcpy(ptr
, dptr
->ldap_ret
.ldap_u
.buff
, sizeof (*ptr
));
1087 setadmin(ldap_call_t
*ptr
)
1091 new = (admin_t
*)ptr
->ldap_u
.domainname
;
1094 * global admin stuff
1097 if ((cachemgr_set_lf(¤t_admin
, new->logfile
) < 0) ||
1098 cachemgr_set_dl(¤t_admin
, new->debug_level
) < 0) {
1102 if (cachemgr_set_ttl(¤t_admin
.ldap_stat
,
1104 new->ldap_stat
.ldap_ttl
) < 0) {
1120 u
.data
.ldap_call
.ldap_callnumber
= KILLSERVER
;
1122 adata
= sizeof (ldap_call_t
);
1125 __ns_ldap_trydoorcall(&dptr
, &ndata
, &adata
);
1130 client_setadmin(admin_t
*ptr
)
1137 u
.data
.ldap_call
.ldap_callnumber
= SETADMIN
;
1138 (void) memcpy(u
.data
.ldap_call
.ldap_u
.domainname
, ptr
, sizeof (*ptr
));
1140 adata
= sizeof (*ptr
);
1143 if (__ns_ldap_trydoorcall(&dptr
, &ndata
, &adata
) != NS_CACHE_SUCCESS
) {
1151 client_showstats(admin_t
*ptr
)
1157 char *rbuf
, *sptr
, *rest
;
1162 (void) printf(gettext("\ncachemgr configuration:\n"));
1163 (void) printf(gettext("server debug level %10d\n"), ptr
->debug_level
);
1164 (void) printf(gettext("server log file\t\"%s\"\n"), ptr
->logfile
);
1165 (void) printf(gettext("number of calls to ldapcachemgr %10d\n"),
1166 ptr
->ldap_stat
.ldap_numbercalls
);
1169 * get cache data statistics
1171 u
.data
.ldap_call
.ldap_callnumber
= GETCACHESTAT
;
1173 adata
= sizeof (ldap_call_t
);
1176 if (__ns_ldap_trydoorcall(&dptr
, &ndata
, &adata
) != NS_CACHE_SUCCESS
) {
1178 gettext("\nCache data statistics not available!\n"));
1183 * print cache data statistics line by line
1185 (void) printf(gettext("\ncachemgr cache data statistics:\n"));
1186 rbuf
= dptr
->ldap_ret
.ldap_u
.buff
;
1187 sptr
= strtok_r(rbuf
, DOORLINESEP
, &rest
);
1189 (void) printf("%s\n", sptr
);
1190 sptr
= strtok_r(NULL
, DOORLINESEP
, &rest
);
1202 detachfromtty(char *pgm
)
1210 * Block the SIGUSR1 signal
1211 * just in case that the child
1212 * process may run faster than
1213 * the parent process and
1214 * send this signal before
1215 * the signal handler is ready
1216 * in the parent process.
1217 * This error will cause the parent
1218 * to exit with the User Signal 1
1221 (void) sighold(SIGUSR1
);
1225 logit("detachfromtty(): fork1() call failed\n");
1226 (void) fprintf(stderr
,
1227 gettext("%s: fork1() call failed.\n"),
1230 gettext("ldap_cachemgr: fork1() call failed."));
1235 * child process does not
1236 * need to worry about
1237 * the SIGUSR1 signal
1239 (void) sigrelse(SIGUSR1
);
1244 * Wait forever until the child process
1245 * has exited, or has signalled that at
1246 * least one server in the server list
1249 if (signal(SIGUSR1
, sig_ok_to_exit
) == SIG_ERR
) {
1250 logit("detachfromtty(): "
1251 "can't set up signal handler to "
1252 " catch SIGUSR1.\n");
1253 (void) fprintf(stderr
,
1254 gettext("%s: signal() call failed.\n"),
1256 syslog(LOG_ERR
, gettext("ldap_cachemgr: "
1257 "can't set up signal handler to "
1258 " catch SIGUSR1."));
1263 * now unblock the SIGUSR1 signal
1264 * to handle the pending or
1265 * soon to arrive SIGUSR1 signal
1267 (void) sigrelse(SIGUSR1
);
1268 wret
= waitpid(pid
, &status
, 0);
1271 logit("detachfromtty(): "
1272 "waitpid() call failed\n");
1273 (void) fprintf(stderr
,
1274 gettext("%s: waitpid() call failed.\n"),
1277 gettext("ldap_cachemgr: waitpid() "
1282 logit("detachfromtty(): "
1283 "waitpid() returned %ld when "
1284 "child pid was %ld\n",
1286 (void) fprintf(stderr
,
1288 "%s: waitpid() returned %ld when "
1289 "child pid was %ld.\n"),
1292 gettext("ldap_cachemgr: waitpid() "
1293 "returned different "
1298 /* evaluate return status */
1299 if (WIFEXITED(status
)) {
1300 if (WEXITSTATUS(status
) == 0) {
1303 logit("detachfromtty(): "
1304 "child failed (rc = %d).\n",
1305 WEXITSTATUS(status
));
1306 (void) fprintf(stderr
,
1307 gettext("%s: failed. Please see "
1308 "syslog for details.\n"),
1311 gettext("ldap_cachemgr: failed "
1313 WEXITSTATUS(status
));
1314 } else if (WIFSIGNALED(status
)) {
1315 logit("detachfromtty(): "
1316 "child terminated by signal %d.\n",
1318 (void) fprintf(stderr
,
1319 gettext("%s: terminated by signal %d.\n"),
1320 pgm
, WTERMSIG(status
));
1322 gettext("ldap_cachemgr: terminated by "
1325 } else if (WCOREDUMP(status
)) {
1326 logit("detachfromtty(): child core dumped.\n"),
1327 (void) fprintf(stderr
,
1328 gettext("%s: core dumped.\n"),
1331 gettext("ldap_cachemgr: "
1338 if (open("/dev/null", O_RDWR
, 0) != -1) {
1345 * Check if the door client's euid is 0
1347 * We could check for some privilege or re-design the interfaces that
1348 * lead to is_root() being called so that we rely on SMF and RBAC, but
1349 * we need this check only for dealing with undocumented-but-possibly-
1350 * used interfaces. Anything beyond checking for euid == 0 here would
1351 * be overkill considering that those are undocumented interfaces.
1353 * If free_uc is 0, the caller is responsible for freeing *ucp.
1355 * return - 0 euid != 0
1359 is_root(int free_uc
, char *dc_str
, ucred_t
**ucp
)
1363 if (door_ucred(ucp
) != 0) {
1365 logit("door_ucred() call failed %s\n", strerror(rc
));
1366 syslog(LOG_ERR
, gettext("ldap_cachemgr: door_ucred() call %s "
1367 "failed %s"), strerror(rc
));
1372 if (ucred_geteuid(*ucp
) != 0) {
1374 if (current_admin
.debug_level
>= DBG_CANT_FIND
)
1375 logit("%s call failed(cred): caller pid %ld, uid %u, "
1376 "euid %u (if uid or euid is %u, it may be "
1377 "unavailable)\n", dc_str
, ucred_getpid(*ucp
),
1378 ucred_getruid(*ucp
), ucred_geteuid(*ucp
), -1);
1383 if (current_admin
.debug_level
>= DBG_ALL
)
1384 logit("received %s call from pid %ld, uid %u, euid %u "
1385 "(if uid or euid is %u, it may be unavailable)\n",
1386 dc_str
, ucred_getpid(*ucp
), ucred_getruid(*ucp
),
1387 ucred_geteuid(*ucp
), -1);
1398 * Check if pid is nscd
1400 * Input: pid - process id of the door client that calls ldap_cachemgr
1407 is_called_from_nscd(pid_t pid
)
1410 static mutex_t _door_lock
= DEFAULTMUTEX
;
1411 static int doorfd
= -1;
1413 door_info_t my_door
;
1416 * the first time in we try and open and validate the door.
1417 * the validations are that the door must have been
1418 * created with the door cookie and
1419 * that the file attached to the door is owned by root
1420 * and readonly by user, group and other. If any of these
1421 * validations fail we refuse to use the door.
1424 (void) mutex_lock(&_door_lock
);
1430 if ((doorfd
= open(NAME_SERVICE_DOOR
, O_RDONLY
, 0))
1432 (void) mutex_unlock(&_door_lock
);
1436 if (door_info(doorfd
, &my_door
) == -1 ||
1437 (my_door
.di_attributes
& DOOR_REVOKED
) ||
1438 my_door
.di_data
!= (uintptr_t)NAME_SERVICE_DOOR_COOKIE
) {
1440 * we should close doorfd because we just opened it
1442 (void) close(doorfd
);
1444 (void) mutex_unlock(&_door_lock
);
1449 * doorfd is cached. Double check just in case
1450 * the door server is restarted or is down.
1452 if (door_info(doorfd
, &my_door
) == -1 ||
1453 my_door
.di_data
!= (uintptr_t)NAME_SERVICE_DOOR_COOKIE
) {
1456 * someone else has clobbered fd
1462 if (my_door
.di_attributes
& DOOR_REVOKED
) {
1463 (void) close(doorfd
);
1464 doorfd
= -1; /* try and restart connection */
1470 * door descriptor exists and is valid
1472 if (pid
== my_door
.di_target
)
1477 (void) mutex_unlock(&_door_lock
);
1484 * new_attr(name, value)
1486 * create a new LDAP attribute to be sent to the server
1488 static ns_ldap_attr_t
*
1489 new_attr(char *name
, char *value
)
1491 ns_ldap_attr_t
*tmp
;
1493 tmp
= malloc(sizeof (*tmp
));
1495 tmp
->attrname
= name
;
1496 tmp
->attrvalue
= (char **)calloc(2, sizeof (char *));
1497 if (tmp
->attrvalue
== NULL
) {
1501 tmp
->attrvalue
[0] = value
;
1502 tmp
->value_count
= 1;
1509 * Convert the flatten ldap attributes in a ns_ldap_attr_t back
1510 * to an ns_ldap_attr_t array.
1512 * strlist->ldap_offsets[] contains offsets to strings:
1513 * "dn", <dn value>, <attr 1>, <attrval 1>, ... <attr n>, <attrval n>
1514 * where n is (strlist->ldap_count/2 -1).
1515 * The output ns_ldap_attr_t array has a size of (strlist->ldap_count/2)
1516 * the first (strlist->ldap_count/2 -1) contains all the attribute data,
1517 * the last one is a NULL pointer. DN will be extracted out and pointed
1520 static ns_ldap_attr_t
**
1521 str2attrs(ldap_strlist_t
*strlist
, char **dn
)
1526 ns_ldap_attr_t
**ret
;
1528 c
= strlist
->ldap_count
;
1529 ret
= calloc(c
/2, sizeof (ns_ldap_attr_t
*));
1532 *dn
= (char *)strlist
+ strlist
->ldap_offsets
[1];
1535 * skip the first 'dn'/<dn value> pair, for all other attr type/value
1536 * pairs, get pointers to the attr type (offset [i]) and attr value
1537 * (offset [i+1]) and put in ns_ldap_attr_t at ret[j]
1539 for (i
= 2, j
= 0; i
< c
; i
= i
+ 2, j
++) {
1540 ret
[j
] = new_attr((char *)strlist
+ strlist
->ldap_offsets
[i
],
1541 (char *)strlist
+ strlist
->ldap_offsets
[i
+ 1]);
1547 get_admin_dn(ns_cred_t
*credp
, int *status
, ns_ldap_error_t
**errorp
)
1549 void **paramVal
= NULL
;
1552 /* get bind DN for shadow update */
1553 rc
= __ns_ldap_getParam(NS_LDAP_ADMIN_BINDDN_P
,
1555 if (rc
!= NS_LDAP_SUCCESS
)
1558 if (paramVal
== NULL
|| *paramVal
== NULL
) {
1559 rc
= NS_LDAP_CONFIG
;
1560 *status
= NS_CONFIG_NOTALLOW
;
1561 if (paramVal
!= NULL
)
1562 (void) __ns_ldap_freeParam(¶mVal
);
1565 credp
->cred
.unix_cred
.userID
= strdup((char *)*paramVal
);
1566 (void) __ns_ldap_freeParam(¶mVal
);
1567 if (credp
->cred
.unix_cred
.userID
== NULL
)
1568 return (NS_LDAP_MEMORY
);
1570 return (NS_LDAP_SUCCESS
);
1574 * admin_modify() does a privileged modify within the ldap_cachemgr daemon
1575 * process using the admin DN/password configured with parameters
1576 * NS_LDAP_ADMIN_BINDDN and NS_LDAP_ADMIN_BINDPASSWD. It will only
1577 * be done if NS_LDAP_ENABLE_SHADOW_UPDATE is set to TRUE.
1579 * The input ldap_call_t (*in) contains LDAP shadowAccount attributes to
1580 * be modified. The data is a flatten ns_ldap_attr_t arrary stored in
1581 * the strlist element of the input ldap_call_t.
1582 * The output will be in LineBuf (*config_info), an ldap_admin_mod_result_t
1583 * structure that contains error code, error status, and error message.
1586 admin_modify(LineBuf
*config_info
, ldap_call_t
*in
)
1588 int rc
= NS_LDAP_SUCCESS
;
1590 int shadow_enabled
= 0;
1592 char **certpath
= NULL
;
1593 char **enable_shadow
= NULL
;
1595 ns_auth_t
**authpp
= NULL
;
1596 ns_auth_t
*authp
= NULL
;
1597 ns_cred_t
*credp
= NULL
;
1598 char buffer
[MAXERROR
];
1599 const int rlen
= offsetof(ldap_admin_mod_result_t
, msg
);
1601 const int msgmax
= MAXERROR
- rlen
;
1604 ldap_strlist_t
*strlist
;
1605 ns_ldap_attr_t
**attrs
= NULL
;
1606 ns_ldap_error_t
*error
= NULL
;
1607 ldap_admin_mod_result_t
*result
;
1609 (void) memset((char *)config_info
, 0, sizeof (LineBuf
));
1611 /* only root or an ALL privs user can do admin modify */
1612 if (is_root_or_all_privs("ADMINMODIFY", &uc
) == 0) {
1613 mlen
= snprintf(buffer
, msgmax
, "%s",
1614 gettext("shadow update by a non-root and no ALL privilege "
1615 "user not allowed"));
1616 rc
= NS_LDAP_CONFIG
;
1620 /* check to see if shadow update is enabled */
1621 rc
= __ns_ldap_getParam(NS_LDAP_ENABLE_SHADOW_UPDATE_P
,
1622 (void ***)&enable_shadow
, &error
);
1623 if (rc
!= NS_LDAP_SUCCESS
)
1625 if (enable_shadow
!= NULL
&& *enable_shadow
!= NULL
) {
1626 shadow_enabled
= (*(int *)enable_shadow
[0] ==
1627 NS_LDAP_ENABLE_SHADOW_UPDATE_TRUE
);
1629 if (enable_shadow
!= NULL
)
1630 (void) __ns_ldap_freeParam((void ***)&enable_shadow
);
1631 if (shadow_enabled
== 0) {
1632 rc
= NS_LDAP_CONFIG
;
1633 status
= NS_CONFIG_NOTALLOW
;
1634 mlen
= snprintf(buffer
, msgmax
, "%s",
1635 gettext("shadow update not enabled"));
1639 /* convert attributes in string buffer into an ldap attribute array */
1640 strlist
= &in
->ldap_u
.strlist
;
1641 attrs
= str2attrs(strlist
, &dn
);
1642 if (attrs
== NULL
|| *attrs
== NULL
|| dn
== NULL
|| *dn
== '\0') {
1643 rc
= NS_LDAP_INVALID_PARAM
;
1647 if ((credp
= (ns_cred_t
*)calloc(1, sizeof (ns_cred_t
))) == NULL
) {
1648 rc
= NS_LDAP_MEMORY
;
1652 /* get host certificate path, if one is configured */
1653 rc
= __ns_ldap_getParam(NS_LDAP_HOST_CERTPATH_P
,
1654 (void ***)&certpath
, &error
);
1655 if (rc
!= NS_LDAP_SUCCESS
)
1657 if (certpath
!= NULL
&& *certpath
!= NULL
) {
1658 credp
->hostcertpath
= strdup(*certpath
);
1659 if (credp
->hostcertpath
== NULL
)
1660 rc
= NS_LDAP_MEMORY
;
1662 if (certpath
!= NULL
)
1663 (void) __ns_ldap_freeParam((void ***)&certpath
);
1664 if (rc
!= NS_LDAP_SUCCESS
)
1667 /* Load the service specific authentication method */
1668 rc
= __ns_ldap_getServiceAuthMethods("passwd-cmd", &authpp
,
1670 if (rc
!= NS_LDAP_SUCCESS
) {
1671 if (credp
->hostcertpath
!= NULL
)
1672 free(credp
->hostcertpath
);
1677 * if authpp is null, there is no serviceAuthenticationMethod
1678 * try default authenticationMethod
1680 if (authpp
== NULL
) {
1681 rc
= __ns_ldap_getParam(NS_LDAP_AUTH_P
, (void ***)&authpp
,
1683 if (rc
!= NS_LDAP_SUCCESS
)
1688 * if authpp is still null, then can not authenticate, syslog
1689 * error message and return error
1691 if (authpp
== NULL
) {
1692 rc
= NS_LDAP_CONFIG
;
1693 mlen
= snprintf(buffer
, msgmax
, "%s",
1694 gettext("No legal LDAP authentication method configured"));
1699 * Walk the array and try all authentication methods in order except
1702 for (app
= authpp
; *app
; app
++) {
1704 if (authp
->type
== NS_LDAP_AUTH_NONE
)
1707 credp
->auth
.type
= authp
->type
;
1708 credp
->auth
.tlstype
= authp
->tlstype
;
1709 credp
->auth
.saslmech
= authp
->saslmech
;
1710 credp
->auth
.saslopt
= authp
->saslopt
;
1713 * For GSSAPI, host credential will be used. No admin
1714 * DN is needed. For other authentication methods,
1715 * we need to set admin.
1717 if (credp
->auth
.saslmech
!= NS_LDAP_SASL_GSSAPI
) {
1718 if ((rc
= get_admin_dn(credp
, &status
,
1719 &error
)) != NS_LDAP_SUCCESS
) {
1722 if (status
== NS_CONFIG_NOTALLOW
) {
1723 mlen
= snprintf(buffer
, msgmax
, "%s",
1724 gettext("Admin bind DN not "
1731 rc
= __ns_ldap_repAttr(NS_ADMIN_SHADOW_UPDATE
, dn
,
1732 (const ns_ldap_attr_t
* const *)attrs
,
1734 if (rc
== NS_LDAP_SUCCESS
)
1738 * Other errors might need to be added to this list, for
1739 * the current supported mechanisms this is sufficient.
1741 if (rc
== NS_LDAP_INTERNAL
&&
1742 error
->pwd_mgmt
.status
== NS_PASSWD_GOOD
&&
1743 (error
->status
== LDAP_INAPPROPRIATE_AUTH
||
1744 error
->status
== LDAP_INVALID_CREDENTIALS
))
1748 * If there is error related to password policy,
1749 * return it to caller.
1751 if (rc
== NS_LDAP_INTERNAL
&&
1752 error
->pwd_mgmt
.status
!= NS_PASSWD_GOOD
) {
1753 rc
= NS_LDAP_CONFIG
;
1754 status
= NS_CONFIG_NOTALLOW
;
1755 (void) __ns_ldap_freeError(&error
);
1756 mlen
= snprintf(buffer
, msgmax
, "%s",
1757 gettext("update failed due to "
1758 "password policy on server (%d)"),
1759 error
->pwd_mgmt
.status
);
1763 /* we don't really care about the error, just clean it up */
1765 (void) __ns_ldap_freeError(&error
);
1767 if (authstried
== 0) {
1768 rc
= NS_LDAP_CONFIG
;
1769 mlen
= snprintf(buffer
, msgmax
, "%s",
1770 gettext("No legal LDAP authentication method configured"));
1774 rc
= NS_LDAP_OP_FAILED
;
1778 (void) __ns_ldap_freeCred(&credp
);
1781 (void) __ns_ldap_freeParam((void ***)&authpp
);
1783 if (error
!= NULL
) {
1784 mlen
= snprintf(buffer
, msgmax
, "%s", error
->message
);
1785 status
= error
->status
;
1786 (void) __ns_ldap_freeError(&error
);
1789 if (attrs
!= NULL
) {
1791 for (i
= 0; attrs
[i
]; i
++) {
1792 free(attrs
[i
]->attrvalue
);
1797 config_info
->len
= rlen
+ mlen
+ 1;
1798 config_info
->str
= malloc(config_info
->len
);
1799 if (config_info
->str
== NULL
) {
1800 config_info
->len
= 0;
1803 result
= (ldap_admin_mod_result_t
*)config_info
->str
;
1804 result
->ns_err
= rc
;
1805 result
->status
= status
;
1807 result
->msg_size
= mlen
+ 1;
1808 (void) strcpy(config_info
->str
+ rlen
, buffer
);
1813 * Check to see if the door client's euid is 0 or if it has ALL zone privilege.
1814 * return - 0 No or error
1818 is_root_or_all_privs(char *dc_str
, ucred_t
**ucp
)
1820 const priv_set_t
*ps
; /* door client */
1821 priv_set_t
*zs
; /* zone */
1826 /* no more to do if door client's euid is 0 */
1827 if (is_root(0, dc_str
, ucp
) == 1) {
1832 /* error if couldn't get the ucred_t */
1836 if ((ps
= ucred_getprivset(*ucp
, PRIV_EFFECTIVE
)) != NULL
) {
1837 zs
= priv_str_to_set("zone", ",", NULL
);
1838 if (priv_isequalset(ps
, zs
))
1839 rc
= 1; /* has all zone privs */
1841 if (current_admin
.debug_level
>= DBG_CANT_FIND
)
1842 logit("%s call failed (no all zone privs): "
1843 "caller pid %ld, uid %u, euid %u "
1844 "(if uid or euid is %u, it may "
1845 "be unavailable)\n", dc_str
,
1846 ucred_getpid(*ucp
), ucred_getruid(*ucp
),
1847 ucred_geteuid(*ucp
), -1);