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