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 /*
23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /*
28 * add_allocatable -
29 * a command-line interface to add device to device_allocate and
30 * device_maps.
31 */
32
33 #ifndef __EXTENSIONS__
34 #define __EXTENSIONS__ /* needed for _strtok_r */
35 #endif
36
37 #include <sys/types.h>
38 #include <unistd.h>
39 #include <stdlib.h>
40 #include <strings.h>
41 #include <string.h>
42 #include <locale.h>
43 #include <libintl.h>
44 #include <pwd.h>
45 #include <nss_dbdefs.h>
46 #include <auth_attr.h>
47 #include <auth_list.h>
48 #include <zone.h>
49 #include <tsol/label.h>
50 #include <bsm/devices.h>
51 #include <bsm/devalloc.h>
52
53 #define NO_OVERRIDE -1
54
55 int check_args(da_args *);
56 int process_args(int, char **, da_args *, char *);
57 int scan_label(char *, char *);
58 void usage(da_args *, char *);
59
60 int system_labeled = 0;
61
62 int
main(int argc,char * argv[])63 main(int argc, char *argv[])
64 {
65 int rc;
66 uid_t uid;
67 char *progname;
68 char pwbuf[NSS_LINELEN_PASSWD];
69 struct passwd pwd;
70 da_args dargs;
71 devinfo_t devinfo;
72
73 (void) setlocale(LC_ALL, "");
74 #if !defined(TEXT_DOMAIN)
75 #define TEXT_DOMAIN "SYS_TEST"
76 #endif
77 (void) textdomain(TEXT_DOMAIN);
78 if ((progname = strrchr(argv[0], '/')) == NULL)
79 progname = argv[0];
80 else
81 progname++;
82
83 system_labeled = is_system_labeled();
84 if (system_labeled) {
85 /*
86 * this command can be run only in the global zone.
87 */
88 if (getzoneid() != GLOBAL_ZONEID) {
89 (void) fprintf(stderr, "%s%s", progname,
90 gettext(" : must be run in global zone\n"));
91 exit(1);
92 }
93 } else {
94 /*
95 * this command works in Trusted Extensions only.
96 */
97 (void) fprintf(stderr, "%s%s", progname,
98 gettext(" : need to install Trusted Extensions\n"));
99 exit(1);
100 }
101
102 dargs.optflag = 0;
103 dargs.rootdir = NULL;
104 dargs.devnames = NULL;
105 dargs.devinfo = &devinfo;
106
107 if (strcmp(progname, "add_allocatable") == 0) {
108 dargs.optflag |= DA_ADD;
109 } else if (strcmp(progname, "remove_allocatable") == 0) {
110 dargs.optflag |= DA_REMOVE;
111 } else {
112 usage(&dargs, progname);
113 exit(1);
114 }
115
116 uid = getuid();
117 if ((getpwuid_r(uid, &pwd, pwbuf, sizeof (pwbuf))) == NULL) {
118 (void) fprintf(stderr, "%s%s", progname,
119 gettext(" : getpwuid_r failed: "));
120 (void) fprintf(stderr, "%s\n", strerror(errno));
121 exit(2);
122 }
123
124 if (chkauthattr(DEVICE_CONFIG_AUTH, pwd.pw_name) != 1) {
125 (void) fprintf(stderr, "%s%s%s", progname,
126 gettext(" : user lacks authorization: \n"),
127 DEVICE_CONFIG_AUTH);
128 exit(4);
129 }
130
131 if (process_args(argc, argv, &dargs, progname) != 0) {
132 usage(&dargs, progname);
133 exit(1);
134 }
135
136 if (dargs.optflag & DA_ADD) {
137 if (check_args(&dargs) == NO_OVERRIDE) {
138 (void) fprintf(stderr, "%s%s%s%s", progname,
139 gettext(" : entry exists for "),
140 dargs.devinfo->devname, gettext("\n"));
141 usage(&dargs, progname);
142 exit(3);
143 }
144 }
145
146 if (dargs.optflag & DA_DEFATTRS)
147 rc = da_update_defattrs(&dargs);
148 else
149 rc = da_update_device(&dargs);
150
151 if ((rc != 0) && (!(dargs.optflag & DA_SILENT))) {
152 if (rc == -2)
153 (void) fprintf(stderr, "%s%s", progname,
154 gettext(" : device name/type/list missing\n"));
155 else if (dargs.optflag & DA_ADD)
156 (void) fprintf(stderr, "%s%s", progname,
157 gettext(" : error adding/updating device\n"));
158 else if (dargs.optflag & DA_REMOVE)
159 (void) fprintf(stderr, "%s%s", progname,
160 gettext(" : error removing device\n"));
161 rc = 2; /* exit code for 'Unknown system error' in man page */
162 }
163
164 return (rc);
165 }
166
167 int
process_args(int argc,char ** argv,da_args * dargs,char * progname)168 process_args(int argc, char **argv, da_args *dargs, char *progname)
169 {
170 int c;
171 int aflag, cflag, dflag, fflag, lflag, nflag, oflag, tflag;
172 extern char *optarg;
173 devinfo_t *devinfo;
174
175 devinfo = dargs->devinfo;
176 aflag = cflag = dflag = fflag = lflag = nflag = oflag = tflag = 0;
177 devinfo->devname = devinfo->devtype = devinfo->devauths =
178 devinfo->devexec = devinfo->devopts = devinfo->devlist = NULL;
179 devinfo->instance = 0;
180
181 while ((c = getopt(argc, argv, "a:c:dfl:n:o:st:")) != EOF) {
182 switch (c) {
183 case 'a':
184 devinfo->devauths = optarg;
185 aflag++;
186 break;
187 case 'c':
188 devinfo->devexec = optarg;
189 if (strlen(devinfo->devexec) == 0) {
190 if (!(dargs->optflag & DA_SILENT))
191 (void) fprintf(stderr, "%s%s", progname,
192 gettext(" : device clean program"
193 " name not found\n"));
194 return (1);
195 }
196 cflag++;
197 break;
198 case 'd':
199 dargs->optflag |= DA_DEFATTRS;
200 dflag++;
201 break;
202 case 'l':
203 devinfo->devlist = optarg;
204 if (strlen(devinfo->devlist) == 0) {
205 if (!(dargs->optflag & DA_SILENT))
206 (void) fprintf(stderr, "%s%s", progname,
207 gettext(" : device file list"
208 " not found\n"));
209 return (1);
210 }
211 lflag++;
212 break;
213 case 'f':
214 dargs->optflag |= DA_FORCE;
215 fflag++;
216 break;
217 case 'n':
218 devinfo->devname = optarg;
219 if (strlen(devinfo->devname) == 0) {
220 if (!(dargs->optflag & DA_SILENT))
221 (void) fprintf(stderr, "%s%s", progname,
222 gettext(" : device name "
223 "not found\n"));
224 return (1);
225 }
226 nflag++;
227 break;
228 case 'o':
229 /* check for field delimiters in the option */
230 if (strpbrk(optarg, ":;=") == NULL) {
231 if (!(dargs->optflag & DA_SILENT)) {
232 (void) fprintf(stderr, "%s%s%s",
233 progname,
234 gettext(" : invalid "
235 "key=val string: "),
236 optarg);
237 (void) fprintf(stderr, "%s",
238 gettext("\n"));
239 }
240 return (1);
241 }
242 devinfo->devopts = optarg;
243 if (dargs->optflag & DA_ADD) {
244 if (scan_label(devinfo->devopts, progname) != 0)
245 return (1);
246 }
247 oflag++;
248 break;
249 case 's':
250 dargs->optflag |= DA_SILENT;
251 break;
252 case 't':
253 devinfo->devtype = optarg;
254 if (strlen(devinfo->devtype) == 0) {
255 if (!(dargs->optflag & DA_SILENT))
256 (void) fprintf(stderr, "%s%s", progname,
257 gettext(" : device type "
258 "not found\n"));
259 return (1);
260 }
261 tflag++;
262 break;
263 default :
264 return (1);
265 }
266 }
267
268
269 if (dargs->optflag & DA_ADD) {
270 if (dflag) {
271 /* -d requires -t, but does not like -n */
272 if (nflag || tflag == 0)
273 return (1);
274 } else if (nflag == 0 && tflag == 0 && lflag == 0) {
275 /* require at least -n or -t or -l to be specified */
276 if (!(dargs->optflag & DA_SILENT))
277 (void) fprintf(stderr, "%s%s", progname,
278 gettext(" : required options missing\n"));
279 return (1);
280 }
281 } else if (dargs->optflag & DA_REMOVE) {
282 if (dflag) {
283 /* -d requires -t, but does not like -n */
284 if (nflag || tflag == 0)
285 return (1);
286 } else if (nflag == 0 && tflag == 0) {
287 /* require at least -n or -t to be specified */
288 if (!(dargs->optflag & DA_SILENT))
289 (void) fprintf(stderr, "%s%s", progname,
290 gettext(" : required options missing\n"));
291 return (1);
292 }
293 /* there's a bunch not accepted by remove_allocatable */
294 if (aflag || cflag || lflag || oflag)
295 return (1);
296 } else {
297 return (1);
298 }
299
300 /* check for option specified more than once */
301 if (aflag > 1 || cflag > 1 || lflag > 1 || fflag > 1 ||
302 nflag > 1 || tflag > 1) {
303 if (!(dargs->optflag & DA_SILENT))
304 (void) fprintf(stderr, "%s%s", progname,
305 gettext(" : multiple-defined options\n"));
306 return (1);
307 }
308
309 return (0);
310 }
311
312 int
verify_label(char * token,char * progname)313 verify_label(char *token, char *progname)
314 {
315 int error = 0;
316 char *p, *val, *str;
317
318 if ((strstr(token, DAOPT_MINLABEL) == NULL) &&
319 (strstr(token, DAOPT_MAXLABEL) == NULL)) {
320 /* no label specified */
321 return (0);
322 }
323 if ((val = strchr(token, '=')) == NULL)
324 return (1);
325 val++;
326 /*
327 * if non-default labels are specified, check if they are correct
328 */
329 if ((strcmp(val, DA_DEFAULT_MIN) != 0) &&
330 (strcmp(val, DA_DEFAULT_MAX) != 0)) {
331 m_label_t *slabel = NULL;
332
333 str = strdup(val);
334 /* get rid of double quotes if they exist */
335 while (*str == '"')
336 str++;
337 if ((p = strchr(str, '"')) != NULL)
338 *p = '\0';
339 if (str_to_label(str, &slabel, MAC_LABEL, L_NO_CORRECTION,
340 &error) == -1) {
341 (void) fprintf(stderr, "%s%s%s", progname,
342 gettext(" : bad label input: "),
343 val);
344 (void) fprintf(stderr, "%s", gettext("\n"));
345 free(str);
346 m_label_free(slabel);
347 return (1);
348 }
349 free(str);
350 m_label_free(slabel);
351 }
352
353 return (0);
354 }
355
356 int
scan_label(char * devopts,char * progname)357 scan_label(char *devopts, char *progname)
358 {
359 char *tok = NULL;
360 char *lasts, *optsarg;
361
362 if (devopts == NULL)
363 return (0);
364
365 if ((optsarg = strdup(devopts)) == NULL)
366 return (1);
367
368 if ((tok = strtok_r(optsarg, KV_TOKEN_DELIMIT, &lasts)) == NULL)
369 return (1);
370
371 if (verify_label(tok, progname) != 0) {
372 free(optsarg);
373 return (1);
374 }
375
376 while ((tok = strtok_r(NULL, KV_TOKEN_DELIMIT, &lasts)) != NULL) {
377 if (verify_label(tok, progname) != 0) {
378 free(optsarg);
379 return (1);
380 }
381 }
382
383 return (0);
384 }
385
386 int
check_args(da_args * dargs)387 check_args(da_args *dargs)
388 {
389 int nlen;
390 char *kval, *nopts, *ntok, *nstr,
391 *defmin, *defmax, *defauths, *defexec;
392 kva_t *kva;
393 devinfo_t *devinfo;
394 devalloc_t *da = NULL;
395 da_defs_t *da_defs = NULL;
396
397 devinfo = dargs->devinfo;
398 /*
399 * check if we're updating an existing entry without -f
400 */
401 setdaent();
402 da = getdanam(devinfo->devname);
403 enddaent();
404 if (da && !(dargs->optflag & DA_FORCE)) {
405 freedaent(da);
406 return (NO_OVERRIDE);
407 }
408 if ((devinfo->devopts == NULL) ||
409 (strstr(devinfo->devopts, DAOPT_MINLABEL) == NULL) ||
410 (strstr(devinfo->devopts, DAOPT_MAXLABEL) == NULL) ||
411 (devinfo->devauths == NULL) ||
412 (devinfo->devexec == NULL)) {
413 /* fill in defaults as required */
414 defmin = DA_DEFAULT_MIN;
415 defmax = DA_DEFAULT_MAX;
416 defauths = DEFAULT_DEV_ALLOC_AUTH;
417 defexec = DA_DEFAULT_CLEAN;
418 setdadefent();
419 if (da_defs = getdadeftype(devinfo->devtype)) {
420 kva = da_defs->devopts;
421 if ((kval = kva_match(kva, DAOPT_MINLABEL)) != NULL)
422 defmin = strdup(kval);
423 if ((kval = kva_match(kva, DAOPT_MAXLABEL)) != NULL)
424 defmax = strdup(kval);
425 if ((kval = kva_match(kva, DAOPT_AUTHS)) != NULL)
426 defauths = strdup(kval);
427 if ((kval = kva_match(kva, DAOPT_CSCRIPT)) != NULL)
428 defexec = strdup(kval);
429 freedadefent(da_defs);
430 }
431 enddadefent();
432 if (devinfo->devauths == NULL)
433 devinfo->devauths = defauths;
434 if (devinfo->devexec == NULL)
435 devinfo->devexec = defexec;
436 if (devinfo->devopts == NULL) {
437 /* add default minlabel and maxlabel */
438 nlen = strlen(DAOPT_MINLABEL) + strlen(KV_ASSIGN) +
439 strlen(defmin) + strlen(KV_TOKEN_DELIMIT) +
440 strlen(DAOPT_MAXLABEL) + strlen(KV_ASSIGN) +
441 strlen(defmax) + 1; /* +1 for terminator */
442 if (nopts = (char *)malloc(nlen)) {
443 (void) snprintf(nopts, nlen, "%s%s%s%s%s%s%s",
444 DAOPT_MINLABEL, KV_ASSIGN, defmin,
445 KV_TOKEN_DELIMIT,
446 DAOPT_MAXLABEL, KV_ASSIGN, defmax);
447 devinfo->devopts = nopts;
448 }
449 } else {
450 if (strstr(devinfo->devopts, DAOPT_MINLABEL) == NULL) {
451 /* add default minlabel */
452 ntok = DAOPT_MINLABEL;
453 nstr = defmin;
454 nlen = strlen(devinfo->devopts) +
455 strlen(KV_TOKEN_DELIMIT) +
456 strlen(ntok) + strlen(KV_ASSIGN) +
457 strlen(nstr) + 1;
458 if (nopts = (char *)malloc(nlen)) {
459 (void) snprintf(nopts, nlen,
460 "%s%s%s%s%s",
461 devinfo->devopts, KV_TOKEN_DELIMIT,
462 ntok, KV_ASSIGN, nstr);
463 devinfo->devopts = nopts;
464 }
465 }
466 if (strstr(devinfo->devopts, DAOPT_MAXLABEL) == NULL) {
467 /* add default maxlabel */
468 ntok = DAOPT_MAXLABEL;
469 nstr = defmax;
470 nlen = strlen(devinfo->devopts) +
471 strlen(KV_TOKEN_DELIMIT) +
472 strlen(ntok) + strlen(KV_ASSIGN) +
473 strlen(nstr) + 1;
474 if (nopts = (char *)malloc(nlen)) {
475 (void) snprintf(nopts, nlen,
476 "%s%s%s%s%s",
477 devinfo->devopts, KV_TOKEN_DELIMIT,
478 ntok, KV_ASSIGN, nstr);
479 devinfo->devopts = nopts;
480 }
481 }
482 }
483 }
484
485 return (0);
486 }
487
488 void
usage(da_args * dargs,char * progname)489 usage(da_args *dargs, char *progname)
490 {
491 if (dargs->optflag & DA_SILENT)
492 return;
493 if (dargs->optflag & DA_ADD)
494 (void) fprintf(stderr, "%s%s%s", gettext("Usage: "), progname,
495 gettext(" [-f][-s][-d] -n name -t type -l device-list"
496 "\n\t[-a authorization] [-c cleaning program] "
497 "[-o key=value]\n"));
498 else if (dargs->optflag & DA_REMOVE)
499 (void) fprintf(stderr, "%s%s%s", gettext("Usage: "), progname,
500 gettext(" [-f][-s][-d] [-n name|-t type]\n"));
501 else
502 (void) fprintf(stderr, gettext("Invalid usage\n"), progname);
503 }
504