1129590Smarius/*-
2129590Smarius * Copyright (c) 2004 Marius Strobl
3129590Smarius * All rights reserved.
4129590Smarius *
5129590Smarius * Redistribution and use in source and binary forms, with or without
6129590Smarius * modification, are permitted provided that the following conditions
7129590Smarius * are met:
8129590Smarius * 1. Redistributions of source code must retain the above copyright
9129590Smarius *    notice, this list of conditions and the following disclaimer.
10129590Smarius * 2. Redistributions in binary form must reproduce the above copyright
11129590Smarius *    notice, this list of conditions and the following disclaimer in the
12129590Smarius *    documentation and/or other materials provided with the distribution.
13129590Smarius *
14129590Smarius * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15129590Smarius * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16129590Smarius * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17129590Smarius * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
18129590Smarius * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19129590Smarius * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20129590Smarius * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21129590Smarius * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22129590Smarius * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
23129590Smarius * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24129590Smarius */
25129590Smarius
26129590Smarius#include <sys/cdefs.h>
27129590Smarius__FBSDID("$FreeBSD$");
28129590Smarius
29129590Smarius/*
30129590Smarius * Handlers for Open Firmware /options node.
31129590Smarius */
32129590Smarius
33129590Smarius#include <sys/types.h>
34129590Smarius
35129590Smarius#include <dev/ofw/openfirm.h>
36129590Smarius
37129590Smarius#include <err.h>
38129590Smarius#include <fcntl.h>
39129590Smarius#include <readpassphrase.h>
40129590Smarius#include <stdio.h>
41129590Smarius#include <stdlib.h>
42129590Smarius#include <string.h>
43129590Smarius#include <sysexits.h>
44129590Smarius#include <unistd.h>
45129590Smarius
46129590Smarius#include "ofw_options.h"
47129590Smarius#include "ofw_util.h"
48129590Smarius
49129590Smarius#define	OFWO_LOGO	512
50129590Smarius#define	OFWO_MAXPROP	31
51129590Smarius#define	OFWO_MAXPWD	8
52129590Smarius
53129590Smariusstruct ofwo_extabent {
54129590Smarius	const char	*ex_prop;
55190097Smarius	int		(*ex_handler)(const struct ofwo_extabent *, int,
56190097Smarius			    const void *, int, const char *);
57129590Smarius};
58129590Smarius
59190097Smariusstatic int	ofwo_oemlogo(const struct ofwo_extabent *, int, const void *,
60190097Smarius		    int, const char *);
61190097Smariusstatic int	ofwo_secmode(const struct ofwo_extabent *, int, const void *,
62190097Smarius		    int, const char *);
63190097Smariusstatic int	ofwo_secpwd(const struct ofwo_extabent *, int, const void *,
64190097Smarius		    int, const char *);
65129590Smarius
66263763Sdimstatic const struct ofwo_extabent ofwo_extab[] = {
67129590Smarius	{ "oem-logo",			ofwo_oemlogo },
68129590Smarius	{ "security-mode",		ofwo_secmode },
69129590Smarius	{ "security-password",		ofwo_secpwd },
70129590Smarius	{ NULL,				NULL }
71129590Smarius};
72129590Smarius
73161834Smariusstatic int	ofwo_setpass(int);
74161834Smariusstatic int	ofwo_setstr(int, const void *, int, const char *, const char *);
75129590Smarius
76132788Skanstatic __inline void
77132788Skanofwo_printprop(const char *prop, const char* buf, int buflen)
78132788Skan{
79132788Skan
80132788Skan	printf("%s: %.*s\n", prop, buflen, buf);
81132788Skan}
82132788Skan
83129590Smariusstatic int
84190097Smariusofwo_oemlogo(const struct ofwo_extabent *exent, int fd, const void *buf,
85190097Smarius    int buflen, const char *val)
86129590Smarius{
87129590Smarius	int lfd;
88129590Smarius	char logo[OFWO_LOGO + 1];
89129590Smarius
90129590Smarius	if (val) {
91129590Smarius		if (val[0] == '\0')
92129590Smarius			ofw_setprop(fd, ofw_optnode(fd), exent->ex_prop, "", 1);
93129590Smarius		else {
94129590Smarius			if ((lfd = open(val, O_RDONLY)) == -1) {
95129590Smarius				warn("could not open '%s'", val);
96129590Smarius				return (EX_USAGE);
97129590Smarius			}
98129590Smarius			if (read(lfd, logo, OFWO_LOGO) != OFWO_LOGO ||
99129590Smarius			    lseek(lfd, 0, SEEK_END) != OFWO_LOGO) {
100129590Smarius				close(lfd);
101129590Smarius				warnx("logo '%s' has wrong size.", val);
102129590Smarius				return (EX_USAGE);
103129590Smarius			}
104129590Smarius			close(lfd);
105129590Smarius			logo[OFWO_LOGO] = '\0';
106129590Smarius			if (ofw_setprop(fd, ofw_optnode(fd), exent->ex_prop,
107129590Smarius			    logo, OFWO_LOGO + 1) != OFWO_LOGO)
108129590Smarius				errx(EX_IOERR, "writing logo failed.");
109129590Smarius		}
110129590Smarius	} else
111129590Smarius		if (buflen != 0)
112129590Smarius			printf("%s: <logo data>\n", exent->ex_prop);
113129590Smarius		else
114129590Smarius			ofwo_printprop(exent->ex_prop, (const char *)buf,
115129590Smarius			    buflen);
116129590Smarius	return (EX_OK);
117129590Smarius}
118129590Smarius
119129590Smariusstatic int
120190097Smariusofwo_secmode(const struct ofwo_extabent *exent, int fd, const void *buf,
121190097Smarius    int buflen, const char *val)
122129590Smarius{
123129590Smarius	int res;
124129590Smarius
125129590Smarius	if (val) {
126129590Smarius		if (strcmp(val, "full") == 0 || strcmp(val, "command") == 0) {
127129590Smarius			if ((res = ofwo_setpass(fd)) != EX_OK)
128129590Smarius				return (res);
129129590Smarius			if ((res = ofwo_setstr(fd, buf, buflen, exent->ex_prop,
130129590Smarius			    val)) != EX_OK)
131129590Smarius				ofw_setprop(fd, ofw_optnode(fd),
132129590Smarius				    "security-password", "", 1);
133129590Smarius			return (res);
134129590Smarius		}
135129590Smarius		if (strcmp(val, "none") == 0) {
136129590Smarius			ofw_setprop(fd, ofw_optnode(fd), "security-password",
137129590Smarius			    "", 1);
138129590Smarius			return (ofwo_setstr(fd, buf, buflen, exent->ex_prop,
139129590Smarius			    val));
140129590Smarius		}
141129590Smarius		return (EX_DATAERR);
142129590Smarius	} else
143129590Smarius		ofwo_printprop(exent->ex_prop, (const char *)buf, buflen);
144129590Smarius	return (EX_OK);
145129590Smarius}
146129590Smarius
147129590Smariusstatic int
148190097Smariusofwo_secpwd(const struct ofwo_extabent *exent, int fd, const void *buf,
149190097Smarius    int buflen, const char *val)
150129590Smarius{
151129590Smarius	void *pbuf;
152129590Smarius	int len, pblen, rv;
153129590Smarius
154129590Smarius	pblen = 0;
155129590Smarius	rv = EX_OK;
156129590Smarius	pbuf = NULL;
157129590Smarius	if (val) {
158129590Smarius		len = ofw_getprop_alloc(fd, ofw_optnode(fd), "security-mode",
159129590Smarius		    &pbuf, &pblen, 1);
160129590Smarius		if (len <= 0 || strncmp("none", (char *)pbuf, len) == 0) {
161129590Smarius			rv = EX_CONFIG;
162129590Smarius			warnx("no security mode set.");
163129590Smarius		} else if (strncmp("command", (char *)pbuf, len) == 0 ||
164129590Smarius		    strncmp("full", (char *)pbuf, len) == 0) {
165129590Smarius			rv = ofwo_setpass(fd);
166129590Smarius		} else {
167129590Smarius			rv = EX_CONFIG;
168129590Smarius			warnx("invalid security mode.");
169129590Smarius		}
170129590Smarius	} else
171129590Smarius		ofwo_printprop(exent->ex_prop, (const char *)buf, buflen);
172129590Smarius	if (pbuf != NULL)
173129590Smarius		free(pbuf);
174129590Smarius	return (rv);
175129590Smarius}
176129590Smarius
177129590Smariusstatic int
178129590Smariusofwo_setpass(int fd)
179129590Smarius{
180129590Smarius	char pwd1[OFWO_MAXPWD + 1], pwd2[OFWO_MAXPWD + 1];
181129590Smarius
182129590Smarius	if (readpassphrase("New password:", pwd1, sizeof(pwd1),
183129590Smarius	    RPP_ECHO_OFF | RPP_REQUIRE_TTY) == NULL ||
184129590Smarius	    readpassphrase("Retype new password:", pwd2, sizeof(pwd2),
185129590Smarius	    RPP_ECHO_OFF | RPP_REQUIRE_TTY) == NULL)
186129590Smarius		errx(EX_USAGE, "failed to get password.");
187129590Smarius	if (strlen(pwd1) == 0) {
188129590Smarius		printf("Password unchanged.\n");
189129590Smarius		return (EX_OK);
190129590Smarius	}
191129590Smarius	if (strcmp(pwd1, pwd2) != 0) {
192129590Smarius		printf("Mismatch - password unchanged.\n");
193129590Smarius		return (EX_USAGE);
194129590Smarius	}
195129590Smarius	ofw_setprop(fd, ofw_optnode(fd), "security-password", pwd1,
196129590Smarius	    strlen(pwd1) + 1);
197129590Smarius	return (EX_OK);
198129590Smarius}
199129590Smarius
200129590Smariusstatic int
201129590Smariusofwo_setstr(int fd, const void *buf, int buflen, const char *prop,
202129590Smarius    const char *val)
203129590Smarius{
204129590Smarius	void *pbuf;
205129590Smarius	int len, pblen, rv;
206129590Smarius	phandle_t optnode;
207129590Smarius	char *oval;
208129590Smarius
209129590Smarius	pblen = 0;
210129590Smarius	rv = EX_OK;
211129590Smarius	pbuf = NULL;
212129590Smarius	optnode = ofw_optnode(fd);
213129590Smarius	ofw_setprop(fd, optnode, prop, val, strlen(val) + 1);
214129590Smarius	len = ofw_getprop_alloc(fd, optnode, prop, &pbuf, &pblen, 1);
215129590Smarius	if (len < 0 || strncmp(val, (char *)pbuf, len) != 0) {
216129590Smarius		/*
217129590Smarius		 * The value is too long for this property and the OFW has
218129590Smarius		 * truncated it to fit or the value is illegal and a legal
219129590Smarius		 * one has been written instead (e.g. attempted to write
220129590Smarius		 * "foobar" to a "true"/"false"-property) - try to recover
221129590Smarius		 * the old value.
222129590Smarius		 */
223129590Smarius		rv = EX_DATAERR;
224129590Smarius		if ((oval = malloc(buflen + 1)) == NULL)
225129590Smarius			err(EX_OSERR, "malloc() failed.");
226129590Smarius		strncpy(oval, buf, buflen);
227129590Smarius		oval[buflen] = '\0';
228129590Smarius		len = ofw_setprop(fd, optnode, prop, oval, buflen + 1);
229129590Smarius		if (len != buflen)
230129590Smarius			errx(EX_IOERR, "recovery of old value failed.");
231129590Smarius		free(oval);
232129590Smarius		goto out;
233129590Smarius	}
234129590Smarius	printf("%s: %.*s%s->%s%.*s\n", prop, buflen, (const char *)buf,
235129590Smarius	    buflen > 0 ? " " : "", len > 0 ? " " : "", len, (char *)pbuf);
236129590Smariusout:
237129590Smarius	if (pbuf != NULL)
238129590Smarius		free(pbuf);
239129590Smarius	return (rv);
240129590Smarius}
241129590Smarius
242129590Smariusvoid
243129590Smariusofwo_dump(void)
244129590Smarius{
245129590Smarius	void *pbuf;
246129590Smarius	int fd, len, nlen, pblen;
247129590Smarius	phandle_t optnode;
248129590Smarius	char prop[OFWO_MAXPROP + 1];
249190097Smarius	const struct ofwo_extabent *ex;
250129590Smarius
251129590Smarius	pblen = 0;
252129590Smarius	pbuf = NULL;
253129590Smarius	fd = ofw_open(O_RDONLY);
254129590Smarius	optnode = ofw_optnode(fd);
255129590Smarius	for (nlen = ofw_firstprop(fd, optnode, prop, sizeof(prop)); nlen != 0;
256190097Smarius	    nlen = ofw_nextprop(fd, optnode, prop, prop, sizeof(prop))) {
257129590Smarius		len = ofw_getprop_alloc(fd, optnode, prop, &pbuf, &pblen, 1);
258129590Smarius		if (len < 0)
259129590Smarius			continue;
260129590Smarius		if (strcmp(prop, "name") == 0)
261129590Smarius			continue;
262129590Smarius		for (ex = ofwo_extab; ex->ex_prop != NULL; ++ex)
263129590Smarius			if (strcmp(ex->ex_prop, prop) == 0)
264129590Smarius				break;
265129590Smarius		if (ex->ex_prop != NULL)
266129590Smarius			(*ex->ex_handler)(ex, fd, pbuf, len, NULL);
267129590Smarius		else
268129590Smarius			ofwo_printprop(prop, (char *)pbuf, len);
269129590Smarius	}
270129590Smarius	if (pbuf != NULL)
271129590Smarius		free(pbuf);
272129590Smarius	ofw_close(fd);
273129590Smarius}
274129590Smarius
275129590Smariusint
276129590Smariusofwo_action(const char *prop, const char *val)
277129590Smarius{
278129590Smarius	void *pbuf;
279129590Smarius	int fd, len, pblen, rv;
280190097Smarius	const struct ofwo_extabent *ex;
281129590Smarius
282129590Smarius	pblen = 0;
283129590Smarius	rv = EX_OK;
284129590Smarius	pbuf = NULL;
285129590Smarius	if (strcmp(prop, "name") == 0)
286129590Smarius		return (EX_UNAVAILABLE);
287129590Smarius	if (val)
288129590Smarius		fd = ofw_open(O_RDWR);
289129590Smarius	else
290129590Smarius		fd = ofw_open(O_RDONLY);
291133768Smarius	len = ofw_getprop_alloc(fd, ofw_optnode(fd), prop, &pbuf, &pblen, 1);
292129590Smarius	if (len < 0) {
293129590Smarius		rv = EX_UNAVAILABLE;
294129590Smarius		goto out;
295129590Smarius	}
296129590Smarius	for (ex = ofwo_extab; ex->ex_prop != NULL; ++ex)
297129590Smarius		if (strcmp(ex->ex_prop, prop) == 0)
298129590Smarius			break;
299129590Smarius	if (ex->ex_prop != NULL)
300129590Smarius		rv = (*ex->ex_handler)(ex, fd, pbuf, len, val);
301129590Smarius	else if (val)
302129590Smarius		rv = ofwo_setstr(fd, pbuf, len, prop, val);
303190097Smarius	else
304129590Smarius		ofwo_printprop(prop, (char *)pbuf, len);
305129590Smariusout:
306129590Smarius	if (pbuf != NULL)
307129590Smarius		free(pbuf);
308129590Smarius	ofw_close(fd);
309129590Smarius	return (rv);
310129590Smarius}
311