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
);
451 (void) cachemgr_set_lf(¤t_admin
, current_admin
.logfile
);
453 * validate the range of debug level number
454 * and set the number to current_admin.debug_level
456 if (cachemgr_set_dl(¤t_admin
, debug_level
) < 0) {
458 * print error messages to the screen
459 * cachemgr_set_dl prints msgs to cachemgr.log
462 (void) fprintf(stderr
,
463 gettext("Incorrect Debug Level: %d\n"
464 "It should be between %d and %d\n"),
465 debug_level
, DBG_OFF
, MAXDEBUG
);
469 if (strlen(current_admin
.logfile
) == 0)
470 (void) strcpy(current_admin
.logfile
, "/dev/null");
471 (void) cachemgr_set_lf(¤t_admin
, current_admin
.logfile
);
475 detachfromtty(argv
[0]);
478 * perform some initialization
481 initialize_lookup_clearance();
483 if (getldap_init() != 0)
487 * Establish our own server thread pool
490 (void) door_server_create(server_create
);
491 if (thr_keycreate(&server_key
, server_destroy
) != 0) {
492 logit("thr_keycreate() call failed\n");
494 gettext("ldap_cachemgr: thr_keycreate() call failed"));
495 perror("thr_keycreate");
503 if ((did
= door_create(switcher
, LDAP_CACHE_DOOR_COOKIE
,
504 DOOR_UNREF
| DOOR_REFUSE_DESC
| DOOR_NO_CANCEL
)) < 0) {
505 logit("door_create() call failed\n");
506 syslog(LOG_ERR
, gettext(
507 "ldap_cachemgr: door_create() call failed"));
508 perror("door_create");
513 * bind to file system
516 if (stat(LDAP_CACHE_DOOR
, &buf
) < 0) {
519 if ((newfd
= creat(LDAP_CACHE_DOOR
, 0444)) < 0) {
520 logit("Cannot create %s:%s\n",
528 if (fattach(did
, LDAP_CACHE_DOOR
) < 0) {
529 if ((errno
!= EBUSY
) ||
530 (fdetach(LDAP_CACHE_DOOR
) < 0) ||
531 (fattach(did
, LDAP_CACHE_DOOR
) < 0)) {
532 logit("fattach() call failed\n");
533 syslog(LOG_ERR
, gettext(
534 "ldap_cachemgr: fattach() call failed"));
540 /* catch SIGHUP revalid signals */
541 sighupaction
.sa_handler
= getldap_revalidate
;
542 sighupaction
.sa_flags
= 0;
543 (void) sigemptyset(&sighupaction
.sa_mask
);
544 (void) sigemptyset(&myset
);
545 (void) sigaddset(&myset
, SIGHUP
);
547 if (sigaction(SIGHUP
, &sighupaction
, NULL
) < 0) {
548 logit("sigaction() call failed\n");
550 gettext("ldap_cachemgr: sigaction() call failed"));
555 if (thr_sigsetmask(SIG_BLOCK
, &myset
, NULL
) < 0) {
556 logit("thr_sigsetmask() call failed\n");
558 gettext("ldap_cachemgr: thr_sigsetmask() call failed"));
559 perror("thr_sigsetmask");
564 * kick off revalidate threads only if ttl != 0
567 if (thr_create(NULL
, 0, (void *(*)(void*))getldap_refresh
,
568 NULL
, 0, NULL
) != 0) {
569 logit("thr_create() call failed\n");
571 gettext("ldap_cachemgr: thr_create() call failed"));
572 perror("thr_create");
577 * kick off the thread which refreshes the server info
580 if (thr_create(NULL
, 0, (void *(*)(void*))getldap_serverInfo_refresh
,
581 NULL
, 0, NULL
) != 0) {
582 logit("thr_create() call failed\n");
584 gettext("ldap_cachemgr: thr_create() call failed"));
585 perror("thr_create");
590 * kick off the thread which cleans up waiting threads for
594 if (thr_create(NULL
, 0, chg_cleanup_waiting_threads
,
595 NULL
, 0, NULL
) != 0) {
596 logit("thr_create() chg_cleanup_waiting_threads call failed\n");
598 gettext("ldap_cachemgr: thr_create() "
599 "chg_cleanup_waiting_threads call failed"));
605 /* kick off SLP discovery thread */
606 if (thr_create(NULL
, 0, (void *(*)(void *))discover
,
607 (void *)&refresh
, 0, NULL
) != 0) {
608 logit("thr_create() call failed\n");
609 syslog(LOG_ERR
, gettext("ldap_cachemgr: thr_create() "
611 perror("thr_create");
617 if (thr_sigsetmask(SIG_UNBLOCK
, &myset
, NULL
) < 0) {
618 logit("thr_sigsetmask() call failed\n");
620 gettext("ldap_cachemgr: the_sigsetmask() call failed"));
621 perror("thr_sigsetmask");
630 /*LINTED E_FUNC_HAS_NO_RETURN_STMT*/
635 * Before calling the alloca() function we have to be sure that we won't get
636 * beyond the stack. Since we don't know the precise layout of the stack,
637 * the address of an automatic of the function gives us a rough idea, plus/minus
638 * a bit. We also need a bit more of stackspace after the call to be able
639 * to call further functions. Even something as simple as making a system call
640 * from within this function can take ~100 Bytes of stackspace.
642 #define SAFETY_BUFFER 32 * 1024 /* 32KB */
646 get_data_size(LineBuf
*config_info
, int *err_code
)
648 size_t configSize
= sizeof (ldap_return_t
);
649 dataunion
*buf
= NULL
; /* For the 'sizeof' purpose */
651 if (config_info
->str
!= NULL
&&
652 config_info
->len
>= sizeof (buf
->data
.ldap_ret
.ldap_u
.config
)) {
653 configSize
= sizeof (buf
->space
) +
655 sizeof (buf
->data
.ldap_ret
.ldap_u
.config
);
657 if (!stack_inbounds((char *)&buf
-
658 (configSize
+ SAFETY_BUFFER
))) {
660 * We do not have enough space on the stack
661 * to accomodate the whole DUAProfile
663 logit("The DUAProfile is too big. There is not enough "
664 "space to process it. Ignoring it.\n");
665 syslog(LOG_ERR
, gettext("ldap_cachemgr: The DUAProfile "
666 "is too big. There is not enough space "
667 "to process it. Ignoring it."));
669 *err_code
= NS_CACHE_SERVERERROR
;
671 free(config_info
->str
);
672 config_info
->str
= NULL
;
673 config_info
->len
= 0;
674 configSize
= sizeof (ldap_return_t
);
683 switcher(void *cookie
, char *argp
, size_t arg_size
,
684 door_desc_t
*dp
, uint_t n_desc
)
687 #define ALLOCATE 1001
689 ldap_call_t
*ptr
= (ldap_call_t
*)argp
;
693 dataunion
*buf
= NULL
;
696 * By default the size of a buffer to be passed down to a client
697 * is equal to the size of the ldap_return_t structure. We need
698 * a bigger buffer in a few cases.
700 size_t configSize
= sizeof (ldap_return_t
);
701 int ldapErrno
= 0, state
, callnumber
;
708 if (argp
== DOOR_UNREF_DATA
) {
709 logit("Door Slam... invalid door param\n");
710 syslog(LOG_ERR
, gettext("ldap_cachemgr: Door Slam... "
711 "invalid door param"));
712 (void) printf(gettext("Door Slam... invalid door param\n"));
716 if (ptr
== NULL
) { /* empty door call */
717 (void) door_return(NULL
, 0, 0, 0); /* return the favor */
720 bzero(&dataSource
, sizeof (dataSource
));
723 * We presume that sizeof (ldap_return_t) bytes are always available
726 callnumber
= ptr
->ldap_callnumber
;
728 switch (callnumber
) {
731 * Just a 'ping'. Use the default size
732 * of the buffer and set the
739 * Get the current LDAP configuration.
740 * Since this is dynamic data and its size can exceed
741 * the size of ldap_return_t, the next step will
742 * calculate how much space exactly is required.
744 getldap_lookup(&configInfo
, ptr
);
750 * Get the current Admin Credentials (DN and password).
751 * Since this is dynamic data and its size can exceed
752 * the size of ldap_return_t, the next step will
753 * calculate how much space exactly is required.
755 getldap_admincred(&configInfo
, ptr
);
761 * Get the root DSE for a next server in the list.
762 * Since this is dynamic data and its size can exceed
763 * the size of ldap_return_t, the next step will
764 * calculate how much space exactly is required.
766 getldap_getserver(&configInfo
, ptr
);
772 * Get the cache stattistics.
773 * Since this is dynamic data and its size can exceed
774 * the size of ldap_return_t, the next step will
775 * calculate how much space exactly is required.
777 getldap_get_cacheStat(&configInfo
);
783 * Get current configuration and statistics.
784 * The size of the statistics structure is less then
785 * sizeof (ldap_return_t). So specify the source
786 * where to take the info and proceed with the memory
791 if (ldapErrno
== 0) {
792 dataSource
.begin
= ¤t_admin
;
793 dataSource
.size
= sizeof (current_admin
);
794 dataSource
.destroy
= 0;
799 * Process the request and proceed with the default
802 if (is_root(1, "KILLSERVER", &uc
))
810 * Process the request and proceed with the default
813 if (is_root(1, "SETADMIN", &uc
))
814 ldapErrno
= setadmin(ptr
);
822 * Get the cache stattistics.
823 * Since this is dynamic data and its size can exceed
824 * the size of ldap_return_t, the next step will
825 * calculate how much space exactly is required.
827 getldap_get_cacheData(&configInfo
, ptr
);
833 * Process the request and proceed with the default
836 if (is_root(0, "SETCACHE", &uc
) &&
837 is_called_from_nscd(ucred_getpid(uc
))) {
838 ldapErrno
= getldap_set_cacheData(ptr
);
839 current_admin
.ldap_stat
.ldap_numbercalls
++;
848 admin_modify(&configInfo
, ptr
);
852 case GETSTATUSCHANGE
:
854 * Process the request and proceed with the default
857 (void) mutex_lock(&chg_threads_num_lock
);
859 if (chg_threads_num
> MAX_CHG_THREADS
) {
861 (void) mutex_unlock(&chg_threads_num_lock
);
862 ldapErrno
= CHG_EXCEED_MAX_THREADS
;
866 (void) mutex_unlock(&chg_threads_num_lock
);
868 if (is_root(0, "GETSTATUSCHANGE", &uc
) &&
869 is_called_from_nscd(ucred_getpid(uc
))) {
870 ldapErrno
= chg_get_statusChange(
871 &configInfo
, ptr
, ucred_getpid(uc
));
880 (void) mutex_lock(&chg_threads_num_lock
);
882 (void) mutex_unlock(&chg_threads_num_lock
);
886 * This means an unknown request type. Proceed with
887 * the default buffer allocation.
889 logit("Unknown ldap service door call op %d\n",
890 ptr
->ldap_callnumber
);
900 * This stage calculates how much data will be
901 * passed down to the client, checks if there is
902 * enough space on the stack to accommodate the data,
903 * increases the value of the configSize variable
904 * if necessary and specifies the data source.
905 * In case of any error occurred ldapErrno will be set
908 if (configInfo
.str
== NULL
) {
912 configSize
= get_data_size(&configInfo
, &ldapErrno
);
914 if (ldapErrno
== 0) {
915 dataSource
.begin
= configInfo
.str
;
916 dataSource
.size
= configInfo
.len
;
917 dataSource
.destroy
= 1;
920 current_admin
.ldap_stat
.ldap_numbercalls
++;
924 * Allocate a buffer of the calculated (or default) size
925 * and proceed with populating it with data.
927 buf
= (dataunion
*) alloca(configSize
);
930 * Set a return code and, if a data source is specified,
931 * copy data from the source to the buffer.
933 buf
->data
.ldap_ret
.ldap_errno
= ldapErrno
;
934 buf
->data
.ldap_ret
.ldap_return_code
= ldapErrno
;
935 buf
->data
.ldap_ret
.ldap_bufferbytesused
= configSize
;
937 if (dataSource
.begin
!= NULL
) {
938 (void) memcpy(buf
->data
.ldap_ret
.ldap_u
.config
,
941 if (dataSource
.destroy
) {
942 free(dataSource
.begin
);
947 (void) door_return((char *)&buf
->data
,
948 buf
->data
.ldap_ret
.ldap_bufferbytesused
,
958 (void) fprintf(stderr
,
959 gettext("Usage: %s [-d debug_level] [-l logfilename]\n"), s
);
960 (void) fprintf(stderr
, gettext(" [-K] "
961 "[-r revalidate_interval] "));
963 (void) fprintf(stderr
, gettext(" [-g]\n"));
965 (void) fprintf(stderr
, gettext(" [-g] [-s]\n"));
971 static int logfd
= -1;
974 cachemgr_set_lf(admin_t
*ptr
, char *logfile
)
979 * we don't really want to try and open the log file
980 * /dev/null since that will fail w/ our security fixes
983 if (logfile
== NULL
|| *logfile
== 0) {
985 } else if (strcmp(logfile
, "/dev/null") == 0) {
986 (void) strcpy(current_admin
.logfile
, "/dev/null");
991 open(logfile
, O_EXCL
|O_WRONLY
|O_CREAT
, 0644)) < 0) {
993 * File already exists... now we need to get cute
994 * since opening a file in a world-writeable directory
995 * safely is hard = it could be a hard link or a
996 * symbolic link to a system file.
1001 if (lstat(logfile
, &before
) < 0) {
1002 logit("Cannot open new logfile \"%s\": %sn",
1003 logfile
, strerror(errno
));
1006 if (S_ISREG(before
.st_mode
) && /* no symbolic links */
1007 (before
.st_nlink
== 1) && /* no hard links */
1008 (before
.st_uid
== 0)) { /* owned by root */
1011 O_APPEND
|O_WRONLY
, 0644)) < 0) {
1012 logit("Cannot open new logfile "
1014 logfile
, strerror(errno
));
1018 logit("Cannot use specified logfile "
1019 "\"%s\": file is/has links or isn't "
1020 "owned by root\n", logfile
);
1024 (void) strlcpy(ptr
->logfile
, logfile
, sizeof (ptr
->logfile
));
1025 (void) close(logfd
);
1027 logit("Starting ldap_cachemgr, logfile %s\n", logfile
);
1034 logit(char *format
, ...)
1036 static mutex_t loglock
;
1038 char buffer
[BUFSIZ
];
1041 va_start(ap
, format
);
1046 (void) gettimeofday(&tv
, NULL
);
1047 (void) ctime_r(&tv
.tv_sec
, buffer
, BUFSIZ
);
1048 (void) snprintf(buffer
+19, BUFSIZE
, ".%.4ld ",
1050 safechars
= sizeof (buffer
) - 30;
1051 if (vsnprintf(buffer
+25, safechars
, format
, ap
) > safechars
)
1052 (void) strcat(buffer
, "...\n");
1053 (void) mutex_lock(&loglock
);
1054 (void) write(logfd
, buffer
, strlen(buffer
));
1055 (void) mutex_unlock(&loglock
);
1062 client_getadmin(admin_t
*ptr
)
1069 u
.data
.ldap_call
.ldap_callnumber
= GETADMIN
;
1071 adata
= sizeof (u
.data
);
1074 if (__ns_ldap_trydoorcall(&dptr
, &ndata
, &adata
) != NS_CACHE_SUCCESS
) {
1077 (void) memcpy(ptr
, dptr
->ldap_ret
.ldap_u
.buff
, sizeof (*ptr
));
1084 setadmin(ldap_call_t
*ptr
)
1088 new = (admin_t
*)ptr
->ldap_u
.domainname
;
1091 * global admin stuff
1094 if ((cachemgr_set_lf(¤t_admin
, new->logfile
) < 0) ||
1095 cachemgr_set_dl(¤t_admin
, new->debug_level
) < 0) {
1099 if (cachemgr_set_ttl(¤t_admin
.ldap_stat
,
1101 new->ldap_stat
.ldap_ttl
) < 0) {
1117 u
.data
.ldap_call
.ldap_callnumber
= KILLSERVER
;
1119 adata
= sizeof (ldap_call_t
);
1122 __ns_ldap_trydoorcall(&dptr
, &ndata
, &adata
);
1127 client_setadmin(admin_t
*ptr
)
1134 u
.data
.ldap_call
.ldap_callnumber
= SETADMIN
;
1135 (void) memcpy(u
.data
.ldap_call
.ldap_u
.domainname
, ptr
, sizeof (*ptr
));
1137 adata
= sizeof (*ptr
);
1140 if (__ns_ldap_trydoorcall(&dptr
, &ndata
, &adata
) != NS_CACHE_SUCCESS
) {
1148 client_showstats(admin_t
*ptr
)
1154 char *rbuf
, *sptr
, *rest
;
1159 (void) printf(gettext("\ncachemgr configuration:\n"));
1160 (void) printf(gettext("server debug level %10d\n"), ptr
->debug_level
);
1161 (void) printf(gettext("server log file\t\"%s\"\n"), ptr
->logfile
);
1162 (void) printf(gettext("number of calls to ldapcachemgr %10d\n"),
1163 ptr
->ldap_stat
.ldap_numbercalls
);
1166 * get cache data statistics
1168 u
.data
.ldap_call
.ldap_callnumber
= GETCACHESTAT
;
1170 adata
= sizeof (ldap_call_t
);
1173 if (__ns_ldap_trydoorcall(&dptr
, &ndata
, &adata
) != NS_CACHE_SUCCESS
) {
1175 gettext("\nCache data statistics not available!\n"));
1180 * print cache data statistics line by line
1182 (void) printf(gettext("\ncachemgr cache data statistics:\n"));
1183 rbuf
= dptr
->ldap_ret
.ldap_u
.buff
;
1184 sptr
= strtok_r(rbuf
, DOORLINESEP
, &rest
);
1186 (void) printf("%s\n", sptr
);
1187 sptr
= strtok_r(NULL
, DOORLINESEP
, &rest
);
1199 detachfromtty(char *pgm
)
1207 * Block the SIGUSR1 signal
1208 * just in case that the child
1209 * process may run faster than
1210 * the parent process and
1211 * send this signal before
1212 * the signal handler is ready
1213 * in the parent process.
1214 * This error will cause the parent
1215 * to exit with the User Signal 1
1218 (void) sighold(SIGUSR1
);
1222 logit("detachfromtty(): fork1() call failed\n");
1223 (void) fprintf(stderr
,
1224 gettext("%s: fork1() call failed.\n"),
1227 gettext("ldap_cachemgr: fork1() call failed."));
1232 * child process does not
1233 * need to worry about
1234 * the SIGUSR1 signal
1236 (void) sigrelse(SIGUSR1
);
1241 * Wait forever until the child process
1242 * has exited, or has signalled that at
1243 * least one server in the server list
1246 if (signal(SIGUSR1
, sig_ok_to_exit
) == SIG_ERR
) {
1247 logit("detachfromtty(): "
1248 "can't set up signal handler to "
1249 " catch SIGUSR1.\n");
1250 (void) fprintf(stderr
,
1251 gettext("%s: signal() call failed.\n"),
1253 syslog(LOG_ERR
, gettext("ldap_cachemgr: "
1254 "can't set up signal handler to "
1255 " catch SIGUSR1."));
1260 * now unblock the SIGUSR1 signal
1261 * to handle the pending or
1262 * soon to arrive SIGUSR1 signal
1264 (void) sigrelse(SIGUSR1
);
1265 wret
= waitpid(pid
, &status
, 0);
1268 logit("detachfromtty(): "
1269 "waitpid() call failed\n");
1270 (void) fprintf(stderr
,
1271 gettext("%s: waitpid() call failed.\n"),
1274 gettext("ldap_cachemgr: waitpid() "
1279 logit("detachfromtty(): "
1280 "waitpid() returned %ld when "
1281 "child pid was %ld\n",
1283 (void) fprintf(stderr
,
1285 "%s: waitpid() returned %ld when "
1286 "child pid was %ld.\n"),
1289 gettext("ldap_cachemgr: waitpid() "
1290 "returned different "
1295 /* evaluate return status */
1296 if (WIFEXITED(status
)) {
1297 if (WEXITSTATUS(status
) == 0) {
1300 logit("detachfromtty(): "
1301 "child failed (rc = %d).\n",
1302 WEXITSTATUS(status
));
1303 (void) fprintf(stderr
,
1304 gettext("%s: failed. Please see "
1305 "syslog for details.\n"),
1308 gettext("ldap_cachemgr: failed "
1310 WEXITSTATUS(status
));
1311 } else if (WIFSIGNALED(status
)) {
1312 logit("detachfromtty(): "
1313 "child terminated by signal %d.\n",
1315 (void) fprintf(stderr
,
1316 gettext("%s: terminated by signal %d.\n"),
1317 pgm
, WTERMSIG(status
));
1319 gettext("ldap_cachemgr: terminated by "
1322 } else if (WCOREDUMP(status
)) {
1323 logit("detachfromtty(): child core dumped.\n"),
1324 (void) fprintf(stderr
,
1325 gettext("%s: core dumped.\n"),
1328 gettext("ldap_cachemgr: "
1335 if (open("/dev/null", O_RDWR
, 0) != -1) {
1342 * Check if the door client's euid is 0
1344 * We could check for some privilege or re-design the interfaces that
1345 * lead to is_root() being called so that we rely on SMF and RBAC, but
1346 * we need this check only for dealing with undocumented-but-possibly-
1347 * used interfaces. Anything beyond checking for euid == 0 here would
1348 * be overkill considering that those are undocumented interfaces.
1350 * If free_uc is 0, the caller is responsible for freeing *ucp.
1352 * return - 0 euid != 0
1356 is_root(int free_uc
, char *dc_str
, ucred_t
**ucp
)
1360 if (door_ucred(ucp
) != 0) {
1362 logit("door_ucred() call failed %s\n", strerror(rc
));
1363 syslog(LOG_ERR
, gettext("ldap_cachemgr: door_ucred() call %s "
1364 "failed %s"), strerror(rc
));
1369 if (ucred_geteuid(*ucp
) != 0) {
1371 if (current_admin
.debug_level
>= DBG_CANT_FIND
)
1372 logit("%s call failed(cred): caller pid %ld, uid %u, "
1373 "euid %u (if uid or euid is %u, it may be "
1374 "unavailable)\n", dc_str
, ucred_getpid(*ucp
),
1375 ucred_getruid(*ucp
), ucred_geteuid(*ucp
), -1);
1380 if (current_admin
.debug_level
>= DBG_ALL
)
1381 logit("received %s call from pid %ld, uid %u, euid %u "
1382 "(if uid or euid is %u, it may be unavailable)\n",
1383 dc_str
, ucred_getpid(*ucp
), ucred_getruid(*ucp
),
1384 ucred_geteuid(*ucp
), -1);
1395 * Check if pid is nscd
1397 * Input: pid - process id of the door client that calls ldap_cachemgr
1404 is_called_from_nscd(pid_t pid
)
1406 static mutex_t _door_lock
= DEFAULTMUTEX
;
1407 static int doorfd
= -1;
1409 door_info_t my_door
;
1412 * the first time in we try and open and validate the door.
1413 * the validations are that the door must have been
1414 * created with the door cookie and
1415 * that the file attached to the door is owned by root
1416 * and readonly by user, group and other. If any of these
1417 * validations fail we refuse to use the door.
1420 (void) mutex_lock(&_door_lock
);
1426 if ((doorfd
= open(NAME_SERVICE_DOOR
, O_RDONLY
, 0))
1428 (void) mutex_unlock(&_door_lock
);
1432 if (door_info(doorfd
, &my_door
) == -1 ||
1433 (my_door
.di_attributes
& DOOR_REVOKED
) ||
1434 my_door
.di_data
!= (uintptr_t)NAME_SERVICE_DOOR_COOKIE
) {
1436 * we should close doorfd because we just opened it
1438 (void) close(doorfd
);
1440 (void) mutex_unlock(&_door_lock
);
1445 * doorfd is cached. Double check just in case
1446 * the door server is restarted or is down.
1448 if (door_info(doorfd
, &my_door
) == -1 ||
1449 my_door
.di_data
!= (uintptr_t)NAME_SERVICE_DOOR_COOKIE
) {
1452 * someone else has clobbered fd
1458 if (my_door
.di_attributes
& DOOR_REVOKED
) {
1459 (void) close(doorfd
);
1460 doorfd
= -1; /* try and restart connection */
1466 * door descriptor exists and is valid
1468 if (pid
== my_door
.di_target
)
1473 (void) mutex_unlock(&_door_lock
);
1480 * new_attr(name, value)
1482 * create a new LDAP attribute to be sent to the server
1484 static ns_ldap_attr_t
*
1485 new_attr(char *name
, char *value
)
1487 ns_ldap_attr_t
*tmp
;
1489 tmp
= malloc(sizeof (*tmp
));
1491 tmp
->attrname
= name
;
1492 tmp
->attrvalue
= (char **)calloc(2, sizeof (char *));
1493 if (tmp
->attrvalue
== NULL
) {
1497 tmp
->attrvalue
[0] = value
;
1498 tmp
->value_count
= 1;
1505 * Convert the flatten ldap attributes in a ns_ldap_attr_t back
1506 * to an ns_ldap_attr_t array.
1508 * strlist->ldap_offsets[] contains offsets to strings:
1509 * "dn", <dn value>, <attr 1>, <attrval 1>, ... <attr n>, <attrval n>
1510 * where n is (strlist->ldap_count/2 -1).
1511 * The output ns_ldap_attr_t array has a size of (strlist->ldap_count/2)
1512 * the first (strlist->ldap_count/2 -1) contains all the attribute data,
1513 * the last one is a NULL pointer. DN will be extracted out and pointed
1516 static ns_ldap_attr_t
**
1517 str2attrs(ldap_strlist_t
*strlist
, char **dn
)
1522 ns_ldap_attr_t
**ret
;
1524 c
= strlist
->ldap_count
;
1525 ret
= calloc(c
/2, sizeof (ns_ldap_attr_t
*));
1528 *dn
= (char *)strlist
+ strlist
->ldap_offsets
[1];
1531 * skip the first 'dn'/<dn value> pair, for all other attr type/value
1532 * pairs, get pointers to the attr type (offset [i]) and attr value
1533 * (offset [i+1]) and put in ns_ldap_attr_t at ret[j]
1535 for (i
= 2, j
= 0; i
< c
; i
= i
+ 2, j
++) {
1536 ret
[j
] = new_attr((char *)strlist
+ strlist
->ldap_offsets
[i
],
1537 (char *)strlist
+ strlist
->ldap_offsets
[i
+ 1]);
1543 get_admin_dn(ns_cred_t
*credp
, int *status
, ns_ldap_error_t
**errorp
)
1545 void **paramVal
= NULL
;
1548 /* get bind DN for shadow update */
1549 rc
= __ns_ldap_getParam(NS_LDAP_ADMIN_BINDDN_P
,
1551 if (rc
!= NS_LDAP_SUCCESS
)
1554 if (paramVal
== NULL
|| *paramVal
== NULL
) {
1555 rc
= NS_LDAP_CONFIG
;
1556 *status
= NS_CONFIG_NOTALLOW
;
1557 if (paramVal
!= NULL
)
1558 (void) __ns_ldap_freeParam(¶mVal
);
1561 credp
->cred
.unix_cred
.userID
= strdup((char *)*paramVal
);
1562 (void) __ns_ldap_freeParam(¶mVal
);
1563 if (credp
->cred
.unix_cred
.userID
== NULL
)
1564 return (NS_LDAP_MEMORY
);
1566 return (NS_LDAP_SUCCESS
);
1570 * admin_modify() does a privileged modify within the ldap_cachemgr daemon
1571 * process using the admin DN/password configured with parameters
1572 * NS_LDAP_ADMIN_BINDDN and NS_LDAP_ADMIN_BINDPASSWD. It will only
1573 * be done if NS_LDAP_ENABLE_SHADOW_UPDATE is set to TRUE.
1575 * The input ldap_call_t (*in) contains LDAP shadowAccount attributes to
1576 * be modified. The data is a flatten ns_ldap_attr_t arrary stored in
1577 * the strlist element of the input ldap_call_t.
1578 * The output will be in LineBuf (*config_info), an ldap_admin_mod_result_t
1579 * structure that contains error code, error status, and error message.
1582 admin_modify(LineBuf
*config_info
, ldap_call_t
*in
)
1584 int rc
= NS_LDAP_SUCCESS
;
1586 int shadow_enabled
= 0;
1588 char **certpath
= NULL
;
1589 char **enable_shadow
= NULL
;
1591 ns_auth_t
**authpp
= NULL
;
1592 ns_auth_t
*authp
= NULL
;
1593 ns_cred_t
*credp
= NULL
;
1594 char buffer
[MAXERROR
];
1595 const int rlen
= offsetof(ldap_admin_mod_result_t
, msg
);
1597 const int msgmax
= MAXERROR
- rlen
;
1600 ldap_strlist_t
*strlist
;
1601 ns_ldap_attr_t
**attrs
= NULL
;
1602 ns_ldap_error_t
*error
= NULL
;
1603 ldap_admin_mod_result_t
*result
;
1605 (void) memset((char *)config_info
, 0, sizeof (LineBuf
));
1607 /* only root or an ALL privs user can do admin modify */
1608 if (is_root_or_all_privs("ADMINMODIFY", &uc
) == 0) {
1609 mlen
= snprintf(buffer
, msgmax
, "%s",
1610 gettext("shadow update by a non-root and no ALL privilege "
1611 "user not allowed"));
1612 rc
= NS_LDAP_CONFIG
;
1616 /* check to see if shadow update is enabled */
1617 rc
= __ns_ldap_getParam(NS_LDAP_ENABLE_SHADOW_UPDATE_P
,
1618 (void ***)&enable_shadow
, &error
);
1619 if (rc
!= NS_LDAP_SUCCESS
)
1621 if (enable_shadow
!= NULL
&& *enable_shadow
!= NULL
) {
1622 shadow_enabled
= (*(int *)enable_shadow
[0] ==
1623 NS_LDAP_ENABLE_SHADOW_UPDATE_TRUE
);
1625 if (enable_shadow
!= NULL
)
1626 (void) __ns_ldap_freeParam((void ***)&enable_shadow
);
1627 if (shadow_enabled
== 0) {
1628 rc
= NS_LDAP_CONFIG
;
1629 status
= NS_CONFIG_NOTALLOW
;
1630 mlen
= snprintf(buffer
, msgmax
, "%s",
1631 gettext("shadow update not enabled"));
1635 /* convert attributes in string buffer into an ldap attribute array */
1636 strlist
= &in
->ldap_u
.strlist
;
1637 attrs
= str2attrs(strlist
, &dn
);
1638 if (attrs
== NULL
|| *attrs
== NULL
|| dn
== NULL
|| *dn
== '\0') {
1639 rc
= NS_LDAP_INVALID_PARAM
;
1643 if ((credp
= (ns_cred_t
*)calloc(1, sizeof (ns_cred_t
))) == NULL
) {
1644 rc
= NS_LDAP_MEMORY
;
1648 /* get host certificate path, if one is configured */
1649 rc
= __ns_ldap_getParam(NS_LDAP_HOST_CERTPATH_P
,
1650 (void ***)&certpath
, &error
);
1651 if (rc
!= NS_LDAP_SUCCESS
)
1653 if (certpath
!= NULL
&& *certpath
!= NULL
) {
1654 credp
->hostcertpath
= strdup(*certpath
);
1655 if (credp
->hostcertpath
== NULL
)
1656 rc
= NS_LDAP_MEMORY
;
1658 if (certpath
!= NULL
)
1659 (void) __ns_ldap_freeParam((void ***)&certpath
);
1660 if (rc
!= NS_LDAP_SUCCESS
)
1663 /* Load the service specific authentication method */
1664 rc
= __ns_ldap_getServiceAuthMethods("passwd-cmd", &authpp
,
1666 if (rc
!= NS_LDAP_SUCCESS
) {
1667 if (credp
->hostcertpath
!= NULL
)
1668 free(credp
->hostcertpath
);
1673 * if authpp is null, there is no serviceAuthenticationMethod
1674 * try default authenticationMethod
1676 if (authpp
== NULL
) {
1677 rc
= __ns_ldap_getParam(NS_LDAP_AUTH_P
, (void ***)&authpp
,
1679 if (rc
!= NS_LDAP_SUCCESS
)
1684 * if authpp is still null, then can not authenticate, syslog
1685 * error message and return error
1687 if (authpp
== NULL
) {
1688 rc
= NS_LDAP_CONFIG
;
1689 mlen
= snprintf(buffer
, msgmax
, "%s",
1690 gettext("No legal LDAP authentication method configured"));
1695 * Walk the array and try all authentication methods in order except
1698 for (app
= authpp
; *app
; app
++) {
1700 if (authp
->type
== NS_LDAP_AUTH_NONE
)
1703 credp
->auth
.type
= authp
->type
;
1704 credp
->auth
.tlstype
= authp
->tlstype
;
1705 credp
->auth
.saslmech
= authp
->saslmech
;
1706 credp
->auth
.saslopt
= authp
->saslopt
;
1709 * For GSSAPI, host credential will be used. No admin
1710 * DN is needed. For other authentication methods,
1711 * we need to set admin.
1713 if (credp
->auth
.saslmech
!= NS_LDAP_SASL_GSSAPI
) {
1714 if ((rc
= get_admin_dn(credp
, &status
,
1715 &error
)) != NS_LDAP_SUCCESS
) {
1718 if (status
== NS_CONFIG_NOTALLOW
) {
1719 mlen
= snprintf(buffer
, msgmax
, "%s",
1720 gettext("Admin bind DN not "
1727 rc
= __ns_ldap_repAttr(NS_ADMIN_SHADOW_UPDATE
, dn
,
1728 (const ns_ldap_attr_t
* const *)attrs
,
1730 if (rc
== NS_LDAP_SUCCESS
)
1734 * Other errors might need to be added to this list, for
1735 * the current supported mechanisms this is sufficient.
1737 if (rc
== NS_LDAP_INTERNAL
&&
1738 error
->pwd_mgmt
.status
== NS_PASSWD_GOOD
&&
1739 (error
->status
== LDAP_INAPPROPRIATE_AUTH
||
1740 error
->status
== LDAP_INVALID_CREDENTIALS
))
1744 * If there is error related to password policy,
1745 * return it to caller.
1747 if (rc
== NS_LDAP_INTERNAL
&&
1748 error
->pwd_mgmt
.status
!= NS_PASSWD_GOOD
) {
1749 rc
= NS_LDAP_CONFIG
;
1750 status
= NS_CONFIG_NOTALLOW
;
1751 (void) __ns_ldap_freeError(&error
);
1752 mlen
= snprintf(buffer
, msgmax
, "%s",
1753 gettext("update failed due to "
1754 "password policy on server (%d)"),
1755 error
->pwd_mgmt
.status
);
1759 /* we don't really care about the error, just clean it up */
1761 (void) __ns_ldap_freeError(&error
);
1763 if (authstried
== 0) {
1764 rc
= NS_LDAP_CONFIG
;
1765 mlen
= snprintf(buffer
, msgmax
, "%s",
1766 gettext("No legal LDAP authentication method configured"));
1770 rc
= NS_LDAP_OP_FAILED
;
1774 (void) __ns_ldap_freeCred(&credp
);
1777 (void) __ns_ldap_freeParam((void ***)&authpp
);
1779 if (error
!= NULL
) {
1780 mlen
= snprintf(buffer
, msgmax
, "%s", error
->message
);
1781 status
= error
->status
;
1782 (void) __ns_ldap_freeError(&error
);
1785 if (attrs
!= NULL
) {
1787 for (i
= 0; attrs
[i
]; i
++) {
1788 free(attrs
[i
]->attrvalue
);
1793 config_info
->len
= rlen
+ mlen
+ 1;
1794 config_info
->str
= malloc(config_info
->len
);
1795 if (config_info
->str
== NULL
) {
1796 config_info
->len
= 0;
1799 result
= (ldap_admin_mod_result_t
*)config_info
->str
;
1800 result
->ns_err
= rc
;
1801 result
->status
= status
;
1803 result
->msg_size
= mlen
+ 1;
1804 (void) strcpy(config_info
->str
+ rlen
, buffer
);
1809 * Check to see if the door client's euid is 0 or if it has ALL zone privilege.
1810 * return - 0 No or error
1814 is_root_or_all_privs(char *dc_str
, ucred_t
**ucp
)
1816 const priv_set_t
*ps
; /* door client */
1817 priv_set_t
*zs
; /* zone */
1822 /* no more to do if door client's euid is 0 */
1823 if (is_root(0, dc_str
, ucp
) == 1) {
1828 /* error if couldn't get the ucred_t */
1832 if ((ps
= ucred_getprivset(*ucp
, PRIV_EFFECTIVE
)) != NULL
) {
1833 zs
= priv_str_to_set("zone", ",", NULL
);
1834 if (priv_isequalset(ps
, zs
))
1835 rc
= 1; /* has all zone privs */
1837 if (current_admin
.debug_level
>= DBG_CANT_FIND
)
1838 logit("%s call failed (no all zone privs): "
1839 "caller pid %ld, uid %u, euid %u "
1840 "(if uid or euid is %u, it may "
1841 "be unavailable)\n", dc_str
,
1842 ucred_getpid(*ucp
), ucred_getruid(*ucp
),
1843 ucred_geteuid(*ucp
), -1);