17c478bd9Sstevel@tonic-gate /*
2159d09a2SMark Phalan  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
37c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate  */
57c478bd9Sstevel@tonic-gate 
67c478bd9Sstevel@tonic-gate 
77c478bd9Sstevel@tonic-gate /*
87c478bd9Sstevel@tonic-gate  * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
97c478bd9Sstevel@tonic-gate  *
107c478bd9Sstevel@tonic-gate  *	Openvision retains the copyright to derivative works of
117c478bd9Sstevel@tonic-gate  *	this source code.  Do *NOT* create a derivative of this
127c478bd9Sstevel@tonic-gate  *	source code before consulting with your legal department.
137c478bd9Sstevel@tonic-gate  *	Do *NOT* integrate *ANY* of this source code into another
147c478bd9Sstevel@tonic-gate  *	product before consulting with your legal department.
157c478bd9Sstevel@tonic-gate  *
167c478bd9Sstevel@tonic-gate  *	For further information, read the top-level Openvision
177c478bd9Sstevel@tonic-gate  *	copyright which is contained in the top-level MIT Kerberos
187c478bd9Sstevel@tonic-gate  *	copyright.
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
217c478bd9Sstevel@tonic-gate  *
227c478bd9Sstevel@tonic-gate  */
237c478bd9Sstevel@tonic-gate 
247c478bd9Sstevel@tonic-gate 
257c478bd9Sstevel@tonic-gate /*
267c478bd9Sstevel@tonic-gate  * Copyright 1993-1994 OpenVision Technologies, Inc., All Rights Reserved.
27*55fea89dSDan Cross  *
28159d09a2SMark Phalan  * $Header$
297c478bd9Sstevel@tonic-gate  *
307c478bd9Sstevel@tonic-gate  *
317c478bd9Sstevel@tonic-gate  */
327c478bd9Sstevel@tonic-gate 
33159d09a2SMark Phalan static char rcsid[] = "$Id: kpasswd.c 17258 2005-06-21 01:36:03Z raeburn $";
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate #include <kadm5/admin.h>
367c478bd9Sstevel@tonic-gate #include <krb5.h>
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate #include "kpasswd_strings.h"
3956a424ccSmp #define string_text error_message
4056a424ccSmp 
4156a424ccSmp #include "kpasswd.h"
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate #include <stdio.h>
447c478bd9Sstevel@tonic-gate #include <pwd.h>
457c478bd9Sstevel@tonic-gate #include <string.h>
467c478bd9Sstevel@tonic-gate #include <libintl.h>
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate extern char *whoami;
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate extern void display_intro_message();
517c478bd9Sstevel@tonic-gate extern long read_old_password();
527c478bd9Sstevel@tonic-gate extern long read_new_password();
537c478bd9Sstevel@tonic-gate 
5456a424ccSmp #define MISC_EXIT_STATUS 6
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate /*
577c478bd9Sstevel@tonic-gate  * Function: kpasswd
587c478bd9Sstevel@tonic-gate  *
597c478bd9Sstevel@tonic-gate  * Purpose: Initialize and call lower level routines to change a password
607c478bd9Sstevel@tonic-gate  *
617c478bd9Sstevel@tonic-gate  * Arguments:
627c478bd9Sstevel@tonic-gate  *
637c478bd9Sstevel@tonic-gate  *	context		(r) krb5_context to use
647c478bd9Sstevel@tonic-gate  *	argc/argv	(r) principal name to use, optional
657c478bd9Sstevel@tonic-gate  *	read_old_password (f) function to read old password
667c478bd9Sstevel@tonic-gate  *	read_new_password (f) function to read new and change password
677c478bd9Sstevel@tonic-gate  *	display_intro_message (f) function to display intro message
687c478bd9Sstevel@tonic-gate  *	whoami		(extern) argv[0]
69*55fea89dSDan Cross  *
707c478bd9Sstevel@tonic-gate  * Returns:
717c478bd9Sstevel@tonic-gate  *                      exit status of 0 for success
727c478bd9Sstevel@tonic-gate  *			1 principal unknown
737c478bd9Sstevel@tonic-gate  *			2 old password wrong
747c478bd9Sstevel@tonic-gate  *			3 cannot initialize admin server session
757c478bd9Sstevel@tonic-gate  *			4 new passwd mismatch or error trying to change pw
767c478bd9Sstevel@tonic-gate  *                      5 password not typed
777c478bd9Sstevel@tonic-gate  *                      6 misc error
787c478bd9Sstevel@tonic-gate  *                      7 incorrect usage
79*55fea89dSDan Cross  *
807c478bd9Sstevel@tonic-gate  * Requires:
817c478bd9Sstevel@tonic-gate  *	Passwords cannot be more than 255 characters long.
82*55fea89dSDan Cross  *
837c478bd9Sstevel@tonic-gate  * Effects:
847c478bd9Sstevel@tonic-gate  *
857c478bd9Sstevel@tonic-gate  * If argc is 2, the password for the principal specified in argv[1]
867c478bd9Sstevel@tonic-gate  * is changed; otherwise, the principal of the default credential
877c478bd9Sstevel@tonic-gate  * cache or username is used.  display_intro_message is called with
887c478bd9Sstevel@tonic-gate  * the arguments KPW_STR_CHANGING_PW_FOR and the principal name.
897c478bd9Sstevel@tonic-gate  * read_old_password is then called to prompt for the old password.
907c478bd9Sstevel@tonic-gate  * The admin system is then initialized, the principal's policy
917c478bd9Sstevel@tonic-gate  * retrieved and explained, if appropriate, and finally
927c478bd9Sstevel@tonic-gate  * read_new_password is called to read the new password and change the
937c478bd9Sstevel@tonic-gate  * principal's password (presumably ovsec_kadm_chpass_principal).
947c478bd9Sstevel@tonic-gate  * admin system is de-initialized before the function returns.
95*55fea89dSDan Cross  *
967c478bd9Sstevel@tonic-gate  * Modifies:
977c478bd9Sstevel@tonic-gate  *
987c478bd9Sstevel@tonic-gate  * Changes the principal's password.
997c478bd9Sstevel@tonic-gate  *
1007c478bd9Sstevel@tonic-gate  */
1017c478bd9Sstevel@tonic-gate int
kpasswd(context,argc,argv)1027c478bd9Sstevel@tonic-gate kpasswd(context, argc, argv)
10356a424ccSmp    krb5_context context;
10456a424ccSmp    int argc;
10556a424ccSmp    char *argv[];
1067c478bd9Sstevel@tonic-gate {
10756a424ccSmp   kadm5_ret_t code;
10856a424ccSmp   krb5_ccache ccache = NULL;
10956a424ccSmp   krb5_principal princ = 0;
11056a424ccSmp   char *princ_str;
11156a424ccSmp   struct passwd *pw = 0;
11256a424ccSmp   unsigned int pwsize;
11356a424ccSmp   char password[255];  /* I don't really like 255 but that's what kinit uses */
11456a424ccSmp   char msg_ret[1024], admin_realm[1024];
11556a424ccSmp   kadm5_principal_ent_rec principal_entry;
11656a424ccSmp   kadm5_policy_ent_rec policy_entry;
11756a424ccSmp   void *server_handle;
11856a424ccSmp   kadm5_config_params params;
11956a424ccSmp   char *cpw_service;
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate 	memset((char *)&params, 0, sizeof (params));
1227c478bd9Sstevel@tonic-gate 	memset(&principal_entry, 0, sizeof (principal_entry));
1237c478bd9Sstevel@tonic-gate 	memset(&policy_entry, 0, sizeof (policy_entry));
1247c478bd9Sstevel@tonic-gate 
12556a424ccSmp   if (argc > 2) {
12656a424ccSmp       com_err(whoami, KPW_STR_USAGE, 0);
12756a424ccSmp       return(7);
12856a424ccSmp       /*NOTREACHED*/
12956a424ccSmp     }
1307c478bd9Sstevel@tonic-gate 
13156a424ccSmp   /************************************
132*55fea89dSDan Cross    *  Get principal name to change    *
13356a424ccSmp    ************************************/
1347c478bd9Sstevel@tonic-gate 
13556a424ccSmp   /* Look on the command line first, followed by the default credential
13656a424ccSmp      cache, followed by defaulting to the Unix user name */
13756a424ccSmp 
13856a424ccSmp   if (argc == 2)
13956a424ccSmp     princ_str = strdup(argv[1]);
14056a424ccSmp   else {
14156a424ccSmp     code = krb5_cc_default(context, &ccache);
14256a424ccSmp     /* If we succeed, find who is in the credential cache */
14356a424ccSmp     if (code == 0) {
14456a424ccSmp       /* Get default principal from cache if one exists */
14556a424ccSmp       code = krb5_cc_get_principal(context, ccache, &princ);
14656a424ccSmp       /* if we got a principal, unparse it, otherwise get out of the if
14756a424ccSmp 	 with an error code */
14856a424ccSmp       (void) krb5_cc_close(context, ccache);
14956a424ccSmp       if (code == 0) {
15056a424ccSmp 	code = krb5_unparse_name(context, princ, &princ_str);
15156a424ccSmp 	if (code != 0) {
15256a424ccSmp 	  com_err(whoami,  code, string_text(KPW_STR_UNPARSE_NAME));
15356a424ccSmp 	  return(MISC_EXIT_STATUS);
1547c478bd9Sstevel@tonic-gate 	}
15556a424ccSmp       }
15656a424ccSmp     }
1577c478bd9Sstevel@tonic-gate 
15856a424ccSmp     /* this is a crock.. we want to compare against */
15956a424ccSmp     /* "KRB5_CC_DOESNOTEXIST" but there is no such error code, and */
16056a424ccSmp     /* both the file and stdio types return FCC_NOFILE.  If there is */
16156a424ccSmp     /* ever another ccache type (or if the error codes are ever */
16256a424ccSmp     /* fixed), this code will have to be updated. */
16356a424ccSmp     if (code && code != KRB5_FCC_NOFILE) {
16456a424ccSmp       com_err(whoami, code, string_text(KPW_STR_WHILE_LOOKING_AT_CC));
16556a424ccSmp       return(MISC_EXIT_STATUS);
16656a424ccSmp     }
1677c478bd9Sstevel@tonic-gate 
16856a424ccSmp     /* if either krb5_cc failed check the passwd file */
16956a424ccSmp     if (code != 0) {
17056a424ccSmp       pw = getpwuid( getuid());
17156a424ccSmp       if (pw == NULL) {
17256a424ccSmp 	com_err(whoami, 0, string_text(KPW_STR_NOT_IN_PASSWD_FILE));
17356a424ccSmp 	return(MISC_EXIT_STATUS);
17456a424ccSmp       }
17556a424ccSmp       princ_str = strdup(pw->pw_name);
17656a424ccSmp     }
177*55fea89dSDan Cross   }
178*55fea89dSDan Cross 
17956a424ccSmp   display_intro_message(string_text(KPW_STR_CHANGING_PW_FOR), princ_str);
1807c478bd9Sstevel@tonic-gate 
18156a424ccSmp   /* Need to get a krb5_principal, unless we started from with one from
18256a424ccSmp      the credential cache */
1837c478bd9Sstevel@tonic-gate 
18456a424ccSmp   if (! princ) {
18556a424ccSmp       code = krb5_parse_name (context, princ_str, &princ);
18656a424ccSmp       if (code != 0) {
18756a424ccSmp 	  com_err(whoami, code, string_text(KPW_STR_PARSE_NAME), princ_str);
18856a424ccSmp 	  free(princ_str);
18956a424ccSmp 	  return(MISC_EXIT_STATUS);
19056a424ccSmp       }
19156a424ccSmp   }
192*55fea89dSDan Cross 
19356a424ccSmp   pwsize = sizeof(password);
19456a424ccSmp   code = read_old_password(context, password, &pwsize);
19556a424ccSmp 
19656a424ccSmp   if (code != 0) {
19756a424ccSmp     memset(password, 0, sizeof(password));
19856a424ccSmp     com_err(whoami, code, string_text(KPW_STR_WHILE_READING_PASSWORD));
19956a424ccSmp     krb5_free_principal(context, princ);
20056a424ccSmp     free(princ_str);
20156a424ccSmp     return(MISC_EXIT_STATUS);
20256a424ccSmp   }
20356a424ccSmp   if (pwsize == 0) {
20456a424ccSmp     memset(password, 0, sizeof(password));
20556a424ccSmp     com_err(whoami, 0, string_text(KPW_STR_NO_PASSWORD_READ));
20656a424ccSmp     krb5_free_principal(context, princ);
20756a424ccSmp     free(princ_str);
20856a424ccSmp     return(5);
20956a424ccSmp   }
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate 	snprintf(admin_realm, sizeof (admin_realm),
2127c478bd9Sstevel@tonic-gate 		krb5_princ_realm(context, princ)->data);
2137c478bd9Sstevel@tonic-gate 	params.mask |= KADM5_CONFIG_REALM;
2147c478bd9Sstevel@tonic-gate 	params.realm = admin_realm;
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate 	if (kadm5_get_cpw_host_srv_name(context, admin_realm, &cpw_service)) {
2187c478bd9Sstevel@tonic-gate 		fprintf(stderr, gettext("%s: unable to get host based "
2197c478bd9Sstevel@tonic-gate 					"service name for realm %s\n"),
2207c478bd9Sstevel@tonic-gate 			whoami, admin_realm);
2217c478bd9Sstevel@tonic-gate 		exit(1);
2227c478bd9Sstevel@tonic-gate 	}
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate 	code = kadm5_init_with_password(princ_str, password, cpw_service,
2257c478bd9Sstevel@tonic-gate 					&params, KADM5_STRUCT_VERSION,
22654925bf6Swillf 					KADM5_API_VERSION_2, NULL,
22754925bf6Swillf 					&server_handle);
2287c478bd9Sstevel@tonic-gate 	free(cpw_service);
2297c478bd9Sstevel@tonic-gate 	if (code != 0) {
2307c478bd9Sstevel@tonic-gate 		if (code == KADM5_BAD_PASSWORD)
2317c478bd9Sstevel@tonic-gate 			com_err(whoami, 0,
2327c478bd9Sstevel@tonic-gate 				string_text(KPW_STR_OLD_PASSWORD_INCORRECT));
2337c478bd9Sstevel@tonic-gate 		else
2347c478bd9Sstevel@tonic-gate 			com_err(whoami, 0,
2357c478bd9Sstevel@tonic-gate 				string_text(KPW_STR_CANT_OPEN_ADMIN_SERVER),
2367c478bd9Sstevel@tonic-gate 				admin_realm,
2377c478bd9Sstevel@tonic-gate 				error_message(code));
2387c478bd9Sstevel@tonic-gate 		krb5_free_principal(context, princ);
2397c478bd9Sstevel@tonic-gate 		free(princ_str);
2407c478bd9Sstevel@tonic-gate 		return ((code == KADM5_BAD_PASSWORD) ? 2 : 3);
2417c478bd9Sstevel@tonic-gate 	}
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate 	/*
2447c478bd9Sstevel@tonic-gate 	 * we can only check the policy if the server speaks
2457c478bd9Sstevel@tonic-gate 	 * RPCSEC_GSS
2467c478bd9Sstevel@tonic-gate 	 */
2477c478bd9Sstevel@tonic-gate 	if (_kadm5_get_kpasswd_protocol(server_handle) == KRB5_CHGPWD_RPCSEC) {
2487c478bd9Sstevel@tonic-gate 		/* Explain policy restrictions on new password if any. */
2497c478bd9Sstevel@tonic-gate 		/*
2507c478bd9Sstevel@tonic-gate 		 * Note: copy of this exists in login
2517c478bd9Sstevel@tonic-gate 		 * (kverify.c/get_verified_in_tkt).
2527c478bd9Sstevel@tonic-gate 		 */
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate 		code = kadm5_get_principal(server_handle, princ,
2557c478bd9Sstevel@tonic-gate 					&principal_entry,
2567c478bd9Sstevel@tonic-gate 					KADM5_PRINCIPAL_NORMAL_MASK);
2577c478bd9Sstevel@tonic-gate 		if (code != 0) {
2587c478bd9Sstevel@tonic-gate 			com_err(whoami, 0,
2597c478bd9Sstevel@tonic-gate 				string_text((code == KADM5_UNK_PRINC)
2607c478bd9Sstevel@tonic-gate 					    ? KPW_STR_PRIN_UNKNOWN :
2617c478bd9Sstevel@tonic-gate 					    KPW_STR_CANT_GET_POLICY_INFO),
2627c478bd9Sstevel@tonic-gate 				princ_str);
2637c478bd9Sstevel@tonic-gate 			krb5_free_principal(context, princ);
2647c478bd9Sstevel@tonic-gate 			free(princ_str);
2657c478bd9Sstevel@tonic-gate 			(void) kadm5_destroy(server_handle);
2667c478bd9Sstevel@tonic-gate 			return ((code == KADM5_UNK_PRINC) ? 1 :
2677c478bd9Sstevel@tonic-gate 				MISC_EXIT_STATUS);
2687c478bd9Sstevel@tonic-gate 		}
2697c478bd9Sstevel@tonic-gate 		if ((principal_entry.aux_attributes & KADM5_POLICY) != 0) {
2707c478bd9Sstevel@tonic-gate 			code = kadm5_get_policy(server_handle,
2717c478bd9Sstevel@tonic-gate 						principal_entry.policy,
2727c478bd9Sstevel@tonic-gate 						&policy_entry);
2737c478bd9Sstevel@tonic-gate 			if (code != 0) {
2747c478bd9Sstevel@tonic-gate 				/*
2757c478bd9Sstevel@tonic-gate 				 * doesn't matter which error comes back,
2767c478bd9Sstevel@tonic-gate 				 * there's no nice recovery or need to
2777c478bd9Sstevel@tonic-gate 				 * differentiate to the user
2787c478bd9Sstevel@tonic-gate 				 */
2797c478bd9Sstevel@tonic-gate 				com_err(whoami, 0,
2807c478bd9Sstevel@tonic-gate 				string_text(KPW_STR_CANT_GET_POLICY_INFO),
2817c478bd9Sstevel@tonic-gate 				princ_str);
2827c478bd9Sstevel@tonic-gate 				(void) kadm5_free_principal_ent(server_handle,
2837c478bd9Sstevel@tonic-gate 							&principal_entry);
2847c478bd9Sstevel@tonic-gate 				krb5_free_principal(context, princ);
2857c478bd9Sstevel@tonic-gate 				free(princ_str);
2867c478bd9Sstevel@tonic-gate 				free(princ_str);
2877c478bd9Sstevel@tonic-gate 				(void) kadm5_destroy(server_handle);
2887c478bd9Sstevel@tonic-gate 				return (MISC_EXIT_STATUS);
2897c478bd9Sstevel@tonic-gate 			}
2907c478bd9Sstevel@tonic-gate 			com_err(whoami, 0,
2917c478bd9Sstevel@tonic-gate 				string_text(KPW_STR_POLICY_EXPLANATION),
2927c478bd9Sstevel@tonic-gate 				princ_str, principal_entry.policy,
2937c478bd9Sstevel@tonic-gate 				policy_entry.pw_min_length,
2947c478bd9Sstevel@tonic-gate 				policy_entry.pw_min_classes);
2957c478bd9Sstevel@tonic-gate 			if (code = kadm5_free_principal_ent(server_handle,
2967c478bd9Sstevel@tonic-gate 						    &principal_entry)) {
2977c478bd9Sstevel@tonic-gate 				(void) kadm5_free_policy_ent(server_handle,
2987c478bd9Sstevel@tonic-gate 							    &policy_entry);
2997c478bd9Sstevel@tonic-gate 				krb5_free_principal(context, princ);
3007c478bd9Sstevel@tonic-gate 				free(princ_str);
3017c478bd9Sstevel@tonic-gate 				com_err(whoami, code,
3027c478bd9Sstevel@tonic-gate 				string_text(KPW_STR_WHILE_FREEING_PRINCIPAL));
3037c478bd9Sstevel@tonic-gate 				(void) kadm5_destroy(server_handle);
3047c478bd9Sstevel@tonic-gate 				return (MISC_EXIT_STATUS);
3057c478bd9Sstevel@tonic-gate 			}
3067c478bd9Sstevel@tonic-gate 			if (code = kadm5_free_policy_ent(server_handle,
3077c478bd9Sstevel@tonic-gate 							&policy_entry)) {
3087c478bd9Sstevel@tonic-gate 				krb5_free_principal(context, princ);
3097c478bd9Sstevel@tonic-gate 				free(princ_str);
3107c478bd9Sstevel@tonic-gate 				com_err(whoami, code,
3117c478bd9Sstevel@tonic-gate 				string_text(KPW_STR_WHILE_FREEING_POLICY));
3127c478bd9Sstevel@tonic-gate 				(void) kadm5_destroy(server_handle);
3137c478bd9Sstevel@tonic-gate 				return (MISC_EXIT_STATUS);
3147c478bd9Sstevel@tonic-gate 			}
3157c478bd9Sstevel@tonic-gate 		} else {
3167c478bd9Sstevel@tonic-gate 			/*
3177c478bd9Sstevel@tonic-gate 			 * kpasswd *COULD* output something here to
3187c478bd9Sstevel@tonic-gate 			 * encourage the choice of good passwords,
3197c478bd9Sstevel@tonic-gate 			 * in the absence of an enforced policy.
3207c478bd9Sstevel@tonic-gate 			 */
3217c478bd9Sstevel@tonic-gate 			if (code = kadm5_free_principal_ent(server_handle,
3227c478bd9Sstevel@tonic-gate 						    &principal_entry)) {
3237c478bd9Sstevel@tonic-gate 				krb5_free_principal(context, princ);
3247c478bd9Sstevel@tonic-gate 				free(princ_str);
3257c478bd9Sstevel@tonic-gate 				com_err(whoami, code,
3267c478bd9Sstevel@tonic-gate 				string_text(KPW_STR_WHILE_FREEING_PRINCIPAL));
3277c478bd9Sstevel@tonic-gate 				(void) kadm5_destroy(server_handle);
3287c478bd9Sstevel@tonic-gate 				return (MISC_EXIT_STATUS);
3297c478bd9Sstevel@tonic-gate 			}
3307c478bd9Sstevel@tonic-gate 		}
3317c478bd9Sstevel@tonic-gate 	} /* if protocol == KRB5_CHGPWD_RPCSEC */
3327c478bd9Sstevel@tonic-gate 
33356a424ccSmp   pwsize = sizeof(password);
33456a424ccSmp   code = read_new_password(server_handle, password, &pwsize, msg_ret, sizeof (msg_ret), princ);
33556a424ccSmp   memset(password, 0, sizeof(password));
3367c478bd9Sstevel@tonic-gate 
33756a424ccSmp   if (code)
33856a424ccSmp     com_err(whoami, 0, msg_ret);
3397c478bd9Sstevel@tonic-gate 
34056a424ccSmp   krb5_free_principal(context, princ);
34156a424ccSmp   free(princ_str);
3427c478bd9Sstevel@tonic-gate 
34356a424ccSmp   (void) kadm5_destroy(server_handle);
344*55fea89dSDan Cross 
34556a424ccSmp   if (code == KRB5_LIBOS_CANTREADPWD)
34656a424ccSmp      return(5);
34756a424ccSmp   else if (code)
34856a424ccSmp      return(4);
34956a424ccSmp   else
35056a424ccSmp      return(0);
3517c478bd9Sstevel@tonic-gate }
352