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