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