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 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <ipsec_util.h>
29 #include <stdlib.h>
30 #include <strings.h>
31 #include <netdb.h>
32 #include <fcntl.h>
33 #include <unistd.h>
34 #include <libintl.h>
35 #include <errno.h>
36
37 static char *preamble =
38 "# /etc/inet/ipsecalgs output from ipsecalgs(8)\n"
39 "#\n"
40 "# DO NOT EDIT OR PARSE THIS FILE!\n"
41 "#\n"
42 "# Use the ipsecalgs(8) command to change the contents of this file.\n"
43 "# The algorithm descriptions contained in this file are synchronised to the\n"
44 "# kernel with ipsecalgs -s, the kernel validates the entries at this point."
45 "\n\n"
46 "# PROTO|protocol-id|protocol-name|exec-mode\n"
47 "## NOTE: Some protocol numbers are well-known and defined in <netdb.h>\n\n"
48 "# ALG|protocol-id|alg-id|name,name,...|ef-id| \n"
49 "# {default/}{key,key..}or{key-key,inc}|block_size or MAC-size|\n"
50 "# [parameter,parameter..]|[flags]\n\n"
51 "#\n"
52 "## Note: Parameters and flags only apply to certain algorithms.\n\n";
53
54 #define CFG_PERMS S_IRUSR | S_IRGRP | S_IROTH /* Perms 0444. */
55 #define CFG_OWNER 0 /* root */
56 #define CFG_GROUP 1 /* "other" */
57
58 /*
59 * write_new_algfile() helper macros to check for write errors.
60 */
61
62 #define FPRINTF_ERR(fcall) if ((fcall) < 0) { \
63 rc = LIBIPSEC_ALGS_DIAG_ALGSFILEWRITE; \
64 goto bail; \
65 }
66
67 #define FPUT_ERR(fcall) if ((fcall) == EOF) { \
68 rc = LIBIPSEC_ALGS_DIAG_ALGSFILEWRITE; \
69 goto bail; \
70 }
71
72 /*
73 * Helper macros to start and finish a list of entries that were added
74 * as part of a package installation.
75 */
76
77 #define PKG_SEC_START(pkgname, doing_pkg, cur_pkg) { \
78 (void) strcpy((cur_pkg), (pkgname)); \
79 FPRINTF_ERR(fprintf(f, "%s%s\n", \
80 LIBIPSEC_ALGS_LINE_PKGSTART, (cur_pkg))); \
81 (doing_pkg) = B_TRUE; \
82 }
83
84 #define PKG_SEC_END(doing_pkg, cur_pkg) { \
85 if (doing_pkg) { \
86 FPRINTF_ERR(fprintf(f, "%s%s\n", \
87 LIBIPSEC_ALGS_LINE_PKGEND, (cur_pkg))); \
88 (doing_pkg) = B_FALSE; \
89 } \
90 }
91
92 /*
93 * Take a zero-terminated int array and print int1,int2...,intN.
94 * If zero-only, then print a single '0'.
95 * Returns 0 on success, -1 if an error occurred while writing to
96 * the specified file.
97 */
98 int
list_ints(FILE * f,int * floater)99 list_ints(FILE *f, int *floater)
100 {
101 boolean_t executed = B_FALSE;
102
103 while (*floater != 0) {
104 executed = B_TRUE;
105 if (fprintf(f, "%d", *floater) < 0)
106 return (-1);
107 if (*(++floater) != 0)
108 if (fputc(',', f) == EOF)
109 return (-1);
110 }
111
112 if (!executed)
113 if (fputc('0', f) == EOF)
114 return (-1);
115
116 return (0);
117 }
118
119 /*
120 * If the specified algorithm was defined within a package section, i.e.
121 * between the lines "# Start <pkgname>" and "# End <pkgname>", returns
122 * the value of <pkgname>.
123 */
124 static char *
alg_has_pkg(ipsec_proto_t * proto,struct ipsecalgent * alg)125 alg_has_pkg(ipsec_proto_t *proto, struct ipsecalgent *alg)
126 {
127 int i;
128
129 if (proto->proto_algs_pkgs == NULL)
130 return (NULL);
131
132 for (i = 0; i < proto->proto_algs_npkgs; i++)
133 if (proto->proto_algs_pkgs[i].alg_num == alg->a_alg_num)
134 return (proto->proto_algs_pkgs[i].pkg_name);
135
136 return (NULL);
137 }
138
139 /*
140 * Writes the package start/end delimiters according to the package
141 * name associated with the current protocol or algorithm, and
142 * the state of the packaging information already written to the file.
143 * Called by write_new_algfile(). Returns 0 on success, one of the
144 * LIBIPSEC_DIAG codes on failure.
145 */
146 static int
pkg_section(FILE * f,char * pkg_name,boolean_t * doing_pkg,char * cur_pkg)147 pkg_section(FILE *f, char *pkg_name, boolean_t *doing_pkg, char *cur_pkg)
148 {
149 int rc = 0;
150
151 if (pkg_name != NULL) {
152 /* protocol or algorithm is associated with a package */
153 if (!*doing_pkg) {
154 /* start of a new package section */
155 PKG_SEC_START(pkg_name, *doing_pkg, cur_pkg);
156 } else {
157 /* already in a package section */
158 if (strcmp(pkg_name, cur_pkg) != 0) {
159 /* different package name */
160 PKG_SEC_END(*doing_pkg, cur_pkg);
161 PKG_SEC_START(pkg_name, *doing_pkg, cur_pkg);
162 }
163 }
164 } else if (*doing_pkg) {
165 /* in a package section when the entry isn't */
166 PKG_SEC_END(*doing_pkg, cur_pkg);
167 }
168 bail:
169 return (rc);
170 }
171
172 /*
173 * Given a list of protocols and number, write them to a new algorithm file.
174 * This function takes num_protos + num_protos * dois-per-alg operations.
175 * Also free the protocol structure.
176 *
177 * Note that no locking spans the read/update/write phases that can be
178 * used by callers of this routine. This could cause this function to suffer
179 * from the "lost update" problem. Since updates to the IPsec protocols
180 * and algorithm tables are very infrequent, this should not be a issue in
181 * practice.
182 */
183 static int
write_new_algfile(ipsec_proto_t * protos,int num_protos)184 write_new_algfile(ipsec_proto_t *protos, int num_protos)
185 {
186 FILE *f;
187 int fd, i, j, k;
188 int rc = 0;
189 struct ipsecalgent *alg;
190 char cur_pkg[1024];
191 boolean_t doing_pkg = B_FALSE;
192 char *alg_pkg;
193 char tmp_name_template[] = INET_IPSECALGSPATH "ipsecalgsXXXXXX";
194 char *tmp_name;
195
196 /*
197 * In order to avoid potentially corrupting the configuration
198 * file on file system failure, write the new configuration info
199 * to a temporary file which is then renamed to the configuration
200 * file (INET_IPSECALGSFILE.)
201 */
202 tmp_name = mktemp(tmp_name_template);
203
204 fd = open(tmp_name, O_WRONLY|O_CREAT|O_EXCL, CFG_PERMS);
205 if (fd == -1) {
206 rc = LIBIPSEC_ALGS_DIAG_ALGSFILEOPEN;
207 goto bail;
208 }
209
210 f = fdopen(fd, "w");
211 if (f == NULL) {
212 (void) close(fd);
213 rc = LIBIPSEC_ALGS_DIAG_ALGSFILEFDOPEN;
214 goto bail;
215 }
216
217 FPUT_ERR(fputs(preamble, f));
218
219 /* Write protocol entries. */
220 for (i = 0; i < num_protos; i++) {
221
222 /* add package section delimiters if needed */
223 rc = pkg_section(f, protos[i].proto_pkg, &doing_pkg, cur_pkg);
224 if (rc != 0)
225 goto bail;
226
227 FPRINTF_ERR(fprintf(f, "%s%d|%s|",
228 LIBIPSEC_ALGS_LINE_PROTO,
229 protos[i].proto_num, protos[i].proto_name));
230 switch (protos[i].proto_exec_mode) {
231 case LIBIPSEC_ALGS_EXEC_SYNC:
232 FPRINTF_ERR(fprintf(f, "sync\n"));
233 break;
234 case LIBIPSEC_ALGS_EXEC_ASYNC:
235 FPRINTF_ERR(fprintf(f, "async\n"));
236 break;
237 }
238 }
239
240 /* terminate the package section for the protocols if needed */
241 PKG_SEC_END(doing_pkg, cur_pkg);
242
243 FPUT_ERR(fputs("\n", f));
244
245 /* Write algorithm entries. */
246
247 for (i = 0; i < num_protos; i++) {
248 for (j = 0; j < protos[i].proto_numalgs; j++) {
249 alg = protos[i].proto_algs[j];
250
251 /* add package section delimiters if needed */
252 alg_pkg = alg_has_pkg(&protos[i], alg);
253 rc = pkg_section(f, alg_pkg, &doing_pkg, cur_pkg);
254 if (rc != 0)
255 goto bail;
256
257 /* protocol and algorithm numbers */
258 FPRINTF_ERR(fprintf(f, "%s%d|%d|",
259 LIBIPSEC_ALGS_LINE_ALG,
260 alg->a_proto_num, alg->a_alg_num));
261
262 /* algorithm names */
263 for (k = 0; alg->a_names[k] != NULL; k++) {
264 FPRINTF_ERR(fprintf(f, "%s", alg->a_names[k]));
265 if (alg->a_names[k+1] != NULL)
266 FPRINTF_ERR(fprintf(f, ","));
267 }
268
269 /* mechanism name */
270 FPRINTF_ERR(fprintf(f, "|%s|", alg->a_mech_name));
271
272 /* key sizes */
273 if (alg->a_key_increment == 0) {
274 /* key sizes defined by enumeration */
275 if (list_ints(f, alg->a_key_sizes) == -1) {
276 rc = LIBIPSEC_ALGS_DIAG_ALGSFILEWRITE;
277 goto bail;
278 }
279 } else {
280 /* key sizes defined by range */
281 FPRINTF_ERR(fprintf(f, "%d/%d-%d,%d",
282 alg->a_key_sizes[0], alg->a_key_sizes[1],
283 alg->a_key_sizes[2], alg->a_key_increment));
284 }
285 FPUT_ERR(fputc('|', f));
286
287 /* block sizes */
288 if (list_ints(f, alg->a_block_sizes) == -1) {
289 rc = LIBIPSEC_ALGS_DIAG_ALGSFILEWRITE;
290 goto bail;
291 }
292 FPUT_ERR(fputc('|', f));
293
294 /*
295 * Some algorithms require extra parameters, these
296 * are stored in an array. For algorithms that don't
297 * need these parameters, or flags (below), these
298 * extra fields in the ipsecalgs file must contain a
299 * zero. This fuction will get called if a algorithm
300 * entry is added, at this point the extra fields will
301 * be added to the file.
302 */
303 if (list_ints(f, alg->a_mech_params) == -1) {
304 rc = LIBIPSEC_ALGS_DIAG_ALGSFILEWRITE;
305 goto bail;
306 }
307 /* flags */
308 FPRINTF_ERR(fprintf(f, "|%d\n", alg->a_alg_flags));
309 }
310 }
311
312 /* terminate the package section for the algorithms if needed */
313 PKG_SEC_END(doing_pkg, cur_pkg);
314
315 if (fchmod(fd, CFG_PERMS) == -1) {
316 rc = LIBIPSEC_ALGS_DIAG_ALGSFILECHMOD;
317 goto bail;
318 }
319 if (fchown(fd, CFG_OWNER, CFG_GROUP) == -1) {
320 rc = LIBIPSEC_ALGS_DIAG_ALGSFILECHOWN;
321 goto bail;
322 }
323 if (fclose(f) == EOF) {
324 rc = LIBIPSEC_ALGS_DIAG_ALGSFILECLOSE;
325 goto bail;
326 }
327
328 if (rename(tmp_name, INET_IPSECALGSFILE) == -1)
329 rc = LIBIPSEC_ALGS_DIAG_ALGSFILERENAME;
330
331 bail:
332 _clean_trash(protos, num_protos);
333 return (rc);
334 }
335
336 /*
337 * Return a pointer to the protocol entry corresponding to the specified
338 * protocol num proto_num. Also builds the list of currently defined
339 * protocols.
340 */
341 static ipsec_proto_t *
proto_setup(ipsec_proto_t ** protos,int * num_protos,int proto_num,boolean_t cleanup)342 proto_setup(ipsec_proto_t **protos, int *num_protos, int proto_num,
343 boolean_t cleanup)
344 {
345 int i;
346 ipsec_proto_t *current_proto, *ret_proto = NULL;
347
348 _build_internal_algs(protos, num_protos);
349
350 if (*protos == NULL)
351 return (NULL);
352
353 for (i = 0; i < *num_protos; i++) {
354 current_proto = (*protos) + i;
355 if (current_proto->proto_num == proto_num) {
356 ret_proto = current_proto;
357 break;
358 }
359 }
360
361 if (ret_proto == NULL) {
362 if (cleanup)
363 _clean_trash(*protos, *num_protos);
364 /* else caller wants parsed /etc/inet/ipsecalgs anyway */
365 }
366
367 return (ret_proto);
368 }
369
370 /*
371 * Delete the first found algorithm of the specified protocol which
372 * has the same name as the one specified by alg_name. Deletion of
373 * the entry takes place only if the delete_it flag is set. If an
374 * entry was found, return B_TRUE, otherwise return B_FALSE.
375 */
376 static boolean_t
delipsecalgbyname_common(const char * name,ipsec_proto_t * proto,boolean_t delete_it)377 delipsecalgbyname_common(const char *name, ipsec_proto_t *proto,
378 boolean_t delete_it)
379 {
380 int i;
381 char **name_check;
382 boolean_t found_match = B_FALSE;
383
384 for (i = 0; i < proto->proto_numalgs; i++) {
385 if (!found_match) {
386 for (name_check =
387 proto->proto_algs[i]->a_names;
388 *name_check != NULL; name_check++) {
389 /*
390 * Can use strcmp because the algorithm names
391 * are bound.
392 */
393 if (strcmp(*name_check, name) == 0) {
394 found_match = B_TRUE;
395 if (!delete_it)
396 return (found_match);
397 freeipsecalgent(proto->proto_algs[i]);
398 break;
399 }
400 }
401 } else {
402 proto->proto_algs[i - 1] = proto->proto_algs[i];
403 }
404 }
405
406 if (found_match)
407 proto->proto_numalgs--;
408
409 return (found_match);
410 }
411
412 /*
413 * Returns B_TRUE if the specified 0-terminated lists of key or
414 * block sizes match, B_FALSE otherwise.
415 */
416 static boolean_t
sizes_match(int * a1,int * a2)417 sizes_match(int *a1, int *a2)
418 {
419 int i;
420
421 for (i = 0; (a1[i] != 0) && (a2[i] != 0); i++) {
422 if (a1[i] != a2[i])
423 return (B_FALSE);
424 }
425 if ((a1[i] != 0) || (a2[i] != 0))
426 return (B_FALSE);
427
428 return (B_TRUE);
429 }
430
431 /*
432 * Returns B_TRUE if an _exact_ equivalent of the specified algorithm
433 * already exists, B_FALSE otherwise.
434 */
435 static boolean_t
ipsecalg_exists(struct ipsecalgent * newbie,ipsec_proto_t * proto)436 ipsecalg_exists(struct ipsecalgent *newbie, ipsec_proto_t *proto)
437 {
438 struct ipsecalgent *curalg;
439 char **curname, **newbiename;
440 int i;
441 boolean_t match;
442
443 for (i = 0; i < proto->proto_numalgs; i++) {
444 curalg = proto->proto_algs[i];
445
446 if (curalg->a_alg_num != newbie->a_alg_num)
447 continue;
448
449 if (curalg->a_key_increment != newbie->a_key_increment)
450 continue;
451
452 if (strcmp(curalg->a_mech_name, newbie->a_mech_name) != 0)
453 continue;
454
455 curname = curalg->a_names;
456 newbiename = newbie->a_names;
457 match = B_TRUE;
458 while ((*curname != NULL) && (*newbiename != NULL) && match) {
459 match = (strcmp(*curname, *newbiename) == 0);
460 curname++;
461 newbiename++;
462 }
463 if (!match || (*curname != NULL) || (*newbiename != NULL))
464 continue;
465
466 if (!sizes_match(curalg->a_block_sizes, newbie->a_block_sizes))
467 continue;
468
469 if (!sizes_match(curalg->a_key_sizes, newbie->a_key_sizes))
470 continue;
471
472 /* we found an exact match */
473 return (B_TRUE);
474 }
475
476 return (B_FALSE);
477 }
478
479 /*
480 * Add a new algorithm to the /etc/inet/ipsecalgs file. Caller must free
481 * or otherwise address "newbie".
482 */
483 int
addipsecalg(struct ipsecalgent * newbie,uint_t flags)484 addipsecalg(struct ipsecalgent *newbie, uint_t flags)
485 {
486 ipsec_proto_t *protos, *current_proto;
487 struct ipsecalgent *clone, **holder;
488 int num_protos, i;
489 char **name_check;
490 boolean_t forced_add = (flags & LIBIPSEC_ALGS_ADD_FORCE) != 0;
491 boolean_t found_match;
492
493 if ((current_proto = proto_setup(&protos, &num_protos,
494 newbie->a_proto_num, B_TRUE)) == NULL)
495 return (LIBIPSEC_ALGS_DIAG_UNKN_PROTO);
496
497 /*
498 * If an algorithm that matches _exactly_ the new algorithm
499 * already exists, we're done.
500 */
501 if (ipsecalg_exists(newbie, current_proto))
502 return (0);
503
504 /*
505 * We don't allow a new algorithm to be created if one of
506 * its names is already defined for an existing algorithm,
507 * unless the operation is forced, in which case existing
508 * algorithm entries that conflict with the new one are
509 * deleted.
510 */
511 for (name_check = newbie->a_names; *name_check != NULL; name_check++) {
512 found_match = delipsecalgbyname_common(*name_check,
513 current_proto, forced_add);
514 if (found_match && !forced_add) {
515 /*
516 * Duplicate entry found, but the addition was
517 * not forced.
518 */
519 _clean_trash(protos, num_protos);
520 return (LIBIPSEC_ALGS_DIAG_ALG_EXISTS);
521 }
522 }
523
524 for (i = 0; i < current_proto->proto_numalgs; i++) {
525 if (current_proto->proto_algs[i]->a_alg_num ==
526 newbie->a_alg_num) {
527 /*
528 * An algorithm with the same protocol number
529 * and algorithm number already exists. Fail
530 * addition unless the operation is forced.
531 */
532 if (flags & LIBIPSEC_ALGS_ADD_FORCE) {
533 clone = _duplicate_alg(newbie);
534 if (clone != NULL) {
535 freeipsecalgent(
536 current_proto->proto_algs[i]);
537 current_proto->proto_algs[i] = clone;
538 return (write_new_algfile(protos,
539 num_protos));
540 } else {
541 _clean_trash(protos, num_protos);
542 return (LIBIPSEC_ALGS_DIAG_NOMEM);
543 }
544 } else {
545 _clean_trash(protos, num_protos);
546 return (LIBIPSEC_ALGS_DIAG_ALG_EXISTS);
547 }
548 }
549 }
550
551 /* append the new algorithm */
552 holder = realloc(current_proto->proto_algs,
553 sizeof (struct ipsecalgent *) * (i + 1));
554 if (holder == NULL) {
555 _clean_trash(protos, num_protos);
556 return (LIBIPSEC_ALGS_DIAG_NOMEM);
557 }
558 clone = _duplicate_alg(newbie);
559 if (clone == NULL) {
560 free(holder);
561 _clean_trash(protos, num_protos);
562 return (LIBIPSEC_ALGS_DIAG_NOMEM);
563 }
564 current_proto->proto_numalgs++;
565 current_proto->proto_algs = holder;
566 current_proto->proto_algs[i] = clone;
567 return (write_new_algfile(protos, num_protos));
568 }
569
570 /*
571 * Delete an algorithm by name & protocol number from /etc/inet/ipsecalgs.
572 * Only deletes the first encountered instance.
573 */
574 int
delipsecalgbyname(const char * name,int proto_num)575 delipsecalgbyname(const char *name, int proto_num)
576 {
577 ipsec_proto_t *protos, *current_proto;
578 int num_protos;
579
580 if ((current_proto = proto_setup(&protos, &num_protos, proto_num,
581 B_TRUE)) == NULL)
582 return (LIBIPSEC_ALGS_DIAG_UNKN_PROTO);
583
584 if (delipsecalgbyname_common(name, current_proto, B_TRUE))
585 return (write_new_algfile(protos, num_protos));
586
587 _clean_trash(protos, num_protos);
588 return (LIBIPSEC_ALGS_DIAG_UNKN_ALG);
589 }
590
591 /*
592 * Delete an algorithm by num + protocol num from /etc/inet/ipsecalgs.
593 */
594 int
delipsecalgbynum(int alg_num,int proto_num)595 delipsecalgbynum(int alg_num, int proto_num)
596 {
597 ipsec_proto_t *protos, *current_proto;
598 int i, num_protos;
599 boolean_t found_match = B_FALSE;
600
601 if ((current_proto = proto_setup(&protos, &num_protos, proto_num,
602 B_TRUE)) == NULL)
603 return (LIBIPSEC_ALGS_DIAG_UNKN_PROTO);
604
605 for (i = 0; i < current_proto->proto_numalgs; i++) {
606 if (!found_match) {
607 if (current_proto->proto_algs[i]->a_alg_num ==
608 alg_num) {
609 found_match = B_TRUE;
610 freeipsecalgent(current_proto->proto_algs[i]);
611 }
612 } else {
613 current_proto->proto_algs[i - 1] =
614 current_proto->proto_algs[i];
615 }
616 }
617
618 if (found_match) {
619 current_proto->proto_numalgs--;
620 return (write_new_algfile(protos, num_protos));
621 }
622
623 _clean_trash(protos, num_protos);
624 return (LIBIPSEC_ALGS_DIAG_UNKN_ALG);
625 }
626
627 /*
628 * Remove the specified protocol entry from the list of protocols.
629 */
630 static void
delipsecproto_common(ipsec_proto_t * protos,int num_protos,ipsec_proto_t * proto)631 delipsecproto_common(ipsec_proto_t *protos, int num_protos,
632 ipsec_proto_t *proto)
633 {
634 int i;
635
636 /* free protocol storage */
637 free(proto->proto_name);
638 for (i = 0; i < proto->proto_numalgs; i++)
639 freeipsecalgent(proto->proto_algs[i]);
640
641 /* remove from list of prototocols */
642 for (i = (proto - protos + 1); i < num_protos; i++)
643 protos[i - 1] = protos[i];
644 }
645
646 /*
647 * Add an IPsec protocol to /etc/inet/ipsecalgs.
648 */
649 int
addipsecproto(const char * proto_name,int proto_num,ipsecalgs_exec_mode_t proto_exec_mode,uint_t flags)650 addipsecproto(const char *proto_name, int proto_num,
651 ipsecalgs_exec_mode_t proto_exec_mode, uint_t flags)
652 {
653 ipsec_proto_t *protos, *current_proto, *new_proto;
654 int i, num_protos;
655
656 /*
657 * NOTE:If build_internal_algs returns NULL for any
658 * reason, we will end up clobbering /etc/inet/ipsecalgs!
659 */
660
661 current_proto = proto_setup(&protos, &num_protos, proto_num, B_FALSE);
662
663 /* check for protocol with duplicate id */
664 if (current_proto != NULL) {
665 if ((strcmp(proto_name, current_proto->proto_name) == 0) &&
666 (proto_exec_mode == current_proto->proto_exec_mode)) {
667 /*
668 * The current protocol being added matches
669 * exactly an existing protocol, we're done.
670 */
671 return (0);
672 }
673 if (!(flags & LIBIPSEC_ALGS_ADD_FORCE))
674 return (LIBIPSEC_ALGS_DIAG_PROTO_EXISTS);
675 delipsecproto_common(protos, num_protos--, current_proto);
676 }
677
678 /* check for protocol with duplicate name */
679 for (i = 0; i < num_protos; i++) {
680 if (strcmp(protos[i].proto_name, proto_name) == 0) {
681 if (!(flags & LIBIPSEC_ALGS_ADD_FORCE))
682 return (LIBIPSEC_ALGS_DIAG_PROTO_EXISTS);
683 delipsecproto_common(protos, num_protos--, &protos[i]);
684 break;
685 }
686 }
687
688 /* add new protocol */
689 num_protos++;
690 new_proto = realloc(protos, num_protos *
691 sizeof (ipsec_proto_t));
692 if (new_proto == NULL) {
693 _clean_trash(protos, num_protos - 1);
694 return (LIBIPSEC_ALGS_DIAG_NOMEM);
695 }
696 protos = new_proto;
697 new_proto += (num_protos - 1);
698
699 /* initialize protocol entry */
700 new_proto->proto_num = proto_num;
701 new_proto->proto_numalgs = 0;
702 new_proto->proto_algs = NULL;
703 new_proto->proto_name = strdup(proto_name);
704 if (new_proto->proto_name == NULL) {
705 _clean_trash(protos, num_protos);
706 return (LIBIPSEC_ALGS_DIAG_NOMEM);
707 }
708 new_proto->proto_pkg = NULL;
709 new_proto->proto_algs_pkgs = NULL;
710 new_proto->proto_algs_npkgs = 0;
711 new_proto->proto_exec_mode = proto_exec_mode;
712
713 return (write_new_algfile(protos, num_protos));
714 }
715
716 /*
717 * Delete an IPsec protocol entry from /etc/inet/ipsecalgs. This also
718 * nukes the associated algorithms.
719 */
720 int
delipsecprotobynum(int proto_num)721 delipsecprotobynum(int proto_num)
722 {
723 ipsec_proto_t *protos, *current_proto;
724 int num_protos;
725
726 if ((current_proto = proto_setup(&protos, &num_protos, proto_num,
727 B_TRUE)) == NULL)
728 return (LIBIPSEC_ALGS_DIAG_UNKN_PROTO);
729
730 delipsecproto_common(protos, num_protos--, current_proto);
731
732 return (write_new_algfile(protos, num_protos));
733 }
734
735 int
delipsecprotobyname(const char * proto_name)736 delipsecprotobyname(const char *proto_name)
737 {
738 int proto_num;
739
740 proto_num = getipsecprotobyname(proto_name);
741 if (proto_num == -1)
742 return (LIBIPSEC_ALGS_DIAG_UNKN_PROTO);
743
744 return (delipsecprotobynum(proto_num));
745 }
746
747 /*
748 * Implement these in libnsl since these are read-only operations.
749 */
750 int *
getipsecprotos(int * nentries)751 getipsecprotos(int *nentries)
752 {
753 return (_real_getipsecprotos(nentries));
754 }
755
756 int *
getipsecalgs(int * nentries,int proto_num)757 getipsecalgs(int *nentries, int proto_num)
758 {
759 return (_real_getipsecalgs(nentries, proto_num));
760 }
761
762 const char *
ipsecalgs_diag(int diag)763 ipsecalgs_diag(int diag)
764 {
765 switch (diag) {
766 case LIBIPSEC_ALGS_DIAG_ALG_EXISTS:
767 return (dgettext(TEXT_DOMAIN, "Algorithm already exists"));
768 case LIBIPSEC_ALGS_DIAG_PROTO_EXISTS:
769 return (dgettext(TEXT_DOMAIN, "Protocol already exists"));
770 case LIBIPSEC_ALGS_DIAG_UNKN_PROTO:
771 return (dgettext(TEXT_DOMAIN, "Unknown protocol"));
772 case LIBIPSEC_ALGS_DIAG_UNKN_ALG:
773 return (dgettext(TEXT_DOMAIN, "Unknown algorithm"));
774 case LIBIPSEC_ALGS_DIAG_NOMEM:
775 return (dgettext(TEXT_DOMAIN, "Out of memory"));
776 case LIBIPSEC_ALGS_DIAG_ALGSFILEOPEN:
777 return (dgettext(TEXT_DOMAIN, "open() failed"));
778 case LIBIPSEC_ALGS_DIAG_ALGSFILEFDOPEN:
779 return (dgettext(TEXT_DOMAIN, "fdopen() failed"));
780 case LIBIPSEC_ALGS_DIAG_ALGSFILELOCK:
781 return (dgettext(TEXT_DOMAIN, "lockf() failed"));
782 case LIBIPSEC_ALGS_DIAG_ALGSFILERENAME:
783 return (dgettext(TEXT_DOMAIN, "rename() failed"));
784 case LIBIPSEC_ALGS_DIAG_ALGSFILEWRITE:
785 return (dgettext(TEXT_DOMAIN, "write to file failed"));
786 case LIBIPSEC_ALGS_DIAG_ALGSFILECHMOD:
787 return (dgettext(TEXT_DOMAIN, "chmod() failed"));
788 case LIBIPSEC_ALGS_DIAG_ALGSFILECHOWN:
789 return (dgettext(TEXT_DOMAIN, "chown() failed"));
790 case LIBIPSEC_ALGS_DIAG_ALGSFILECLOSE:
791 return (dgettext(TEXT_DOMAIN, "close() failed"));
792 default:
793 return (dgettext(TEXT_DOMAIN, "failed"));
794 }
795 }
796
797 /*
798 * Get the execution mode corresponding to the specified protocol.
799 * Returns 0 on success, one of the LIBIPSEC_ALGS_DIAG_* values on
800 * failure.
801 */
802 int
ipsecproto_get_exec_mode(int proto_num,ipsecalgs_exec_mode_t * exec_mode)803 ipsecproto_get_exec_mode(int proto_num, ipsecalgs_exec_mode_t *exec_mode)
804 {
805 ipsec_proto_t *protos, *current_proto;
806 int num_protos;
807
808 if ((current_proto = proto_setup(&protos, &num_protos, proto_num,
809 B_TRUE)) == NULL)
810 return (LIBIPSEC_ALGS_DIAG_UNKN_PROTO);
811
812 *exec_mode = current_proto->proto_exec_mode;
813
814 _clean_trash(protos, num_protos);
815 return (0);
816 }
817
818 /*
819 * Set the execution mode of the specified protocol. Returns 0 on success,
820 * or one of the LIBIPSEC_ALGS_DIAG_* values on failure.
821 */
822 int
ipsecproto_set_exec_mode(int proto_num,ipsecalgs_exec_mode_t exec_mode)823 ipsecproto_set_exec_mode(int proto_num, ipsecalgs_exec_mode_t exec_mode)
824 {
825 ipsec_proto_t *protos, *current_proto;
826 int num_protos;
827
828 if ((current_proto = proto_setup(&protos, &num_protos, proto_num,
829 B_TRUE)) == NULL)
830 return (LIBIPSEC_ALGS_DIAG_UNKN_PROTO);
831
832 current_proto->proto_exec_mode = exec_mode;
833
834 return (write_new_algfile(protos, num_protos));
835 }
836