1cdf63a70SMartin Matuska /*-
2cdf63a70SMartin Matuska * Copyright (c) 2014 Michihiro NAKAJIMA
3cdf63a70SMartin Matuska * All rights reserved.
4cdf63a70SMartin Matuska *
5cdf63a70SMartin Matuska * Redistribution and use in source and binary forms, with or without
6cdf63a70SMartin Matuska * modification, are permitted provided that the following conditions
7cdf63a70SMartin Matuska * are met:
8cdf63a70SMartin Matuska * 1. Redistributions of source code must retain the above copyright
9cdf63a70SMartin Matuska * notice, this list of conditions and the following disclaimer
10cdf63a70SMartin Matuska * in this position and unchanged.
11cdf63a70SMartin Matuska * 2. Redistributions in binary form must reproduce the above copyright
12cdf63a70SMartin Matuska * notice, this list of conditions and the following disclaimer in the
13cdf63a70SMartin Matuska * documentation and/or other materials provided with the distribution.
14cdf63a70SMartin Matuska *
15cdf63a70SMartin Matuska * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
16cdf63a70SMartin Matuska * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17cdf63a70SMartin Matuska * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18cdf63a70SMartin Matuska * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
19cdf63a70SMartin Matuska * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20cdf63a70SMartin Matuska * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21cdf63a70SMartin Matuska * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22cdf63a70SMartin Matuska * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23cdf63a70SMartin Matuska * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24cdf63a70SMartin Matuska * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25cdf63a70SMartin Matuska */
26fae5c36eSMartin Matuska /* $OpenBSD: readpassphrase.c,v 1.27 2019/01/25 00:19:25 millert Exp $ */
27fae5c36eSMartin Matuska
28cdf63a70SMartin Matuska /*
29fae5c36eSMartin Matuska * Copyright (c) 2000-2002, 2007, 2010
30fae5c36eSMartin Matuska * Todd C. Miller <millert@openbsd.org>
31cdf63a70SMartin Matuska *
32cdf63a70SMartin Matuska * Permission to use, copy, modify, and distribute this software for any
33cdf63a70SMartin Matuska * purpose with or without fee is hereby granted, provided that the above
34cdf63a70SMartin Matuska * copyright notice and this permission notice appear in all copies.
35cdf63a70SMartin Matuska *
36cdf63a70SMartin Matuska * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
37cdf63a70SMartin Matuska * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
38cdf63a70SMartin Matuska * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
39cdf63a70SMartin Matuska * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
40cdf63a70SMartin Matuska * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
41cdf63a70SMartin Matuska * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
42cdf63a70SMartin Matuska * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
43cdf63a70SMartin Matuska *
44cdf63a70SMartin Matuska * Sponsored in part by the Defense Advanced Research Projects
45cdf63a70SMartin Matuska * Agency (DARPA) and Air Force Research Laboratory, Air Force
46cdf63a70SMartin Matuska * Materiel Command, USAF, under agreement number F39502-99-1-0512.
47cdf63a70SMartin Matuska */
48cdf63a70SMartin Matuska
49cdf63a70SMartin Matuska /* OPENBSD ORIGINAL: lib/libc/gen/readpassphrase.c */
50cdf63a70SMartin Matuska
51cdf63a70SMartin Matuska
52cdf63a70SMartin Matuska #include "lafe_platform.h"
53cdf63a70SMartin Matuska #include <errno.h>
54cdf63a70SMartin Matuska #ifdef HAVE_STDLIB_H
55cdf63a70SMartin Matuska #include <stdlib.h>
56cdf63a70SMartin Matuska #endif
57cdf63a70SMartin Matuska #ifdef HAVE_UNISTD_H
58cdf63a70SMartin Matuska #include <unistd.h>
59cdf63a70SMartin Matuska #endif
60cdf63a70SMartin Matuska #ifdef HAVE_READPASSPHRASE_H
61cdf63a70SMartin Matuska #include <readpassphrase.h>
62cdf63a70SMartin Matuska #endif
63cdf63a70SMartin Matuska
64cdf63a70SMartin Matuska #include "err.h"
65cdf63a70SMartin Matuska #include "passphrase.h"
66cdf63a70SMartin Matuska
67cdf63a70SMartin Matuska #ifndef HAVE_READPASSPHRASE
68cdf63a70SMartin Matuska
69cdf63a70SMartin Matuska #define RPP_ECHO_OFF 0x00 /* Turn off echo (default). */
70cdf63a70SMartin Matuska #define RPP_ECHO_ON 0x01 /* Leave echo on. */
71cdf63a70SMartin Matuska #define RPP_REQUIRE_TTY 0x02 /* Fail if there is no tty. */
72cdf63a70SMartin Matuska #define RPP_FORCELOWER 0x04 /* Force input to lower case. */
73cdf63a70SMartin Matuska #define RPP_FORCEUPPER 0x08 /* Force input to upper case. */
74cdf63a70SMartin Matuska #define RPP_SEVENBIT 0x10 /* Strip the high bit from input. */
75cdf63a70SMartin Matuska #define RPP_STDIN 0x20 /* Read from stdin, not /dev/tty */
76cdf63a70SMartin Matuska
77cdf63a70SMartin Matuska
78cdf63a70SMartin Matuska #if defined(_WIN32) && !defined(__CYGWIN__)
79*13d826ffSMartin Matuska #include <string.h>
80cdf63a70SMartin Matuska #include <windows.h>
81cdf63a70SMartin Matuska
82cdf63a70SMartin Matuska static char *
readpassphrase(const char * prompt,char * buf,size_t bufsiz,int flags)83cdf63a70SMartin Matuska readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags)
84cdf63a70SMartin Matuska {
85cdf63a70SMartin Matuska HANDLE hStdin, hStdout;
86cdf63a70SMartin Matuska DWORD mode, rbytes;
87cdf63a70SMartin Matuska BOOL success;
88cdf63a70SMartin Matuska
89cdf63a70SMartin Matuska (void)flags;
90cdf63a70SMartin Matuska
91cdf63a70SMartin Matuska hStdin = GetStdHandle(STD_INPUT_HANDLE);
92cdf63a70SMartin Matuska if (hStdin == INVALID_HANDLE_VALUE)
93cdf63a70SMartin Matuska return (NULL);
94cdf63a70SMartin Matuska hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
95cdf63a70SMartin Matuska if (hStdout == INVALID_HANDLE_VALUE)
96cdf63a70SMartin Matuska return (NULL);
97cdf63a70SMartin Matuska
98cdf63a70SMartin Matuska success = GetConsoleMode(hStdin, &mode);
99cdf63a70SMartin Matuska if (!success)
100cdf63a70SMartin Matuska return (NULL);
101cdf63a70SMartin Matuska mode &= ~ENABLE_ECHO_INPUT;
102cdf63a70SMartin Matuska mode |= ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT;
103cdf63a70SMartin Matuska success = SetConsoleMode(hStdin, mode);
104cdf63a70SMartin Matuska if (!success)
105cdf63a70SMartin Matuska return (NULL);
106cdf63a70SMartin Matuska
107cdf63a70SMartin Matuska success = WriteFile(hStdout, prompt, (DWORD)strlen(prompt),
108cdf63a70SMartin Matuska NULL, NULL);
109cdf63a70SMartin Matuska if (!success)
110cdf63a70SMartin Matuska return (NULL);
111cdf63a70SMartin Matuska success = ReadFile(hStdin, buf, (DWORD)bufsiz - 1, &rbytes, NULL);
112cdf63a70SMartin Matuska if (!success)
113cdf63a70SMartin Matuska return (NULL);
114cdf63a70SMartin Matuska WriteFile(hStdout, "\r\n", 2, NULL, NULL);
115cdf63a70SMartin Matuska buf[rbytes] = '\0';
116cdf63a70SMartin Matuska /* Remove trailing carriage return(s). */
117*13d826ffSMartin Matuska buf[strcspn(buf, "\r\n")] = '\0';
118cdf63a70SMartin Matuska
119cdf63a70SMartin Matuska return (buf);
120cdf63a70SMartin Matuska }
121cdf63a70SMartin Matuska
122cdf63a70SMartin Matuska #else /* _WIN32 && !__CYGWIN__ */
123cdf63a70SMartin Matuska
124f061a221SMartin Matuska #include <assert.h>
125cdf63a70SMartin Matuska #include <ctype.h>
126cdf63a70SMartin Matuska #include <fcntl.h>
127cdf63a70SMartin Matuska #ifdef HAVE_PATHS_H
128cdf63a70SMartin Matuska #include <paths.h>
129cdf63a70SMartin Matuska #endif
130f061a221SMartin Matuska #include <signal.h>
131cdf63a70SMartin Matuska #include <string.h>
132f061a221SMartin Matuska #include <termios.h>
133cdf63a70SMartin Matuska #include <unistd.h>
134cdf63a70SMartin Matuska
135ae5876eaSMartin Matuska #ifndef _PATH_TTY
136ae5876eaSMartin Matuska #define _PATH_TTY "/dev/tty"
137ae5876eaSMartin Matuska #endif
138ae5876eaSMartin Matuska
139cdf63a70SMartin Matuska #ifdef TCSASOFT
140cdf63a70SMartin Matuska # define _T_FLUSH (TCSAFLUSH|TCSASOFT)
141cdf63a70SMartin Matuska #else
142cdf63a70SMartin Matuska # define _T_FLUSH (TCSAFLUSH)
143cdf63a70SMartin Matuska #endif
144cdf63a70SMartin Matuska
145cdf63a70SMartin Matuska /* SunOS 4.x which lacks _POSIX_VDISABLE, but has VDISABLE */
146cdf63a70SMartin Matuska #if !defined(_POSIX_VDISABLE) && defined(VDISABLE)
147cdf63a70SMartin Matuska # define _POSIX_VDISABLE VDISABLE
148cdf63a70SMartin Matuska #endif
149cdf63a70SMartin Matuska
150f061a221SMartin Matuska #define M(a,b) (a > b ? a : b)
151f061a221SMartin Matuska #define MAX_SIGNO M(M(M(SIGALRM, SIGHUP), \
152f061a221SMartin Matuska M(SIGINT, SIGPIPE)), \
153f061a221SMartin Matuska M(M(SIGQUIT, SIGTERM), \
154f061a221SMartin Matuska M(M(SIGTSTP, SIGTTIN), SIGTTOU)))
155f061a221SMartin Matuska
156f061a221SMartin Matuska static volatile sig_atomic_t signo[MAX_SIGNO + 1];
157cdf63a70SMartin Matuska
158cdf63a70SMartin Matuska static void
handler(int s)159cdf63a70SMartin Matuska handler(int s)
160cdf63a70SMartin Matuska {
161f061a221SMartin Matuska assert(s <= MAX_SIGNO);
162cdf63a70SMartin Matuska signo[s] = 1;
163cdf63a70SMartin Matuska }
164cdf63a70SMartin Matuska
165cdf63a70SMartin Matuska static char *
readpassphrase(const char * prompt,char * buf,size_t bufsiz,int flags)166cdf63a70SMartin Matuska readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags)
167cdf63a70SMartin Matuska {
168cdf63a70SMartin Matuska ssize_t nr;
169cdf63a70SMartin Matuska int input, output, save_errno, i, need_restart;
170cdf63a70SMartin Matuska char ch, *p, *end;
171cdf63a70SMartin Matuska struct termios term, oterm;
172e64fe029SMartin Matuska #ifdef HAVE_SIGACTION
173cdf63a70SMartin Matuska struct sigaction sa, savealrm, saveint, savehup, savequit, saveterm;
174cdf63a70SMartin Matuska struct sigaction savetstp, savettin, savettou, savepipe;
175e64fe029SMartin Matuska #endif
176cdf63a70SMartin Matuska
177cdf63a70SMartin Matuska /* I suppose we could alloc on demand in this case (XXX). */
178cdf63a70SMartin Matuska if (bufsiz == 0) {
179cdf63a70SMartin Matuska errno = EINVAL;
180cdf63a70SMartin Matuska return(NULL);
181cdf63a70SMartin Matuska }
182cdf63a70SMartin Matuska
183cdf63a70SMartin Matuska restart:
184f061a221SMartin Matuska for (i = 0; i <= MAX_SIGNO; i++)
185cdf63a70SMartin Matuska signo[i] = 0;
186cdf63a70SMartin Matuska nr = -1;
187cdf63a70SMartin Matuska save_errno = 0;
188cdf63a70SMartin Matuska need_restart = 0;
189cdf63a70SMartin Matuska /*
190cdf63a70SMartin Matuska * Read and write to /dev/tty if available. If not, read from
191cdf63a70SMartin Matuska * stdin and write to stderr unless a tty is required.
192cdf63a70SMartin Matuska */
193cdf63a70SMartin Matuska if ((flags & RPP_STDIN) ||
194cdf63a70SMartin Matuska (input = output = open(_PATH_TTY, O_RDWR)) == -1) {
195cdf63a70SMartin Matuska if (flags & RPP_REQUIRE_TTY) {
196cdf63a70SMartin Matuska errno = ENOTTY;
197cdf63a70SMartin Matuska return(NULL);
198cdf63a70SMartin Matuska }
199cdf63a70SMartin Matuska input = STDIN_FILENO;
200cdf63a70SMartin Matuska output = STDERR_FILENO;
201cdf63a70SMartin Matuska }
202cdf63a70SMartin Matuska
203cdf63a70SMartin Matuska /*
204fae5c36eSMartin Matuska * Turn off echo if possible.
205fae5c36eSMartin Matuska * If we are using a tty but are not the foreground pgrp this will
206fae5c36eSMartin Matuska * generate SIGTTOU, so do it *before* installing the signal handlers.
207fae5c36eSMartin Matuska */
208fae5c36eSMartin Matuska if (input != STDIN_FILENO && tcgetattr(input, &oterm) == 0) {
209fae5c36eSMartin Matuska memcpy(&term, &oterm, sizeof(term));
210fae5c36eSMartin Matuska if (!(flags & RPP_ECHO_ON))
211fae5c36eSMartin Matuska term.c_lflag &= ~(ECHO | ECHONL);
212fae5c36eSMartin Matuska #ifdef VSTATUS
213fae5c36eSMartin Matuska if (term.c_cc[VSTATUS] != _POSIX_VDISABLE)
214fae5c36eSMartin Matuska term.c_cc[VSTATUS] = _POSIX_VDISABLE;
215fae5c36eSMartin Matuska #endif
216fae5c36eSMartin Matuska (void)tcsetattr(input, _T_FLUSH, &term);
217fae5c36eSMartin Matuska } else {
218fae5c36eSMartin Matuska memset(&term, 0, sizeof(term));
219fae5c36eSMartin Matuska term.c_lflag |= ECHO;
220fae5c36eSMartin Matuska memset(&oterm, 0, sizeof(oterm));
221fae5c36eSMartin Matuska oterm.c_lflag |= ECHO;
222fae5c36eSMartin Matuska }
223fae5c36eSMartin Matuska
224e64fe029SMartin Matuska #ifdef HAVE_SIGACTION
225fae5c36eSMartin Matuska /*
226cdf63a70SMartin Matuska * Catch signals that would otherwise cause the user to end
227cdf63a70SMartin Matuska * up with echo turned off in the shell. Don't worry about
228cdf63a70SMartin Matuska * things like SIGXCPU and SIGVTALRM for now.
229cdf63a70SMartin Matuska */
230cdf63a70SMartin Matuska sigemptyset(&sa.sa_mask);
231cdf63a70SMartin Matuska sa.sa_flags = 0; /* don't restart system calls */
232cdf63a70SMartin Matuska sa.sa_handler = handler;
233f061a221SMartin Matuska /* Keep this list in sync with MAX_SIGNO! */
234cdf63a70SMartin Matuska (void)sigaction(SIGALRM, &sa, &savealrm);
235cdf63a70SMartin Matuska (void)sigaction(SIGHUP, &sa, &savehup);
236cdf63a70SMartin Matuska (void)sigaction(SIGINT, &sa, &saveint);
237cdf63a70SMartin Matuska (void)sigaction(SIGPIPE, &sa, &savepipe);
238cdf63a70SMartin Matuska (void)sigaction(SIGQUIT, &sa, &savequit);
239cdf63a70SMartin Matuska (void)sigaction(SIGTERM, &sa, &saveterm);
240cdf63a70SMartin Matuska (void)sigaction(SIGTSTP, &sa, &savetstp);
241cdf63a70SMartin Matuska (void)sigaction(SIGTTIN, &sa, &savettin);
242cdf63a70SMartin Matuska (void)sigaction(SIGTTOU, &sa, &savettou);
243e64fe029SMartin Matuska #endif
244cdf63a70SMartin Matuska
245cdf63a70SMartin Matuska if (!(flags & RPP_STDIN)) {
246cdf63a70SMartin Matuska int r = write(output, prompt, strlen(prompt));
247cdf63a70SMartin Matuska (void)r;
248cdf63a70SMartin Matuska }
249cdf63a70SMartin Matuska end = buf + bufsiz - 1;
250cdf63a70SMartin Matuska p = buf;
251cdf63a70SMartin Matuska while ((nr = read(input, &ch, 1)) == 1 && ch != '\n' && ch != '\r') {
252cdf63a70SMartin Matuska if (p < end) {
253cdf63a70SMartin Matuska if ((flags & RPP_SEVENBIT))
254cdf63a70SMartin Matuska ch &= 0x7f;
255f061a221SMartin Matuska if (isalpha((unsigned char)ch)) {
256cdf63a70SMartin Matuska if ((flags & RPP_FORCELOWER))
257f061a221SMartin Matuska ch = (char)tolower((unsigned char)ch);
258cdf63a70SMartin Matuska if ((flags & RPP_FORCEUPPER))
259f061a221SMartin Matuska ch = (char)toupper((unsigned char)ch);
260cdf63a70SMartin Matuska }
261cdf63a70SMartin Matuska *p++ = ch;
262cdf63a70SMartin Matuska }
263cdf63a70SMartin Matuska }
264cdf63a70SMartin Matuska *p = '\0';
265cdf63a70SMartin Matuska save_errno = errno;
266cdf63a70SMartin Matuska if (!(term.c_lflag & ECHO)) {
267cdf63a70SMartin Matuska int r = write(output, "\n", 1);
268cdf63a70SMartin Matuska (void)r;
269cdf63a70SMartin Matuska }
270cdf63a70SMartin Matuska
271cdf63a70SMartin Matuska /* Restore old terminal settings and signals. */
272cdf63a70SMartin Matuska if (memcmp(&term, &oterm, sizeof(term)) != 0) {
273fae5c36eSMartin Matuska const int sigttou = signo[SIGTTOU];
274fae5c36eSMartin Matuska
275fae5c36eSMartin Matuska /* Ignore SIGTTOU generated when we are not the fg pgrp. */
276cdf63a70SMartin Matuska while (tcsetattr(input, _T_FLUSH, &oterm) == -1 &&
277fae5c36eSMartin Matuska errno == EINTR && !signo[SIGTTOU])
278cdf63a70SMartin Matuska continue;
279fae5c36eSMartin Matuska signo[SIGTTOU] = sigttou;
280cdf63a70SMartin Matuska }
281e64fe029SMartin Matuska #ifdef HAVE_SIGACTION
282cdf63a70SMartin Matuska (void)sigaction(SIGALRM, &savealrm, NULL);
283cdf63a70SMartin Matuska (void)sigaction(SIGHUP, &savehup, NULL);
284cdf63a70SMartin Matuska (void)sigaction(SIGINT, &saveint, NULL);
285cdf63a70SMartin Matuska (void)sigaction(SIGQUIT, &savequit, NULL);
286cdf63a70SMartin Matuska (void)sigaction(SIGPIPE, &savepipe, NULL);
287cdf63a70SMartin Matuska (void)sigaction(SIGTERM, &saveterm, NULL);
288cdf63a70SMartin Matuska (void)sigaction(SIGTSTP, &savetstp, NULL);
289cdf63a70SMartin Matuska (void)sigaction(SIGTTIN, &savettin, NULL);
290cdf63a70SMartin Matuska (void)sigaction(SIGTTOU, &savettou, NULL);
291e64fe029SMartin Matuska #endif
292cdf63a70SMartin Matuska if (input != STDIN_FILENO)
293cdf63a70SMartin Matuska (void)close(input);
294cdf63a70SMartin Matuska
295cdf63a70SMartin Matuska /*
296cdf63a70SMartin Matuska * If we were interrupted by a signal, resend it to ourselves
297cdf63a70SMartin Matuska * now that we have restored the signal handlers.
298cdf63a70SMartin Matuska */
299f061a221SMartin Matuska for (i = 0; i <= MAX_SIGNO; i++) {
300cdf63a70SMartin Matuska if (signo[i]) {
301cdf63a70SMartin Matuska kill(getpid(), i);
302cdf63a70SMartin Matuska switch (i) {
303cdf63a70SMartin Matuska case SIGTSTP:
304cdf63a70SMartin Matuska case SIGTTIN:
305cdf63a70SMartin Matuska case SIGTTOU:
306cdf63a70SMartin Matuska need_restart = 1;
307cdf63a70SMartin Matuska }
308cdf63a70SMartin Matuska }
309cdf63a70SMartin Matuska }
310cdf63a70SMartin Matuska if (need_restart)
311cdf63a70SMartin Matuska goto restart;
312cdf63a70SMartin Matuska
313cdf63a70SMartin Matuska if (save_errno)
314cdf63a70SMartin Matuska errno = save_errno;
315cdf63a70SMartin Matuska return(nr == -1 ? NULL : buf);
316cdf63a70SMartin Matuska }
317cdf63a70SMartin Matuska #endif /* _WIN32 && !__CYGWIN__ */
318cdf63a70SMartin Matuska #endif /* HAVE_READPASSPHRASE */
319cdf63a70SMartin Matuska
320cdf63a70SMartin Matuska char *
lafe_readpassphrase(const char * prompt,char * buf,size_t bufsiz)321cdf63a70SMartin Matuska lafe_readpassphrase(const char *prompt, char *buf, size_t bufsiz)
322cdf63a70SMartin Matuska {
323cdf63a70SMartin Matuska char *p;
324cdf63a70SMartin Matuska
325cdf63a70SMartin Matuska p = readpassphrase(prompt, buf, bufsiz, RPP_ECHO_OFF);
326cdf63a70SMartin Matuska if (p == NULL) {
327cdf63a70SMartin Matuska switch (errno) {
328cdf63a70SMartin Matuska case EINTR:
329cdf63a70SMartin Matuska break;
330cdf63a70SMartin Matuska default:
331cdf63a70SMartin Matuska lafe_errc(1, errno, "Couldn't read passphrase");
332b9128a37SMartin Matuska /* NOTREACHED */
333cdf63a70SMartin Matuska }
334cdf63a70SMartin Matuska }
335cdf63a70SMartin Matuska return (p);
336cdf63a70SMartin Matuska }
337cdf63a70SMartin Matuska
338