diff options
author | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
---|---|---|
committer | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
commit | 7c478bd95313f5f23a4c958a745db2134aa03244 (patch) | |
tree | c871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/lib/libipsecutil/common/algs.c | |
download | illumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz |
OpenSolaris Launch
Diffstat (limited to 'usr/src/lib/libipsecutil/common/algs.c')
-rw-r--r-- | usr/src/lib/libipsecutil/common/algs.c | 813 |
1 files changed, 813 insertions, 0 deletions
diff --git a/usr/src/lib/libipsecutil/common/algs.c b/usr/src/lib/libipsecutil/common/algs.c new file mode 100644 index 0000000000..9027fc23d4 --- /dev/null +++ b/usr/src/lib/libipsecutil/common/algs.c @@ -0,0 +1,813 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/stat.h> +#include <ipsec_util.h> +#include <stdlib.h> +#include <strings.h> +#include <netdb.h> +#include <fcntl.h> +#include <unistd.h> +#include <libintl.h> +#include <errno.h> + +static char *preamble = +"# /etc/inet/ipsecalgs output from ipsecalgs(1m)\n" +"#\n" +"# DO NOT EDIT OR PARSE THIS FILE!\n" +"#\n" +"# Use the ipsecalgs(1m) command to change the contents of this file.\n" +"\n"; + +#define CFG_PERMS S_IRUSR | S_IRGRP | S_IROTH /* Perms 0444. */ +#define CFG_OWNER 0 /* root */ +#define CFG_GROUP 1 /* "other" */ + +/* + * write_new_algfile() helper macros to check for write errors. + */ + +#define FPRINTF_ERR(fcall) if ((fcall) < 0) { \ + rc = LIBIPSEC_ALGS_DIAG_ALGSFILEWRITE; \ + goto bail; \ +} + +#define FPUT_ERR(fcall) if ((fcall) == EOF) { \ + rc = LIBIPSEC_ALGS_DIAG_ALGSFILEWRITE; \ + goto bail; \ +} + +/* + * Helper macros to start and finish a list of entries that were added + * as part of a package installation. + */ + +#define PKG_SEC_START(pkgname, doing_pkg, cur_pkg) { \ + (void) strcpy((cur_pkg), (pkgname)); \ + FPRINTF_ERR(fprintf(f, "%s%s\n", \ + LIBIPSEC_ALGS_LINE_PKGSTART, (cur_pkg))); \ + (doing_pkg) = B_TRUE; \ +} + +#define PKG_SEC_END(doing_pkg, cur_pkg) { \ + if (doing_pkg) { \ + FPRINTF_ERR(fprintf(f, "%s%s\n", \ + LIBIPSEC_ALGS_LINE_PKGEND, (cur_pkg))); \ + (doing_pkg) = B_FALSE; \ + } \ +} + +/* + * Take a zero-terminated int array and print int1,int2...,intN. + * If zero-only, then print a single '0'. + * Returns 0 on success, -1 if an error occurred while writing to + * the specified file. + */ +int +list_ints(FILE *f, int *floater) +{ + boolean_t executed = B_FALSE; + + while (*floater != 0) { + executed = B_TRUE; + if (fprintf(f, "%d", *floater) < 0) + return (-1); + if (*(++floater) != 0) + if (fputc(',', f) == EOF) + return (-1); + } + + if (!executed) + if (fputc('0', f) == EOF) + return (-1); + + return (0); +} + +/* + * If the specified algorithm was defined within a package section, i.e. + * between the lines "# Start <pkgname>" and "# End <pkgname>", returns + * the value of <pkgname>. + */ +static char * +alg_has_pkg(ipsec_proto_t *proto, struct ipsecalgent *alg) +{ + int i; + + if (proto->proto_algs_pkgs == NULL) + return (NULL); + + for (i = 0; i < proto->proto_algs_npkgs; i++) + if (proto->proto_algs_pkgs[i].alg_num == alg->a_alg_num) + return (proto->proto_algs_pkgs[i].pkg_name); + + return (NULL); +} + +/* + * Writes the package start/end delimiters according to the package + * name associated with the current protocol or algorithm, and + * the state of the packaging information already written to the file. + * Called by write_new_algfile(). Returns 0 on success, one of the + * LIBIPSEC_DIAG codes on failure. + */ +static int +pkg_section(FILE *f, char *pkg_name, boolean_t *doing_pkg, char *cur_pkg) +{ + int rc = 0; + + if (pkg_name != NULL) { + /* protocol or algorithm is associated with a package */ + if (!*doing_pkg) { + /* start of a new package section */ + PKG_SEC_START(pkg_name, *doing_pkg, cur_pkg); + } else { + /* already in a package section */ + if (strcmp(pkg_name, cur_pkg) != 0) { + /* different package name */ + PKG_SEC_END(*doing_pkg, cur_pkg); + PKG_SEC_START(pkg_name, *doing_pkg, cur_pkg); + } + } + } else if (*doing_pkg) { + /* in a package section when the entry isn't */ + PKG_SEC_END(*doing_pkg, cur_pkg); + } +bail: + return (rc); +} + +/* + * Given a list of protocols and number, write them to a new algorithm file. + * This function takes num_protos + num_protos * dois-per-alg operations. + * Also free the protocol structure. + * + * Note that no locking spans the read/update/write phases that can be + * used by callers of this routine. This could cause this function to suffer + * from the "lost update" problem. Since updates to the IPsec protocols + * and algorithm tables are very infrequent, this should not be a issue in + * practice. + */ +static int +write_new_algfile(ipsec_proto_t *protos, int num_protos) +{ + FILE *f; + int fd, i, j, k; + int rc = 0; + struct ipsecalgent *alg; + char cur_pkg[1024]; + boolean_t doing_pkg = B_FALSE; + char *alg_pkg; + char *tmp_name_template = INET_IPSECALGSPATH "ipsecalgsXXXXXX"; + char *tmp_name; + + /* + * In order to avoid potentially corrupting the configuration + * file on file system failure, write the new configuration info + * to a temporary file which is then renamed to the configuration + * file (INET_IPSECALGSFILE.) + */ + tmp_name = mktemp(tmp_name_template); + + fd = open(tmp_name, O_WRONLY|O_CREAT|O_EXCL, CFG_PERMS); + if (fd == -1) { + rc = LIBIPSEC_ALGS_DIAG_ALGSFILEOPEN; + goto bail; + } + + f = fdopen(fd, "w"); + if (f == NULL) { + (void) close(fd); + rc = LIBIPSEC_ALGS_DIAG_ALGSFILEFDOPEN; + goto bail; + } + + FPUT_ERR(fputs(preamble, f)); + + /* Write protocol entries. */ + for (i = 0; i < num_protos; i++) { + + /* add package section delimiters if needed */ + rc = pkg_section(f, protos[i].proto_pkg, &doing_pkg, cur_pkg); + if (rc != 0) + goto bail; + + FPRINTF_ERR(fprintf(f, "%s%d|%s|", + LIBIPSEC_ALGS_LINE_PROTO, + protos[i].proto_num, protos[i].proto_name)); + switch (protos[i].proto_exec_mode) { + case LIBIPSEC_ALGS_EXEC_SYNC: + FPRINTF_ERR(fprintf(f, "sync\n")); + break; + case LIBIPSEC_ALGS_EXEC_ASYNC: + FPRINTF_ERR(fprintf(f, "async\n")); + break; + } + } + + /* terminate the package section for the protocols if needed */ + PKG_SEC_END(doing_pkg, cur_pkg); + + FPUT_ERR(fputs("\n", f)); + + /* Write algorithm entries. */ + + for (i = 0; i < num_protos; i++) { + for (j = 0; j < protos[i].proto_numalgs; j++) { + alg = protos[i].proto_algs[j]; + + /* add package section delimiters if needed */ + alg_pkg = alg_has_pkg(&protos[i], alg); + rc = pkg_section(f, alg_pkg, &doing_pkg, cur_pkg); + if (rc != 0) + goto bail; + + /* protocol and algorithm numbers */ + FPRINTF_ERR(fprintf(f, "%s%d|%d|", + LIBIPSEC_ALGS_LINE_ALG, + alg->a_proto_num, alg->a_alg_num)); + + /* algorithm names */ + for (k = 0; alg->a_names[k] != NULL; k++) { + FPRINTF_ERR(fprintf(f, "%s", alg->a_names[k])); + if (alg->a_names[k+1] != NULL) + FPRINTF_ERR(fprintf(f, ",")); + } + + /* mechanism name */ + FPRINTF_ERR(fprintf(f, "|%s|", alg->a_mech_name)); + + /* key sizes */ + if (alg->a_key_increment == 0) { + /* key sizes defined by enumeration */ + if (list_ints(f, alg->a_key_sizes) == -1) { + rc = LIBIPSEC_ALGS_DIAG_ALGSFILEWRITE; + goto bail; + } + } else { + /* key sizes defined by range */ + FPRINTF_ERR(fprintf(f, "%d/%d-%d,%d", + alg->a_key_sizes[0], alg->a_key_sizes[1], + alg->a_key_sizes[2], alg->a_key_increment)); + } + FPUT_ERR(fputc('|', f)); + + /* block sizes */ + if (list_ints(f, alg->a_block_sizes) == -1) { + rc = LIBIPSEC_ALGS_DIAG_ALGSFILEWRITE; + goto bail; + } + FPUT_ERR(fputc('\n', f)); + } + } + + /* terminate the package section for the algorithms if needed */ + PKG_SEC_END(doing_pkg, cur_pkg); + + if (fchmod(fd, CFG_PERMS) == -1) { + rc = LIBIPSEC_ALGS_DIAG_ALGSFILECHMOD; + goto bail; + } + if (fchown(fd, CFG_OWNER, CFG_GROUP) == -1) { + rc = LIBIPSEC_ALGS_DIAG_ALGSFILECHOWN; + goto bail; + } + if (fclose(f) == EOF) { + rc = LIBIPSEC_ALGS_DIAG_ALGSFILECLOSE; + goto bail; + } + + if (rename(tmp_name, INET_IPSECALGSFILE) == -1) + rc = LIBIPSEC_ALGS_DIAG_ALGSFILERENAME; + +bail: + _clean_trash(protos, num_protos); + return (rc); +} + +/* + * Return a pointer to the protocol entry corresponding to the specified + * protocol num proto_num. Also builds the list of currently defined + * protocols. + */ +static ipsec_proto_t * +proto_setup(ipsec_proto_t **protos, int *num_protos, int proto_num, + boolean_t cleanup) +{ + int i; + ipsec_proto_t *current_proto, *ret_proto = NULL; + + _build_internal_algs(protos, num_protos); + + if (*protos == NULL) + return (NULL); + + for (i = 0; i < *num_protos; i++) { + current_proto = (*protos) + i; + if (current_proto->proto_num == proto_num) { + ret_proto = current_proto; + break; + } + } + + if (ret_proto == NULL) { + if (cleanup) + _clean_trash(*protos, *num_protos); + /* else caller wants parsed /etc/inet/ipsecalgs anyway */ + } + + return (ret_proto); +} + +/* + * Delete the first found algorithm of the specified protocol which + * has the same name as the one specified by alg_name. Deletion of + * the entry takes place only if the delete_it flag is set. If an + * entry was found, return B_TRUE, otherwise return B_FALSE. + */ +static boolean_t +delipsecalgbyname_common(const char *name, ipsec_proto_t *proto, + boolean_t delete_it) +{ + int i; + char **name_check; + boolean_t found_match = B_FALSE; + + for (i = 0; i < proto->proto_numalgs; i++) { + if (!found_match) { + for (name_check = + proto->proto_algs[i]->a_names; + *name_check != NULL; name_check++) { + /* + * Can use strcmp because the algorithm names + * are bound. + */ + if (strcmp(*name_check, name) == 0) { + found_match = B_TRUE; + if (!delete_it) + return (found_match); + freeipsecalgent(proto->proto_algs[i]); + break; + } + } + } else { + proto->proto_algs[i - 1] = proto->proto_algs[i]; + } + } + + if (found_match) + proto->proto_numalgs--; + + return (found_match); +} + +/* + * Returns B_TRUE if the specified 0-terminated lists of key or + * block sizes match, B_FALSE otherwise. + */ +static boolean_t +sizes_match(int *a1, int *a2) +{ + int i; + + for (i = 0; (a1[i] != 0) && (a2[i] != 0); i++) { + if (a1[i] != a2[i]) + return (B_FALSE); + } + if ((a1[i] != 0) || (a2[i] != 0)) + return (B_FALSE); + + return (B_TRUE); +} + +/* + * Returns B_TRUE if an _exact_ equivalent of the specified algorithm + * already exists, B_FALSE otherwise. + */ +static boolean_t +ipsecalg_exists(struct ipsecalgent *newbie, ipsec_proto_t *proto) +{ + struct ipsecalgent *curalg; + char **curname, **newbiename; + int i; + boolean_t match; + + for (i = 0; i < proto->proto_numalgs; i++) { + curalg = proto->proto_algs[i]; + + if (curalg->a_alg_num != newbie->a_alg_num) + continue; + + if (curalg->a_key_increment != newbie->a_key_increment) + continue; + + if (strcmp(curalg->a_mech_name, newbie->a_mech_name) != 0) + continue; + + curname = curalg->a_names; + newbiename = newbie->a_names; + match = B_TRUE; + while ((*curname != NULL) && (*newbiename != NULL) && match) { + match = (strcmp(*curname, *newbiename) == 0); + curname++; + newbiename++; + } + if (!match || (*curname != NULL) || (*newbiename != NULL)) + continue; + + if (!sizes_match(curalg->a_block_sizes, newbie->a_block_sizes)) + continue; + + if (!sizes_match(curalg->a_key_sizes, newbie->a_key_sizes)) + continue; + + /* we found an exact match */ + return (B_TRUE); + } + + return (B_FALSE); +} + +/* + * Add a new algorithm to the /etc/inet/ipsecalgs file. Caller must free + * or otherwise address "newbie". + */ +int +addipsecalg(struct ipsecalgent *newbie, uint_t flags) +{ + ipsec_proto_t *protos, *current_proto; + struct ipsecalgent *clone, **holder; + int num_protos, i; + char **name_check; + boolean_t forced_add = (flags & LIBIPSEC_ALGS_ADD_FORCE) != 0; + boolean_t found_match; + + if ((current_proto = proto_setup(&protos, &num_protos, + newbie->a_proto_num, B_TRUE)) == NULL) + return (LIBIPSEC_ALGS_DIAG_UNKN_PROTO); + + /* + * If an algorithm that matches _exactly_ the new algorithm + * already exists, we're done. + */ + if (ipsecalg_exists(newbie, current_proto)) + return (0); + + /* + * We don't allow a new algorithm to be created if one of + * its names is already defined for an existing algorithm, + * unless the operation is forced, in which case existing + * algorithm entries that conflict with the new one are + * deleted. + */ + for (name_check = newbie->a_names; *name_check != NULL; name_check++) { + found_match = delipsecalgbyname_common(*name_check, + current_proto, forced_add); + if (found_match && !forced_add) { + /* + * Duplicate entry found, but the addition was + * not forced. + */ + _clean_trash(protos, num_protos); + return (LIBIPSEC_ALGS_DIAG_ALG_EXISTS); + } + } + + for (i = 0; i < current_proto->proto_numalgs; i++) { + if (current_proto->proto_algs[i]->a_alg_num == + newbie->a_alg_num) { + /* + * An algorithm with the same protocol number + * and algorithm number already exists. Fail + * addition unless the operation is forced. + */ + if (flags & LIBIPSEC_ALGS_ADD_FORCE) { + clone = _duplicate_alg(newbie); + if (clone != NULL) { + freeipsecalgent( + current_proto->proto_algs[i]); + current_proto->proto_algs[i] = clone; + return (write_new_algfile(protos, + num_protos)); + } else { + _clean_trash(protos, num_protos); + return (LIBIPSEC_ALGS_DIAG_NOMEM); + } + } else { + _clean_trash(protos, num_protos); + return (LIBIPSEC_ALGS_DIAG_ALG_EXISTS); + } + } + } + + /* append the new algorithm */ + holder = realloc(current_proto->proto_algs, + sizeof (struct ipsecalgent *) * (i + 1)); + if (holder == NULL) { + _clean_trash(protos, num_protos); + return (LIBIPSEC_ALGS_DIAG_NOMEM); + } + clone = _duplicate_alg(newbie); + if (clone == NULL) { + free(holder); + _clean_trash(protos, num_protos); + return (LIBIPSEC_ALGS_DIAG_NOMEM); + } + current_proto->proto_numalgs++; + current_proto->proto_algs = holder; + current_proto->proto_algs[i] = clone; + return (write_new_algfile(protos, num_protos)); +} + +/* + * Delete an algorithm by name & protocol number from /etc/inet/ipsecalgs. + * Only deletes the first encountered instance. + */ +int +delipsecalgbyname(const char *name, int proto_num) +{ + ipsec_proto_t *protos, *current_proto; + int num_protos; + + if ((current_proto = proto_setup(&protos, &num_protos, proto_num, + B_TRUE)) == NULL) + return (LIBIPSEC_ALGS_DIAG_UNKN_PROTO); + + if (delipsecalgbyname_common(name, current_proto, B_TRUE)) + return (write_new_algfile(protos, num_protos)); + + _clean_trash(protos, num_protos); + return (LIBIPSEC_ALGS_DIAG_UNKN_ALG); +} + +/* + * Delete an algorithm by num + protocol num from /etc/inet/ipsecalgs. + */ +int +delipsecalgbynum(int alg_num, int proto_num) +{ + ipsec_proto_t *protos, *current_proto; + int i, num_protos; + boolean_t found_match = B_FALSE; + + if ((current_proto = proto_setup(&protos, &num_protos, proto_num, + B_TRUE)) == NULL) + return (LIBIPSEC_ALGS_DIAG_UNKN_PROTO); + + for (i = 0; i < current_proto->proto_numalgs; i++) { + if (!found_match) { + if (current_proto->proto_algs[i]->a_alg_num == + alg_num) { + found_match = B_TRUE; + freeipsecalgent(current_proto->proto_algs[i]); + } + } else { + current_proto->proto_algs[i - 1] = + current_proto->proto_algs[i]; + } + } + + if (found_match) { + current_proto->proto_numalgs--; + return (write_new_algfile(protos, num_protos)); + } + + _clean_trash(protos, num_protos); + return (LIBIPSEC_ALGS_DIAG_UNKN_ALG); +} + +/* + * Remove the specified protocol entry from the list of protocols. + */ +static void +delipsecproto_common(ipsec_proto_t *protos, int num_protos, + ipsec_proto_t *proto) +{ + int i; + + /* free protocol storage */ + free(proto->proto_name); + for (i = 0; i < proto->proto_numalgs; i++) + freeipsecalgent(proto->proto_algs[i]); + + /* remove from list of prototocols */ + for (i = (proto - protos + 1); i < num_protos; i++) + protos[i - 1] = protos[i]; +} + +/* + * Add an IPsec protocol to /etc/inet/ipsecalgs. + */ +int +addipsecproto(const char *proto_name, int proto_num, + ipsecalgs_exec_mode_t proto_exec_mode, uint_t flags) +{ + ipsec_proto_t *protos, *current_proto, *new_proto; + int i, num_protos; + + /* + * NOTE:If build_internal_algs returns NULL for any + * reason, we will end up clobbering /etc/inet/ipsecalgs! + */ + + current_proto = proto_setup(&protos, &num_protos, proto_num, B_FALSE); + + /* check for protocol with duplicate id */ + if (current_proto != NULL) { + if ((strcmp(proto_name, current_proto->proto_name) == 0) && + (proto_exec_mode == current_proto->proto_exec_mode)) { + /* + * The current protocol being added matches + * exactly an existing protocol, we're done. + */ + return (0); + } + if (!(flags & LIBIPSEC_ALGS_ADD_FORCE)) + return (LIBIPSEC_ALGS_DIAG_PROTO_EXISTS); + delipsecproto_common(protos, num_protos--, current_proto); + } + + /* check for protocol with duplicate name */ + for (i = 0; i < num_protos; i++) { + if (strcmp(protos[i].proto_name, proto_name) == 0) { + if (!(flags & LIBIPSEC_ALGS_ADD_FORCE)) + return (LIBIPSEC_ALGS_DIAG_PROTO_EXISTS); + delipsecproto_common(protos, num_protos--, &protos[i]); + break; + } + } + + /* add new protocol */ + num_protos++; + new_proto = realloc(protos, num_protos * + sizeof (ipsec_proto_t)); + if (new_proto == NULL) { + _clean_trash(protos, num_protos - 1); + return (LIBIPSEC_ALGS_DIAG_NOMEM); + } + protos = new_proto; + new_proto += (num_protos - 1); + + /* initialize protocol entry */ + new_proto->proto_num = proto_num; + new_proto->proto_numalgs = 0; + new_proto->proto_algs = NULL; + new_proto->proto_name = strdup(proto_name); + if (new_proto->proto_name == NULL) { + _clean_trash(protos, num_protos); + return (LIBIPSEC_ALGS_DIAG_NOMEM); + } + new_proto->proto_pkg = NULL; + new_proto->proto_algs_pkgs = NULL; + new_proto->proto_algs_npkgs = 0; + new_proto->proto_exec_mode = proto_exec_mode; + + return (write_new_algfile(protos, num_protos)); +} + +/* + * Delete an IPsec protocol entry from /etc/inet/ipsecalgs. This also + * nukes the associated algorithms. + */ +int +delipsecprotobynum(int proto_num) +{ + ipsec_proto_t *protos, *current_proto; + int num_protos; + + if ((current_proto = proto_setup(&protos, &num_protos, proto_num, + B_TRUE)) == NULL) + return (LIBIPSEC_ALGS_DIAG_UNKN_PROTO); + + delipsecproto_common(protos, num_protos--, current_proto); + + return (write_new_algfile(protos, num_protos)); +} + +int +delipsecprotobyname(const char *proto_name) +{ + int proto_num; + + proto_num = getipsecprotobyname(proto_name); + if (proto_num == -1) + return (LIBIPSEC_ALGS_DIAG_UNKN_PROTO); + + return (delipsecprotobynum(proto_num)); +} + +/* + * Implement these in libnsl since these are read-only operations. + */ +int * +getipsecprotos(int *nentries) +{ + return (_real_getipsecprotos(nentries)); +} + +int * +getipsecalgs(int *nentries, int proto_num) +{ + return (_real_getipsecalgs(nentries, proto_num)); +} + +const char * +ipsecalgs_diag(int diag) +{ + switch (diag) { + case LIBIPSEC_ALGS_DIAG_ALG_EXISTS: + return (gettext("Algorithm already exists")); + case LIBIPSEC_ALGS_DIAG_PROTO_EXISTS: + return (gettext("Protocol already exists")); + case LIBIPSEC_ALGS_DIAG_UNKN_PROTO: + return (gettext("Unknown protocol")); + case LIBIPSEC_ALGS_DIAG_UNKN_ALG: + return (gettext("Unknown algorithm")); + case LIBIPSEC_ALGS_DIAG_NOMEM: + return (gettext("Out of memory")); + case LIBIPSEC_ALGS_DIAG_ALGSFILEOPEN: + return (gettext("open() failed")); + case LIBIPSEC_ALGS_DIAG_ALGSFILEFDOPEN: + return (gettext("fdopen() failed")); + case LIBIPSEC_ALGS_DIAG_ALGSFILELOCK: + return (gettext("lockf() failed")); + case LIBIPSEC_ALGS_DIAG_ALGSFILERENAME: + return (gettext("rename() failed")); + case LIBIPSEC_ALGS_DIAG_ALGSFILEWRITE: + return (gettext("write to file failed")); + case LIBIPSEC_ALGS_DIAG_ALGSFILECHMOD: + return (gettext("chmod() failed")); + case LIBIPSEC_ALGS_DIAG_ALGSFILECHOWN: + return (gettext("chown() failed")); + case LIBIPSEC_ALGS_DIAG_ALGSFILECLOSE: + return (gettext("close() failed")); + default: + return (gettext("failed")); + } +} + +/* + * Get the execution mode corresponding to the specified protocol. + * Returns 0 on success, one of the LIBIPSEC_ALGS_DIAG_* values on + * failure. + */ +int +ipsecproto_get_exec_mode(int proto_num, ipsecalgs_exec_mode_t *exec_mode) +{ + ipsec_proto_t *protos, *current_proto; + int num_protos; + + if ((current_proto = proto_setup(&protos, &num_protos, proto_num, + B_TRUE)) == NULL) + return (LIBIPSEC_ALGS_DIAG_UNKN_PROTO); + + *exec_mode = current_proto->proto_exec_mode; + + _clean_trash(protos, num_protos); + return (0); +} + +/* + * Set the execution mode of the specified protocol. Returns 0 on success, + * or one of the LIBIPSEC_ALGS_DIAG_* values on failure. + */ +int +ipsecproto_set_exec_mode(int proto_num, ipsecalgs_exec_mode_t exec_mode) +{ + ipsec_proto_t *protos, *current_proto; + int num_protos; + + if ((current_proto = proto_setup(&protos, &num_protos, proto_num, + B_TRUE)) == NULL) + return (LIBIPSEC_ALGS_DIAG_UNKN_PROTO); + + current_proto->proto_exec_mode = exec_mode; + + return (write_new_algfile(protos, num_protos)); +} |