xref: /titanic_51/usr/src/cmd/ldap/ns_ldap/ldapclient.c (revision 8eea8e29cc4374d1ee24c25a07f45af132db3499)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * ldapclient command. To make (initiailize) or uninitialize a machines as
31  * and LDAP client.  This command MUST be run as root (or it will simply exit).
32  *
33  *	-I	Install. No file_backup/recover for installing only (no doc).
34  *
35  *	init	Initialze (create) an LDAP client from a profile stored
36  *		in a directory-server.
37  *	manual	Initialze (create) an LDAP client by hand (-file option
38  *		reads from file).
39  *	mod	Modify the LDAP client configuration on this machine by hand.
40  *	list	List the contents of the LDAP client cache files.
41  *	uninit	Uninitialize this machine.
42  *
43  *	-v	Verbose flag.
44  *	-q	Quiet flag (mutually exclusive with -v).
45  *
46  *	-a attrName=attrVal
47  *	<attrName> can be one of the following:
48  *
49  *	attributeMap
50  *		Attribute map.  Can be multiple instances of this option.
51  *		(no former option)
52  *	authenticationMethod
53  *		Authentication method (formerly -a)
54  *	bindTimeLimit
55  *		Bind time limit. (no former option)
56  *	certificatePath
57  *		Path to certificates used for secure bind (no former option)
58  *	credentialLevel
59  *		Client credential level (no former option)
60  *	defaultServerList
61  *		Default server (no former option) Refer to DUA Config
62  *		Schema draft.
63  *	defaultSearchBase
64  *		Search Base DN. e.g. dc=eng,dc=sun,dc=com (formerly -b)
65  *	defaultSearchScope
66  *		Search scope. (formerly -s)
67  *	domainName
68  *		Hosts lookup domain (DNS)  Ex. eng.sun.com (formerly -d)
69  *	followReferrals
70  *		Search dereference. followref or noref (default followref)
71  *		(formerly -r)
72  *	objectclassMap
73  *		Objectclass map.  Can be multiple instances of this option.
74  *		(no former option)
75  *	preferredServerList
76  *		Server preference list. Comma ',' seperated list of IPaddr.
77  *		(formerly -p)
78  *	profileName
79  *		Profile name to use for init (ldapclient) or
80  *		generate (gen_profile). (formerly -P)
81  *	profileTTL
82  *		Client info TTL.  If set to 0 this information will not be
83  *		automatically updated by the ldap_cachemgr(1M).
84  *		(formerly -e)
85  *	proxyDN
86  *		Binding DN.  Ex. cn=client,ou=people,cd=eng,dc=sun,dc=com
87  *		(formerly -D)
88  *	proxyPassword
89  *		Client password not needed for authentication "none".
90  *		(formerly -w)
91  *	searchTimeLimit
92  *		Timeout value. (formerly -o)
93  *	serviceSearchDescriptor
94  *		Service search scope. (no former option)
95  *	serviceAuthenticationMethod
96  *		Service authenticaion method (no former option)
97  *	serviceCredentialLevel
98  *		Service credential level (no former option)
99  *
100  */
101 
102 #include <stdlib.h>
103 #include <stdio.h>
104 #include <unistd.h>
105 #include <errno.h>
106 #include <sys/types.h>
107 #include <time.h>
108 #include <sys/param.h>
109 #include <sys/stat.h>
110 #include <sys/systeminfo.h>
111 #include <fcntl.h>
112 #include <xti.h>
113 #include <strings.h>
114 #include <limits.h>
115 #include <locale.h>
116 #include <syslog.h>
117 #include "../../../lib/libsldap/common/ns_sldap.h"
118 #include <libscf.h>
119 #include <assert.h>
120 /*
121  * We need ns_internal.h for the #defines of:
122  *	NSCREDFILE, NSCONFIGFILE
123  * and the function prototypes of:
124  *	__ns_ldap_setServer(), __ns_ldap_LoadConfiguration(),
125  *	__ns_ldap_DumpConfiguration(), __ns_ldap_DumpLdif()
126  */
127 #include "../../../lib/libsldap/common/ns_internal.h"
128 
129 #if !defined(TEXT_DOMAIN)
130 #define	TEXT_DOMAIN "SUNW_OST_OSCMD"
131 #endif
132 
133 /* error codes */
134 /* The manpage doc only allows for SUCCESS(0), FAIL(1) and CRED(2) on exit */
135 #define	CLIENT_SUCCESS		0
136 #define	CLIENT_ERR_PARSE	-1
137 #define	CLIENT_ERR_FAIL		1
138 #define	CLIENT_ERR_CREDENTIAL	2
139 #define	CLIENT_ERR_MEMORY	3
140 #define	CLIENT_ERR_RESTORE	4
141 #define	CLIENT_ERR_RENAME	5
142 #define	CLIENT_ERR_RECOVER	6
143 #define	CLIENT_ERR_TIMEDOUT	7
144 #define	CLIENT_ERR_MAINTENANCE	8
145 
146 /* Reset flag for start_services() */
147 #define	START_INIT	1
148 #define	START_RESET	2
149 #define	START_UNINIT	3
150 
151 /* Reset flag for stop_services() */
152 #define	STATE_NOSAVE	0
153 #define	STATE_SAVE	1
154 
155 /* files to (possibiliy) restore */
156 #define	LDAP_RESTORE_DIR	"/var/ldap/restore"
157 
158 #define	DOMAINNAME_DIR		"/etc"
159 #define	DOMAINNAME_FILE		"defaultdomain"
160 #define	DOMAINNAME		DOMAINNAME_DIR "/" DOMAINNAME_FILE
161 #define	DOMAINNAME_BACK		LDAP_RESTORE_DIR "/" DOMAINNAME_FILE
162 
163 #define	NSSWITCH_DIR		"/etc"
164 #define	NSSWITCH_FILE		"nsswitch.conf"
165 #define	NSSWITCH_CONF		NSSWITCH_DIR "/" NSSWITCH_FILE
166 #define	NSSWITCH_BACK		LDAP_RESTORE_DIR "/" NSSWITCH_FILE
167 #define	NSSWITCH_LDAP		"/etc/nsswitch.ldap"
168 
169 #define	NIS_COLDSTART_DIR	"/var/nis"
170 #define	NIS_COLDSTART_FILE	"NIS_COLD_START"
171 #define	NIS_COLDSTART		NIS_COLDSTART_DIR "/" NIS_COLDSTART_FILE
172 #define	NIS_COLDSTART_BACK	LDAP_RESTORE_DIR "/" NIS_COLDSTART_FILE
173 
174 #define	YP_BIND_DIR		"/var/yp/binding"
175 
176 /* Define the service FMRIs */
177 #define	SENDMAIL_FMRI		"network/smtp:sendmail"
178 #define	NSCD_FMRI		"system/name-service-cache:default"
179 #define	AUTOFS_FMRI		"system/filesystem/autofs:default"
180 #define	LDAP_FMRI		"network/ldap/client:default"
181 #define	NISD_FMRI		"network/rpc/nisplus:default"
182 #define	YP_FMRI			"network/nis/client:default"
183 #define	NS_MILESTONE_FMRI	"milestone/name-services:default"
184 
185 /* Define flags for checking if services were enabled */
186 #define	SENDMAIL_ON	0x1
187 #define	NSCD_ON		0x10
188 #define	AUTOFS_ON	0x100
189 
190 #define	CMD_DOMAIN_START	"/usr/bin/domainname"
191 
192 /* Command to copy files */
193 #define	CMD_CP			"/bin/cp -f"
194 #define	CMD_MV			"/bin/mv -f"
195 #define	CMD_RM			"/bin/rm -f"
196 
197 #define	TO_DEV_NULL		" >/dev/null 2>&1"
198 
199 /* Files that need to be just removed */
200 #define	NIS_PRIVATE_CACHE	"/var/nis/.NIS_PRIVATE_DIRCACHE"
201 #define	NIS_SHARED_CACHE	"/var/nis/NIS_SHARED_DIRCACHE"
202 #define	NIS_CLIENT_INFO		"/var/nis/client_info"
203 #define	LDAP_CACHE_LOG		"/var/ldap/cachemgr.log"
204 
205 /* Output defines to supress if quiet mode set */
206 #define	CLIENT_FPUTS if (!mode_quiet) (void) fputs
207 #define	CLIENT_FPRINTF if (!mode_quiet) (void) fprintf
208 #define	CLIENT_FPUTC if (!mode_quiet) (void) fputc
209 
210 #define	restart_service(fmri, waitflag)\
211 		do_service(fmri, waitflag, RESTART_SERVICE,\
212 		SCF_STATE_STRING_ONLINE)
213 #define	start_service(fmri, waitflag)	\
214 		do_service(fmri, waitflag, START_SERVICE,\
215 		SCF_STATE_STRING_ONLINE)
216 #define	disable_service(fmri, waitflag)	\
217 		do_service(fmri, waitflag, STOP_SERVICE,\
218 		SCF_STATE_STRING_DISABLED)
219 
220 /*
221  * There isn't a domainName defined as a param, so we set a value here
222  * (1001) should be big enough
223  */
224 #define	LOCAL_DOMAIN_P 1001
225 
226 #define	START_SERVICE	1
227 #define	STOP_SERVICE	2
228 #define	RESTART_SERVICE	3
229 
230 #define	DEFAULT_TIMEOUT	60000000
231 
232 #define	INIT_WAIT_USECS	50000
233 
234 /* Used to turn off profile checking */
235 #define	CACHETTL_OFF "0"
236 
237 /* Globals */
238 static char *cmd;
239 
240 static char *dname = NULL;
241 static char dname_buf[BUFSIZ];
242 
243 static boolean_t sysid_install = B_FALSE;
244 
245 static int mode_verbose = 0;
246 static int mode_quiet = 0;
247 static int gen = 0;
248 
249 static int gStartLdap = 0;
250 static int gStartYp = 0;
251 static int gStartNisd = 0;
252 
253 static int enableFlag = 0;
254 
255 /* multival_t is used to hold params that can have more than one value */
256 typedef struct {
257 	int count;
258 	char **optlist;
259 } multival_t;
260 
261 static multival_t *multival_new();
262 static int multival_add(multival_t *list, char *opt);
263 static void multival_free(multival_t *list);
264 
265 /*
266  * clientopts_t is used to hold and pass around the param values from
267  * the cmd line
268  */
269 typedef struct {
270 	multival_t	*attributeMap;
271 	char		*authenticationMethod;
272 	char		*bindTimeLimit;
273 	char		*certificatePath;
274 	char		*credentialLevel;
275 	char		*defaultSearchBase;
276 	char		*defaultServerList;
277 	char		*domainName;
278 	char		*followReferrals;
279 	multival_t	*objectclassMap;
280 	char		*preferredServerList;
281 	char		*profileName;
282 	char		*profileTTL;
283 	char		*proxyDN;
284 	char		*proxyPassword;
285 	char		*defaultSearchScope;
286 	char		*searchTimeLimit;
287 	multival_t	*serviceAuthenticationMethod;
288 	multival_t	*serviceCredentialLevel;
289 	multival_t	*serviceSearchDescriptor;
290 } clientopts_t;
291 
292 static clientopts_t *clientopts_new();
293 static void clientopts_free(clientopts_t *list);
294 
295 extern ns_ldap_error_t *__ns_ldap_print_config(int);
296 extern void __ns_ldap_default_config();
297 extern int __ns_ldap_download(char *, char *, char *, ns_ldap_error_t **);
298 
299 /* Function prototypes (these could be static) */
300 static void usage(void);
301 
302 static int credCheck(clientopts_t *arglist);
303 static char *findBaseDN(char *);
304 static int clientSetParam(clientopts_t *optlist, int paramFlag, char *attrVal);
305 static int parseParam(char *param, char **paramVal);
306 static void dumpargs(clientopts_t *arglist);
307 static int num_args(clientopts_t *arglist);
308 
309 static int file_backup(void);
310 static int recover(int saveState);
311 static int mod_backup(void);
312 static int mod_recover(void);
313 static void mod_cleanup(void);
314 
315 static int client_list(clientopts_t *arglist);
316 static int client_manual(clientopts_t *arglist);
317 static int client_mod(clientopts_t *arglist);
318 static int client_uninit(clientopts_t *arglist);
319 static int client_genProfile(clientopts_t *arglist);
320 static int client_init(clientopts_t *arglist);
321 static boolean_t is_config_ok(const clientopts_t *list, boolean_t get_config);
322 static int file_move(const char *from, const char *to);
323 
324 static int start_services(int flag);
325 static int stop_services(int saveState);
326 static boolean_t is_service(const char *fmri, const char *state);
327 static int wait_till(const char *fmri, const char *state, useconds_t max,
328 		const char *what, boolean_t check_maint);
329 static int do_service(const char *fmri, boolean_t waitflag, int dowhat,
330 		const char *state);
331 static useconds_t get_timeout_value(int dowhat, const char *fmri,
332 		useconds_t default_val);
333 
334 void
335 main(argc, argv)
336 	int argc;
337 	char **argv;
338 {
339 	char *ret_locale, *ret_textdomain;
340 	int retcode;
341 	int paramFlag;
342 	char *attrVal;
343 	int sysinfostatus;
344 	clientopts_t *optlist = NULL;
345 	int op_manual = 0, op_mod = 0, op_uninit = 0;
346 	int op_list = 0, op_init = 0, op_genprofile = 0;
347 	extern char *optarg;
348 	extern int optind;
349 	int option;
350 
351 
352 	ret_locale = setlocale(LC_ALL, "");
353 	if (ret_locale == NULL) {
354 		CLIENT_FPUTS(gettext("Unable to set locale.\n"), stderr);
355 	}
356 	ret_textdomain = textdomain(TEXT_DOMAIN);
357 	if (ret_textdomain == NULL) {
358 		CLIENT_FPUTS(gettext("Unable to set textdomain.\n"), stderr);
359 	}
360 
361 	openlog("ldapclient", LOG_PID, LOG_USER);
362 
363 	/* get name that invoked us */
364 	if (cmd = strrchr(argv[0], '/'))
365 		++cmd;
366 	else
367 		cmd = argv[0];
368 
369 	sysinfostatus = sysinfo(SI_SRPC_DOMAIN, dname_buf, BUFSIZ);
370 	if (0 < sysinfostatus)
371 		dname = &dname_buf[0];
372 
373 	optlist = clientopts_new();
374 	if (optlist == NULL) {
375 		CLIENT_FPUTS(
376 			gettext("Error getting optlist (malloc fail)\n"),
377 			stderr);
378 		exit(CLIENT_ERR_FAIL);
379 	}
380 
381 	optind = 1;
382 	while (optind < argc) {
383 		option = getopt(argc, argv, "vqa:I");
384 
385 		switch (option) {
386 		case 'v':
387 			mode_verbose = 1;
388 			break;
389 		case 'q':
390 			mode_quiet = 1;
391 			break;
392 		case 'a':
393 			attrVal = NULL;
394 			paramFlag = parseParam(optarg, &attrVal);
395 			if (paramFlag == CLIENT_ERR_PARSE) {
396 				CLIENT_FPRINTF(stderr,
397 					gettext("Unrecognized "
398 						"parameter \"%s\"\n"),
399 					optarg);
400 				usage();
401 				exit(CLIENT_ERR_FAIL);
402 			}
403 			retcode = clientSetParam(optlist, paramFlag, attrVal);
404 			if (retcode != CLIENT_SUCCESS) {
405 				CLIENT_FPRINTF(
406 					stderr,
407 					gettext("Error (%d) setting "
408 						"param \"%s\"\n"),
409 					retcode, optarg);
410 				usage();
411 				exit(CLIENT_ERR_FAIL);
412 			}
413 			break;
414 		case EOF:
415 			if (strcmp(argv[optind], "init") == 0) {
416 				op_init = 1;
417 			} else if (strcmp(argv[optind], "manual") == 0) {
418 				op_manual = 1;
419 			} else if (strcmp(argv[optind], "mod") == 0) {
420 				op_mod = 1;
421 			} else if (strcmp(argv[optind], "list") == 0) {
422 				op_list = 1;
423 			} else if (strcmp(argv[optind], "uninit") == 0) {
424 				op_uninit = 1;
425 			} else if (strcmp(argv[optind], "genprofile") == 0) {
426 				gen = 1;
427 				op_genprofile = 1;
428 			} else if (optind == argc-1) {
429 				retcode = clientSetParam(
430 					optlist,
431 					NS_LDAP_SERVERS_P,
432 					argv[optind]);	/* ipAddr */
433 				if (retcode != CLIENT_SUCCESS) {
434 					CLIENT_FPRINTF(
435 						stderr,
436 						gettext("Error (%d) setting "
437 							"serverList param.\n"),
438 						retcode);
439 					usage();
440 					exit(CLIENT_ERR_FAIL);
441 				}
442 			} else {
443 				CLIENT_FPUTS(
444 					gettext("Error parsing "
445 						"command line\n"),
446 					stderr);
447 				usage();
448 				exit(CLIENT_ERR_FAIL);
449 			}
450 			optind++;	/* get past the verb and keep trying */
451 			break;
452 		/* Backwards compatibility to support system install */
453 		case 'I':
454 			sysid_install = B_TRUE;
455 			op_init = 1;
456 			mode_quiet = 1;
457 			break;
458 		case '?':
459 			usage();
460 			CLIENT_FPUTS(gettext("\nOr\n\n"), stderr);
461 			gen = 1;
462 			usage();
463 			exit(CLIENT_ERR_FAIL);
464 			break;
465 		}
466 
467 	}
468 
469 	if ((getuid() != 0) && (!op_genprofile)) {
470 		(void) puts(
471 			"You must be root (SuperUser) to run this command.");
472 		usage();
473 		exit(CLIENT_ERR_FAIL);
474 	}
475 
476 /*
477  *	All command line arguments are finished being parsed now
478  */
479 
480 /* *** Do semantic checking here *** */
481 
482 /* if gen and no no searchBase then err */
483 	if (gen && !optlist->defaultSearchBase) {
484 		CLIENT_FPUTS(
485 			gettext("ldapclient: Missing required attrName "
486 				"defaultSearchBase\n"),
487 			stderr);
488 		usage();
489 		clientopts_free(optlist);
490 		exit(CLIENT_ERR_FAIL);
491 	}
492 
493 /* Only one verb can be specified */
494 	if ((op_init + op_manual + op_mod + op_uninit +
495 		op_list + op_genprofile) != 1) {
496 		usage();
497 		clientopts_free(optlist);
498 		exit(CLIENT_ERR_FAIL);
499 	}
500 
501 /* *** We passed semantic checking, so now do the operation *** */
502 
503 	if (mode_verbose) {
504 		CLIENT_FPUTS(gettext("Arguments parsed:\n"), stderr);
505 		dumpargs(optlist);
506 	}
507 
508 
509 /* handle "ldapclient list" here.  err checking done in func */
510 	if (op_list) {
511 		if (mode_verbose)
512 			CLIENT_FPUTS(
513 				gettext("Handling list option\n"),
514 				stderr);
515 		retcode = client_list(optlist);
516 	}
517 
518 /* handle "ldapclient uninit" here */
519 	if (op_uninit) {
520 		if (mode_verbose)
521 			CLIENT_FPUTS(
522 				gettext("Handling uninit option\n"),
523 				stderr);
524 		retcode = client_uninit(optlist);
525 	}
526 
527 /* handle "ldapclient init" (profile) */
528 	if (op_init) {
529 		if (mode_verbose)
530 			CLIENT_FPUTS(
531 				gettext("Handling init option\n"),
532 				stderr);
533 		retcode = client_init(optlist);
534 	}
535 
536 /* handle "genprofile" here */
537 	if (op_genprofile) {
538 		if (mode_verbose)
539 			CLIENT_FPUTS(
540 				gettext("Handling genProfile\n"),
541 				stderr);
542 		retcode = client_genProfile(optlist);
543 	}
544 
545 /* handle "ldapclient manual" here */
546 	if (op_manual) {
547 		if (mode_verbose)
548 			CLIENT_FPUTS(
549 				gettext("Handling manual option\n"),
550 				stderr);
551 		retcode = client_manual(optlist);
552 	}
553 
554 /* handle "ldapclient mod" here */
555 	if (op_mod) {
556 		if (mode_verbose)
557 			CLIENT_FPUTS(
558 				gettext("Handling mod option\n"),
559 				stderr);
560 		retcode = client_mod(optlist);
561 	}
562 
563 	clientopts_free(optlist);
564 	if ((retcode == CLIENT_SUCCESS) ||
565 			(retcode == CLIENT_ERR_FAIL) ||
566 			(retcode == CLIENT_ERR_CREDENTIAL))
567 		exit(retcode);
568 	else
569 		exit(CLIENT_ERR_FAIL);
570 }
571 
572 static int
573 client_list(clientopts_t *arglist)
574 {
575 	ns_ldap_error_t *errorp;
576 	int retcode = CLIENT_SUCCESS;
577 
578 	if (num_args(arglist) > 0) {
579 		CLIENT_FPUTS(
580 			gettext("No args supported with \"list\" option\n"),
581 			stderr);
582 		usage();
583 		return (CLIENT_ERR_FAIL);	/* exit code here ? */
584 	}
585 	if ((errorp = __ns_ldap_print_config(mode_verbose)) != NULL) {
586 		retcode = CLIENT_ERR_FAIL;
587 		CLIENT_FPUTS(
588 			gettext("Cannot get print configuration\n"),
589 			stderr);
590 		CLIENT_FPUTS(errorp->message, stderr);
591 		(void) __ns_ldap_freeError(&errorp);
592 		CLIENT_FPUTC('\n', stderr);
593 	}
594 
595 	return (retcode);
596 }
597 
598 static int
599 client_uninit(clientopts_t *arglist)
600 {
601 	int retcode = CLIENT_SUCCESS;
602 
603 	if (mode_verbose) {
604 		CLIENT_FPUTS(
605 			gettext("Restoring machine to previous "
606 				"configuration state\n"),
607 			stderr);
608 	}
609 
610 	if (num_args(arglist) > 0) {
611 		CLIENT_FPUTS(
612 			gettext("No args supported with \"uninit\" option\n"),
613 			stderr);
614 		usage();
615 		return (CLIENT_ERR_FAIL);
616 	}
617 
618 	retcode = stop_services(STATE_SAVE);
619 	if (retcode != CLIENT_SUCCESS) {
620 		CLIENT_FPUTS(
621 			gettext("Errors stopping network services.\n"), stderr);
622 		/* restart whatever services we can */
623 		(void) start_services(START_RESET);
624 		return (CLIENT_ERR_FAIL);
625 	}
626 
627 	retcode = recover(STATE_SAVE);
628 	if (retcode != CLIENT_SUCCESS) {
629 		CLIENT_FPUTS(
630 			gettext("Cannot recover the configuration on "
631 				"this machine.\n"),
632 			stderr);
633 		(void) start_services(START_RESET);
634 	} else {
635 		retcode = start_services(START_UNINIT);
636 		if (retcode != CLIENT_SUCCESS) {
637 			CLIENT_FPUTS(
638 				gettext("Config restored but problems "
639 					"encountered resetting network "
640 					"services.\n"),
641 				stderr);
642 		}
643 	}
644 
645 	if (retcode == CLIENT_SUCCESS) {
646 		CLIENT_FPUTS(
647 			gettext("System successfully recovered\n"),
648 			stderr);
649 	}
650 
651 	return (retcode);
652 }
653 
654 /*
655  * The following macro is used to do a __ns_ldap_setParam().
656  * On every call, the return code is checked, and if there was
657  * a problem then the error message is printed, the ldaperr
658  * is freed and we return from the function with the offending
659  * error return code.  This macro keeps us from having to
660  * repeat this code for every call to setParam as was done
661  * in the previous incarnation of ldapclient.
662  *
663  * assumes a "retcode" variable is available for status
664  */
665 #define	LDAP_SET_PARAM(argval, argdef)	\
666 retcode = 0;	\
667 if (NULL != argval) {	\
668 	ns_ldap_error_t *ldaperr;	\
669 	retcode = __ns_ldap_setParam(argdef, (void *)argval, &ldaperr);	\
670 	if (retcode != NS_LDAP_SUCCESS) {	\
671 		if (NULL != ldaperr) {	\
672 			CLIENT_FPUTS(ldaperr->message, stderr);	\
673 			CLIENT_FPUTC('\n', stderr);	\
674 			(void) __ns_ldap_freeError(&ldaperr);	\
675 		}	\
676 		return (retcode ? CLIENT_ERR_FAIL : CLIENT_SUCCESS);	\
677 	}	\
678 }
679 
680 static int
681 client_manual(clientopts_t *arglist)
682 {
683 	int counter;
684 	int domain_fp;
685 	ns_ldap_error_t *errorp;
686 	int ret_copy;
687 	int reset_ret;
688 	int retcode = CLIENT_SUCCESS;
689 
690 	if (dname == NULL) {
691 		CLIENT_FPUTS(
692 			gettext("Manual failed: System domain not set and "
693 				"no domainName specified.\n"),
694 			stderr);
695 		return (CLIENT_ERR_FAIL);
696 	}
697 
698 	if (arglist->defaultSearchBase == NULL) {
699 		CLIENT_FPUTS(
700 			gettext("Manual failed: Missing required "
701 				"defaultSearchBase attribute.\n"),
702 			stderr);
703 		return (CLIENT_ERR_FAIL);
704 	}
705 
706 	if ((arglist->defaultServerList == NULL) &&
707 		(arglist->preferredServerList == NULL)) {
708 		CLIENT_FPUTS(
709 			gettext("Manual failed: Missing required "
710 				"defaultServerList or preferredServerList "
711 				"attribute.\n"),
712 			stderr);
713 		return (CLIENT_ERR_FAIL);
714 	}
715 
716 	if (arglist->profileTTL != NULL) {
717 		CLIENT_FPUTS(
718 			gettext("Manual aborted: profileTTL is not supported "
719 				"in manual mode.\n"),
720 			stderr);
721 		return (CLIENT_ERR_FAIL);
722 	}
723 
724 	if (arglist->profileName != NULL) {
725 		CLIENT_FPUTS(
726 			gettext("Manual aborted: profileName is not supported "
727 				"in manual mode.\n"),
728 			stderr);
729 		return (CLIENT_ERR_FAIL);
730 	}
731 
732 	if (!is_config_ok(arglist, B_FALSE)) {
733 		CLIENT_FPRINTF(stderr,
734 			gettext("Cannot specify LDAP port with tls\n"));
735 		return (CLIENT_ERR_FAIL);
736 	}
737 
738 	__ns_ldap_setServer(TRUE);	/* Need this for _ns_setParam() */
739 	__ns_ldap_default_config();
740 
741 	/* Set version to latest (not version 1) */
742 	LDAP_SET_PARAM(NS_LDAP_VERSION, NS_LDAP_FILE_VERSION_P);
743 
744 	/* Set profileTTL to 0 since NO profile on manual */
745 	LDAP_SET_PARAM(CACHETTL_OFF, NS_LDAP_CACHETTL_P);
746 
747 	/* Set additional valid params from command line */
748 	LDAP_SET_PARAM(arglist->authenticationMethod, NS_LDAP_AUTH_P);
749 	LDAP_SET_PARAM(arglist->defaultSearchBase, NS_LDAP_SEARCH_BASEDN_P);
750 	LDAP_SET_PARAM(arglist->credentialLevel, NS_LDAP_CREDENTIAL_LEVEL_P);
751 	LDAP_SET_PARAM(arglist->proxyDN, NS_LDAP_BINDDN_P);
752 	LDAP_SET_PARAM(arglist->searchTimeLimit, NS_LDAP_SEARCH_TIME_P);
753 	LDAP_SET_PARAM(arglist->preferredServerList, NS_LDAP_SERVER_PREF_P);
754 	LDAP_SET_PARAM(arglist->profileName, NS_LDAP_PROFILE_P);
755 	LDAP_SET_PARAM(arglist->followReferrals, NS_LDAP_SEARCH_REF_P);
756 	LDAP_SET_PARAM(arglist->defaultSearchScope, NS_LDAP_SEARCH_SCOPE_P);
757 	LDAP_SET_PARAM(arglist->bindTimeLimit, NS_LDAP_BIND_TIME_P);
758 	LDAP_SET_PARAM(arglist->proxyPassword, NS_LDAP_BINDPASSWD_P);
759 	LDAP_SET_PARAM(arglist->defaultServerList, NS_LDAP_SERVERS_P);
760 	LDAP_SET_PARAM(arglist->certificatePath, NS_LDAP_HOST_CERTPATH_P);
761 
762 	for (counter = 0;
763 		counter < arglist->serviceAuthenticationMethod->count;
764 		counter++) {
765 
766 		LDAP_SET_PARAM(
767 			arglist->serviceAuthenticationMethod->optlist[counter],
768 			NS_LDAP_SERVICE_AUTH_METHOD_P);
769 	}
770 	for (counter = 0;
771 		counter < arglist->serviceCredentialLevel->count;
772 		counter++) {
773 
774 		LDAP_SET_PARAM(
775 			arglist->serviceCredentialLevel->optlist[counter],
776 			NS_LDAP_SERVICE_CRED_LEVEL_P);
777 	}
778 	for (counter = 0;
779 		counter < arglist->objectclassMap->count;
780 		counter++) {
781 
782 		LDAP_SET_PARAM(arglist->objectclassMap->optlist[counter],
783 			NS_LDAP_OBJECTCLASSMAP_P);
784 	}
785 	for (counter = 0; counter < arglist->attributeMap->count; counter++) {
786 		LDAP_SET_PARAM(arglist->attributeMap->optlist[counter],
787 			NS_LDAP_ATTRIBUTEMAP_P);
788 	}
789 	for (counter = 0;
790 		counter < arglist->serviceSearchDescriptor->count;
791 		counter++) {
792 
793 		LDAP_SET_PARAM(
794 			arglist->serviceSearchDescriptor->optlist[counter],
795 			NS_LDAP_SERVICE_SEARCH_DESC_P);
796 	}
797 
798 	retcode = credCheck(arglist);
799 	if (retcode != CLIENT_SUCCESS) {
800 		CLIENT_FPUTS(
801 			gettext("Error in setting up credentials\n"),
802 			stderr);
803 		return (retcode);
804 	}
805 
806 	if (mode_verbose)
807 		CLIENT_FPUTS(
808 			gettext("About to modify this machines "
809 				"configuration by writing the files\n"),
810 			stderr);
811 
812 	/* get ready to start playing with files */
813 	retcode = stop_services(STATE_SAVE);
814 	if (retcode != CLIENT_SUCCESS) {
815 		CLIENT_FPUTS(
816 			gettext("Errors stopping network services.\n"), stderr);
817 		return (CLIENT_ERR_FAIL);
818 	}
819 
820 	/* Save orig versions of files */
821 	retcode = file_backup();
822 	if (retcode == CLIENT_ERR_RESTORE) {
823 		CLIENT_FPUTS(
824 			gettext("System not in state to enable ldap client.\n"),
825 			stderr);
826 
827 		reset_ret = start_services(START_RESET);
828 		if (reset_ret != CLIENT_SUCCESS) {
829 			CLIENT_FPRINTF(stderr, gettext("Error (%d) while "
830 					"starting services during reset\n"),
831 					reset_ret);
832 		}
833 		return (retcode);
834 	} else if (retcode != CLIENT_SUCCESS) {
835 		CLIENT_FPUTS(
836 			gettext("Save of system configuration failed!  "
837 				"Attempting recovery.\n"),
838 			stderr);
839 		retcode = recover(STATE_NOSAVE);
840 		if (retcode != CLIENT_SUCCESS) {
841 			CLIENT_FPUTS(
842 				gettext("Recovery of systems configuration "
843 					"failed.  Manual intervention of "
844 					"config files is required.\n"),
845 				stderr);
846 			return (retcode);
847 		}
848 
849 		reset_ret = start_services(START_RESET);
850 		if (reset_ret != CLIENT_SUCCESS) {
851 			CLIENT_FPRINTF(stderr, gettext("Error (%d) while "
852 					"starting services during reset\n"),
853 					reset_ret);
854 		}
855 
856 		return (retcode);
857 	}
858 
859 	/* Dump new files */
860 	errorp = __ns_ldap_DumpConfiguration(NSCONFIGFILE);
861 	if (errorp != NULL) {
862 		CLIENT_FPRINTF(stderr,
863 			gettext("%s manual: errorp is not NULL; %s\n"),
864 			cmd, errorp->message);
865 		retcode = recover(STATE_NOSAVE);
866 		if (retcode != CLIENT_SUCCESS) {
867 			CLIENT_FPUTS(
868 				gettext("Recovery of systems configuration "
869 					"failed.  Manual intervention of "
870 					"config files is required.\n"),
871 				stderr);
872 			return (retcode);
873 		}
874 		reset_ret = start_services(START_RESET);
875 		if (reset_ret != CLIENT_SUCCESS) {
876 			CLIENT_FPRINTF(stderr, gettext("Error (%d) while "
877 					"starting services during reset\n"),
878 					reset_ret);
879 		}
880 		(void) __ns_ldap_freeError(&errorp);
881 		return (CLIENT_ERR_FAIL);
882 	}
883 
884 	/* if (credargs(arglist)) */
885 	errorp = __ns_ldap_DumpConfiguration(NSCREDFILE);
886 	if (errorp != NULL) {
887 		CLIENT_FPRINTF(stderr,
888 			gettext("%s init: errorp is not NULL; %s\n"),
889 			cmd, errorp->message);
890 		retcode = recover(STATE_NOSAVE);
891 		if (retcode != CLIENT_SUCCESS) {
892 			CLIENT_FPUTS(
893 				gettext("Recovery of systems configuration "
894 					"failed.  Manual intervention of "
895 					"config files is required.\n"),
896 				stderr);
897 			return (retcode);
898 		}
899 		reset_ret = start_services(START_RESET);
900 		if (reset_ret != CLIENT_SUCCESS) {
901 			CLIENT_FPRINTF(stderr, gettext("Error (%d) while "
902 					"starting services during reset\n"),
903 					reset_ret);
904 		}
905 		(void) __ns_ldap_freeError(&errorp);
906 		return (CLIENT_ERR_FAIL);
907 	}
908 
909 	ret_copy = system(CMD_CP " " NSSWITCH_LDAP " " NSSWITCH_CONF);
910 	if (ret_copy != 0) {
911 		CLIENT_FPRINTF(stderr,
912 			gettext("Error %d copying (%s) -> (%s)\n"),
913 			ret_copy, NSSWITCH_LDAP, NSSWITCH_CONF);
914 		retcode = recover(STATE_NOSAVE);
915 		if (retcode != CLIENT_SUCCESS) {
916 			CLIENT_FPUTS(
917 				gettext("Recovery of systems configuration "
918 					"failed.  Manual intervention of "
919 					"config files is required.\n"),
920 				stderr);
921 		}
922 		reset_ret = start_services(START_RESET);
923 		if (reset_ret != CLIENT_SUCCESS) {
924 			CLIENT_FPRINTF(stderr, gettext("Error (%d) while "
925 					"starting services during reset\n"),
926 					reset_ret);
927 		}
928 		return (CLIENT_ERR_FAIL);
929 	}
930 
931 	if ((domain_fp = open(DOMAINNAME, O_WRONLY|O_CREAT|O_TRUNC,
932 		S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1) { /* 0644 */
933 		CLIENT_FPRINTF(stderr, gettext("Cannot open %s\n"), DOMAINNAME);
934 		retcode = recover(STATE_NOSAVE);
935 		if (retcode != CLIENT_SUCCESS) {
936 			CLIENT_FPUTS(
937 				gettext("Recovery of systems configuration "
938 					"failed.  Manual intervention of "
939 					"config files is required.\n"),
940 				stderr);
941 			return (CLIENT_ERR_FAIL);
942 		}
943 		reset_ret = start_services(START_RESET);
944 		if (reset_ret != CLIENT_SUCCESS) {
945 			CLIENT_FPRINTF(stderr, gettext("Error (%d) while "
946 					"starting services during reset\n"),
947 					reset_ret);
948 		}
949 		return (CLIENT_ERR_FAIL);
950 	}
951 	(void) write(domain_fp, dname, strlen(dname));
952 	(void) write(domain_fp, "\n", 1);
953 	(void) close(domain_fp);
954 
955 	retcode = start_services(START_INIT);
956 
957 	if (retcode == CLIENT_SUCCESS) {
958 		CLIENT_FPUTS(gettext("System successfully configured\n"),
959 								stderr);
960 	} else {
961 		CLIENT_FPUTS(gettext("Error resetting system.\n"
962 			"Recovering old system settings.\n"), stderr),
963 
964 		/* stop any started services for recover */
965 		/* don't stomp on history of saved services state */
966 		reset_ret = stop_services(STATE_NOSAVE);
967 		if (reset_ret != CLIENT_SUCCESS) {
968 			CLIENT_FPRINTF(stderr, gettext("Error (%d) while "
969 					"stopping services during reset\n"),
970 					reset_ret);
971 			/* Coninue and try to recover what we can */
972 		}
973 		reset_ret = recover(STATE_NOSAVE);
974 		if (reset_ret != CLIENT_SUCCESS) {
975 			CLIENT_FPRINTF(stderr, gettext("Error (%d) while "
976 					"recovering service files during "
977 					"reset\n"), reset_ret);
978 			/* Continue and start what we can */
979 		}
980 		reset_ret = start_services(START_RESET);
981 		if (reset_ret != CLIENT_SUCCESS) {
982 			CLIENT_FPRINTF(stderr, gettext("Error (%d) while "
983 					"starting services during reset\n"),
984 					reset_ret);
985 		}
986 	}
987 
988 	return (retcode);
989 }
990 
991 static int
992 client_mod(clientopts_t *arglist)
993 {
994 	int counter;
995 	int domain_fp;
996 	ns_ldap_error_t *errorp;
997 	int reset_ret;
998 	int retcode = CLIENT_SUCCESS;
999 
1000 	__ns_ldap_setServer(TRUE);	/* Need this for _ns_setParam() */
1001 	if ((errorp = __ns_ldap_LoadConfiguration()) != NULL) {
1002 		CLIENT_FPUTS(gettext("Cannot get load configuration\n"),
1003 			stderr);
1004 		CLIENT_FPUTS(errorp->message, stderr);
1005 		CLIENT_FPUTC('\n', stderr);
1006 		(void) __ns_ldap_freeError(&errorp);
1007 		return (CLIENT_ERR_FAIL);
1008 	}
1009 
1010 	if (arglist->profileTTL != NULL) {
1011 		CLIENT_FPUTS(
1012 			gettext("Mod aborted: profileTTL modification is "
1013 				"not allowed in mod mode.\n"),
1014 			stderr);
1015 		return (CLIENT_ERR_FAIL);
1016 	}
1017 
1018 	if (arglist->profileName != NULL) {
1019 		CLIENT_FPUTS(
1020 			gettext("Mod aborted: profileName modification is "
1021 				"not allowed.  If you want to use profiles "
1022 				"generate one with genProfile and load it "
1023 				"on the server with ldapadd.\n"),
1024 			stderr);
1025 		return (CLIENT_ERR_FAIL);
1026 	}
1027 
1028 	if (!is_config_ok(arglist, B_TRUE)) {
1029 		CLIENT_FPRINTF(stderr,
1030 			gettext("Cannot specify LDAP port with tls\n"));
1031 		return (CLIENT_ERR_FAIL);
1032 	}
1033 
1034 	/* Set additional valid params from command line */
1035 	LDAP_SET_PARAM(arglist->authenticationMethod, NS_LDAP_AUTH_P);
1036 	LDAP_SET_PARAM(arglist->defaultSearchBase, NS_LDAP_SEARCH_BASEDN_P);
1037 	LDAP_SET_PARAM(arglist->credentialLevel, NS_LDAP_CREDENTIAL_LEVEL_P);
1038 	LDAP_SET_PARAM(arglist->proxyDN, NS_LDAP_BINDDN_P);
1039 	LDAP_SET_PARAM(arglist->profileTTL, NS_LDAP_CACHETTL_P);
1040 	LDAP_SET_PARAM(arglist->searchTimeLimit, NS_LDAP_SEARCH_TIME_P);
1041 	LDAP_SET_PARAM(arglist->preferredServerList, NS_LDAP_SERVER_PREF_P);
1042 	LDAP_SET_PARAM(arglist->profileName, NS_LDAP_PROFILE_P);
1043 	LDAP_SET_PARAM(arglist->followReferrals, NS_LDAP_SEARCH_REF_P);
1044 	LDAP_SET_PARAM(arglist->defaultSearchScope, NS_LDAP_SEARCH_SCOPE_P);
1045 	LDAP_SET_PARAM(arglist->bindTimeLimit, NS_LDAP_BIND_TIME_P);
1046 	LDAP_SET_PARAM(arglist->proxyPassword, NS_LDAP_BINDPASSWD_P);
1047 	LDAP_SET_PARAM(arglist->defaultServerList, NS_LDAP_SERVERS_P);
1048 	LDAP_SET_PARAM(arglist->certificatePath, NS_LDAP_HOST_CERTPATH_P);
1049 
1050 	for (counter = 0;
1051 		counter < arglist->serviceAuthenticationMethod->count;
1052 		counter++) {
1053 
1054 		LDAP_SET_PARAM(
1055 			arglist->serviceAuthenticationMethod->optlist[counter],
1056 			NS_LDAP_SERVICE_AUTH_METHOD_P);
1057 	}
1058 	for (counter = 0;
1059 		counter < arglist->serviceCredentialLevel->count;
1060 		counter++) {
1061 
1062 		LDAP_SET_PARAM(
1063 			arglist->serviceCredentialLevel->optlist[counter],
1064 			NS_LDAP_SERVICE_CRED_LEVEL_P);
1065 	}
1066 	for (counter = 0;
1067 		counter < arglist->objectclassMap->count;
1068 		counter++) {
1069 
1070 		LDAP_SET_PARAM(
1071 			arglist->objectclassMap->optlist[counter],
1072 			NS_LDAP_OBJECTCLASSMAP_P);
1073 	}
1074 	for (counter = 0;
1075 		counter < arglist->attributeMap->count;
1076 		counter++) {
1077 
1078 		LDAP_SET_PARAM(
1079 			arglist->attributeMap->optlist[counter],
1080 			NS_LDAP_ATTRIBUTEMAP_P);
1081 	}
1082 	for (counter = 0;
1083 		counter < arglist->serviceSearchDescriptor->count;
1084 		counter++) {
1085 
1086 		LDAP_SET_PARAM(
1087 			arglist->serviceSearchDescriptor->optlist[counter],
1088 			NS_LDAP_SERVICE_SEARCH_DESC_P);
1089 	}
1090 
1091 	retcode = credCheck(arglist);
1092 	if (retcode != CLIENT_SUCCESS) {
1093 		CLIENT_FPUTS(
1094 			gettext("Error in setting up credentials\n"),
1095 			stderr);
1096 		return (retcode);
1097 	}
1098 
1099 	if (mode_verbose)
1100 		CLIENT_FPUTS(
1101 			gettext("About to modify this machines configuration "
1102 				"by writing the files\n"),
1103 			stderr);
1104 
1105 	/* get ready to start playing with files */
1106 	retcode = stop_services(STATE_SAVE);
1107 	if (retcode != CLIENT_SUCCESS) {
1108 		CLIENT_FPUTS(
1109 			gettext("Errors stopping network services.\n"), stderr);
1110 		return (CLIENT_ERR_FAIL);
1111 	}
1112 
1113 	/* Temporarily save orig versions of files */
1114 	retcode = mod_backup();
1115 	if (retcode != CLIENT_SUCCESS) {
1116 		CLIENT_FPUTS(
1117 			gettext("Unable to backup the ldap client files!\n"),
1118 			stderr);
1119 
1120 		return (retcode);
1121 
1122 	}
1123 
1124 	/* Dump new files */
1125 	errorp = __ns_ldap_DumpConfiguration(NSCONFIGFILE);
1126 	if (errorp != NULL) {
1127 		CLIENT_FPRINTF(stderr,
1128 			gettext("%s mod: errorp is not NULL; %s\n"),
1129 			cmd, errorp->message);
1130 		retcode = mod_recover();
1131 		if (retcode != CLIENT_SUCCESS) {
1132 			CLIENT_FPUTS(
1133 				gettext("Recovery of systems configuration "
1134 					"failed.  Manual intervention of "
1135 					"config files is required.\n"),
1136 				stderr);
1137 		}
1138 		(void) __ns_ldap_freeError(&errorp);
1139 		reset_ret = start_services(START_RESET);
1140 		if (reset_ret != CLIENT_SUCCESS) {
1141 			CLIENT_FPRINTF(stderr, gettext("Error (%d) while "
1142 					"starting services during reset\n"),
1143 					reset_ret);
1144 		}
1145 		return (CLIENT_ERR_FAIL);
1146 	}
1147 
1148 	/* if (credargs(arglist)) */
1149 	errorp = __ns_ldap_DumpConfiguration(NSCREDFILE);
1150 	if (errorp != NULL) {
1151 		CLIENT_FPRINTF(stderr,
1152 			gettext("%s mod: errorp is not NULL; %s\n"),
1153 			cmd, errorp->message);
1154 		retcode = mod_recover();
1155 		if (retcode != CLIENT_SUCCESS) {
1156 			CLIENT_FPUTS(
1157 				gettext("Recovery of systems configuration "
1158 					"failed.  Manual intervention of "
1159 					"config files is required.\n"),
1160 				stderr);
1161 		}
1162 		(void) __ns_ldap_freeError(&errorp);
1163 		reset_ret = start_services(START_RESET);
1164 		if (reset_ret != CLIENT_SUCCESS) {
1165 			CLIENT_FPRINTF(stderr, gettext("Error (%d) while "
1166 					"starting services during reset\n"),
1167 					reset_ret);
1168 		}
1169 		return (CLIENT_ERR_FAIL);
1170 	}
1171 
1172 	if ((domain_fp = open(DOMAINNAME, O_WRONLY|O_CREAT|O_TRUNC,
1173 		S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1) { /* 0644 */
1174 		CLIENT_FPRINTF(stderr, gettext("Cannot open %s\n"), DOMAINNAME);
1175 		retcode = mod_recover();
1176 		if (retcode != CLIENT_SUCCESS) {
1177 			CLIENT_FPUTS(
1178 				gettext("Recovery of systems configuration "
1179 					"failed!  Machine needs to be "
1180 					"fixed!\n"),
1181 				stderr);
1182 		}
1183 		reset_ret = start_services(START_RESET);
1184 		if (reset_ret != CLIENT_SUCCESS) {
1185 			CLIENT_FPRINTF(stderr, gettext("Error (%d) while "
1186 					"starting services during reset\n"),
1187 					reset_ret);
1188 		}
1189 		return (CLIENT_ERR_FAIL);
1190 	}
1191 	(void) write(domain_fp, dname, strlen(dname));
1192 	(void) write(domain_fp, "\n", 1);
1193 	(void) close(domain_fp);
1194 
1195 	retcode = start_services(START_INIT);
1196 
1197 	if (retcode == CLIENT_SUCCESS) {
1198 		CLIENT_FPUTS(gettext("System successfully configured\n"),
1199 								stderr);
1200 	} else {
1201 		CLIENT_FPUTS(gettext("Error resetting system.\n"
1202 			"Recovering old system settings.\n"), stderr),
1203 
1204 		/* stop any started services for recover */
1205 		/* don't stomp on history of saved services state */
1206 		reset_ret = stop_services(STATE_NOSAVE);
1207 		if (reset_ret != CLIENT_SUCCESS) {
1208 			CLIENT_FPRINTF(stderr, gettext("Error (%d) while "
1209 					"stopping services during reset\n"),
1210 					reset_ret);
1211 			/* Coninue and try to recover what we can */
1212 		}
1213 		reset_ret = mod_recover();
1214 		if (reset_ret != CLIENT_SUCCESS) {
1215 			CLIENT_FPRINTF(stderr, gettext("Error (%d) while "
1216 					"recovering service files during "
1217 					"reset\n"), reset_ret);
1218 			/* Continue and start what we can */
1219 		}
1220 		reset_ret = start_services(START_RESET);
1221 		if (reset_ret != CLIENT_SUCCESS) {
1222 			CLIENT_FPRINTF(stderr, gettext("Error (%d) while "
1223 					"starting services during reset\n"),
1224 					reset_ret);
1225 		}
1226 	}
1227 
1228 	/* Cleanup temporary files created by mod_backup() */
1229 	mod_cleanup();
1230 
1231 	return (retcode);
1232 }
1233 
1234 
1235 /*
1236  * The following macro is used to check if an arg has already been set
1237  * and issues an error message, a usage message and then returns an error.
1238  * This was made into a macro to avoid the duplication of this code many
1239  * times in the function below.
1240  */
1241 #define	LDAP_CHECK_INVALID(arg, param)	\
1242 if (arg) {	\
1243 	CLIENT_FPRINTF(stderr, gettext("Invalid parameter (%s) " \
1244 		"specified\n"), param);	\
1245 	usage();	\
1246 	return (CLIENT_ERR_FAIL);	\
1247 }
1248 
1249 static int
1250 client_genProfile(clientopts_t *arglist)
1251 {
1252 	int counter;
1253 	int retcode;	/* required for LDAP_SET_PARAM macro */
1254 	ns_ldap_error_t *errorp;
1255 
1256 	if (mode_verbose)
1257 		CLIENT_FPUTS(gettext("About to generate a profile\n"), stderr);
1258 
1259 	/* *** Check for invalid args *** */
1260 	LDAP_CHECK_INVALID(arglist->proxyDN, "proxyDN");
1261 	LDAP_CHECK_INVALID(arglist->proxyPassword, "proxyPassword");
1262 	LDAP_CHECK_INVALID(arglist->certificatePath, "certificatePath");
1263 	LDAP_CHECK_INVALID(arglist->domainName, "domainName");
1264 	/* *** End check for invalid args *** */
1265 
1266 	if (arglist->profileName == NULL) {
1267 		if (mode_verbose)
1268 			CLIENT_FPUTS(
1269 				gettext("No profile specified. "
1270 					"Using \"default\"\n"),
1271 				stderr);
1272 		arglist->profileName = "default";
1273 	}
1274 
1275 	__ns_ldap_setServer(TRUE);
1276 	__ns_ldap_default_config();
1277 
1278 	/* Set version to latest (not version 1) */
1279 	LDAP_SET_PARAM(NS_LDAP_VERSION, NS_LDAP_FILE_VERSION_P);
1280 
1281 	/* Set additional valid params from command line */
1282 	LDAP_SET_PARAM(arglist->authenticationMethod, NS_LDAP_AUTH_P);
1283 	LDAP_SET_PARAM(arglist->defaultSearchBase, NS_LDAP_SEARCH_BASEDN_P);
1284 	LDAP_SET_PARAM(arglist->credentialLevel, NS_LDAP_CREDENTIAL_LEVEL_P);
1285 	LDAP_SET_PARAM(arglist->profileTTL, NS_LDAP_CACHETTL_P);
1286 	LDAP_SET_PARAM(arglist->searchTimeLimit, NS_LDAP_SEARCH_TIME_P);
1287 	LDAP_SET_PARAM(arglist->preferredServerList, NS_LDAP_SERVER_PREF_P);
1288 	LDAP_SET_PARAM(arglist->profileName, NS_LDAP_PROFILE_P);
1289 	LDAP_SET_PARAM(arglist->followReferrals, NS_LDAP_SEARCH_REF_P);
1290 	LDAP_SET_PARAM(arglist->defaultSearchScope, NS_LDAP_SEARCH_SCOPE_P);
1291 	LDAP_SET_PARAM(arglist->bindTimeLimit, NS_LDAP_BIND_TIME_P);
1292 	LDAP_SET_PARAM(arglist->defaultServerList, NS_LDAP_SERVERS_P);
1293 
1294 	for (counter = 0;
1295 		counter < arglist->serviceAuthenticationMethod->count;
1296 		counter++) {
1297 
1298 		LDAP_SET_PARAM(
1299 			arglist->serviceAuthenticationMethod->optlist[counter],
1300 			NS_LDAP_SERVICE_AUTH_METHOD_P);
1301 	}
1302 	for (counter = 0;
1303 		counter < arglist->serviceCredentialLevel->count;
1304 		counter++) {
1305 
1306 		LDAP_SET_PARAM(
1307 			arglist->serviceCredentialLevel->optlist[counter],
1308 			NS_LDAP_SERVICE_CRED_LEVEL_P);
1309 	}
1310 	for (counter = 0;
1311 		counter < arglist->objectclassMap->count;
1312 		counter++) {
1313 
1314 		LDAP_SET_PARAM(
1315 			arglist->objectclassMap->optlist[counter],
1316 			NS_LDAP_OBJECTCLASSMAP_P);
1317 	}
1318 	for (counter = 0;
1319 		counter < arglist->attributeMap->count;
1320 		counter++) {
1321 
1322 		LDAP_SET_PARAM(
1323 			arglist->attributeMap->optlist[counter],
1324 			NS_LDAP_ATTRIBUTEMAP_P);
1325 	}
1326 	for (counter = 0;
1327 		counter < arglist->serviceSearchDescriptor->count;
1328 		counter++) {
1329 
1330 		LDAP_SET_PARAM(
1331 			arglist->serviceSearchDescriptor->optlist[counter],
1332 			NS_LDAP_SERVICE_SEARCH_DESC_P);
1333 	}
1334 
1335 	if (!is_config_ok(arglist, B_FALSE)) {
1336 		CLIENT_FPRINTF(stderr,
1337 			gettext("WARNING: some clients do not support an LDAP "
1338 				"port with tls\n"));
1339 	}
1340 
1341 	errorp = __ns_ldap_DumpLdif(NULL);
1342 	if (errorp != NULL) {
1343 		CLIENT_FPUTS(errorp->message, stderr);
1344 		CLIENT_FPUTC('\n', stderr);
1345 		(void) __ns_ldap_freeError(&errorp);
1346 		return (CLIENT_ERR_FAIL);
1347 	}
1348 
1349 	return (CLIENT_SUCCESS);
1350 }
1351 
1352 static int
1353 client_init(clientopts_t *arglist)
1354 {
1355 	int profile_fp;
1356 	int retcode = CLIENT_SUCCESS;
1357 	char *nisBaseDN = NULL;
1358 	ns_ldap_error_t *errorp;
1359 	int reset_ret;
1360 	int ret_copy;
1361 
1362 	if (mode_verbose)
1363 		CLIENT_FPUTS(
1364 			gettext("About to configure machine by downloading "
1365 				"a profile\n"),
1366 			stderr);
1367 
1368 	if (dname == NULL) {
1369 		CLIENT_FPUTS(
1370 			gettext("Init failed: System domain not set and "
1371 				"no domainName specified.\n"),
1372 			stderr);
1373 		return (CLIENT_ERR_FAIL);
1374 	}
1375 
1376 	if (!arglist->defaultServerList) {
1377 		CLIENT_FPUTS(gettext("Missing LDAP server address\n"), stderr);
1378 		return (CLIENT_ERR_FAIL);
1379 	}
1380 
1381 	/* *** Check for invalid args *** */
1382 	LDAP_CHECK_INVALID(arglist->authenticationMethod,
1383 		"authenticationMethod");
1384 	LDAP_CHECK_INVALID(arglist->defaultSearchBase,
1385 		"defaultSearchBase");
1386 	LDAP_CHECK_INVALID(arglist->credentialLevel,
1387 		"credentialLevel");
1388 	LDAP_CHECK_INVALID(arglist->profileTTL,
1389 		"profileTTL");
1390 	LDAP_CHECK_INVALID(arglist->searchTimeLimit,
1391 		"searchTimeLimit");
1392 	LDAP_CHECK_INVALID(arglist->preferredServerList,
1393 		"preferredServerList");
1394 	LDAP_CHECK_INVALID(arglist->followReferrals,
1395 		"followReferrals");
1396 	LDAP_CHECK_INVALID(arglist->defaultSearchScope,
1397 		"defaultSearchScope");
1398 	LDAP_CHECK_INVALID(arglist->bindTimeLimit,
1399 		"bindTimeLimit");
1400 
1401 	LDAP_CHECK_INVALID(arglist->objectclassMap->count,
1402 		"objectclassMap");
1403 	LDAP_CHECK_INVALID(arglist->attributeMap->count,
1404 		"attributeMap");
1405 	LDAP_CHECK_INVALID(arglist->serviceAuthenticationMethod->count,
1406 		"serviceAuthenticationMethod");
1407 	LDAP_CHECK_INVALID(arglist->serviceCredentialLevel->count,
1408 		"serviceCredentialLevel");
1409 	LDAP_CHECK_INVALID(arglist->serviceSearchDescriptor->count,
1410 		"serviceSearchDescriptor");
1411 	/* *** End check for invalid args *** */
1412 
1413 	__ns_ldap_setServer(TRUE);
1414 
1415 	if (arglist->profileName == NULL) {
1416 		if (mode_verbose)
1417 			CLIENT_FPUTS(
1418 				gettext("No profile specified. "
1419 					"Using \"default\"\n"),
1420 				stderr);
1421 		arglist->profileName = "default";
1422 	}
1423 
1424 	/* need to free nisBaseDN */
1425 	nisBaseDN = findBaseDN(arglist->defaultServerList);
1426 	if (nisBaseDN == NULL) {
1427 		CLIENT_FPRINTF(stderr,
1428 			gettext("Failed to find defaultSearchBase for "
1429 				"domain %s\n"),
1430 			dname);
1431 
1432 		if (gStartLdap == START_RESET)
1433 			(void) start_service(LDAP_FMRI, B_TRUE);
1434 
1435 		return (CLIENT_ERR_FAIL);
1436 	}
1437 	retcode = __ns_ldap_setParam(
1438 			NS_LDAP_SEARCH_BASEDN_P,
1439 			(void *)nisBaseDN,
1440 			&errorp);
1441 	if (retcode != 0) {
1442 		CLIENT_FPUTS(
1443 			gettext("Unable to set search baseDN.\n"), stderr);
1444 		/* non-fatal */
1445 	}
1446 
1447 	LDAP_SET_PARAM(arglist->defaultServerList, NS_LDAP_SERVERS_P);
1448 	if (retcode != 0) {
1449 		CLIENT_FPUTS(
1450 			gettext("Unable to set server address.\n"), stderr);
1451 		/* non-fatal */
1452 	}
1453 
1454 	/* Get and set profile params */
1455 	retcode = __ns_ldap_download(
1456 			arglist->profileName,
1457 			arglist->defaultServerList,
1458 			nisBaseDN,
1459 			&errorp);
1460 	if (retcode != NS_LDAP_SUCCESS) {
1461 		CLIENT_FPRINTF(stderr,
1462 			gettext("The download of the profile failed.\n"));
1463 		if (errorp != NULL) {
1464 			CLIENT_FPRINTF(stderr, "%s\n", errorp->message);
1465 			(void) __ns_ldap_freeError(&errorp);
1466 		} else if (retcode == NS_LDAP_NOTFOUND) {
1467 			CLIENT_FPRINTF(stderr,
1468 			gettext("Could not read the profile '%s'.\n"
1469 				"Perhaps it does not exist or you don't "
1470 				"have sufficient rights to read it.\n"),
1471 				arglist->profileName);
1472 		}
1473 
1474 		if (gStartLdap == START_RESET)
1475 			(void) start_service(LDAP_FMRI, B_TRUE);
1476 
1477 		return (CLIENT_ERR_FAIL);
1478 	}
1479 
1480 	/* Set additional valid params from command line */
1481 	/* note that the domainName is not used in setParam */
1482 	LDAP_SET_PARAM(arglist->proxyDN, NS_LDAP_BINDDN_P);
1483 	if (retcode != 0) {
1484 		CLIENT_FPUTS(gettext("setParam proxyDN failed.\n"), stderr);
1485 		/* non-fatal */
1486 	}
1487 	LDAP_SET_PARAM(arglist->proxyPassword, NS_LDAP_BINDPASSWD_P);
1488 	if (retcode != 0) {
1489 		CLIENT_FPUTS(
1490 			gettext("setParam proxyPassword failed.\n"), stderr);
1491 		/* non-fatal */
1492 	}
1493 	LDAP_SET_PARAM(arglist->certificatePath, NS_LDAP_HOST_CERTPATH_P);
1494 
1495 	retcode = credCheck(arglist);
1496 	if (retcode != CLIENT_SUCCESS) {
1497 		CLIENT_FPUTS(
1498 			gettext("Error in setting up credentials\n"), stderr);
1499 
1500 		if (gStartLdap == START_RESET)
1501 			(void) start_service(LDAP_FMRI, B_TRUE);
1502 
1503 		return (retcode);
1504 	}
1505 
1506 	if (mode_verbose)
1507 		CLIENT_FPUTS(
1508 			gettext("About to modify this machines configuration "
1509 				"by writing the files\n"),
1510 			stderr);
1511 
1512 	/* get ready to start playing with files */
1513 	retcode = stop_services(STATE_SAVE);
1514 	if (retcode != CLIENT_SUCCESS) {
1515 		CLIENT_FPUTS(
1516 			gettext("Errors stopping network services.\n"), stderr);
1517 
1518 		if (gStartLdap == START_RESET)
1519 			(void) start_service(LDAP_FMRI, B_TRUE);
1520 
1521 		return (CLIENT_ERR_FAIL);
1522 	}
1523 
1524 	/* Save orig versions of files */
1525 	retcode = file_backup();
1526 	if (retcode == CLIENT_ERR_RESTORE) {
1527 		CLIENT_FPUTS(
1528 			gettext("System not in state to enable ldap client.\n"),
1529 			stderr);
1530 
1531 		return (retcode);
1532 
1533 	} else if (retcode != CLIENT_SUCCESS) {
1534 		CLIENT_FPUTS(
1535 			gettext("Save of system configuration failed.  "
1536 				"Attempting recovery.\n"),
1537 			stderr);
1538 		retcode = recover(STATE_NOSAVE);
1539 		if (retcode != CLIENT_SUCCESS) {
1540 			CLIENT_FPUTS(
1541 				gettext("Recovery of systems configuration "
1542 					"failed.  Manual intervention of "
1543 					"config files is required.\n"),
1544 				stderr);
1545 		}
1546 
1547 		reset_ret = start_services(START_RESET);
1548 		if (reset_ret != CLIENT_SUCCESS) {
1549 			CLIENT_FPRINTF(stderr, gettext("Error (%d) while "
1550 					"starting services during reset\n"),
1551 					reset_ret);
1552 		}
1553 
1554 		return (retcode);
1555 	}
1556 
1557 	/* Dump new files */
1558 	errorp = __ns_ldap_DumpConfiguration(NSCONFIGFILE);
1559 	if (NULL != errorp) {
1560 		CLIENT_FPRINTF(stderr,
1561 			gettext("%s init: errorp is not NULL; %s\n"),
1562 			cmd, errorp->message);
1563 		retcode = recover(STATE_NOSAVE);
1564 		if (retcode != CLIENT_SUCCESS) {
1565 			CLIENT_FPUTS(
1566 				gettext("Recovery of systems configuration "
1567 					"failed.  Manual intervention of "
1568 					"config files is required.\n"),
1569 				stderr);
1570 			return (CLIENT_ERR_FAIL);
1571 		}
1572 		(void) __ns_ldap_freeError(&errorp);
1573 		reset_ret = start_services(START_RESET);
1574 		if (reset_ret != CLIENT_SUCCESS) {
1575 			CLIENT_FPRINTF(stderr, gettext("Error (%d) while "
1576 					"starting services during reset\n"),
1577 					reset_ret);
1578 		}
1579 		return (CLIENT_ERR_FAIL);
1580 	}
1581 
1582 	/* if (credargs(arglist)) */
1583 	errorp = __ns_ldap_DumpConfiguration(NSCREDFILE);
1584 	if (NULL != errorp) {
1585 		CLIENT_FPRINTF(stderr,
1586 			gettext("%s init: errorp is not NULL; %s\n"),
1587 			cmd, errorp->message);
1588 		retcode = recover(STATE_NOSAVE);
1589 		if (retcode != CLIENT_SUCCESS) {
1590 			CLIENT_FPUTS(
1591 				gettext("Recovery of systems configuration "
1592 					"failed.  Manual intervention of "
1593 					"config files is required.\n"),
1594 				stderr);
1595 			return (CLIENT_ERR_FAIL);
1596 		}
1597 		(void) __ns_ldap_freeError(&errorp);
1598 		reset_ret = start_services(START_RESET);
1599 		if (reset_ret != CLIENT_SUCCESS) {
1600 			CLIENT_FPRINTF(stderr, gettext("Error (%d) while "
1601 					"starting services during reset\n"),
1602 					reset_ret);
1603 		}
1604 		return (CLIENT_ERR_FAIL);
1605 	}
1606 
1607 	ret_copy = system(CMD_CP " " NSSWITCH_LDAP " " NSSWITCH_CONF);
1608 	if (ret_copy != 0) {
1609 		CLIENT_FPRINTF(stderr,
1610 			gettext("Error %d copying (%s) -> (%s)\n"),
1611 			ret_copy, NSSWITCH_LDAP, NSSWITCH_CONF);
1612 		retcode = recover(STATE_NOSAVE);
1613 		if (retcode != CLIENT_SUCCESS) {
1614 			CLIENT_FPUTS(
1615 				gettext("Recovery of systems configuration "
1616 					"failed.  Manual intervention of "
1617 					"config files is required.\n"),
1618 				stderr);
1619 		}
1620 		reset_ret = start_services(START_RESET);
1621 		if (reset_ret != CLIENT_SUCCESS) {
1622 			CLIENT_FPRINTF(stderr, gettext("Error (%d) while "
1623 					"starting services during reset\n"),
1624 					reset_ret);
1625 		}
1626 		return (CLIENT_ERR_FAIL);
1627 	}
1628 
1629 	if ((profile_fp = open(DOMAINNAME, O_WRONLY|O_CREAT|O_TRUNC,
1630 		S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1) { /* 0644 */
1631 		CLIENT_FPRINTF(stderr, gettext("Cannot open %s\n"), DOMAINNAME);
1632 		retcode = recover(STATE_NOSAVE);
1633 		if (retcode != CLIENT_SUCCESS) {
1634 			CLIENT_FPUTS(
1635 				gettext("Recovery of systems configuration "
1636 					"failed.  Manual intervention of "
1637 					"config files is required.\n"),
1638 				stderr);
1639 			return (CLIENT_ERR_FAIL);
1640 		}
1641 		reset_ret = start_services(START_RESET);
1642 		if (reset_ret != CLIENT_SUCCESS) {
1643 			CLIENT_FPRINTF(stderr, gettext("Error (%d) while "
1644 					"starting services during reset\n"),
1645 					reset_ret);
1646 		}
1647 		return (CLIENT_ERR_FAIL);
1648 	}
1649 	(void) write(profile_fp, dname, strlen(dname));
1650 	(void) write(profile_fp, "\n", 1);
1651 	(void) close(profile_fp);
1652 
1653 	retcode = start_services(START_INIT);
1654 
1655 	if (retcode == CLIENT_SUCCESS) {
1656 		CLIENT_FPUTS(gettext("System successfully configured\n"),
1657 								stderr);
1658 	} else {
1659 		CLIENT_FPUTS(gettext("Error resetting system.\n"
1660 			"Recovering old system settings.\n"), stderr),
1661 
1662 		/* stop any started services for recover */
1663 		/* don't stomp on history of saved services state */
1664 		reset_ret = stop_services(STATE_NOSAVE);
1665 		if (reset_ret != CLIENT_SUCCESS) {
1666 			CLIENT_FPRINTF(stderr, gettext("Error (%d) while "
1667 					"stopping services during reset\n"),
1668 					reset_ret);
1669 			/* Coninue and try to recover what we can */
1670 		}
1671 		reset_ret = recover(STATE_NOSAVE);
1672 		if (reset_ret != CLIENT_SUCCESS) {
1673 			CLIENT_FPRINTF(stderr, gettext("Error (%d) while "
1674 					"recovering service files during "
1675 					"reset\n"), reset_ret);
1676 			/* Continue and start what we can */
1677 		}
1678 		reset_ret = start_services(START_RESET);
1679 		if (reset_ret != CLIENT_SUCCESS) {
1680 			CLIENT_FPRINTF(stderr, gettext("Error (%d) while "
1681 					"starting services during reset\n"),
1682 					reset_ret);
1683 		}
1684 	}
1685 
1686 	return (retcode);
1687 }
1688 
1689 
1690 static void
1691 usage(void)
1692 {
1693 	if (mode_quiet)
1694 		return;
1695 
1696 	if (gen == 0) {
1697 		CLIENT_FPRINTF(stderr,
1698 			gettext("Usage: %s [-v | -q] init | manual | mod | "
1699 				"list | uninit [<args>]\n"),
1700 			cmd);
1701 
1702 		CLIENT_FPUTS(
1703 			gettext("\nSet up a server or workstation as a "
1704 				"client of an LDAP namespace.\n"),
1705 			stderr);
1706 	} else {	/* genprofile */
1707 		CLIENT_FPRINTF(stderr,
1708 			gettext("Usage: %s [-v | -q] genprofile "
1709 				"-a profileName=<name> "
1710 				"-a defaultSearchBase=<base> <args>\n"),
1711 			cmd);
1712 
1713 		CLIENT_FPUTS(
1714 			gettext("\nGenerate a profile used to set up clients "
1715 				"of an LDAP namespace.\n"),
1716 			stderr);
1717 	}
1718 	CLIENT_FPUTS(
1719 		gettext("<args> take the form of \'-a attrName=attrVal\' as "
1720 			"described in the\n"),
1721 		stderr);
1722 	CLIENT_FPUTS(gettext("man page: ldapclient(1M)\n"), stderr);
1723 }
1724 
1725 
1726 /*
1727  * stop_services is called to stop network services prior to their
1728  * config files being moved/changed.  In case a later recovery is needed
1729  * (an error occurs during config), we detect whether the service is
1730  * running and store that info so that a reset will only start services
1731  * that were stopped here.
1732  *
1733  * In terms of SMF, this translates to disabling the services. So we
1734  * try to disable them if they are in any other state
1735  *
1736  * Stop order :
1737  * sendmail, nscd, autofs, ldap.client, nisd (rpc), inetinit(domainname)
1738  */
1739 static int
1740 stop_services(int saveState)
1741 {
1742 	int ret;
1743 
1744 	if (mode_verbose) {
1745 		CLIENT_FPUTS(gettext("Stopping network services\n"), stderr);
1746 	}
1747 
1748 	if (!is_service(SENDMAIL_FMRI, SCF_STATE_STRING_DISABLED)) {
1749 		if (mode_verbose)
1750 			CLIENT_FPUTS(gettext("Stopping sendmail\n"), stderr);
1751 		ret = disable_service(SENDMAIL_FMRI, B_TRUE);
1752 		if (ret != CLIENT_SUCCESS) {
1753 			/* Not serious, but tell user what to do */
1754 			CLIENT_FPRINTF(stderr, gettext("Stopping sendmail "
1755 				"failed with (%d). You may need to restart "
1756 				"it manually for changes to take effect.\n"),
1757 				ret);
1758 		} else enableFlag |= SENDMAIL_ON;
1759 	} else {
1760 		if (mode_verbose)
1761 			CLIENT_FPUTS(gettext("sendmail not running\n"), stderr);
1762 	}
1763 
1764 	if (!is_service(NSCD_FMRI, SCF_STATE_STRING_DISABLED)) {
1765 		if (mode_verbose)
1766 			CLIENT_FPUTS(gettext("Stopping nscd\n"), stderr);
1767 		ret = disable_service(NSCD_FMRI, B_TRUE);
1768 		if (ret != CLIENT_SUCCESS) {
1769 			CLIENT_FPRINTF(stderr, gettext("Stopping nscd "
1770 			    "failed with (%d)\n"), ret);
1771 			return (CLIENT_ERR_FAIL);
1772 		} else enableFlag |= NSCD_ON;
1773 	} else {
1774 		if (mode_verbose)
1775 			CLIENT_FPUTS(gettext("nscd not running\n"), stderr);
1776 	}
1777 
1778 	if (!is_service(AUTOFS_FMRI, SCF_STATE_STRING_DISABLED)) {
1779 		if (mode_verbose)
1780 			CLIENT_FPUTS(gettext("Stopping autofs\n"), stderr);
1781 		ret = disable_service(AUTOFS_FMRI, B_TRUE);
1782 		if (ret != CLIENT_SUCCESS) {
1783 			/* Not serious, but tell user what to do */
1784 			CLIENT_FPRINTF(stderr, gettext("Stopping autofs "
1785 				"failed with (%d). You may need to restart "
1786 				"it manually for changes to take effect.\n"),
1787 				ret);
1788 		} else enableFlag |= AUTOFS_ON;
1789 	} else {
1790 		if (mode_verbose)
1791 			CLIENT_FPUTS(gettext("autofs not running\n"), stderr);
1792 	}
1793 
1794 	if (!is_service(LDAP_FMRI, SCF_STATE_STRING_DISABLED)) {
1795 		if (saveState)
1796 			gStartLdap = START_RESET;
1797 		if (mode_verbose)
1798 			CLIENT_FPUTS(gettext("Stopping ldap\n"), stderr);
1799 		ret = disable_service(LDAP_FMRI, B_TRUE);
1800 		if (ret != CLIENT_SUCCESS) {
1801 			CLIENT_FPRINTF(stderr, gettext("Stopping ldap "
1802 			    "failed with (%d)\n"), ret);
1803 			return (CLIENT_ERR_FAIL);
1804 		}
1805 	} else {
1806 		if (mode_verbose)
1807 			CLIENT_FPUTS(gettext("ldap not running\n"),
1808 								stderr);
1809 	}
1810 
1811 	if (!is_service(NISD_FMRI, SCF_STATE_STRING_DISABLED)) {
1812 		if (mode_verbose)
1813 			CLIENT_FPUTS(gettext("Stopping nisd\n"), stderr);
1814 		ret = disable_service(NISD_FMRI, B_TRUE);
1815 		if (ret != CLIENT_SUCCESS) {
1816 			CLIENT_FPRINTF(stderr, gettext("Stopping nisd "
1817 			    "failed with (%d)\n"), ret);
1818 			return (CLIENT_ERR_FAIL);
1819 		}
1820 	} else {
1821 		if (mode_verbose)
1822 			CLIENT_FPUTS(gettext("nisd not running\n"),
1823 								stderr);
1824 	}
1825 
1826 	if (!is_service(YP_FMRI, SCF_STATE_STRING_DISABLED)) {
1827 		if (saveState)
1828 			gStartYp = START_RESET;
1829 		if (mode_verbose)
1830 			CLIENT_FPUTS(gettext("Stopping nis(yp)\n"), stderr);
1831 		ret = disable_service(YP_FMRI, B_TRUE);
1832 		if (ret != 0) {
1833 			CLIENT_FPRINTF(stderr, gettext("Stopping nis(yp) "
1834 			    "failed with (%d)\n"), ret);
1835 			return (CLIENT_ERR_FAIL);
1836 		}
1837 	} else {
1838 		if (mode_verbose)
1839 			CLIENT_FPUTS(gettext("nis(yp) not running\n"),
1840 								stderr);
1841 	}
1842 
1843 	return (CLIENT_SUCCESS);
1844 }
1845 
1846 /*
1847  * start_services is called to start up network services after config
1848  * files have all been setup or recovered.  In the case of an error, the
1849  * files will be recovered and start_services will be called with the
1850  * "reset" flag set so that only those services that were earlier stopped
1851  * will be started.  If it is not a reset, then the services associated
1852  * with files "recovered" will attempt to be started.
1853  */
1854 static int
1855 start_services(int flag)
1856 {
1857 	int sysret, retcode = CLIENT_SUCCESS;
1858 	FILE *domain_fp;
1859 	char domainname[BUFSIZ];
1860 	char cmd_domain_start[BUFSIZ];
1861 	int domainlen;
1862 
1863 	if (mode_verbose) {
1864 		CLIENT_FPUTS(gettext("Starting network services\n"), stderr);
1865 	}
1866 
1867 	/* Read in current defaultdomain so we can set it */
1868 	domain_fp = fopen(DOMAINNAME, "r");
1869 	if (domain_fp == NULL) {
1870 		CLIENT_FPRINTF(stderr, gettext("Error opening defaultdomain "
1871 							"(%d)\n"), errno);
1872 		/* if we did an ldap init, we must have domain */
1873 		if (flag == START_INIT)
1874 			return (CLIENT_ERR_FAIL);
1875 	} else {
1876 		if (fgets(domainname, BUFSIZ, domain_fp) == NULL) {
1877 			CLIENT_FPUTS(gettext("Error reading defaultdomain\n"),
1878 				stderr);
1879 			return (CLIENT_ERR_FAIL);
1880 		}
1881 
1882 		if (fclose(domain_fp) != 0) {
1883 			CLIENT_FPRINTF(stderr,
1884 				gettext("Error closing defaultdomain (%d)\n"),
1885 				errno);
1886 			return (CLIENT_ERR_FAIL);
1887 		}
1888 		domainlen = strlen(domainname);
1889 		/* sanity check to make sure sprintf will fit */
1890 		if (domainlen > (BUFSIZE - sizeof (CMD_DOMAIN_START) -
1891 						sizeof (TO_DEV_NULL) - 3)) {
1892 			CLIENT_FPUTS(gettext("Specified domainname is "
1893 						"too large\n"), stderr);
1894 			return (CLIENT_ERR_FAIL);
1895 		}
1896 		if (domainname[domainlen-1] == '\n')
1897 			domainname[domainlen-1] = 0;
1898 		/* buffer size is checked above */
1899 		(void) sprintf(cmd_domain_start, "%s %s %s", CMD_DOMAIN_START,
1900 						domainname, TO_DEV_NULL);
1901 	}
1902 
1903 	/*
1904 	 * We can be starting services after an init in which case
1905 	 * we want to start ldap and not start yp or nis+.
1906 	 */
1907 	if (flag == START_INIT) {
1908 		sysret = system(cmd_domain_start);
1909 		if (mode_verbose)
1910 			CLIENT_FPRINTF(stderr, "start: %s %s... %s\n",
1911 					CMD_DOMAIN_START, domainname,
1912 					(sysret == 0) ? gettext("success") :
1913 							gettext("failed"));
1914 		if (sysret != 0) {
1915 			CLIENT_FPRINTF(stderr, gettext("\"%s\" returned: %d\n"),
1916 					CMD_DOMAIN_START, sysret);
1917 
1918 			retcode = CLIENT_ERR_FAIL;
1919 		}
1920 
1921 		if (start_service(LDAP_FMRI, B_TRUE) != CLIENT_SUCCESS)
1922 			retcode = CLIENT_ERR_FAIL;
1923 
1924 		/* No YP or NIS+ after init */
1925 	/*
1926 	 * Or we can be starting services after an uninit or error
1927 	 * recovery.  We want to start whatever services were running
1928 	 * before.  In the case of error recovery, it is the services
1929 	 * that were running before we stopped them (flags set in
1930 	 * stop_services).  If it is an uninit then we determine
1931 	 * which services to start based on the files we recovered
1932 	 * (flags set in recover).
1933 	 */
1934 	} else {
1935 		/* uninit and recover should set flags of what to start */
1936 		if (domain_fp) {
1937 			sysret = system(cmd_domain_start);
1938 			if (mode_verbose)
1939 				CLIENT_FPRINTF(stderr, "start: %s %s... %s\n",
1940 					CMD_DOMAIN_START, domainname,
1941 					(sysret == 0) ? gettext("success") :
1942 							gettext("failed"));
1943 			if (sysret != 0) {
1944 				CLIENT_FPRINTF(stderr, gettext("\"%s\" "
1945 						"returned: %d\n"),
1946 						CMD_DOMAIN_START, sysret);
1947 
1948 				retcode = CLIENT_ERR_FAIL;
1949 			}
1950 		}
1951 
1952 		if (gStartLdap == flag) {
1953 			if (!(is_service(LDAP_FMRI, SCF_STATE_STRING_ONLINE)))
1954 				if (start_service(LDAP_FMRI, B_TRUE)
1955 							!= CLIENT_SUCCESS)
1956 					retcode = CLIENT_ERR_FAIL;
1957 		}
1958 
1959 		if (gStartYp == flag) {
1960 			if (!(is_service(YP_FMRI, SCF_STATE_STRING_ONLINE)))
1961 				(void) start_service(YP_FMRI, B_TRUE);
1962 		}
1963 
1964 		if (gStartNisd == flag) {
1965 			if (!(is_service(NISD_FMRI, SCF_STATE_STRING_ONLINE)))
1966 				(void) start_service(NISD_FMRI, B_TRUE);
1967 		}
1968 
1969 	}
1970 	if ((enableFlag & AUTOFS_ON) &&
1971 	    !(is_service(AUTOFS_FMRI, SCF_STATE_STRING_ONLINE)))
1972 		(void) start_service(AUTOFS_FMRI, B_TRUE);
1973 
1974 	if ((enableFlag & NSCD_ON) &&
1975 	    !(is_service(NSCD_FMRI, SCF_STATE_STRING_ONLINE)))
1976 		(void) start_service(NSCD_FMRI, B_TRUE);
1977 
1978 	if ((enableFlag & SENDMAIL_ON) &&
1979 	    !(is_service(SENDMAIL_FMRI, SCF_STATE_STRING_ONLINE)))
1980 		(void) start_service(SENDMAIL_FMRI, B_TRUE);
1981 
1982 	/*
1983 	 * Restart name-service milestone so that any consumer
1984 	 * which depends on it will be restarted.
1985 	 */
1986 	(void) restart_service(NS_MILESTONE_FMRI, B_TRUE);
1987 	return (retcode);
1988 }
1989 
1990 /*
1991  * credCheck is called to check if credentials are required for this
1992  * configuration.  Currently, this means that if any credentialLevel is
1993  * proxy and any authenticationMethod is something other than none, then
1994  * credential info is required (proxyDN and proxyPassword).
1995  */
1996 static int
1997 credCheck(clientopts_t *arglist)
1998 {
1999 	int counter;
2000 	int **credLevel;
2001 	ns_auth_t **authMethod;
2002 	char **proxyDN, **proxyPassword;
2003 	ns_ldap_error_t *errorp;
2004 	int credProxy, authNotNone;
2005 	int retcode;
2006 
2007 /* If credentialLevel is proxy, make sure we have proxyDN and proxyPassword */
2008 	retcode = __ns_ldap_getParam(NS_LDAP_CREDENTIAL_LEVEL_P,
2009 			(void ***)&credLevel, &errorp);
2010 	if (retcode != 0) {
2011 		CLIENT_FPRINTF(stderr,
2012 			gettext("Error %d while trying to retrieve "
2013 				"credLevel\n"),
2014 			retcode);
2015 		return (CLIENT_ERR_FAIL);
2016 	}
2017 	retcode = __ns_ldap_getParam(NS_LDAP_AUTH_P,
2018 			(void ***)&authMethod, &errorp);
2019 	if (retcode != 0) {
2020 		CLIENT_FPRINTF(stderr,
2021 			gettext("Error %d while trying to retrieve "
2022 				"authMethod\n"), retcode);
2023 		return (CLIENT_ERR_FAIL);
2024 	}
2025 	retcode = __ns_ldap_getParam(NS_LDAP_BINDDN_P,
2026 			(void ***)&proxyDN, &errorp);
2027 	if (retcode != 0) {
2028 		CLIENT_FPRINTF(stderr,
2029 			gettext("Error %d while trying to retrieve proxyDN\n"),
2030 			retcode);
2031 		return (CLIENT_ERR_FAIL);
2032 	}
2033 	retcode = __ns_ldap_getParam(NS_LDAP_BINDPASSWD_P,
2034 			(void ***)&proxyPassword, &errorp);
2035 	if (retcode != 0) {
2036 		CLIENT_FPRINTF(stderr,
2037 			gettext("Error %d while trying to retrieve "
2038 				"proxyPassword\n"), retcode);
2039 		return (CLIENT_ERR_FAIL);
2040 	}
2041 
2042 	if (mode_verbose) {
2043 		CLIENT_FPRINTF(stderr,
2044 			gettext("Proxy DN: %s\n"),
2045 			(proxyDN && proxyDN[0]) ? proxyDN[0] : "NULL");
2046 		CLIENT_FPRINTF(stderr,
2047 			gettext("Proxy password: %s\n"),
2048 			(proxyPassword && proxyPassword[0]) ?
2049 				proxyPassword[0] : "NULL");
2050 	}
2051 
2052 	credProxy = 0;	/* flag to indicate if we have a credLevel of proxy */
2053 	for (counter = 0; credLevel && credLevel[counter] != NULL; counter++) {
2054 		if (mode_verbose)
2055 			CLIENT_FPRINTF(stderr,
2056 				gettext("Credential level: %d\n"),
2057 				*credLevel[counter]);
2058 		if (*credLevel[counter] == NS_LDAP_CRED_PROXY) {
2059 			credProxy = 1;
2060 			break;
2061 		}
2062 	}
2063 
2064 	authNotNone = 0;	/* flag for authMethod other than none */
2065 	for (counter = 0;
2066 		authMethod && authMethod[counter] != NULL;
2067 		counter++) {
2068 
2069 		if (mode_verbose)
2070 			CLIENT_FPRINTF(stderr,
2071 				gettext("Authentication method: %d\n"),
2072 				authMethod[counter]->type);
2073 		if (authMethod[counter]->type != NS_LDAP_AUTH_NONE &&
2074 		    !(authMethod[counter]->type == NS_LDAP_AUTH_TLS &&
2075 		    authMethod[counter]->tlstype == NS_LDAP_TLS_NONE)) {
2076 			authNotNone = 1;
2077 			break;
2078 		}
2079 	}
2080 
2081 	/* First, if we don't need proxyDN/Password then just return ok */
2082 	if (!(credProxy && authNotNone)) {
2083 		if (mode_verbose)
2084 			CLIENT_FPUTS(
2085 				gettext("No proxyDN/proxyPassword required\n"),
2086 				stderr);
2087 		return (CLIENT_SUCCESS);
2088 	}
2089 
2090 	/* Now let's check if we have the cred stuff we need */
2091 	if (!proxyDN || !proxyDN[0]) {
2092 		CLIENT_FPUTS(
2093 			gettext("credentialLevel is proxy and no proxyDN "
2094 				"specified\n"),
2095 			stderr);
2096 		return (CLIENT_ERR_CREDENTIAL);
2097 	}
2098 
2099 	/* If we need proxyPassword (prompt) */
2100 	if (!proxyPassword || !proxyPassword[0]) {
2101 		CLIENT_FPUTS(
2102 			gettext("credentialLevel requires proxyPassword\n"),
2103 			stderr);
2104 		arglist->proxyPassword = getpassphrase("Proxy Bind Password:");
2105 		if (arglist->proxyPassword == NULL) {
2106 			CLIENT_FPUTS(gettext("Get password failed\n"), stderr);
2107 			return (CLIENT_ERR_CREDENTIAL);
2108 		}
2109 		LDAP_SET_PARAM(arglist->proxyPassword, NS_LDAP_BINDPASSWD_P);
2110 		if (retcode != 0) {
2111 			CLIENT_FPUTS(
2112 				gettext("setParam proxyPassword failed.\n"),
2113 				stderr);
2114 			return (CLIENT_ERR_CREDENTIAL);
2115 		}
2116 	}
2117 
2118 	return (CLIENT_SUCCESS);
2119 }
2120 
2121 /*
2122  * try to restore the previous name space on this machine
2123  */
2124 static int
2125 recover(int saveState)
2126 {
2127 	struct stat buf;
2128 	int stat_ret, retcode, fd;
2129 	int domain = 0, domainlen;
2130 	char yp_dir[BUFSIZE], yp_dir_back[BUFSIZE];
2131 	char name[BUFSIZ];
2132 	char *ldap_conf_file, *ldap_cred_file;
2133 	char ldap_file_back[BUFSIZE], ldap_cred_back[BUFSIZE];
2134 
2135 	/* If running as Sysid Install become a no-op */
2136 	if (sysid_install == B_TRUE)
2137 		return (CLIENT_SUCCESS);
2138 
2139 	stat_ret = stat(LDAP_RESTORE_DIR, &buf);
2140 	if (stat_ret != 0) {
2141 		CLIENT_FPUTS(
2142 			gettext("Cannot recover.  No backup files "
2143 				"found.\n"),
2144 			stderr);
2145 		CLIENT_FPUTS(
2146 			gettext("\t Either this machine was not initialized\n"),
2147 			stderr);
2148 		CLIENT_FPUTS(
2149 			gettext("\t by ldapclient or the backup files "
2150 				"have been\n"),
2151 			stderr);
2152 		CLIENT_FPUTS(
2153 			gettext("\t removed manually or with an \"uninit\"\n"),
2154 			stderr);
2155 		return (CLIENT_ERR_RESTORE);	/* invalid backup */
2156 	}
2157 
2158 	/*
2159 	 * Get domainname.  Allow no domainname for the case where "files"
2160 	 * config was backed up.
2161 	 */
2162 	stat_ret = stat(DOMAINNAME_BACK, &buf);
2163 	if (mode_verbose)
2164 		CLIENT_FPRINTF(stderr,
2165 			gettext("recover: stat(%s)=%d\n"),
2166 			DOMAINNAME_BACK, stat_ret);
2167 	if (stat_ret == 0) {
2168 		if (mode_verbose)
2169 			CLIENT_FPRINTF(stderr,
2170 				gettext("recover: open(%s)\n"),
2171 					DOMAINNAME_BACK);
2172 		fd = open(DOMAINNAME_BACK, O_RDONLY);
2173 		if (mode_verbose)
2174 			CLIENT_FPRINTF(stderr,
2175 				gettext("recover: read(%s)\n"),
2176 					DOMAINNAME_BACK);
2177 		domainlen = read(fd, &(name[0]), BUFSIZ-1);
2178 		(void) close(fd);
2179 		if (domainlen < 0) {
2180 			CLIENT_FPUTS(
2181 				gettext("Cannot recover.  Cannot determine "
2182 					"previous domain name.\n"),
2183 				stderr);
2184 			return (CLIENT_ERR_RESTORE);	/* invalid backup */
2185 		} else 	{
2186 			char *ptr;
2187 
2188 			ptr = strchr(&(name[0]), '\n');
2189 			if (ptr != NULL)
2190 				*ptr = '\0';
2191 			else
2192 				name[domainlen] = '\0';
2193 
2194 			if (mode_verbose)
2195 				CLIENT_FPRINTF(stderr,
2196 					gettext("recover: old domainname "
2197 						"\"%s\"\n"), name);
2198 
2199 			if (strlen(name) == 0)
2200 				domain = 0;
2201 			else
2202 				domain = 1;	/* flag that we have domain */
2203 
2204 		}
2205 	}
2206 
2207 
2208 	/*
2209 	 * we can recover at this point
2210 	 * remove LDAP config files before restore
2211 	 */
2212 	(void) unlink(NSCONFIGFILE);
2213 	(void) unlink(NSCREDFILE);
2214 
2215 	ldap_conf_file = strrchr(NSCONFIGFILE, '/') + 1;
2216 	ldap_cred_file = strrchr(NSCREDFILE, '/') + 1;
2217 
2218 	(void) strlcpy(ldap_file_back, LDAP_RESTORE_DIR "/", BUFSIZE);
2219 	(void) strlcat(ldap_file_back, ldap_conf_file, BUFSIZE);
2220 
2221 	stat_ret = stat(ldap_file_back, &buf);
2222 	if (mode_verbose)
2223 		CLIENT_FPRINTF(stderr,
2224 			gettext("recover: stat(%s)=%d\n"),
2225 			ldap_file_back, stat_ret);
2226 	if (stat_ret == 0) {
2227 		if (saveState)
2228 			gStartLdap = START_UNINIT;
2229 		retcode = file_move(ldap_file_back, NSCONFIGFILE);
2230 		if (mode_verbose)
2231 			CLIENT_FPRINTF(stderr,
2232 				gettext("recover: file_move(%s, %s)=%d\n"),
2233 				ldap_file_back, NSCONFIGFILE, retcode);
2234 		if (retcode != 0)
2235 			CLIENT_FPRINTF(stderr,
2236 				gettext("recover: file_move(%s, %s) failed\n"),
2237 				ldap_file_back, NSCONFIGFILE);
2238 	}
2239 
2240 	(void) strlcpy(ldap_cred_back, LDAP_RESTORE_DIR "/", BUFSIZE);
2241 	(void) strlcat(ldap_cred_back, ldap_cred_file, BUFSIZE);
2242 
2243 	stat_ret = stat(ldap_cred_back, &buf);
2244 	if (mode_verbose)
2245 		CLIENT_FPRINTF(stderr,
2246 			gettext("recover: stat(%s)=%d\n"),
2247 			ldap_cred_back, stat_ret);
2248 	if (stat_ret == 0) {
2249 		retcode = file_move(ldap_cred_back, NSCREDFILE);
2250 		if (mode_verbose)
2251 			CLIENT_FPRINTF(stderr,
2252 				gettext("recover: file_move(%s, %s)=%d\n"),
2253 				ldap_cred_back, NSCREDFILE, retcode);
2254 		if (retcode != 0)
2255 			CLIENT_FPRINTF(stderr,
2256 				gettext("recover: file_move(%s, %s) failed\n"),
2257 				ldap_cred_back, NSCREDFILE);
2258 	}
2259 
2260 	/* Check for recovery of NIS+ */
2261 	stat_ret = stat(NIS_COLDSTART_BACK, &buf);
2262 	if (mode_verbose)
2263 		CLIENT_FPRINTF(stderr,
2264 			gettext("recover: stat(%s)=%d\n"),
2265 			NIS_COLDSTART_BACK, stat_ret);
2266 	if (stat_ret == 0) {
2267 		if (saveState) {
2268 			gStartNisd = START_UNINIT;
2269 		}
2270 		if (mode_verbose)
2271 			CLIENT_FPRINTF(stderr,
2272 				gettext("recover: file_move(%s, %s)\n"),
2273 				NIS_COLDSTART_BACK, NIS_COLDSTART);
2274 		retcode = file_move(NIS_COLDSTART_BACK, NIS_COLDSTART);
2275 		if (retcode != 0)
2276 			CLIENT_FPRINTF(stderr,
2277 				gettext("recover: file_move(%s, %s) failed!\n"),
2278 				NIS_COLDSTART_BACK, NIS_COLDSTART);
2279 	}
2280 
2281 	/* Check for recovery of NIS(YP) if we have a domainname */
2282 	if (domain) {
2283 		/* "name" would have to be huge for this, but just in case */
2284 		if (strlen(name) >= (BUFSIZE - strlen(LDAP_RESTORE_DIR)))
2285 			return (CLIENT_ERR_FAIL);
2286 		if (strlen(name) >= (BUFSIZE - strlen(YP_BIND_DIR)))
2287 			return (CLIENT_ERR_FAIL);
2288 
2289 		(void) strlcpy(yp_dir_back, LDAP_RESTORE_DIR "/", BUFSIZE);
2290 		(void) strlcat(yp_dir_back, name, BUFSIZE);
2291 		stat_ret = stat(yp_dir_back, &buf);
2292 		if (mode_verbose)
2293 			CLIENT_FPRINTF(stderr,
2294 				gettext("recover: stat(%s)=%d\n"),
2295 				yp_dir_back, stat_ret);
2296 		if (stat_ret == 0) {
2297 			(void) strlcpy(yp_dir, YP_BIND_DIR "/", BUFSIZE);
2298 			(void) strlcat(yp_dir, name, BUFSIZE);
2299 			retcode = file_move(yp_dir_back, yp_dir);
2300 			if (mode_verbose)
2301 				CLIENT_FPRINTF(stderr,
2302 					gettext("recover: file_move(%s, "
2303 						"%s)=%d\n"),
2304 					yp_dir_back, yp_dir, retcode);
2305 			if (retcode != 0) {
2306 				CLIENT_FPRINTF(stderr,
2307 					gettext("recover: file_move(%s, "
2308 						"%s) failed!\n"),
2309 					yp_dir_back, yp_dir);
2310 			} else {
2311 				if (saveState)
2312 					gStartYp = START_UNINIT;
2313 			}
2314 		}
2315 	}
2316 
2317 	/* restore machine configuration */
2318 	stat_ret = stat(NSSWITCH_BACK, &buf);
2319 	if (mode_verbose)
2320 		CLIENT_FPRINTF(stderr,
2321 			gettext("recover: stat(%s)=%d\n"),
2322 			NSSWITCH_BACK, stat_ret);
2323 	if (stat_ret == 0) {
2324 		retcode = file_move(NSSWITCH_BACK, NSSWITCH_CONF);
2325 		if (mode_verbose)
2326 			CLIENT_FPRINTF(stderr,
2327 				gettext("recover: file_move(%s, %s)=%d\n"),
2328 				NSSWITCH_BACK, NSSWITCH_CONF, retcode);
2329 		if (retcode != 0)
2330 			CLIENT_FPRINTF(stderr,
2331 				gettext("recover: file_move(%s, %s) failed\n"),
2332 				NSSWITCH_BACK, NSSWITCH_CONF);
2333 	}
2334 
2335 	stat_ret = stat(DOMAINNAME_BACK, &buf);
2336 	if (mode_verbose)
2337 		CLIENT_FPRINTF(stderr,
2338 			gettext("recover: stat(%s)=%d\n"),
2339 			DOMAINNAME_BACK, stat_ret);
2340 	if (stat_ret == 0) {
2341 		retcode = file_move(DOMAINNAME_BACK, DOMAINNAME);
2342 		if (mode_verbose)
2343 			CLIENT_FPRINTF(stderr,
2344 				gettext("recover: file_move(%s, %s)=%d\n"),
2345 				DOMAINNAME_BACK, DOMAINNAME, retcode);
2346 		if (retcode != 0)
2347 			CLIENT_FPRINTF(stderr,
2348 				gettext("recover: file_move(%s, %s) failed\n"),
2349 				DOMAINNAME_BACK, DOMAINNAME);
2350 	}
2351 
2352 	retcode = rmdir(LDAP_RESTORE_DIR);
2353 	if (retcode != 0) {
2354 		CLIENT_FPRINTF(stderr,
2355 			gettext("Error removing \"%s\" directory.\n"),
2356 			LDAP_RESTORE_DIR);
2357 	}
2358 
2359 	return (CLIENT_SUCCESS);
2360 }
2361 
2362 /*
2363  * try to save the current state of this machine.
2364  * this just overwrites any old saved configration files.
2365  *
2366  * This function should only be called after network services have been stopped.
2367  *
2368  * Returns 0 on successful save
2369  * Otherwise returns -1
2370  */
2371 static int
2372 file_backup(void)
2373 {
2374 	struct stat buf;
2375 	int domain_stat, conf_stat, ldap_stat;
2376 	int nis_stat, yp_stat, restore_stat;
2377 	int retcode, namelen, ret;
2378 	char yp_dir[BUFSIZ], yp_dir_back[BUFSIZ];
2379 	char name[BUFSIZ];
2380 	char *ldap_conf_file, *ldap_cred_file;
2381 	char ldap_file_back[BUFSIZE], ldap_cred_back[BUFSIZE];
2382 
2383 	ret = CLIENT_SUCCESS;
2384 	/* If running as Sysid Install become a no-op */
2385 	if (sysid_install == B_TRUE)
2386 		return (CLIENT_SUCCESS);
2387 
2388 	/* If existing backup files, clear for this run */
2389 	restore_stat = stat(LDAP_RESTORE_DIR, &buf);
2390 	if (restore_stat == 0) {
2391 		if (mode_verbose) {
2392 			CLIENT_FPUTS(
2393 				gettext("Removing existing restore "
2394 					"directory\n"),
2395 				stderr);
2396 		}
2397 		(void) system("/bin/rm -fr " LDAP_RESTORE_DIR);
2398 		restore_stat = stat(LDAP_RESTORE_DIR, &buf);
2399 		if (restore_stat == 0) {
2400 			CLIENT_FPRINTF(stderr,
2401 				gettext("Unable to remove backup "
2402 					"directory (%s)\n"),
2403 				LDAP_RESTORE_DIR);
2404 			return (CLIENT_ERR_RESTORE);
2405 		}
2406 	}
2407 
2408 	retcode = mkdir(LDAP_RESTORE_DIR, 0755);
2409 	if (retcode != 0) {
2410 		CLIENT_FPRINTF(stderr,
2411 			gettext("file_backup: Failed to make %s backup "
2412 				"directory. mkdir=%d\n"),
2413 			LDAP_RESTORE_DIR, retcode);
2414 		return (CLIENT_ERR_FAIL);
2415 	}
2416 
2417 	conf_stat = stat(NSSWITCH_CONF, &buf);
2418 	if (mode_verbose)
2419 		CLIENT_FPRINTF(stderr,
2420 			gettext("file_backup: stat(%s)=%d\n"),
2421 			NSSWITCH_CONF, conf_stat);
2422 	if (conf_stat == 0) {
2423 		if (mode_verbose)
2424 			CLIENT_FPRINTF(stderr,
2425 				gettext("file_backup: (%s -> %s)\n"),
2426 				NSSWITCH_CONF, NSSWITCH_BACK);
2427 		retcode = file_move(NSSWITCH_CONF, NSSWITCH_BACK);
2428 		if (retcode != 0) {
2429 			CLIENT_FPRINTF(stderr,
2430 				gettext("file_backup: file_move(%s, %s) failed "
2431 					"with %d\n"),
2432 				NSSWITCH_CONF, NSSWITCH_BACK, retcode);
2433 			ret = CLIENT_ERR_RENAME;
2434 		}
2435 	} else {
2436 		if (mode_verbose)
2437 			CLIENT_FPRINTF(stderr,
2438 				gettext("file_backup: No %s file.\n"),
2439 				NSSWITCH_CONF);
2440 	}
2441 
2442 	domain_stat = stat(DOMAINNAME, &buf);
2443 	if (mode_verbose)
2444 		CLIENT_FPRINTF(stderr,
2445 			gettext("file_backup: stat(%s)=%d\n"),
2446 			DOMAINNAME, domain_stat);
2447 	if ((domain_stat == 0) && (buf.st_size > 0)) {
2448 		if (mode_verbose)
2449 			CLIENT_FPRINTF(stderr,
2450 				gettext("file_backup: (%s -> %s)\n"),
2451 				DOMAINNAME, DOMAINNAME_BACK);
2452 		retcode = file_move(DOMAINNAME, DOMAINNAME_BACK);
2453 		if (retcode != 0) {
2454 			CLIENT_FPRINTF(stderr,
2455 				gettext("file_backup: file_move(%s, %s) failed "
2456 					"with %d\n"),
2457 				DOMAINNAME, DOMAINNAME_BACK, retcode);
2458 			ret = CLIENT_ERR_RENAME;
2459 		}
2460 	} else {
2461 		if (mode_verbose)
2462 			if (domain_stat != 0) {
2463 				CLIENT_FPRINTF(stderr,
2464 					gettext("file_backup: No %s file.\n"),
2465 					DOMAINNAME);
2466 			} else {
2467 				CLIENT_FPRINTF(stderr,
2468 					gettext("file_backup: Empty %s "
2469 								"file.\n"),
2470 					DOMAINNAME);
2471 			}
2472 	}
2473 
2474 	nis_stat = stat(NIS_COLDSTART, &buf);
2475 	if (mode_verbose)
2476 		CLIENT_FPRINTF(stderr,
2477 			gettext("file_backup: stat(%s)=%d\n"),
2478 			NIS_COLDSTART, nis_stat);
2479 	if (nis_stat == 0) {
2480 		if (mode_verbose)
2481 			CLIENT_FPRINTF(stderr,
2482 				gettext("file_backup: (%s -> %s)\n"),
2483 				NIS_COLDSTART, NIS_COLDSTART_BACK);
2484 		retcode = file_move(NIS_COLDSTART, NIS_COLDSTART_BACK);
2485 		if (retcode != 0) {
2486 			CLIENT_FPRINTF(stderr,
2487 				gettext("file_backup: file_move(%s, %s) failed "
2488 					"with %d\n"),
2489 				NIS_COLDSTART, NIS_COLDSTART_BACK, retcode);
2490 			ret = CLIENT_ERR_RENAME;
2491 		}
2492 	} else {
2493 		if (mode_verbose)
2494 			CLIENT_FPRINTF(stderr,
2495 				gettext("file_backup: No %s file.\n"),
2496 				NIS_COLDSTART);
2497 	}
2498 
2499 	namelen = BUFSIZ;
2500 	(void) sysinfo(SI_SRPC_DOMAIN, &(name[0]), namelen);
2501 	namelen = strlen(name);
2502 
2503 	if (mode_verbose)
2504 		CLIENT_FPRINTF(stderr,
2505 			gettext("file_backup: nis domain is \"%s\"\n"),
2506 			(namelen > 0) ? name : "EMPTY");
2507 	/* check for domain name if not set cannot save NIS(YP) state */
2508 	if (namelen > 0) {
2509 		/* moving /var/yp/binding will cause ypbind to core dump */
2510 		(void) strlcpy(yp_dir, YP_BIND_DIR "/", BUFSIZE);
2511 		(void) strlcat(yp_dir, name, BUFSIZE);
2512 		yp_stat = stat(yp_dir, &buf);
2513 		if (mode_verbose)
2514 			CLIENT_FPRINTF(stderr,
2515 				gettext("file_backup: stat(%s)=%d\n"),
2516 				yp_dir, yp_stat);
2517 		if (yp_stat == 0) {
2518 			(void) strlcpy(yp_dir_back, LDAP_RESTORE_DIR "/",
2519 				BUFSIZE);
2520 			(void) strlcat(yp_dir_back, name, BUFSIZE);
2521 			if (mode_verbose)
2522 				CLIENT_FPRINTF(stderr,
2523 					gettext("file_backup: (%s -> %s)\n"),
2524 					yp_dir, yp_dir_back);
2525 			retcode = file_move(yp_dir, yp_dir_back);
2526 			if (retcode != 0) {
2527 				CLIENT_FPRINTF(stderr,
2528 					gettext("file_backup: file_move(%s, %s)"
2529 						" failed with %d\n"),
2530 					yp_dir, yp_dir_back, retcode);
2531 				ret = CLIENT_ERR_RENAME;
2532 			}
2533 		} else {
2534 			if (mode_verbose)
2535 				CLIENT_FPRINTF(stderr,
2536 					gettext("file_backup: No %s "
2537 						"directory.\n"), yp_dir);
2538 		}
2539 	}
2540 
2541 
2542 	/* point to file name, not path delim (/) */
2543 	ldap_conf_file = strrchr(NSCONFIGFILE, '/') + 1;
2544 	ldap_cred_file = strrchr(NSCREDFILE, '/') + 1;
2545 
2546 	ldap_stat = stat(NSCONFIGFILE, &buf);
2547 	if (mode_verbose)
2548 		CLIENT_FPRINTF(stderr,
2549 			gettext("file_backup: stat(%s)=%d\n"),
2550 			NSCONFIGFILE, ldap_stat);
2551 	if (ldap_stat == 0) {
2552 		(void) strlcpy(ldap_file_back, LDAP_RESTORE_DIR "/", BUFSIZE);
2553 		(void) strlcat(ldap_file_back, ldap_conf_file, BUFSIZE);
2554 		if (mode_verbose)
2555 			CLIENT_FPRINTF(stderr,
2556 				gettext("file_backup: (%s -> %s)\n"),
2557 				NSCONFIGFILE, ldap_file_back);
2558 		retcode = file_move(NSCONFIGFILE, ldap_file_back);
2559 		if (retcode != 0) {
2560 			CLIENT_FPRINTF(stderr,
2561 				gettext("file_backup: file_move(%s, %s) failed "
2562 					"with %d\n"),
2563 				NSCONFIGFILE, ldap_file_back, retcode);
2564 			ret = CLIENT_ERR_RENAME;
2565 		}
2566 
2567 		(void) strlcpy(ldap_cred_back, LDAP_RESTORE_DIR "/", BUFSIZE);
2568 		(void) strlcat(ldap_cred_back, ldap_cred_file, BUFSIZE);
2569 		if (mode_verbose)
2570 			CLIENT_FPRINTF(stderr,
2571 				gettext("file_backup: (%s -> %s)\n"),
2572 				NSCREDFILE, ldap_cred_back);
2573 		retcode = file_move(NSCREDFILE, ldap_cred_back);
2574 		if (retcode != 0) {
2575 			CLIENT_FPRINTF(stderr,
2576 				gettext("file_backup: file_move(%s, %s) failed "
2577 					"with %d\n"),
2578 				NSCREDFILE, ldap_cred_back, retcode);
2579 			ret = CLIENT_ERR_RENAME;
2580 		}
2581 	} else {
2582 		if (mode_verbose)
2583 			CLIENT_FPRINTF(stderr,
2584 				gettext("file_backup: No %s file.\n"),
2585 				NSCONFIGFILE);
2586 	}
2587 
2588 	return (ret);
2589 }
2590 
2591 /*
2592  * mod_backup()
2593  *
2594  * This function is used to temporily backup the LDAP client files in /var/ldap
2595  * that the "mod" operation needs to update.  If an error occurs then the
2596  * function mod_recover() can be invoke to recover the unmodified files.
2597  */
2598 static int
2599 mod_backup(void)
2600 {
2601 	int rc;
2602 	int retcode = CLIENT_SUCCESS;
2603 
2604 	rc = system(CMD_CP " " NSCONFIGFILE " " NSCONFIGFILE ".mod");
2605 	retcode += rc;
2606 	if (mode_verbose)
2607 		CLIENT_FPRINTF(stderr,
2608 		    gettext("mod_backup: backup %s for %s\n"),
2609 		    rc ? "failed" : "successful", NSCONFIGFILE);
2610 
2611 	rc = system(CMD_CP " " NSCREDFILE " " NSCREDFILE ".mod");
2612 	retcode += rc;
2613 	if (mode_verbose)
2614 		CLIENT_FPRINTF(stderr,
2615 		    gettext("mod_backup: backup %s for %s\n"),
2616 		    rc ? "failed" : "successful", NSCREDFILE);
2617 
2618 	rc = system(CMD_CP " " DOMAINNAME " " DOMAINNAME ".mod");
2619 	retcode += rc;
2620 	if (mode_verbose)
2621 		CLIENT_FPRINTF(stderr,
2622 		    gettext("mod_backup: backup %s for %s\n"),
2623 		    rc ? "failed" : "successful", DOMAINNAME);
2624 
2625 	if (retcode != CLIENT_SUCCESS)
2626 		retcode = CLIENT_ERR_RENAME;
2627 	return (retcode);
2628 }
2629 
2630 /*
2631  * mod_recover()
2632  *
2633  * This function is used to recover the temporily backed up files by
2634  * the mod_backup() function if an error occurs during the "mod"
2635  * operation.
2636  */
2637 static int
2638 mod_recover(void)
2639 {
2640 	int rc;
2641 	int retcode = CLIENT_SUCCESS;
2642 
2643 	rc = system(CMD_MV " " NSCONFIGFILE ".mod " NSCONFIGFILE);
2644 	retcode += rc;
2645 	if (mode_verbose)
2646 		CLIENT_FPRINTF(stderr,
2647 		    gettext("mod_recover: recovery %s for %s\n"),
2648 		    rc ? "failed" : "successful", NSCONFIGFILE);
2649 
2650 	rc = system(CMD_MV " " NSCREDFILE ".mod " NSCREDFILE);
2651 	retcode += rc;
2652 	if (mode_verbose)
2653 		CLIENT_FPRINTF(stderr,
2654 		    gettext("mod_recover: recovery %s for %s\n"),
2655 		    rc ? "failed" : "successful", NSCREDFILE);
2656 
2657 	rc = system(CMD_MV " " DOMAINNAME ".mod " DOMAINNAME);
2658 	retcode += rc;
2659 	if (mode_verbose)
2660 		CLIENT_FPRINTF(stderr,
2661 		    gettext("mod_recover: recovery %s for %s\n"),
2662 		    rc ? "failed" : "successful", DOMAINNAME);
2663 
2664 	if (retcode != CLIENT_SUCCESS)
2665 		retcode = CLIENT_ERR_RENAME;
2666 	return (retcode);
2667 }
2668 
2669 /*
2670  * mod_cleanup()
2671  *
2672  * This function removes the .mod files in /var/ldap.
2673  */
2674 static void
2675 mod_cleanup(void)
2676 {
2677 	(void) system(CMD_RM " " NSCONFIGFILE ".mod " TO_DEV_NULL);
2678 	(void) system(CMD_RM " " NSCREDFILE ".mod " TO_DEV_NULL);
2679 	(void) system(CMD_RM " " DOMAINNAME ".mod " TO_DEV_NULL);
2680 }
2681 
2682 #define	MAX_DN_ARRAY 100
2683 #define	LDAP_NAMINGCONTEXTS	"namingcontexts"
2684 
2685 static char *
2686 findBaseDN(char *server)
2687 {
2688 	int ret;
2689 	ns_ldap_entry_t *entry;
2690 	ns_ldap_result_t *resultp;
2691 	ns_ldap_error_t *errorp = NULL;
2692 	char filter[BUFSIZ], *rootDN[MAX_DN_ARRAY], *nisBaseDN;
2693 	char *attribute[] = { LDAP_NAMINGCONTEXTS, NULL };
2694 	int root_cnt, found_cxt;
2695 	int i, j, k, retcode;
2696 
2697 	if (mode_verbose)
2698 		CLIENT_FPUTS(gettext("findBaseDN: begins\n"), stderr);
2699 
2700 	if (dname == NULL)
2701 		return (NULL);
2702 
2703 	if (is_service(LDAP_FMRI, SCF_STATE_STRING_ONLINE)) {
2704 		gStartLdap = START_RESET; /* reset flag for err cases */
2705 		if (mode_verbose)
2706 			CLIENT_FPUTS(gettext("findBaseDN: Stopping ldap\n"),
2707 								stderr);
2708 		ret = disable_service(LDAP_FMRI, B_TRUE);
2709 		if (ret != 0) {
2710 			CLIENT_FPRINTF(stderr, gettext("findBaseDN: Stopping "
2711 					"ldap failed with (%d)\n"), ret);
2712 			return (NULL);
2713 		}
2714 		(void) unlink(LDAP_CACHE_LOG);
2715 	} else {
2716 		if (mode_verbose)
2717 			CLIENT_FPUTS(gettext("findBaseDN: ldap not running\n"),
2718 			    stderr);
2719 	}
2720 
2721 	if (mode_verbose)
2722 		CLIENT_FPUTS(
2723 			gettext("findBaseDN: calling "
2724 				"__ns_ldap_default_config()\n"),
2725 			stderr);
2726 	__ns_ldap_default_config();
2727 
2728 	retcode = __ns_ldap_setParam(NS_LDAP_SERVERS_P,
2729 				(void *)server, &errorp);
2730 	if (retcode != NS_LDAP_SUCCESS) {
2731 		goto findDN_err_exit;
2732 	}
2733 
2734 	retcode = __ns_ldap_setParam(NS_LDAP_AUTH_P,
2735 			(void *)"NS_LDAP_AUTH_NONE", &errorp);
2736 	if (retcode != NS_LDAP_SUCCESS) {
2737 		goto findDN_err_exit;
2738 	}
2739 
2740 	retcode = __ns_ldap_setParam(NS_LDAP_TRANSPORT_SEC_P,
2741 			(void *)"NS_LDAP_SEC_NONE", &errorp);
2742 	if (retcode != NS_LDAP_SUCCESS) {
2743 		goto findDN_err_exit;
2744 	}
2745 
2746 	retcode = __ns_ldap_setParam(NS_LDAP_SEARCH_BASEDN_P,
2747 			(void *)"", &errorp);
2748 	if (retcode != NS_LDAP_SUCCESS) {
2749 		goto findDN_err_exit;
2750 	}
2751 
2752 	retcode = __ns_ldap_setParam(NS_LDAP_SEARCH_SCOPE_P,
2753 			(void *)"NS_LDAP_SCOPE_BASE", &errorp);
2754 	if (retcode != NS_LDAP_SUCCESS) {
2755 		goto findDN_err_exit;
2756 	}
2757 
2758 	(void) strcpy(&filter[0], "(objectclass=*)");
2759 
2760 	ret = __ns_ldap_list(NULL, filter, NULL, (const char **)attribute,
2761 				NULL, 0, &resultp, &errorp, NULL, NULL);
2762 	if (NULL == resultp) {
2763 		if (mode_verbose)
2764 			CLIENT_FPUTS(
2765 				gettext("__ns_ldap_list return NULL resultp\n"),
2766 				stderr);
2767 
2768 		goto findDN_err_exit;
2769 	}
2770 
2771 	for (i = 0; i < MAX_DN_ARRAY; i++)
2772 		rootDN[i] = NULL;
2773 	root_cnt = 0;
2774 	entry = resultp->entry;
2775 	for (i = 0; i < resultp->entries_count; i++) {
2776 	    for (j = 0; j < entry->attr_count; j++) {
2777 		char *cp;
2778 
2779 		cp = entry->attr_pair[j]->attrname;
2780 		if (0 != j) {
2781 		    for (k = 0; entry->attr_pair[j]->attrvalue[k]; k++)
2782 			if (0 == strcasecmp(cp, LDAP_NAMINGCONTEXTS)) {
2783 			    if (NULL == rootDN[root_cnt])
2784 				rootDN[root_cnt++] = strdup(entry->attr_pair[j]
2785 							->attrvalue[k]);
2786 				if (rootDN[root_cnt-1] == NULL) {
2787 					root_cnt--;
2788 					CLIENT_FPUTS(gettext("Memory "
2789 						"allocation error.\n"), stderr);
2790 			/*
2791 			 * fall through and let processing happen on the
2792 			 * rootDNs found to this point.  Most likely
2793 			 * things will fall apart if we are out of memory!
2794 			 */
2795 					break;
2796 				}
2797 			}
2798 		}
2799 	    }
2800 	    entry = entry->next;
2801 	}
2802 	(void) __ns_ldap_freeResult(&resultp);
2803 	if (mode_verbose)
2804 		CLIENT_FPRINTF(stderr,
2805 			gettext("found %d namingcontexts\n"), root_cnt);
2806 	if (root_cnt == 0) {
2807 		CLIENT_FPUTS(gettext("Cannot find the rootDN\n"), stderr);
2808 		goto findDN_err_exit;
2809 	}
2810 	found_cxt = -1;
2811 	for (i = 0; i < root_cnt; i++) {
2812 		retcode = __ns_ldap_setParam(NS_LDAP_SEARCH_BASEDN_P,
2813 						(void *)rootDN[i], &errorp);
2814 		if (NS_LDAP_SUCCESS != retcode) {
2815 			CLIENT_FPUTS(
2816 				gettext("Error setting param "
2817 					"NS_LDAP_SEARCH_BASEDN_P\n"), stderr);
2818 			goto findDN_err_exit;
2819 		}
2820 		retcode = __ns_ldap_setParam(NS_LDAP_SEARCH_SCOPE_P,
2821 				(void *)"NS_LDAP_SCOPE_SUBTREE", &errorp);
2822 		if (NS_LDAP_SUCCESS != retcode) {
2823 			CLIENT_FPUTS(
2824 				gettext("Error setting param "
2825 					"NS_LDAP_SEARCH_SCOPE_P\n"),
2826 				stderr);
2827 			goto findDN_err_exit;
2828 		}
2829 		(void) snprintf(&filter[0], BUFSIZ,
2830 			"(&(objectclass=nisDomainObject)(nisdomain=%s))",
2831 			dname);
2832 		if (mode_verbose) {
2833 		    CLIENT_FPRINTF(stderr,
2834 			gettext("findBaseDN: __ns_ldap_list(NULL, \"%s\"\n"),
2835 			filter);
2836 		    CLIENT_FPRINTF(stderr,
2837 			gettext("rootDN[%d] %s\n"), i, rootDN[i]);
2838 		}
2839 		ret = __ns_ldap_list(NULL, filter, NULL, (const char **)NULL,
2840 					NULL, 0, &resultp, &errorp, NULL, NULL);
2841 		if (ret == NS_LDAP_SUCCESS) {
2842 			found_cxt = i;
2843 			break;
2844 		} else {
2845 		    if (mode_verbose)
2846 			CLIENT_FPRINTF(stderr,
2847 				gettext("NOTFOUND:Could not find the "
2848 					"nisDomainObject for DN %s\n"),
2849 				rootDN[i]);
2850 		}
2851 	}
2852 	if (-1 == found_cxt) {
2853 		if (mode_verbose)
2854 			CLIENT_FPUTS(gettext("found_cxt = -1\n"), stderr);
2855 		goto findDN_err_exit;
2856 	}
2857 	if (resultp == NULL) {
2858 		CLIENT_FPUTS(gettext("resultp is NULL\n"), stderr);
2859 		goto findDN_err_exit;
2860 	}
2861 	entry = resultp->entry;
2862 	if (entry == NULL) {
2863 		CLIENT_FPUTS(gettext("entry is NULL\n"), stderr);
2864 		goto findDN_err_exit;
2865 	}
2866 
2867 	nisBaseDN = strdup(entry->attr_pair[0]->attrvalue[0]);
2868 
2869 	(void) __ns_ldap_freeResult(&resultp);
2870 
2871 	if (mode_verbose)
2872 		CLIENT_FPRINTF(stderr,
2873 			gettext("found baseDN %s for domain %s\n"),
2874 			nisBaseDN ? nisBaseDN : "NULL", dname);
2875 
2876 	return (nisBaseDN);
2877 
2878 findDN_err_exit:
2879 	if (mode_verbose) {
2880 		CLIENT_FPUTS(gettext("findBaseDN: Err exit\n"), stderr);
2881 	}
2882 	if (NULL != errorp) {
2883 		CLIENT_FPRINTF(stderr, gettext("\t%s\n"), errorp->message);
2884 		(void) __ns_ldap_freeError(&errorp);
2885 	}
2886 	return (NULL);
2887 }
2888 
2889 static multival_t *
2890 multival_new()
2891 {
2892 	multival_t *hold;
2893 
2894 	hold = calloc(1, sizeof (multival_t));
2895 	if (hold == NULL) {
2896 		CLIENT_FPUTS(
2897 			gettext("multival_new: Memory allocation error\n"),
2898 			stderr);
2899 	}
2900 	return (hold);	/* NULL -> error */
2901 }
2902 
2903 static int
2904 multival_add(multival_t *list, char *opt)
2905 {
2906 	if (opt == NULL) {
2907 		CLIENT_FPUTS(
2908 			gettext("Empty value passed to multival_add\n"),
2909 			stderr);
2910 		return (CLIENT_ERR_FAIL);
2911 	}
2912 
2913 	if (list->count == 0) {
2914 		list->optlist = (char **)malloc(sizeof (char **));
2915 	} else {
2916 		list->optlist = (char **)realloc(list->optlist,
2917 			(list->count + 1) * sizeof (char **));
2918 	}
2919 
2920 	if (list->optlist == NULL) {
2921 		CLIENT_FPUTS(gettext("Error allocating memory\n"), stderr);
2922 		return (CLIENT_ERR_MEMORY);	/* 0 is success */
2923 	}
2924 
2925 	list->optlist[list->count] = opt;
2926 	list->count++;
2927 
2928 	return (CLIENT_SUCCESS);
2929 }
2930 
2931 static void
2932 multival_free(multival_t *list)
2933 {
2934 	if (list == NULL)
2935 		return;
2936 
2937 	if (list->optlist != NULL)
2938 		free(list->optlist);
2939 	free(list);
2940 }
2941 
2942 static clientopts_t *
2943 clientopts_new()
2944 {
2945 	clientopts_t *hold;
2946 
2947 	hold = calloc(1, sizeof (clientopts_t));
2948 	if (NULL == hold) {
2949 		CLIENT_FPUTS(gettext("Error allocating memory for "
2950 				"clientopts structure\n"), stderr);
2951 		return (hold);	/* NULL -> error */
2952 	}
2953 
2954 	hold->serviceAuthenticationMethod = multival_new();
2955 	if (NULL == hold->serviceAuthenticationMethod) {
2956 		CLIENT_FPUTS(gettext("Error allocating memory for "
2957 				"serviceAuthenticationMethod\n"), stderr);
2958 		free(hold);
2959 		return (NULL);	/* NULL -> error */
2960 	}
2961 
2962 	hold->serviceCredentialLevel = multival_new();
2963 	if (NULL == hold->serviceCredentialLevel) {
2964 		CLIENT_FPUTS(gettext("Error allocating memory for "
2965 				"serviceCredentialLevel\n"), stderr);
2966 		multival_free(hold->serviceAuthenticationMethod);
2967 		free(hold);
2968 		return (NULL);	/* NULL -> error */
2969 	}
2970 
2971 	hold->objectclassMap = multival_new();
2972 	if (NULL == hold->objectclassMap) {
2973 		CLIENT_FPUTS(gettext("Error allocating memory for "
2974 				"objectclassMap\n"), stderr);
2975 		multival_free(hold->serviceAuthenticationMethod);
2976 		multival_free(hold->serviceCredentialLevel);
2977 		free(hold);
2978 		return (NULL);	/* NULL -> error */
2979 	}
2980 
2981 	hold->attributeMap = multival_new();
2982 	if (NULL == hold->attributeMap) {
2983 		CLIENT_FPUTS(gettext("Error allocating memory for "
2984 				"attributeMap\n"), stderr);
2985 		multival_free(hold->serviceAuthenticationMethod);
2986 		multival_free(hold->serviceCredentialLevel);
2987 		multival_free(hold->objectclassMap);
2988 		free(hold);
2989 		return (NULL);	/* NULL -> error */
2990 	}
2991 
2992 	hold->serviceSearchDescriptor = multival_new();
2993 	if (NULL == hold->serviceSearchDescriptor) {
2994 		CLIENT_FPUTS(gettext("Error allocating memory for "
2995 				"serviceSearchDescriptor\n"), stderr);
2996 		multival_free(hold->serviceAuthenticationMethod);
2997 		multival_free(hold->serviceCredentialLevel);
2998 		multival_free(hold->objectclassMap);
2999 		multival_free(hold->attributeMap);
3000 		free(hold);
3001 		return (NULL);	/* NULL -> error */
3002 	}
3003 
3004 	return (hold);
3005 }
3006 
3007 static void
3008 clientopts_free(clientopts_t *list)
3009 {
3010 	if (NULL == list)
3011 		return;
3012 
3013 	multival_free(list->serviceAuthenticationMethod);
3014 	multival_free(list->serviceCredentialLevel);
3015 	multival_free(list->objectclassMap);
3016 	multival_free(list->attributeMap);
3017 	multival_free(list->serviceSearchDescriptor);
3018 
3019 	free(list);
3020 
3021 }
3022 
3023 static void
3024 multival_list(char *opt, multival_t *list)
3025 {
3026 	int i;
3027 
3028 	if (list->count == 0)
3029 		return;
3030 
3031 	(void) puts(opt);
3032 	for (i = 0; i < list->count; i++) {
3033 		(void) printf("\t\targ[%d]: %s\n", i, list->optlist[i]);
3034 	}
3035 }
3036 
3037 /* return the number of arguments specified in the command line */
3038 static int
3039 num_args(clientopts_t *list)
3040 {
3041 	int arg_count = 0;
3042 
3043 	arg_count += list->authenticationMethod ? 1 : 0;
3044 	arg_count += list->serviceAuthenticationMethod->count;
3045 	arg_count += list->defaultSearchBase ? 1 : 0;
3046 	arg_count += list->credentialLevel ? 1 : 0;
3047 	arg_count += list->serviceCredentialLevel->count;
3048 	arg_count += list->domainName ? 1 : 0;
3049 	arg_count += list->proxyDN ? 1 : 0;
3050 	arg_count += list->profileTTL ? 1 : 0;
3051 	arg_count += list->objectclassMap->count;
3052 	arg_count += list->searchTimeLimit ? 1 : 0;
3053 	arg_count += list->preferredServerList ? 1 : 0;
3054 	arg_count += list->profileName ? 1 : 0;
3055 	arg_count += list->followReferrals ? 1 : 0;
3056 	arg_count += list->attributeMap->count;
3057 	arg_count += list->defaultSearchScope ? 1 : 0;
3058 	arg_count += list->serviceSearchDescriptor->count;
3059 	arg_count += list->bindTimeLimit ? 1 : 0;
3060 	arg_count += list->proxyPassword ? 1 : 0;
3061 	arg_count += list->defaultServerList ? 1 : 0;
3062 	arg_count += list->certificatePath ? 1 : 0;
3063 
3064 	return (arg_count);
3065 }
3066 
3067 #define	CLIENT_PRINT(opt, str) if (str) \
3068 		(void) printf("%s%s\n", (opt), (str))
3069 
3070 static void
3071 dumpargs(clientopts_t *list)
3072 {
3073 	CLIENT_PRINT("\tauthenticationMethod: ", list->authenticationMethod);
3074 	multival_list("\tserviceAuthenticationMethod: ",
3075 		list->serviceAuthenticationMethod);
3076 	CLIENT_PRINT("\tdefaultSearchBase: ", list->defaultSearchBase);
3077 	CLIENT_PRINT("\tcredentialLevel: ", list->credentialLevel);
3078 	multival_list("\tserviceCredentialLevel: ",
3079 		list->serviceCredentialLevel);
3080 	CLIENT_PRINT("\tdomainName: ", list->domainName);
3081 	CLIENT_PRINT("\tproxyDN: ", list->proxyDN);
3082 	CLIENT_PRINT("\tprofileTTL: ", list->profileTTL);
3083 	multival_list("\tobjectclassMap: ", list->objectclassMap);
3084 	CLIENT_PRINT("\tsearchTimeLimit: ", list->searchTimeLimit);
3085 	CLIENT_PRINT("\tpreferredServerList: ", list->preferredServerList);
3086 	CLIENT_PRINT("\tprofileName: ", list->profileName);
3087 	CLIENT_PRINT("\tfollowReferrals: ", list->followReferrals);
3088 	multival_list("\tattributeMap: ", list->attributeMap);
3089 	CLIENT_PRINT("\tdefaultSearchScope: ", list->defaultSearchScope);
3090 	multival_list("\tserviceSearchDescriptor: ",
3091 		list->serviceSearchDescriptor);
3092 	CLIENT_PRINT("\tbindTimeLimit: ", list->bindTimeLimit);
3093 	CLIENT_PRINT("\tproxyPassword: ", list->proxyPassword);
3094 	CLIENT_PRINT("\tdefaultServerList: ", list->defaultServerList);
3095 	CLIENT_PRINT("\tcertificatePath: ", list->certificatePath);
3096 }
3097 
3098 
3099 /* These definitions are only used in parseParam() below. */
3100 struct param {
3101 	char	*name;
3102 	int	index;
3103 };
3104 
3105 static struct param paramArray[] = {
3106 	{"proxyDN", NS_LDAP_BINDDN_P},
3107 	{"proxyPassword", NS_LDAP_BINDPASSWD_P},
3108 	{"defaultServerList", NS_LDAP_SERVERS_P},
3109 	{"defaultSearchBase", NS_LDAP_SEARCH_BASEDN_P},
3110 	{"authenticationMethod", NS_LDAP_AUTH_P},
3111 	{"followReferrals", NS_LDAP_SEARCH_REF_P},
3112 	{"profileTTL", NS_LDAP_CACHETTL_P},
3113 	{"certificatePath", NS_LDAP_HOST_CERTPATH_P},
3114 	{"defaultSearchScope", NS_LDAP_SEARCH_SCOPE_P},
3115 	{"bindTimeLimit", NS_LDAP_BIND_TIME_P},
3116 	{"searchTimeLimit", NS_LDAP_SEARCH_TIME_P},
3117 	{"preferredServerList", NS_LDAP_SERVER_PREF_P},
3118 	{"profileName", NS_LDAP_PROFILE_P},
3119 	{"credentialLevel", NS_LDAP_CREDENTIAL_LEVEL_P},
3120 	{"serviceSearchDescriptor", NS_LDAP_SERVICE_SEARCH_DESC_P},
3121 	{"attributeMap", NS_LDAP_ATTRIBUTEMAP_P},
3122 	{"objectclassMap", NS_LDAP_OBJECTCLASSMAP_P},
3123 	{"serviceAuthenticationMethod", NS_LDAP_SERVICE_AUTH_METHOD_P},
3124 	{"serviceCredentialLevel", NS_LDAP_SERVICE_CRED_LEVEL_P},
3125 	{"domainName", LOCAL_DOMAIN_P},
3126 	{NULL, 0}
3127 };
3128 
3129 static int
3130 parseParam(char *param, char **paramVal)
3131 {
3132 	char *val = NULL;
3133 	int counter;
3134 
3135 	if (mode_verbose) {
3136 		CLIENT_FPRINTF(stderr, gettext("Parsing %s\n"), param);
3137 	}
3138 
3139 	val = strchr(param, '=');
3140 	if (val == NULL) {
3141 		CLIENT_FPUTS(
3142 			gettext("Didn\'t find \'=\' character in string\n"),
3143 			stderr);
3144 		paramVal = NULL;
3145 		return (CLIENT_ERR_PARSE);
3146 	}
3147 
3148 	*val = '\0';
3149 
3150 	for (counter = 0; paramArray[counter].name != NULL; counter++) {
3151 		if (strcasecmp(paramArray[counter].name, param) == 0) {
3152 			*paramVal = val+1;
3153 			*val = '=';	/* restore original param */
3154 			return (paramArray[counter].index);
3155 		}
3156 	}
3157 
3158 	/* Not found */
3159 	*val = '=';	/* restore original param */
3160 	*paramVal = NULL;
3161 	return (CLIENT_ERR_PARSE);
3162 }
3163 
3164 /*
3165  * The following macro checks if an option has already been specified
3166  * and errs out with usage if so
3167  */
3168 #define	CLIENT_OPT_CHECK(opt, optarg)	\
3169 if (optarg) {			\
3170 	CLIENT_FPUTS(gettext("Invalid use of option\n"), stderr);	\
3171 	usage();		\
3172 	clientopts_free(optlist); \
3173 	return (CLIENT_ERR_FAIL);		\
3174 }
3175 
3176 static int
3177 clientSetParam(clientopts_t *optlist, int paramFlag, char *attrVal)
3178 {
3179 	int retcode = 0;
3180 	int counter;
3181 
3182 
3183 	switch (paramFlag) {
3184 	case NS_LDAP_AUTH_P:
3185 		CLIENT_OPT_CHECK(paramFlag, optlist->authenticationMethod);
3186 		optlist->authenticationMethod = attrVal;
3187 		break;
3188 
3189 	case NS_LDAP_SERVICE_AUTH_METHOD_P:	/* multiple allowed */
3190 		retcode = multival_add(optlist->serviceAuthenticationMethod,
3191 				attrVal);
3192 		if (retcode != CLIENT_SUCCESS) {
3193 			CLIENT_FPRINTF(stderr,
3194 				gettext("Error processing attrVal %s\n"),
3195 				attrVal?attrVal:"NULL");
3196 			usage();
3197 			clientopts_free(optlist);
3198 			return (CLIENT_ERR_FAIL);
3199 		}
3200 		break;
3201 
3202 	case NS_LDAP_SEARCH_BASEDN_P:
3203 		CLIENT_OPT_CHECK(paramFlag, optlist->defaultSearchBase);
3204 		optlist->defaultSearchBase = attrVal;
3205 		break;
3206 
3207 	case NS_LDAP_CREDENTIAL_LEVEL_P:
3208 		CLIENT_OPT_CHECK(paramFlag, optlist->credentialLevel);
3209 		optlist->credentialLevel = attrVal;
3210 		break;
3211 
3212 	case NS_LDAP_SERVICE_CRED_LEVEL_P:	/* multiple allowed */
3213 		retcode = multival_add(optlist->serviceCredentialLevel,
3214 				attrVal);
3215 		if (retcode != CLIENT_SUCCESS) {
3216 			CLIENT_FPRINTF(stderr,
3217 				gettext("Error processing attrVal %s\n"),
3218 				attrVal?attrVal:"NULL");
3219 			usage();
3220 			clientopts_free(optlist);
3221 			return (CLIENT_ERR_FAIL);
3222 		}
3223 		break;
3224 
3225 	case LOCAL_DOMAIN_P:
3226 		CLIENT_OPT_CHECK(paramFlag, optlist->domainName);
3227 		optlist->domainName = attrVal;
3228 		dname = optlist->domainName;
3229 		break;
3230 
3231 	case NS_LDAP_BINDDN_P:
3232 		CLIENT_OPT_CHECK(paramFlag, optlist->proxyDN);
3233 		optlist->proxyDN = attrVal;
3234 		break;
3235 
3236 	case NS_LDAP_CACHETTL_P:
3237 		CLIENT_OPT_CHECK(paramFlag, optlist->profileTTL);
3238 		optlist->profileTTL = attrVal;
3239 		break;
3240 
3241 	case NS_LDAP_OBJECTCLASSMAP_P:	/* multiple allowed */
3242 		retcode = multival_add(optlist->objectclassMap, attrVal);
3243 		if (retcode != CLIENT_SUCCESS) {
3244 			CLIENT_FPRINTF(stderr,
3245 				gettext("Error processing attrVal %s\n"),
3246 				attrVal?attrVal:"NULL");
3247 			usage();
3248 			clientopts_free(optlist);
3249 			return (CLIENT_ERR_FAIL);
3250 		}
3251 		break;
3252 
3253 	case NS_LDAP_SEARCH_TIME_P:
3254 		CLIENT_OPT_CHECK(paramFlag, optlist->searchTimeLimit);
3255 		optlist->searchTimeLimit = attrVal;
3256 		break;
3257 
3258 	case NS_LDAP_SERVER_PREF_P:
3259 		CLIENT_OPT_CHECK(paramFlag, optlist->preferredServerList);
3260 		optlist->preferredServerList = attrVal;
3261 		/* replace ',' chars with ' ' for proper syntax */
3262 		for (counter = 0;
3263 			counter < strlen(optlist->preferredServerList);
3264 			counter++) {
3265 
3266 			if (optlist->preferredServerList[counter] == ',')
3267 				optlist->preferredServerList[counter] = ' ';
3268 		}
3269 		break;
3270 
3271 	case NS_LDAP_PROFILE_P:
3272 		CLIENT_OPT_CHECK(paramFlag, optlist->profileName);
3273 		optlist->profileName = attrVal;
3274 		break;
3275 
3276 	case NS_LDAP_SEARCH_REF_P:
3277 		CLIENT_OPT_CHECK(paramFlag, optlist->followReferrals);
3278 		if (0 == strcasecmp(attrVal, "followref"))
3279 			optlist->followReferrals = "TRUE";
3280 		else if (0 == strcasecmp(attrVal, "noref"))
3281 			optlist->followReferrals = "FALSE";
3282 		else
3283 			optlist->followReferrals = attrVal;
3284 		break;
3285 
3286 	case NS_LDAP_ATTRIBUTEMAP_P:	/* multiple allowed */
3287 		retcode = multival_add(optlist->attributeMap, attrVal);
3288 		if (retcode != CLIENT_SUCCESS) {
3289 			CLIENT_FPRINTF(stderr,
3290 				gettext("Error processing attrVal %s\n"),
3291 				attrVal?attrVal:"NULL");
3292 			usage();
3293 			clientopts_free(optlist);
3294 			return (CLIENT_ERR_FAIL);
3295 		}
3296 		break;
3297 
3298 	case NS_LDAP_SEARCH_SCOPE_P:
3299 		CLIENT_OPT_CHECK(paramFlag, optlist->defaultSearchScope);
3300 		optlist->defaultSearchScope = attrVal;
3301 		break;
3302 
3303 	case NS_LDAP_SERVICE_SEARCH_DESC_P:	/* multiple allowed */
3304 		retcode = multival_add(optlist->serviceSearchDescriptor,
3305 				attrVal);
3306 		if (retcode != CLIENT_SUCCESS) {
3307 			CLIENT_FPRINTF(stderr,
3308 				gettext("Error processing attrVal %s\n"),
3309 				attrVal?attrVal:"NULL");
3310 			usage();
3311 			clientopts_free(optlist);
3312 			return (CLIENT_ERR_FAIL);
3313 		}
3314 		break;
3315 
3316 	case NS_LDAP_BIND_TIME_P:
3317 		CLIENT_OPT_CHECK(paramFlag, optlist->bindTimeLimit);
3318 		optlist->bindTimeLimit = attrVal;
3319 		break;
3320 
3321 	case NS_LDAP_BINDPASSWD_P:
3322 		CLIENT_OPT_CHECK(paramFlag, optlist->proxyPassword);
3323 		optlist->proxyPassword = attrVal;
3324 		break;
3325 
3326 	case NS_LDAP_HOST_CERTPATH_P:
3327 		CLIENT_OPT_CHECK(paramFlag, optlist->certificatePath);
3328 		optlist->certificatePath = attrVal;
3329 		break;
3330 
3331 	case NS_LDAP_SERVERS_P:
3332 		CLIENT_OPT_CHECK(paramFlag, optlist->defaultServerList);
3333 		optlist->defaultServerList = attrVal;
3334 		break;
3335 
3336 	default:
3337 		usage();
3338 		return (CLIENT_ERR_FAIL);
3339 		/* break;  lint doesn't like break before end of switch */
3340 	}
3341 
3342 	return (retcode);
3343 }
3344 
3345 /*
3346  * file_move() - Used to move a config file (backup/restore).
3347  *
3348  * This function uses a system() call with /bin/mv to handle the
3349  * case where the backup directory (/var) is on a different file
3350  * system than the config file (typically /etc).
3351  */
3352 static int
3353 file_move(const char *from, const char *to)
3354 {
3355 	int retcode;
3356 	char mvCommand[] = CMD_MV;
3357 	char cmd_buffer[(2 * MAXPATHLEN) + sizeof (mvCommand) + 3];
3358 
3359 	(void) snprintf(cmd_buffer, sizeof (cmd_buffer), "%s %s %s",
3360 					mvCommand, from, to);
3361 
3362 	/*
3363 	 * This function should only be used internally to move
3364 	 * system files to/from the backup directory.  For security
3365 	 * reasons (this is run as root), don't use this function
3366 	 * with arguments passed into the program.
3367 	 */
3368 	retcode = system(cmd_buffer);
3369 
3370 	return (retcode);
3371 }
3372 
3373 
3374 static boolean_t
3375 has_port(const char *server)
3376 {
3377 	const char	*s;
3378 	const char	*end;
3379 
3380 	/*
3381 	 * Don't check that address is legal - only determine
3382 	 * if there is a port specified - works for both ipv4 and ipv6
3383 	 */
3384 
3385 	while (server != NULL) {
3386 		end = strchr(server, ',');
3387 		if (end == NULL)
3388 			s = server + strlen(server);
3389 		else {
3390 			s = end;
3391 			end = end + 1;
3392 		}
3393 
3394 		while (s >= server) {
3395 			if (*s == ']')
3396 				break;
3397 			else if (*s == ':')
3398 				return (B_TRUE);
3399 			s--;
3400 		}
3401 		server = end;
3402 	}
3403 	return (B_FALSE);
3404 }
3405 
3406 
3407 /*
3408  * Check to see if configured to use tls and some server has a port number
3409  * configured. The goal is to help prevent users from configuring impossible
3410  * profiles
3411  */
3412 
3413 static boolean_t
3414 is_config_ok(const clientopts_t *list, boolean_t get_config)
3415 {
3416 	boolean_t	has_tls = B_FALSE;
3417 	boolean_t	is_ok = B_TRUE;
3418 	multival_t	*m_val;
3419 	int		i, j, len;
3420 	const char	*begin;
3421 	const char	*end;
3422 	ns_auth_t	**authMethod;
3423 	char		**servers;
3424 	char		**sam;
3425 	ns_ldap_error_t	*errorp = NULL;
3426 	int		rc;
3427 
3428 	if (list->authenticationMethod != NULL) {
3429 		begin = list->authenticationMethod;
3430 		len = strlen(begin) - 3;
3431 		for (i = 0; i < len; i++)
3432 			if (strncasecmp(begin + i, "tls:", 4) == 0)
3433 				break;
3434 		has_tls = i < len;
3435 	} else if (get_config) {
3436 		rc = __ns_ldap_getParam(NS_LDAP_AUTH_P,
3437 			(void ***)&authMethod, &errorp);
3438 		if (rc == NS_LDAP_SUCCESS && authMethod != NULL) {
3439 			for (i = 0; authMethod[i] != NULL && !has_tls; i++)
3440 			    has_tls = authMethod[i]->type == NS_LDAP_AUTH_TLS;
3441 			(void) __ns_ldap_freeParam((void ***) &authMethod);
3442 		}
3443 		if (errorp != NULL)
3444 			(void) __ns_ldap_freeError(&errorp);
3445 		errorp = NULL;
3446 	}
3447 
3448 	m_val = list->serviceAuthenticationMethod;
3449 	if (!has_tls && m_val != NULL) {
3450 		for (j = 0; j < m_val->count && !has_tls; j++) {
3451 			begin = m_val->optlist[j];
3452 			/* skip over service tag */
3453 			if (begin != NULL)
3454 				begin = strchr(begin, ':');
3455 			if (begin == NULL)
3456 				continue;
3457 			len = strlen(begin) - 3;
3458 			for (i = 0; i < len; i++)
3459 				if (strncasecmp(begin + i, "tls:", 4) == 0)
3460 					break;
3461 			has_tls = i < len;
3462 		}
3463 	}
3464 	if (!has_tls && get_config) {
3465 		rc = __ns_ldap_getParam(NS_LDAP_SERVICE_AUTH_METHOD_P,
3466 			(void ***)&sam, &errorp);
3467 		if (rc == NS_LDAP_SUCCESS && sam != NULL) {
3468 		    for (i = 0; sam[i] != NULL && !has_tls; i++) {
3469 			if (m_val != NULL) {
3470 			    /* check to see if a new service is replacing */
3471 			    for (j = 0; j < m_val->count; j++) {
3472 				begin = m_val->optlist[j];
3473 				if (begin == NULL)
3474 					continue;
3475 				end = strchr(begin, ':');
3476 				if (end == NULL)
3477 					continue;
3478 				len = end - begin + 1;
3479 				if (strncasecmp(sam[i], begin, len) == 0)
3480 					break;
3481 			    }
3482 			    if (j != m_val->count)
3483 				continue;
3484 			}
3485 			begin = sam[i];
3486 			/* skip over service tag */
3487 			if (begin != NULL)
3488 				begin = strchr(begin, ':');
3489 			if (begin != NULL) {
3490 			    len = strlen(begin) - 3;
3491 			    for (i = 0; i < len; i++)
3492 				if (strncasecmp(begin + i, "tls:", 4) == 0)
3493 					break;
3494 			    has_tls = i < len;
3495 			}
3496 		    }
3497 		    (void) __ns_ldap_freeParam((void ***) &sam);
3498 		}
3499 		if (errorp != NULL)
3500 			(void) __ns_ldap_freeError(&errorp);
3501 		errorp = NULL;
3502 	}
3503 
3504 	if (has_tls) {
3505 		/*
3506 		 * Don't check that address is legal - only determine
3507 		 * if there is a port specified
3508 		 */
3509 		if (list->defaultServerList != NULL)
3510 			is_ok = !has_port(list->defaultServerList);
3511 		else if (get_config && is_ok) {
3512 			rc = __ns_ldap_getParam(NS_LDAP_SERVERS_P,
3513 				(void ***) &servers, &errorp);
3514 			if (rc == NS_LDAP_SUCCESS && servers != NULL) {
3515 				for (i = 0; servers[i] != NULL && is_ok; i++)
3516 					is_ok = !has_port(servers[i]);
3517 				(void) __ns_ldap_freeParam((void ***) &servers);
3518 			}
3519 		}
3520 		if (errorp != NULL)
3521 			(void) __ns_ldap_freeError(&errorp);
3522 		errorp = NULL;
3523 
3524 		if (is_ok)
3525 			is_ok = !has_port(list->preferredServerList);
3526 		else if (get_config && is_ok) {
3527 			rc = __ns_ldap_getParam(NS_LDAP_SERVER_PREF_P,
3528 				(void ***) &servers, &errorp);
3529 			if (rc == NS_LDAP_SUCCESS && servers != NULL) {
3530 				for (i = 0; servers[i] != NULL && is_ok; i++)
3531 					is_ok = !has_port(servers[i]);
3532 				(void) __ns_ldap_freeParam((void ***) &servers);
3533 			}
3534 			if (errorp != NULL)
3535 				(void) __ns_ldap_freeError(&errorp);
3536 		}
3537 	}
3538 
3539 	return (is_ok);
3540 }
3541 
3542 
3543 /*
3544  * Manipulate the service as instructed by "dowhat"
3545  */
3546 static int
3547 do_service(const char *fmri, boolean_t waitflag, int dowhat,
3548 		const char *state) {
3549 
3550 	int		status;
3551 	boolean_t	is_maint;
3552 	const char	*what = gettext("not set");
3553 	useconds_t	max;
3554 
3555 	/* Check if we are in maintenance */
3556 	is_maint = is_service(fmri, SCF_STATE_STRING_MAINT);
3557 
3558 	switch (dowhat) {
3559 	case START_SERVICE:
3560 		what = gettext("start");
3561 		status = smf_enable_instance(fmri,
3562 			(sysid_install == B_TRUE)?SMF_TEMPORARY:0);
3563 		break;
3564 	case STOP_SERVICE:
3565 		what = gettext("stop");
3566 		status = smf_disable_instance(fmri,
3567 			(sysid_install == B_TRUE)?SMF_TEMPORARY:0);
3568 		break;
3569 	case RESTART_SERVICE:
3570 		what = gettext("restart");
3571 		status = smf_restart_instance(fmri);
3572 		break;
3573 	default:
3574 		/* coding error; will not happen */
3575 		assert(0);
3576 	}
3577 
3578 	/*
3579 	 * If the service was previously in maintenance then we need to
3580 	 * clear it immediately.  The "dowhat" action will set the
3581 	 * enabled property of the service as intended by the caller while
3582 	 * clear will actually cause it to be enabled/disabled.
3583 	 * We assume that the caller has called us after taking some
3584 	 * recovery action. Even if it's not the case, we don't lose
3585 	 * anything.
3586 	 */
3587 	if (status == 0 && is_maint == B_TRUE) {
3588 		if (mode_verbose)
3589 			CLIENT_FPRINTF(stderr,
3590 				"%s: %s... %s\n",
3591 				what,
3592 				fmri,
3593 				gettext("restoring from maintenance state"));
3594 		status = smf_restore_instance(fmri);
3595 	}
3596 
3597 	if (status == 0) {
3598 		/* Check if we need to wait ? */
3599 		if (waitflag == B_FALSE) {
3600 			if (mode_verbose)
3601 				CLIENT_FPRINTF(stderr,
3602 					"%s: %s... %s\n",
3603 					what,
3604 					fmri,
3605 					gettext("success"));
3606 			return (CLIENT_SUCCESS);
3607 		}
3608 
3609 		/* Otherwise wait for max seconds (from the manifest) */
3610 		max = get_timeout_value(dowhat, fmri, DEFAULT_TIMEOUT);
3611 		status = wait_till(fmri, state, max, what, !is_maint);
3612 		if (status == CLIENT_SUCCESS)
3613 			return (CLIENT_SUCCESS);
3614 		/* For error fall through for corrective action */
3615 	} else {
3616 		/* Well, service failed ... */
3617 		if (mode_verbose)
3618 			CLIENT_FPRINTF(stderr, "%s: %s... %s: %s\n",
3619 				what,
3620 				fmri,
3621 				gettext("failed"),
3622 				scf_strerror(scf_error()));
3623 		status = CLIENT_ERR_FAIL;
3624 		/* For error fall through for corrective action */
3625 	}
3626 
3627 	/*
3628 	 * If service is still offline after start/restart, then transitioning
3629 	 * failed and guess is restarter failed to apply the timeout as well.
3630 	 * So instead of leaving it offline, let's just disable it until we have
3631 	 * some other mechanism available from smf to handle such situation.
3632 	 */
3633 	if (dowhat != STOP_SERVICE)
3634 		if (is_service(fmri, SCF_STATE_STRING_OFFLINE)) {
3635 			if (mode_verbose)
3636 				CLIENT_FPRINTF(stderr,
3637 					"%s: %s... %s\n",
3638 					what,
3639 					fmri,
3640 					gettext("offline to disable"));
3641 			(void) disable_service(fmri, waitflag);
3642 		}
3643 
3644 	return (status);
3645 }
3646 
3647 
3648 /*
3649  * Wait for "max" usecs for the service described by "fmri" to change
3650  * to "state". If check_maint is true then return immediately if
3651  * service goes into maintenance
3652  */
3653 static int
3654 wait_till(const char *fmri, const char *state, useconds_t max,
3655 		const char *what, boolean_t check_maint) {
3656 	char *st;
3657 	useconds_t usecs = INIT_WAIT_USECS;
3658 
3659 	for (; max > 0; max -= usecs) {
3660 		/* incremental wait */
3661 		usecs *= 2;
3662 		usecs = (usecs > max)?max:usecs;
3663 		if (mode_verbose)
3664 			CLIENT_FPRINTF(stderr,
3665 				"%s: %s %u %s\n",
3666 				what, gettext("sleep"), usecs,
3667 				gettext("microseconds"));
3668 		(void) usleep(usecs);
3669 
3670 		/* Check state after the wait */
3671 		if ((st = smf_get_state(fmri)) != NULL) {
3672 			if (strcmp(st, state) == 0) {
3673 				if (mode_verbose)
3674 					CLIENT_FPRINTF(stderr,
3675 						"%s: %s... %s\n",
3676 						what,
3677 						fmri,
3678 						gettext("success"));
3679 				free(st);
3680 				return (CLIENT_SUCCESS);
3681 			}
3682 
3683 			/*
3684 			 * If service has gone into maintenance then
3685 			 * we will time out anyway, so we are better
3686 			 * off returning now
3687 			 */
3688 			if (check_maint &&
3689 				strcmp(st, SCF_STATE_STRING_MAINT) == 0) {
3690 				if (mode_verbose)
3691 					CLIENT_FPRINTF(stderr,
3692 						"%s: %s... %s\n",
3693 						what,
3694 						fmri,
3695 						gettext("maintenance"));
3696 				free(st);
3697 				return (CLIENT_ERR_MAINTENANCE);
3698 			}
3699 			free(st);
3700 		} else {
3701 			if (mode_verbose)
3702 				CLIENT_FPRINTF(stderr,
3703 						"%s: %s... %s: %s\n",
3704 						what,
3705 						fmri,
3706 						gettext("failed"),
3707 						scf_strerror(scf_error()));
3708 			return (CLIENT_ERR_FAIL);
3709 		}
3710 	}
3711 
3712 	/* Timed out waiting */
3713 	if (mode_verbose)
3714 		CLIENT_FPRINTF(stderr,
3715 			"%s: %s... %s\n",
3716 			what,
3717 			fmri,
3718 			gettext("timed out"));
3719 	return (CLIENT_ERR_TIMEDOUT);
3720 }
3721 
3722 
3723 static boolean_t
3724 is_service(const char *fmri, const char *state) {
3725 	char		*st;
3726 	boolean_t	result = B_FALSE;
3727 
3728 	if ((st = smf_get_state(fmri)) != NULL) {
3729 		if (strcmp(st, state) == 0)
3730 			result = B_TRUE;
3731 		free(st);
3732 	}
3733 	return (result);
3734 }
3735 
3736 
3737 /*
3738  *
3739  * get_timeout_val : returns the timeout value set in fmri manifest
3740  * 	inputs	: action(start/stop)
3741  *	fmri(defined fmri string)
3742  *	Returns default if error, the timeout val otherwise
3743  *
3744  */
3745 
3746 static useconds_t
3747 get_timeout_value(int dowhat, const char *fmri, useconds_t default_val)
3748 {
3749 	scf_simple_prop_t	*sp = NULL;
3750 	uint64_t		*cp = NULL;
3751 	int			timeout = default_val/1000000;
3752 	char			*action = NULL;
3753 	const char		*actionstr = NULL;
3754 
3755 	switch (dowhat)  {
3756 		case START_SERVICE:
3757 		case RESTART_SERVICE:
3758 				action = "start";
3759 				actionstr = gettext("start");
3760 				break;
3761 		case STOP_SERVICE:
3762 				action = "stop";
3763 				actionstr = gettext("stop");
3764 				break;
3765 		default:
3766 			assert(0);
3767 	}
3768 
3769 
3770 	sp = scf_simple_prop_get(NULL, fmri, action, SCF_PROPERTY_TIMEOUT);
3771 	if (sp == NULL) {
3772 		if (mode_verbose)
3773 			CLIENT_FPRINTF(stderr, "%s: %s... %s: %s\n",
3774 				actionstr,
3775 				fmri,
3776 				gettext("failed to retrieve timeout property"),
3777 				scf_strerror(scf_error()));
3778 		return (default_val);
3779 	}
3780 
3781 	cp = scf_simple_prop_next_count(sp);
3782 	if (cp == NULL) {
3783 		if (mode_verbose)
3784 			CLIENT_FPRINTF(stderr, "%s: %s... %s: %s\n",
3785 				actionstr,
3786 				fmri,
3787 				gettext("failed to retrieve timeout value"),
3788 				scf_strerror(scf_error()));
3789 		scf_simple_prop_free(sp);
3790 		return (default_val);
3791 	}
3792 
3793 	if (*cp != 0)
3794 		timeout = *cp;
3795 	scf_simple_prop_free(sp);
3796 	return (timeout * 1000000);
3797 }
3798