0
|
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 "@(#)add_allocatable.c 1.1 07/05/24 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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 }
|