ofw_options.c revision 132788
1/*-
2 * Copyright (c) 2004 Marius Strobl
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
18 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
23 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include <sys/cdefs.h>
27__FBSDID("$FreeBSD: head/usr.sbin/eeprom/ofw_options.c 132788 2004-07-28 07:17:00Z kan $");
28
29/*
30 * Handlers for Open Firmware /options node.
31 */
32
33#include <sys/types.h>
34
35#include <dev/ofw/openfirm.h>
36
37#include <err.h>
38#include <fcntl.h>
39#include <readpassphrase.h>
40#include <stdio.h>
41#include <stdlib.h>
42#include <string.h>
43#include <sysexits.h>
44#include <unistd.h>
45
46#include "ofw_options.h"
47#include "ofw_util.h"
48
49#define	OFWO_LOGO	512
50#define	OFWO_MAXPROP	31
51#define	OFWO_MAXPWD	8
52
53struct ofwo_extabent {
54	const char	*ex_prop;
55	int		(*ex_handler)(struct ofwo_extabent *, int, const void *,
56			    int, const char *);
57};
58
59static int	ofwo_oemlogo(struct ofwo_extabent *, int, const void *, int,
60		    const char *);
61static int	ofwo_secmode(struct ofwo_extabent *, int, const void *, int,
62		    const char *);
63static int	ofwo_secpwd(struct ofwo_extabent *, int, const void *, int,
64		    const char *);
65
66static struct ofwo_extabent ofwo_extab[] = {
67	{ "oem-logo",			ofwo_oemlogo },
68	{ "security-mode",		ofwo_secmode },
69	{ "security-password",		ofwo_secpwd },
70	{ NULL,				NULL }
71};
72
73static int		ofwo_setpass(int);
74static int		ofwo_setstr(int, const void *, int, const char *,
75			    const char *);
76
77static __inline void
78ofwo_printprop(const char *prop, const char* buf, int buflen)
79{
80
81	printf("%s: %.*s\n", prop, buflen, buf);
82}
83
84static int
85ofwo_oemlogo(struct ofwo_extabent *exent, int fd, const void *buf, int buflen,
86    const char *val)
87{
88	int lfd;
89	char logo[OFWO_LOGO + 1];
90
91	if (val) {
92		if (val[0] == '\0')
93			ofw_setprop(fd, ofw_optnode(fd), exent->ex_prop, "", 1);
94		else {
95			if ((lfd = open(val, O_RDONLY)) == -1) {
96				warn("could not open '%s'", val);
97				return (EX_USAGE);
98			}
99			if (read(lfd, logo, OFWO_LOGO) != OFWO_LOGO ||
100			    lseek(lfd, 0, SEEK_END) != OFWO_LOGO) {
101				close(lfd);
102				warnx("logo '%s' has wrong size.", val);
103				return (EX_USAGE);
104			}
105			close(lfd);
106			logo[OFWO_LOGO] = '\0';
107			if (ofw_setprop(fd, ofw_optnode(fd), exent->ex_prop,
108			    logo, OFWO_LOGO + 1) != OFWO_LOGO)
109				errx(EX_IOERR, "writing logo failed.");
110		}
111	} else
112		if (buflen != 0)
113			printf("%s: <logo data>\n", exent->ex_prop);
114		else
115			ofwo_printprop(exent->ex_prop, (const char *)buf,
116			    buflen);
117	return (EX_OK);
118}
119
120static int
121ofwo_secmode(struct ofwo_extabent *exent, int fd, const void *buf, int buflen,
122    const char *val)
123{
124	int res;
125
126	if (val) {
127		if (strcmp(val, "full") == 0 || strcmp(val, "command") == 0) {
128			if ((res = ofwo_setpass(fd)) != EX_OK)
129				return (res);
130			if ((res = ofwo_setstr(fd, buf, buflen, exent->ex_prop,
131			    val)) != EX_OK)
132				ofw_setprop(fd, ofw_optnode(fd),
133				    "security-password", "", 1);
134			return (res);
135		}
136		if (strcmp(val, "none") == 0) {
137			ofw_setprop(fd, ofw_optnode(fd), "security-password",
138			    "", 1);
139			return (ofwo_setstr(fd, buf, buflen, exent->ex_prop,
140			    val));
141		}
142		return (EX_DATAERR);
143	} else
144		ofwo_printprop(exent->ex_prop, (const char *)buf, buflen);
145	return (EX_OK);
146}
147
148static int
149ofwo_secpwd(struct ofwo_extabent *exent, int fd __unused,
150    const void *buf __unused, __unused int buflen, const char *val)
151{
152	void *pbuf;
153	int len, pblen, rv;
154
155	pblen = 0;
156	rv = EX_OK;
157	pbuf = NULL;
158	if (val) {
159		len = ofw_getprop_alloc(fd, ofw_optnode(fd), "security-mode",
160		    &pbuf, &pblen, 1);
161		if (len <= 0 || strncmp("none", (char *)pbuf, len) == 0) {
162			rv = EX_CONFIG;
163			warnx("no security mode set.");
164		} else if (strncmp("command", (char *)pbuf, len) == 0 ||
165		    strncmp("full", (char *)pbuf, len) == 0) {
166			rv = ofwo_setpass(fd);
167		} else {
168			rv = EX_CONFIG;
169			warnx("invalid security mode.");
170		}
171	} else
172		ofwo_printprop(exent->ex_prop, (const char *)buf, buflen);
173	if (pbuf != NULL)
174		free(pbuf);
175	return (rv);
176}
177
178static int
179ofwo_setpass(int fd)
180{
181	char pwd1[OFWO_MAXPWD + 1], pwd2[OFWO_MAXPWD + 1];
182
183	if (readpassphrase("New password:", pwd1, sizeof(pwd1),
184	    RPP_ECHO_OFF | RPP_REQUIRE_TTY) == NULL ||
185	    readpassphrase("Retype new password:", pwd2, sizeof(pwd2),
186	    RPP_ECHO_OFF | RPP_REQUIRE_TTY) == NULL)
187		errx(EX_USAGE, "failed to get password.");
188	if (strlen(pwd1) == 0) {
189		printf("Password unchanged.\n");
190		return (EX_OK);
191	}
192	if (strcmp(pwd1, pwd2) != 0) {
193		printf("Mismatch - password unchanged.\n");
194		return (EX_USAGE);
195	}
196	ofw_setprop(fd, ofw_optnode(fd), "security-password", pwd1,
197	    strlen(pwd1) + 1);
198	return (EX_OK);
199}
200
201static int
202ofwo_setstr(int fd, const void *buf, int buflen, const char *prop,
203    const char *val)
204{
205	void *pbuf;
206	int len, pblen, rv;
207	phandle_t optnode;
208	char *oval;
209
210	pblen = 0;
211	rv = EX_OK;
212	pbuf = NULL;
213	optnode = ofw_optnode(fd);
214	ofw_setprop(fd, optnode, prop, val, strlen(val) + 1);
215	len = ofw_getprop_alloc(fd, optnode, prop, &pbuf, &pblen, 1);
216	if (len < 0 || strncmp(val, (char *)pbuf, len) != 0) {
217		/*
218		 * The value is too long for this property and the OFW has
219		 * truncated it to fit or the value is illegal and a legal
220		 * one has been written instead (e.g. attempted to write
221		 * "foobar" to a "true"/"false"-property) - try to recover
222		 * the old value.
223		 */
224		rv = EX_DATAERR;
225		if ((oval = malloc(buflen + 1)) == NULL)
226			err(EX_OSERR, "malloc() failed.");
227		strncpy(oval, buf, buflen);
228		oval[buflen] = '\0';
229		len = ofw_setprop(fd, optnode, prop, oval, buflen + 1);
230		if (len != buflen)
231			errx(EX_IOERR, "recovery of old value failed.");
232		free(oval);
233		goto out;
234	}
235	printf("%s: %.*s%s->%s%.*s\n", prop, buflen, (const char *)buf,
236	    buflen > 0 ? " " : "", len > 0 ? " " : "", len, (char *)pbuf);
237out:
238	if (pbuf != NULL)
239		free(pbuf);
240	return (rv);
241}
242
243void
244ofwo_dump(void)
245{
246	void *pbuf;
247	int fd, len, nlen, pblen;
248	phandle_t optnode;
249	char prop[OFWO_MAXPROP + 1];
250	struct ofwo_extabent *ex;
251
252	pblen = 0;
253	pbuf = NULL;
254	fd = ofw_open(O_RDONLY);
255	optnode = ofw_optnode(fd);
256	for (nlen = ofw_firstprop(fd, optnode, prop, sizeof(prop)); nlen != 0;
257	     nlen = ofw_nextprop(fd, optnode, prop, prop, sizeof(prop))) {
258		len = ofw_getprop_alloc(fd, optnode, prop, &pbuf, &pblen, 1);
259		if (len < 0)
260			continue;
261		if (strcmp(prop, "name") == 0)
262			continue;
263		for (ex = ofwo_extab; ex->ex_prop != NULL; ++ex)
264			if (strcmp(ex->ex_prop, prop) == 0)
265				break;
266		if (ex->ex_prop != NULL)
267			(*ex->ex_handler)(ex, fd, pbuf, len, NULL);
268		else
269			ofwo_printprop(prop, (char *)pbuf, len);
270	}
271	if (pbuf != NULL)
272		free(pbuf);
273	ofw_close(fd);
274}
275
276int
277ofwo_action(const char *prop, const char *val)
278{
279	void *pbuf;
280	int fd, len, pblen, rv;
281	phandle_t optnode;
282	struct ofwo_extabent *ex;
283
284	pblen = 0;
285	rv = EX_OK;
286	pbuf = NULL;
287	if (strcmp(prop, "name") == 0)
288		return (EX_UNAVAILABLE);
289	if (val)
290		fd = ofw_open(O_RDWR);
291	else
292		fd = ofw_open(O_RDONLY);
293	optnode = ofw_optnode(fd);
294	len = ofw_getprop_alloc(fd, optnode, prop, &pbuf, &pblen, 1);
295	if (len < 0) {
296		rv = EX_UNAVAILABLE;
297		goto out;
298	}
299	for (ex = ofwo_extab; ex->ex_prop != NULL; ++ex)
300		if (strcmp(ex->ex_prop, prop) == 0)
301			break;
302	if (ex->ex_prop != NULL)
303		rv = (*ex->ex_handler)(ex, fd, pbuf, len, val);
304	else if (val)
305		rv = ofwo_setstr(fd, pbuf, len, prop, val);
306	else
307		ofwo_printprop(prop, (char *)pbuf, len);
308out:
309	if (pbuf != NULL)
310		free(pbuf);
311	ofw_close(fd);
312	return (rv);
313}
314