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 2010 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 
27 #include <stdio.h>
28 #include <strings.h>
29 #include <limits.h>
30 #include <stdlib.h>
31 #include <stdarg.h>
32 #include <errno.h>
33 #include <ctype.h>
34 #include <arpa/inet.h>
35 #include <unistd.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <fcntl.h>
39 #include <libintl.h>
40 #include <locale.h>
41 #include <libvscan.h>
42 
43 #if !defined(TEXT_DOMAIN)
44 #define	TEXT_DOMAIN "SYS_TEST"
45 #endif
46 
47 
48 /* Property Names */
49 #define	VS_ADM_MAXSIZE		"max-size"
50 #define	VS_ADM_MAXSIZE_ACTION	"max-size-action"
51 #define	VS_ADM_TYPES		"types"
52 
53 /* Scan Engine Property Names */
54 #define	VS_ADM_SE_ENABLE	"enable"
55 #define	VS_ADM_SE_HOST		"host"
56 #define	VS_ADM_SE_PORT		"port"
57 #define	VS_ADM_SE_MAXCONN	"max-connection"
58 
59 /* Property Values */
60 #define	VS_ADM_ON		"on"
61 #define	VS_ADM_OFF		"off"
62 #define	VS_ADM_ALLOW		"allow"
63 #define	VS_ADM_DENY		"deny"
64 
65 
66 /*
67  * Print buffer length: used for sizing buffers that are filled with
68  * user-readable strings for property values. Define a number that
69  * accounts for some pre-value information, and won't (likely)
70  * wrap an 80-column display
71  */
72 #define	VS_ADM_PRINT_BUF_LEN	4096
73 
74 /* Program exit codes */
75 #define	VS_ADM_EXIT_SUCCESS	0
76 #define	VS_ADM_EXIT_ERROR	1
77 #define	VS_ADM_EXIT_USAGE	2
78 
79 
80 /*
81  * vscanadm property definition. Maps the property ids to a
82  * property name, and includes functions to convert to and from
83  * input strings and native data.
84  */
85 typedef struct vs_adm_property {
86 	const char *vap_name;
87 	uint64_t vap_id;
88 	int (*vap_parse)(const char *, void *);
89 	int (*vap_unparse)(const void *, char *, size_t);
90 } vs_adm_property_t;
91 
92 
93 /* usage/help information for subcommnds */
94 #define	VS_ADM_HELP_GET		("[-p property]...\n" \
95 	"\tdisplay vscan properties")
96 #define	VS_ADM_HELP_SET		("-p property=value [-p property=value]...\n" \
97 	"\tset values of vscan properties")
98 #define	VS_ADM_HELP_GET_ENG	("[-p property] [engine_id]\n" \
99 	"\tdisplay values of scan engine properties")
100 #define	VS_ADM_HELP_ADD_ENG	("[-p property=value]... engine_id\n" \
101 	"\tadd scan engine")
102 #define	VS_ADM_HELP_SET_ENG	("-p property=value [-p property=value]" \
103 	"... engine_id\n\tset values of scan engine properties")
104 #define	VS_ADM_HELP_REM_ENG	("engine_id\n" \
105 	"\tremove scan engine")
106 #define	VS_ADM_HELP_SHOW	("\n\tdisplay the values of all vscan " \
107 	"service and scan engine properties")
108 #define	VS_ADM_HELP_STATS	("[-z]\n\tdisplay vscan service statistics")
109 #define	VS_ADM_HELP_IMPORT	("-p property filename\n" \
110 	"\timport property from file")
111 #define	VS_ADM_HELP_EXPORT	("-p property filename\n" \
112 	"\texport property to file")
113 #define	VS_ADM_HELP_VALIDATE	("-p property filename\n" \
114 	"\tvalidate property in file")
115 
116 
117 /*
118  * vscanadm command structure. Encapsulates the vscanadm
119  * subcommand name, pointer to the subcommand implementation
120  * function, and a help id to get usage/help information.
121  */
122 typedef struct vs_adm_cmd {
123 	int (*vac_func)(int, char *[]);
124 	const char *vac_name;
125 	char *vac_helpid;
126 }
127 vs_adm_cmd_t;
128 
129 
130 /* Subcommand implementation functions */
131 static int vs_adm_set(int, char **);
132 static int vs_adm_get(int, char **);
133 static int vs_adm_set_engine(int, char **);
134 static int vs_adm_get_engine(int, char **);
135 static int vs_adm_rem_engine(int, char **);
136 static int vs_adm_show(int, char **);
137 static int vs_adm_stats(int, char **);
138 static int vs_adm_import(int, char **);
139 static int vs_adm_export(int, char **);
140 static int vs_adm_validate(int, char **);
141 
142 
143 /*
144  * Parse routines to transform libvscan API data into user-readable strings
145  */
146 static int vs_adm_parse_maxsize(const char *, void *);
147 static int vs_adm_parse_maxsize_action(const char *, void *);
148 static int vs_adm_parse_types(const char *, void *);
149 static int vs_adm_parse_enable(const char *, void *);
150 static int vs_adm_parse_host(const char *, void *);
151 static int vs_adm_parse_port(const char *, void *);
152 static int vs_adm_parse_maxconn(const char *, void *);
153 
154 
155 /*
156  * Unparse routines to transform strings from the user input into
157  * API native data.
158  *
159  * While some value validation is performed in the course of unparsing
160  * string data, complete value validation is left to libvscan.
161  * Values that are in unacceptable form, out of range, or otherwise
162  * violate rules for a given property will be rejected
163  */
164 static int vs_adm_unparse_maxsize(const void *, char *, size_t);
165 static int vs_adm_unparse_maxsize_action(const void *, char *, size_t);
166 static int vs_adm_unparse_types(const void *, char *, size_t);
167 static int vs_adm_unparse_enable(const void *, char *, size_t);
168 static int vs_adm_unparse_host(const void *, char *, size_t);
169 static int vs_adm_unparse_port(const void *, char *, size_t);
170 static int vs_adm_unparse_maxconn(const void *, char *, size_t);
171 
172 
173 /*
174  * The properties table includes a vscanadm property entry, specifying
175  * the property nane, property id, parse amd inparse methods,
176  * for each vscanadm property.
177  */
178 static const vs_adm_property_t vs_adm_props_all[] = {
179 	{ VS_ADM_MAXSIZE, VS_PROPID_MAXSIZE,
180 		vs_adm_parse_maxsize, vs_adm_unparse_maxsize },
181 	{ VS_ADM_MAXSIZE_ACTION, VS_PROPID_MAXSIZE_ACTION,
182 		vs_adm_parse_maxsize_action, vs_adm_unparse_maxsize_action },
183 	{ VS_ADM_TYPES, VS_PROPID_TYPES,
184 		vs_adm_parse_types, vs_adm_unparse_types },
185 	{ VS_ADM_SE_ENABLE, VS_PROPID_SE_ENABLE,
186 		vs_adm_parse_enable, vs_adm_unparse_enable },
187 	{ VS_ADM_SE_HOST, VS_PROPID_SE_HOST,
188 		vs_adm_parse_host, vs_adm_unparse_host },
189 	{ VS_ADM_SE_PORT, VS_PROPID_SE_PORT,
190 		vs_adm_parse_port, vs_adm_unparse_port },
191 	{ VS_ADM_SE_MAXCONN, VS_PROPID_SE_MAXCONN,
192 		vs_adm_parse_maxconn, vs_adm_unparse_maxconn },
193 	{ NULL, 0, NULL, NULL }
194 };
195 
196 
197 /*
198  * The subcommand table.  Used to find the subcommand specified
199  * by the user and dispatch the processing for the subcommand.
200  * Also used to display usage information for each subcommand.
201  */
202 static const vs_adm_cmd_t vs_adm_cmds[] =
203 {
204 	{ vs_adm_get, "get", VS_ADM_HELP_GET },
205 	{ vs_adm_set, "set", VS_ADM_HELP_SET },
206 	{ vs_adm_get_engine, "get-engine", VS_ADM_HELP_GET_ENG },
207 	{ vs_adm_set_engine, "set-engine", VS_ADM_HELP_SET_ENG },
208 	{ vs_adm_set_engine, "add-engine", VS_ADM_HELP_ADD_ENG },
209 	{ vs_adm_rem_engine, "remove-engine", VS_ADM_HELP_REM_ENG },
210 	{ vs_adm_import, "import", VS_ADM_HELP_IMPORT },
211 	{ vs_adm_export, "export", VS_ADM_HELP_EXPORT },
212 	{ vs_adm_validate, "validate", VS_ADM_HELP_VALIDATE },
213 	{ vs_adm_show, "show", VS_ADM_HELP_SHOW },
214 	{ vs_adm_stats, "stats", VS_ADM_HELP_STATS },
215 	{ NULL, NULL, NULL }
216 };
217 
218 
219 static const char *vs_adm_cmd;
220 static const char *vs_adm_subcmd;
221 
222 static int vs_adm_usage(FILE *);
223 static int vs_adm_props_from_input(int, char **, vs_props_t *, uint64_t *);
224 static void vs_adm_output_getcmd(uint64_t, const void *);
225 static void vs_adm_output_stats(vs_stats_t *);
226 static const vs_adm_property_t *vs_adm_prop_by_name(const char *);
227 static const vs_adm_property_t *vs_adm_prop_by_id(const uint64_t);
228 static int vs_adm_parse(const vs_adm_property_t *, const char *, void *);
229 static void vs_adm_unparse(const vs_adm_property_t *, const void *,
230     char *, size_t);
231 
232 static int vs_adm_file_read(char *, char *, int);
233 static int vs_adm_file_write(char *, char *);
234 static int vs_adm_file_usage(int argc, char **argv);
235 
236 /*
237  * main
238  */
239 int
main(int argc,char ** argv)240 main(int argc, char **argv)
241 {
242 	const vs_adm_cmd_t *cp;
243 	const char *p;
244 	int i, err;
245 
246 	(void) setlocale(LC_ALL, "");
247 	(void) textdomain(TEXT_DOMAIN);
248 
249 	/* executable and subcommand names */
250 	if ((p = strrchr(argv[0], '/')) == NULL)
251 		vs_adm_cmd = argv[0];
252 	else
253 		vs_adm_cmd = p + 1;
254 
255 	vs_adm_subcmd = argv[1];
256 
257 	/* require at least command and sub-command */
258 	if (argc < 2)
259 		return (vs_adm_usage(stdout));
260 
261 	/* Check for the "-?" help switch */
262 	for (i = 1; i < argc; i++) {
263 		if (strcmp(argv[i], "-?") == 0)
264 			return (vs_adm_usage(stdout));
265 	}
266 
267 	/* Locate the specified subcommand */
268 	for (cp = vs_adm_cmds; cp->vac_name != NULL; cp++) {
269 		if (strcmp(cp->vac_name, vs_adm_subcmd) == 0)
270 			break;
271 	}
272 
273 	if (cp->vac_name == NULL) {
274 		(void) fprintf(stderr, "%s: %s -- %s\n",
275 		    gettext("invalid subcommand"),
276 		    vs_adm_cmd, vs_adm_subcmd);
277 		return (vs_adm_usage(stderr));
278 	}
279 
280 	/* invoke sub-command handler */
281 	err = cp->vac_func(argc, argv);
282 
283 	return (err == VS_ADM_EXIT_USAGE ? vs_adm_usage(stderr) : err);
284 }
285 
286 
287 /*
288  * vs_adm_usage
289  */
290 static int
vs_adm_usage(FILE * fp)291 vs_adm_usage(FILE *fp)
292 {
293 	const vs_adm_cmd_t *cp;
294 
295 	for (cp = vs_adm_cmds; cp->vac_name != NULL; cp++) {
296 		(void) fprintf(fp, "%s %s", vs_adm_cmd, cp->vac_name);
297 		if (cp->vac_helpid != NULL)
298 			(void) fprintf(fp, " %s\n", cp->vac_helpid);
299 	}
300 
301 	return (VS_ADM_EXIT_USAGE);
302 }
303 
304 
305 /*
306  * vs_adm_get
307  *
308  * Gets and displays general vscan service configuration properties.
309  */
310 static int
vs_adm_get(int argc,char ** argv)311 vs_adm_get(int argc, char **argv)
312 {
313 	uint64_t propids;
314 	int i, rc;
315 	vs_props_t vp;
316 	const vs_adm_property_t *vap;
317 
318 	(void) memset(&vp, 0, sizeof (vp));
319 
320 	if (argc <= 2) {
321 		propids = VS_PROPID_GEN_ALL;
322 	} else {
323 		propids = 0LL;
324 		for (i = 2; i < argc; i++) {
325 			/* the "-p" specifier is optional */
326 			if (strcmp(argv[i], "-p") == 0) {
327 				if (++i >= argc)
328 					return (VS_ADM_EXIT_USAGE);
329 			}
330 
331 			if ((vap = vs_adm_prop_by_name(argv[i])) == NULL) {
332 				(void) fprintf(stderr, "%s '%s'\n",
333 				    gettext("invalid property"), argv[i]);
334 				return (VS_ADM_EXIT_ERROR);
335 			}
336 
337 			propids |= vap->vap_id;
338 		}
339 	}
340 
341 	rc = vs_props_get(&vp, propids);
342 	if (rc != VS_ERR_NONE) {
343 		(void) fprintf(stderr, "%s\n", vs_strerror(rc));
344 		return (VS_ADM_EXIT_ERROR);
345 	}
346 
347 	vs_adm_output_getcmd(propids, &vp);
348 
349 	return (VS_ADM_EXIT_SUCCESS);
350 }
351 
352 
353 /*
354  * vs_adm_set
355  *
356  * Sets values for general vscan service configuration properties
357  *
358  * Calls a common function used by the set, add, and remove
359  * subcommands to modify general property values.
360  */
361 static int
vs_adm_set(int argc,char ** argv)362 vs_adm_set(int argc, char **argv)
363 {
364 	vs_props_t vp;
365 	uint64_t propids;
366 	int rc;
367 
368 	if (argc < 3)
369 		return (VS_ADM_EXIT_USAGE);
370 
371 	rc = vs_adm_props_from_input(argc, argv, &vp, &propids);
372 	if (rc != VS_ADM_EXIT_SUCCESS)
373 		return (rc);
374 
375 	rc = vs_props_set(&vp, propids);
376 	if (rc != VS_ERR_NONE) {
377 		(void) fprintf(stderr, "%s\n", vs_strerror(rc));
378 		return (VS_ADM_EXIT_ERROR);
379 	}
380 
381 	return (VS_ADM_EXIT_SUCCESS);
382 }
383 
384 
385 /*
386  * vs_adm_get_engine
387  *
388  * Gets and displays scan engine configuration properties for
389  * one or more scan engines.
390  */
391 static int
vs_adm_get_engine(int argc,char ** argv)392 vs_adm_get_engine(int argc, char **argv)
393 {
394 	int i, rc;
395 	uint64_t propids;
396 	char *engid = NULL;
397 	const vs_adm_property_t *vap;
398 	vs_props_all_t va;
399 
400 	propids = 0LL;
401 	for (i = 2; i < argc; i++) {
402 		/* if not preceded by -p, must be engine id and must be last */
403 		if (strcmp(argv[i], "-p") != 0) {
404 			if (i != (argc - 1))
405 				return (VS_ADM_EXIT_USAGE);
406 
407 			engid = argv[i];
408 			if (strlen(engid) > VS_SE_NAME_LEN) {
409 				(void) fprintf(stderr, "%s\n",
410 				    gettext("invalid scan engine"));
411 				return (VS_ADM_EXIT_ERROR);
412 			}
413 		} else {
414 			/* property should follow the -p */
415 			if (++i >= argc)
416 				return (VS_ADM_EXIT_USAGE);
417 
418 			if ((vap = vs_adm_prop_by_name(argv[i])) == NULL) {
419 				(void) fprintf(stderr, "%s '%s'\n",
420 				    gettext("invalid property"), argv[i]);
421 				return (VS_ADM_EXIT_ERROR);
422 			}
423 
424 			propids |= vap->vap_id;
425 		}
426 	}
427 
428 	if (propids == 0LL)
429 		propids = VS_PROPID_SE_ALL;
430 
431 	/* get properties for specified engine */
432 	if (engid) {
433 		rc = vs_props_se_get(engid, &va.va_se[0], propids);
434 		if (rc != VS_ERR_NONE) {
435 			(void) fprintf(stderr, "%s\n", vs_strerror(rc));
436 			return (VS_ADM_EXIT_ERROR);
437 		}
438 		vs_adm_output_getcmd(propids, &va.va_se[0]);
439 		return (VS_ADM_EXIT_SUCCESS);
440 	}
441 
442 	/* get properties for all engines */
443 	if ((rc = vs_props_get_all(&va)) != VS_ERR_NONE) {
444 		(void) fprintf(stderr, "%s\n", vs_strerror(rc));
445 		return (VS_ADM_EXIT_ERROR);
446 	}
447 
448 	for (i = 0; i < VS_SE_MAX; i++) {
449 		if (*(va.va_se[i].vep_engid) == 0)
450 			break;
451 		vs_adm_output_getcmd(propids, &va.va_se[i]);
452 	}
453 	if (i == 0) {
454 		(void) fprintf(stdout, "%s\n",
455 		    gettext("no scan engines configured"));
456 	}
457 
458 	return (VS_ADM_EXIT_SUCCESS);
459 }
460 
461 
462 /*
463  * vs_adm_set_engine
464  *
465  * Sets one or more scan engine configuration properties for a
466  * single scan engine.
467  */
468 static int
vs_adm_set_engine(int argc,char ** argv)469 vs_adm_set_engine(int argc, char **argv)
470 {
471 	const vs_adm_property_t *vap;
472 	vs_props_se_t sep;
473 	char *val;
474 	uint64_t propids;
475 	int i, rc;
476 	char *engid;
477 	int add = (strcmp(vs_adm_subcmd, "add-engine") == 0) ? 1 : 0;
478 
479 
480 	if ((argc < 3) || ((!add) && (argc < 4)))
481 		return (VS_ADM_EXIT_USAGE);
482 
483 	/* Get the engine id */
484 	engid = argv[argc - 1];
485 	if (strchr(engid, '=') || strcmp(argv[argc - 2], "-p") == 0) {
486 		return (VS_ADM_EXIT_USAGE);
487 	}
488 
489 	if (strlen(engid) > VS_SE_NAME_LEN) {
490 		(void) fprintf(stderr, "%s\n",
491 		    gettext("invalid scan engine"));
492 		return (VS_ADM_EXIT_ERROR);
493 	}
494 
495 	propids = 0LL;
496 
497 	for (i = 2; i < (argc - 1); i++) {
498 		/* The "-p" is optional */
499 		if (strcmp(argv[i], "-p") == 0) {
500 			if (++i >= argc)
501 				return (VS_ADM_EXIT_USAGE);
502 		}
503 
504 		if ((val = strchr(argv[i], '=')) == NULL)
505 			return (VS_ADM_EXIT_USAGE);
506 
507 		*val = 0;
508 		val++;
509 
510 		/* Find the SE property pointer from the SE property name */
511 		if ((vap = vs_adm_prop_by_name(argv[i])) == NULL) {
512 			(void) fprintf(stderr, "%s '%s'\n",
513 			    gettext("invalid property"), argv[i]);
514 			return (VS_ADM_EXIT_ERROR);
515 		}
516 
517 		propids |= vap->vap_id;
518 
519 		if ((vs_adm_parse(vap, val, &sep)) != 0) {
520 			(void) fprintf(stderr, "%s '%s'\n",
521 			    gettext("invalid property value"), val);
522 			return (VS_ADM_EXIT_ERROR);
523 		}
524 	}
525 
526 	if (add)
527 		rc = vs_props_se_create(engid, &sep, propids);
528 	else
529 		rc = vs_props_se_set(engid, &sep, propids);
530 
531 	if (rc != VS_ERR_NONE) {
532 		(void) fprintf(stderr, "%s\n", vs_strerror(rc));
533 		return (VS_ADM_EXIT_ERROR);
534 	}
535 
536 	return (VS_ADM_EXIT_SUCCESS);
537 }
538 
539 
540 /*
541  * vs_adm_rem_engine
542  */
543 /* ARGSUSED */
544 static int
vs_adm_rem_engine(int argc,char ** argv)545 vs_adm_rem_engine(int argc, char **argv)
546 {
547 	int rc;
548 	char *engid;
549 
550 	if (argc != 3)
551 		return (VS_ADM_EXIT_USAGE);
552 
553 	engid = argv[2];
554 
555 	if (strlen(engid) > VS_SE_NAME_LEN) {
556 		(void) fprintf(stderr, "%s\n",
557 		    gettext("invalid scan engine"));
558 		return (VS_ADM_EXIT_ERROR);
559 	}
560 
561 	if ((rc = vs_props_se_delete(engid)) != VS_ERR_NONE) {
562 		(void) fprintf(stderr, "%s\n", vs_strerror(rc));
563 		return (rc);
564 	}
565 
566 	return (VS_ADM_EXIT_SUCCESS);
567 }
568 
569 
570 /*
571  * vs_adm_import
572  */
573 static int
vs_adm_import(int argc,char ** argv)574 vs_adm_import(int argc, char **argv)
575 {
576 	int rc;
577 	vs_props_t vp;
578 	uint64_t propids;
579 	char *filename;
580 
581 	if ((rc = vs_adm_file_usage(argc, argv)) != VS_ADM_EXIT_SUCCESS)
582 		return (rc);
583 
584 	filename = argv[argc - 1];
585 	rc = vs_adm_file_read(filename, vp.vp_types, sizeof (vp.vp_types));
586 	if (rc != VS_ADM_EXIT_SUCCESS)
587 		return (rc);
588 
589 	propids = VS_PROPID_TYPES;
590 	rc = vs_props_set(&vp, propids);
591 	if (rc != VS_ERR_NONE) {
592 		(void) fprintf(stderr, "%s\n", vs_strerror(rc));
593 		return (VS_ADM_EXIT_ERROR);
594 	}
595 
596 	return (VS_ADM_EXIT_SUCCESS);
597 }
598 
599 
600 /*
601  * vs_adm_validate
602  */
603 static int
vs_adm_validate(int argc,char ** argv)604 vs_adm_validate(int argc, char **argv)
605 {
606 	int rc;
607 	vs_props_t vp;
608 	char *filename;
609 
610 	if ((rc = vs_adm_file_usage(argc, argv)) != VS_ADM_EXIT_SUCCESS)
611 		return (rc);
612 
613 	filename = argv[argc - 1];
614 	rc = vs_adm_file_read(filename, vp.vp_types, sizeof (vp.vp_types));
615 	if (rc != VS_ADM_EXIT_SUCCESS)
616 		return (rc);
617 
618 	if (vs_props_validate(&vp, VS_PROPID_TYPES) != VS_ERR_NONE) {
619 		(void) fprintf(stderr, "%s: %s\n", filename, vs_strerror(rc));
620 		return (VS_ADM_EXIT_ERROR);
621 	}
622 
623 	(void) fprintf(stdout, "%s: valid\n", filename);
624 	return (VS_ADM_EXIT_SUCCESS);
625 }
626 
627 
628 /*
629  * vs_adm_export
630  */
631 static int
vs_adm_export(int argc,char ** argv)632 vs_adm_export(int argc, char **argv)
633 {
634 	int rc;
635 	vs_props_t vp;
636 	uint64_t propids;
637 	char *filename;
638 
639 	if ((rc = vs_adm_file_usage(argc, argv)) != VS_ADM_EXIT_SUCCESS)
640 		return (rc);
641 
642 	filename = argv[argc - 1];
643 	(void) memset(&vp, 0, sizeof (vs_props_t));
644 	propids = VS_PROPID_TYPES;
645 	if ((rc = vs_props_get(&vp, propids)) != VS_ERR_NONE) {
646 		(void) fprintf(stderr, "%s: %s\n", filename, vs_strerror(rc));
647 		return (VS_ADM_EXIT_ERROR);
648 	}
649 
650 	rc = vs_adm_file_write(filename, vp.vp_types);
651 	if (rc != VS_ADM_EXIT_SUCCESS)
652 		return (rc);
653 
654 	return (VS_ADM_EXIT_SUCCESS);
655 }
656 
657 
658 /*
659  * vs_adm_file_usage
660  *
661  * import, export and validate - VS_PROPID_TYPES only
662  */
663 static int
vs_adm_file_usage(int argc,char ** argv)664 vs_adm_file_usage(int argc, char **argv)
665 {
666 	const vs_adm_property_t *vap;
667 	char *prop;
668 
669 	if (argc < 4)
670 		return (VS_ADM_EXIT_USAGE);
671 
672 	/* -p optional */
673 	if (strcmp(argv[2], "-p") == 0) {
674 		if (argc != 5)
675 			return (VS_ADM_EXIT_USAGE);
676 	} else if (argc != 4)
677 		return (VS_ADM_EXIT_USAGE);
678 
679 	/* only VS_PROPID_TYPES supported */
680 	prop = argv[argc - 2];
681 	vap = vs_adm_prop_by_name(prop);
682 	if ((vap == NULL) || (vap->vap_id != VS_PROPID_TYPES)) {
683 		(void) fprintf(stderr, "%s '%s'\n",
684 		    gettext("invalid property"), prop);
685 		return (VS_ADM_EXIT_USAGE);
686 	}
687 
688 	return (VS_ADM_EXIT_SUCCESS);
689 }
690 
691 
692 /*
693  * vs_adm_file_read
694  */
695 static int
vs_adm_file_read(char * filename,char * buf,int len)696 vs_adm_file_read(char *filename, char *buf, int len)
697 {
698 	FILE *fp;
699 
700 	if ((fp = fopen(filename, "r")) == NULL) {
701 		(void) fprintf(stderr, "%s: %s\n", filename,
702 		    vs_strerror(VS_ERR_SYS));
703 		return (VS_ADM_EXIT_ERROR);
704 	}
705 
706 	(void) memset(buf, 0, len);
707 	if (fgets(buf, len, fp) == NULL) {
708 		(void) fprintf(stderr, "%s: %s\n", filename,
709 		    gettext("invalid property value"));
710 		(void) fclose(fp);
711 		return (VS_ADM_EXIT_ERROR);
712 	}
713 
714 	(void) fclose(fp);
715 
716 	/* remove newline */
717 	if (buf[strlen(buf) - 1] == '\n')
718 		buf[strlen(buf) - 1] = '\0';
719 
720 	return (VS_ADM_EXIT_SUCCESS);
721 }
722 
723 
724 /*
725  * vs_adm_file_write
726  */
727 static int
vs_adm_file_write(char * filename,char * buf)728 vs_adm_file_write(char *filename, char *buf)
729 {
730 	FILE *fp;
731 	int bytes;
732 
733 	if ((fp = fopen(filename, "w")) == NULL) {
734 		(void) fprintf(stderr, "%s: %s\n", filename,
735 		    vs_strerror(VS_ERR_SYS));
736 		return (VS_ADM_EXIT_ERROR);
737 	}
738 
739 	bytes = fprintf(fp, "%s\n", buf);
740 	if ((bytes < 0) || (bytes != strlen(buf) + 1)) {
741 		(void) fprintf(stderr, "%s: %s\n", filename,
742 		    vs_strerror(VS_ERR_SYS));
743 		(void) fclose(fp);
744 		return (VS_ADM_EXIT_ERROR);
745 	}
746 
747 	(void) fclose(fp);
748 	return (VS_ADM_EXIT_SUCCESS);
749 }
750 
751 
752 /*
753  * vs_adm_show
754  *
755  * Gets and displays all general properties and all scan engine
756  * properties.
757  */
758 /* ARGSUSED */
759 static int
vs_adm_show(int argc,char ** argv)760 vs_adm_show(int argc, char **argv)
761 {
762 	if (argc > 2)
763 		return (VS_ADM_EXIT_USAGE);
764 
765 	(void) vs_adm_get(argc, argv);
766 	(void) vs_adm_get_engine(argc, argv);
767 
768 	return (VS_ADM_EXIT_SUCCESS);
769 }
770 
771 
772 /*
773  * vs_adm_stats
774  *
775  * Gets and displays vscan service statistics.
776  */
777 /* ARGSUSED */
778 static int
vs_adm_stats(int argc,char ** argv)779 vs_adm_stats(int argc, char **argv)
780 {
781 	int rc;
782 	vs_stats_t stats;
783 
784 	/* get statistics */
785 	if (argc == 2) {
786 		if ((rc = vs_statistics(&stats)) == VS_ERR_NONE) {
787 			vs_adm_output_stats(&stats);
788 			return (VS_ADM_EXIT_SUCCESS);
789 		} else {
790 			(void) fprintf(stdout, "%s\n", vs_strerror(rc));
791 			return (VS_ADM_EXIT_ERROR);
792 		}
793 	}
794 
795 	/* reset statistics */
796 	if (argc == 3 && strcmp(argv[2], "-z") == 0) {
797 		if ((rc = vs_statistics_reset()) == VS_ERR_NONE) {
798 			return (VS_ADM_EXIT_SUCCESS);
799 		} else {
800 			(void) fprintf(stdout, "%s\n", vs_strerror(rc));
801 			return (VS_ADM_EXIT_ERROR);
802 		}
803 	}
804 
805 	/* usage error */
806 	return (vs_adm_usage(stdout));
807 }
808 
809 
810 /*
811  * vs_adm_output_stats
812  */
813 static void
vs_adm_output_stats(vs_stats_t * stats)814 vs_adm_output_stats(vs_stats_t *stats)
815 {
816 	int i;
817 	char *engid;
818 
819 	if (stats == NULL)
820 		return;
821 
822 	(void) fprintf(stdout, "scanned=%lld\n", stats->vss_scanned);
823 	(void) fprintf(stdout, "infected=%lld\n", stats->vss_infected);
824 	if (stats->vss_cleaned > 0)
825 		(void) printf("cleaned=%lld\n", stats->vss_cleaned);
826 	(void) fprintf(stdout, "failed=%lld\n", stats->vss_failed);
827 
828 	for (i = 0; i < VS_SE_MAX; i++) {
829 		engid = stats->vss_eng[i].vss_engid;
830 		if (*engid == 0)
831 			break;
832 		(void) fprintf(stdout, "%s:errors=%lld\n", engid,
833 		    stats->vss_eng[i].vss_errors);
834 	}
835 }
836 
837 
838 /*
839  * vs_adm_props_from_input
840  */
841 static int
vs_adm_props_from_input(int argc,char ** argv,vs_props_t * vsprops,uint64_t * propids)842 vs_adm_props_from_input(int argc, char **argv, vs_props_t *vsprops,
843     uint64_t *propids)
844 {
845 	const vs_adm_property_t *vap;
846 	char *val;
847 	int i;
848 
849 	(void) memset(vsprops, 0, sizeof (vs_props_t));
850 
851 	*propids = 0LL;
852 	for (i = 2; i < argc; i++) {
853 		/* The "-p" is optional */
854 		if (strcmp(argv[i], "-p") == 0) {
855 			if (++i >= argc)
856 				return (VS_ADM_EXIT_USAGE);
857 		}
858 
859 		if ((val = strchr(argv[i], '=')) == NULL)
860 			return (VS_ADM_EXIT_USAGE);
861 
862 		/* Find the vscanadm property pointer from the property name */
863 		*val = '\0';
864 		val++;
865 		if ((vap = vs_adm_prop_by_name(argv[i])) == NULL) {
866 			(void) fprintf(stderr, "%s '%s'\n",
867 			    gettext("invalid property"), argv[i]);
868 			return (VS_ADM_EXIT_ERROR);
869 		}
870 
871 		/* Add in the property id and parse the property value */
872 		*propids |= vap->vap_id;
873 		if ((vs_adm_parse(vap, val, vsprops)) != 0) {
874 			(void) fprintf(stderr, "%s '%s'\n",
875 			    gettext("invalid property value"), val);
876 			return (VS_ADM_EXIT_ERROR);
877 		}
878 	}
879 
880 	return (VS_ADM_EXIT_SUCCESS);
881 }
882 
883 
884 /*
885  * vs_adm_output_getcmd
886  *
887  * Prints the results of a get command; both the get for general
888  * configuration properties as well as the get for an engine
889  * properties.
890  *
891  */
892 static void
vs_adm_output_getcmd(uint64_t propids,const void * props)893 vs_adm_output_getcmd(uint64_t propids, const void *props)
894 {
895 	char value[VS_ADM_PRINT_BUF_LEN];
896 	uint64_t propid;
897 	const vs_adm_property_t *vap;
898 	char *label = NULL;
899 
900 	if (VS_PROPID_IS_SE(propids))
901 		label = ((vs_props_se_t *)props)->vep_engid;
902 
903 	/*
904 	 * Unparse values from the property structure into readable strings
905 	 * and print them.
906 	 */
907 	for (propid = 1LL; propid <= VS_PROPID_MAX; propid <<= 1) {
908 		if ((propids & propid) == 0)
909 			continue;
910 
911 		if ((vap = vs_adm_prop_by_id(propid)) == NULL)
912 			continue;
913 
914 		*value = '\0';
915 		vs_adm_unparse(vap, props, value, sizeof (value));
916 
917 		if (label)
918 			(void) fprintf(stdout, "%s:", label);
919 		(void) fprintf(stdout, "%s=%s\n", vap->vap_name, value);
920 	}
921 
922 	(void) fprintf(stdout, "\n");
923 }
924 
925 
926 /*
927  * vs_adm_prop_by_name
928  *
929  * Finds and returns a pointer to a vscan property structure from the
930  * property table by property name.
931  */
932 static const vs_adm_property_t *
vs_adm_prop_by_name(const char * propname)933 vs_adm_prop_by_name(const char *propname)
934 {
935 	const vs_adm_property_t *p;
936 
937 	for (p = vs_adm_props_all; p->vap_name != NULL; p++) {
938 		if (strcmp(propname, p->vap_name) == 0)
939 			return (p);
940 	}
941 
942 	return (NULL);
943 }
944 
945 
946 /*
947  * vs_adm_prop_by_id
948  *
949  * Finds and returns a pointer to a vscan property structure from the
950  * property table by property name.
951  */
952 static const vs_adm_property_t *
vs_adm_prop_by_id(const uint64_t propid)953 vs_adm_prop_by_id(const uint64_t propid)
954 {
955 	const vs_adm_property_t *p;
956 
957 	for (p = vs_adm_props_all; p->vap_id != 0; p++) {
958 		if (propid == p->vap_id)
959 			return (p);
960 	}
961 
962 	return (NULL);
963 }
964 
965 
966 /*
967  * vs_adm_parse
968  *
969  * Entry point for parsing the user input strings into a data structure
970  * used for setting values. Dispatches the actual parsing to the parse
971  * routine for the specified vscanadm property.
972  *
973  * This function is used to dispatch parsing for values supplied by the
974  * user for all subcommands; both the general configuration as well as
975  * scan engine configuration. The structure pointer is therefore typed
976  * as a void pointer, and cast appropriately in the parse routine for
977  * the vscanadm property.
978  */
979 static int
vs_adm_parse(const vs_adm_property_t * vap,const char * valvap_name,void * vp)980 vs_adm_parse(const vs_adm_property_t *vap, const char *valvap_name,
981 	void *vp)
982 {
983 	return ((vap->vap_parse)(valvap_name, vp));
984 }
985 
986 
987 /*
988  * vs_adm_parse_maxsize
989  *
990  * Parses a user-supplied string into a maxsize (decimal) value for
991  * the general vscan configuration properties.
992  */
993 static int
vs_adm_parse_maxsize(const char * valstr,void * vp)994 vs_adm_parse_maxsize(const char *valstr, void *vp)
995 {
996 	vs_props_t *svcp = vp;
997 
998 	uint64_t maxsize;
999 	char *end;
1000 
1001 	errno = 0;
1002 	maxsize = strtoll(valstr, &end, 10);
1003 	if (errno != 0)
1004 		return (-1);
1005 	(void) snprintf(svcp->vp_maxsize, sizeof (svcp->vp_maxsize),
1006 	    "%llu%s", maxsize, end);
1007 
1008 	return (0);
1009 }
1010 
1011 
1012 /*
1013  * vs_adm_parse_maxsize_action
1014  *
1015  * Parses a user-supplied string into a maxsize action value for the
1016  * general vscan configuration properties.
1017  *
1018  * Returns: 0 success
1019  *         -1 failure
1020  */
1021 static int
vs_adm_parse_maxsize_action(const char * valstr,void * vp)1022 vs_adm_parse_maxsize_action(const char *valstr, void *vp)
1023 {
1024 	vs_props_t *svcp = vp;
1025 
1026 	if (strcmp(valstr, VS_ADM_ALLOW) == 0) {
1027 		svcp->vp_maxsize_action = B_TRUE;
1028 		return (0);
1029 	}
1030 
1031 	if (strcmp(valstr, VS_ADM_DENY) == 0) {
1032 		svcp->vp_maxsize_action = B_FALSE;
1033 		return (0);
1034 	}
1035 
1036 	return (-1);
1037 }
1038 
1039 
1040 /*
1041  * vs_adm_parse_types
1042  *
1043  * Returns: 0 success
1044  *         -1 on failure.
1045  */
1046 static int
vs_adm_parse_types(const char * valstr,void * vp)1047 vs_adm_parse_types(const char *valstr, void *vp)
1048 {
1049 	vs_props_t *svcp = vp;
1050 
1051 	if (strlen(valstr) >= sizeof (svcp->vp_types))
1052 		return (-1);
1053 
1054 	if (strlcpy(svcp->vp_types, valstr, sizeof (svcp->vp_types))
1055 	    >= sizeof (svcp->vp_types))
1056 		return (-1);
1057 
1058 	return (0);
1059 }
1060 
1061 
1062 /*
1063  * vs_adm_parse_enable
1064  *
1065  * Parses a user-supplied string into an enable value for the
1066  * properties of a scan engine.
1067  *
1068  * Returns: 0 success
1069  *         -1 on failure.
1070  */
1071 static int
vs_adm_parse_enable(const char * valstr,void * vp)1072 vs_adm_parse_enable(const char *valstr, void *vp)
1073 {
1074 	vs_props_se_t *sep = vp;
1075 
1076 	if (strcmp(valstr, VS_ADM_ON) == 0) {
1077 		sep->vep_enable = B_TRUE;
1078 		return (0);
1079 	}
1080 
1081 	if (strcmp(valstr, VS_ADM_OFF) == 0) {
1082 		sep->vep_enable = B_FALSE;
1083 		return (0);
1084 	}
1085 
1086 	return (-1);
1087 }
1088 
1089 
1090 /*
1091  * vs_adm_parse_host
1092  *
1093  * Parses a user-supplied string into an ip address value for the
1094  * properties of a scan engine.
1095  */
1096 static int
vs_adm_parse_host(const char * valstr,void * vp)1097 vs_adm_parse_host(const char *valstr, void *vp)
1098 {
1099 	vs_props_se_t *sep = vp;
1100 
1101 	if (strlen(valstr) >= sizeof (sep->vep_host))
1102 		return (-1);
1103 
1104 	if (strlcpy(sep->vep_host, valstr, sizeof (sep->vep_host)) >=
1105 	    sizeof (sep->vep_host))
1106 		return (-1);
1107 
1108 	return (0);
1109 }
1110 
1111 
1112 /*
1113  * vs_adm_parse_port
1114  *
1115  * Parses a user-supplied string into a port value for the properties of
1116  * a scan engine. The port is an unsigned short int, but the conversion
1117  * must be done on a word-sized int. Casting the converted int into the
1118  * port member of the property structure can result in a valid but
1119  * unintended value, so the range is checked first for validity.
1120  *
1121  * Returns: 0 success
1122  *         -1 on failure.
1123  */
1124 static int
vs_adm_parse_port(const char * valstr,void * vp)1125 vs_adm_parse_port(const char *valstr, void *vp)
1126 {
1127 	vs_props_se_t *sep = vp;
1128 	unsigned long port;
1129 	char *end;
1130 
1131 	end = 0;
1132 	port = strtoul(valstr, &end, 0);
1133 	if (port > UINT16_MAX || (end < (valstr + strlen(valstr))))
1134 		return (-1);
1135 
1136 	sep->vep_port = port;
1137 
1138 	return (0);
1139 }
1140 
1141 
1142 /*
1143  * vs_adm_parse_maxconn
1144  *
1145  * Parses a user-supplied string into a max connections (decimal) value
1146  * for the properties of a scan engine.
1147  *
1148  * Returns: 0 success
1149  *         -1 on failure.
1150  */
1151 static int
vs_adm_parse_maxconn(const char * valstr,void * vp)1152 vs_adm_parse_maxconn(const char *valstr, void *vp)
1153 {
1154 	vs_props_se_t *sep = vp;
1155 	char *end;
1156 
1157 	sep->vep_maxconn = strtoll(valstr, &end, 10);
1158 	if (end < valstr + strlen(valstr))
1159 		return (-1);
1160 
1161 	return (0);
1162 }
1163 
1164 
1165 /*
1166  * vs_adm_unparse
1167  *
1168  * Entry point for unparsing native data into a readable string
1169  * used for display to the user. Dispatches the actual unparsing to
1170  * the unparse routine for the specified vscanadm property.
1171  *
1172  * This function is used to dispatch unparsing for all subcommands.
1173  * The structure pointer is therefore typed as a void pointer, and
1174  * cast appropriately in the unparse routine for the vscanadm property.
1175  */
1176 static void
vs_adm_unparse(const vs_adm_property_t * vap,const void * vp,char * buf,size_t len)1177 vs_adm_unparse(const vs_adm_property_t *vap, const void *vp,
1178 	char *buf, size_t len)
1179 {
1180 	if ((vap->vap_unparse)(vp, buf, len) != 0)
1181 		(void) snprintf(buf, len, gettext(" (error) "));
1182 }
1183 
1184 
1185 /*
1186  *  vs_adm_unparse_maxsize
1187  *
1188  * Unparses a max fsize value in native data form into a
1189  * user-readable string.
1190  */
1191 /* ARGSUSED */
1192 static int
vs_adm_unparse_maxsize(const void * vp,char * buf,size_t len)1193 vs_adm_unparse_maxsize(const void *vp, char *buf, size_t len)
1194 {
1195 	const vs_props_t *svcp = vp;
1196 
1197 	(void) snprintf(buf, len, "%s", svcp->vp_maxsize);
1198 
1199 	return (0);
1200 }
1201 
1202 
1203 /*
1204  * vs_adm_unparse_maxsize_action
1205  *
1206  * Unparses a max fsize action value in native data form into a
1207  * user-readable string.
1208  */
1209 /* ARGSUSED */
1210 static int
vs_adm_unparse_maxsize_action(const void * vp,char * buf,size_t len)1211 vs_adm_unparse_maxsize_action(const void *vp, char *buf, size_t len)
1212 {
1213 	const vs_props_t *svcp = vp;
1214 
1215 	(void) snprintf(buf, len, "%s",
1216 	    svcp->vp_maxsize_action ?  VS_ADM_ALLOW : VS_ADM_DENY);
1217 
1218 	return (0);
1219 }
1220 
1221 
1222 /*
1223  * vs_adm_unparse_types
1224  *
1225  * Returns: 0 success
1226  *         -1 on failure.
1227  */
1228 static int
vs_adm_unparse_types(const void * vp,char * buf,size_t len)1229 vs_adm_unparse_types(const void *vp, char *buf, size_t len)
1230 {
1231 	const vs_props_t *svcp = vp;
1232 
1233 	(void) strlcpy(buf, svcp->vp_types, len);
1234 
1235 	return (0);
1236 }
1237 
1238 
1239 /*
1240  * vs_adm_unparse_enable
1241  *
1242  * Unparses the enable value for a scan engine in native data
1243  * form into a user-readable string.
1244  */
1245 /* ARGSUSED */
1246 static int
vs_adm_unparse_enable(const void * vp,char * buf,size_t len)1247 vs_adm_unparse_enable(const void *vp, char *buf, size_t len)
1248 {
1249 	const vs_props_se_t *sep = vp;
1250 
1251 	(void) snprintf(buf, len, "%s",
1252 	    sep->vep_enable ?  VS_ADM_ON : VS_ADM_OFF);
1253 
1254 	return (0);
1255 }
1256 
1257 
1258 /*
1259  * vs_adm_unparse_host
1260  *
1261  * Unparses an ip address for a scan engine in native data
1262  * form into a user-readable string.
1263  *
1264  * Returns: 0 success
1265  *         -1 on failure.
1266  */
1267 /* ARGSUSED */
1268 static int
vs_adm_unparse_host(const void * vp,char * buf,size_t len)1269 vs_adm_unparse_host(const void *vp, char *buf, size_t len)
1270 {
1271 	const vs_props_se_t *sep = vp;
1272 
1273 	(void) strlcpy(buf, sep->vep_host, len);
1274 
1275 	return (0);
1276 }
1277 
1278 
1279 /*
1280  * vs_adm_unparse_port
1281  *
1282  * Unparses a port value for a scan engine in native data
1283  * form into a user-readable string.
1284  */
1285 /* ARGSUSED */
1286 static int
vs_adm_unparse_port(const void * vp,char * buf,size_t len)1287 vs_adm_unparse_port(const void *vp, char *buf, size_t len)
1288 {
1289 	const vs_props_se_t *sep = vp;
1290 
1291 	(void) snprintf(buf, len, "%hu", sep->vep_port);
1292 
1293 	return (0);
1294 }
1295 
1296 
1297 /*
1298  * vs_adm_unparse_maxconn
1299  *
1300  * Unparses a max connecctions for a scan engine in native data
1301  * form into a user-readable string.
1302  *
1303  */
1304 /* ARGSUSED */
1305 static int
vs_adm_unparse_maxconn(const void * vp,char * buf,size_t len)1306 vs_adm_unparse_maxconn(const void *vp, char *buf, size_t len)
1307 {
1308 	const vs_props_se_t *sep = vp;
1309 
1310 	(void) snprintf(buf, len, "%lld", sep->vep_maxconn);
1311 
1312 	return (0);
1313 }
1314