tcpip.c revision 8803
1/*
2 * $Id: tcpip.c,v 1.23 1995/05/27 23:52:55 jkh Exp $
3 *
4 * Copyright (c) 1995
5 *      Gary J Palmer. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer,
12 *    verbatim and that no modifications are made prior to this
13 *    point in the file.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 *    must display the following acknowledgement:
19 *      This product includes software developed by Gary J Palmer
20 *	for the FreeBSD Project.
21 * 4. The name of Gary J Palmer or the FreeBSD Project may
22 *    not be used to endorse or promote products derived from this software
23 *    without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY GARY J PALMER ``AS IS'' AND ANY EXPRESS OR
26 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28 * IN NO EVENT SHALL GARY J PALMER BE LIABLE FOR ANY DIRECT, INDIRECT,
29 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
31 * OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
32 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
33 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 *
36 */
37
38/*
39 * All kinds of hacking also performed by jkh on this code.  Don't
40 * blame Gary for every bogosity you see here.. :-)
41 *
42 * -jkh
43 */
44
45#include <stdio.h>
46#include <stdlib.h>
47#include <unistd.h>
48#include <sys/param.h>
49#include <string.h>
50#include <dialog.h>
51#include "ui_objects.h"
52#include "dir.h"
53#include "dialog.priv.h"
54#include "colors.h"
55#include "rc.h"
56#include "sysinstall.h"
57
58#define HOSTNAME_FIELD_LEN	256
59#define IPADDR_FIELD_LEN	16
60#define EXTRAS_FIELD_LEN	256
61
62/* These are nasty, but they make the layout structure a lot easier ... */
63
64static char		hostname[HOSTNAME_FIELD_LEN], domainname[HOSTNAME_FIELD_LEN],
65			gateway[IPADDR_FIELD_LEN], nameserver[IPADDR_FIELD_LEN];
66static int		okbutton, cancelbutton;
67static char		ipaddr[IPADDR_FIELD_LEN], netmask[IPADDR_FIELD_LEN], extras[EXTRAS_FIELD_LEN];
68
69/* What the screen size is meant to be */
70#define TCP_DIALOG_Y		0
71#define TCP_DIALOG_X		8
72#define TCP_DIALOG_WIDTH	COLS - 16
73#define TCP_DIALOG_HEIGHT	LINES - 2
74
75/* This is the structure that Network devices carry around in their private, erm, structures */
76typedef struct _devPriv {
77    char ipaddr[IPADDR_FIELD_LEN];
78    char netmask[IPADDR_FIELD_LEN];
79    char extras[EXTRAS_FIELD_LEN];
80} DevInfo;
81
82/* The screen layout structure */
83typedef struct _layout {
84    int		y;		/* x & Y co-ordinates */
85    int		x;
86    int		len;		/* The size of the dialog on the screen */
87    int		maxlen;		/* How much the user can type in ... */
88    char	*prompt;	/* The string for the prompt */
89    char	*help;		/* The display for the help line */
90    void	*var;		/* The var to set when this changes */
91    int		type;		/* The type of the dialog to create */
92    void	*obj;		/* The obj pointer returned by libdialog */
93} Layout;
94
95static Layout layout[] = {
96{ 1, 2, 25, HOSTNAME_FIELD_LEN - 1,
97      "Host name:", "The name of your machine on a network, e.g. foo.bar.com",
98      hostname, STRINGOBJ, NULL },
99#define LAYOUT_HOSTNAME		0
100{ 1, 35, 20, HOSTNAME_FIELD_LEN - 1,
101      "Domain name:",
102      "The name of the domain that your machine is in, e.g. bar.com",
103      domainname, STRINGOBJ, NULL },
104#define LAYOUT_DOMAINNAME	1
105{ 5, 2, 18, IPADDR_FIELD_LEN - 1,
106      "Gateway:",
107      "IP address of host forwarding packets to non-local destinations",
108      gateway, STRINGOBJ, NULL },
109#define LAYOUT_GATEWAY		2
110{ 5, 35, 18, IPADDR_FIELD_LEN - 1,
111      "Name server:", "IP address of your local DNS server",
112      nameserver, STRINGOBJ, NULL },
113#define LAYOUT_NAMESERVER	3
114{ 10, 10, 18, IPADDR_FIELD_LEN - 1,
115      "IP Address:",
116      "The IP address to be used for this interface",
117      ipaddr, STRINGOBJ, NULL },
118#define LAYOUT_IPADDR		5
119{ 10, 35, 18, IPADDR_FIELD_LEN - 1,
120      "Netmask:",
121      "The netmask for this interfaace, e.g. 0xffffff00 for a class C network",
122      netmask, STRINGOBJ, NULL },
123#define LAYOUT_NETMASK		6
124{ 14, 10, 37, HOSTNAME_FIELD_LEN - 1,
125      "Extra options to ifconfig:",
126      "Any interface-specific options to ifconfig you would like to use",
127      extras, STRINGOBJ, NULL },
128#define LAYOUT_EXTRAS		7
129{ 19, 15, 0, 0,
130      "OK", "Select this if you are happy with these settings",
131      &okbutton, BUTTONOBJ, NULL },
132#define LAYOUT_OKBUTTON		8
133{ 19, 35, 0, 0,
134      "CANCEL", "Select this if you wish to cancel this screen",
135      &cancelbutton, BUTTONOBJ, NULL },
136#define LAYOUT_CANCELBUTTON	9
137{ NULL },
138};
139
140#define _validByte(b) ((b) >= 0 && (b) < 255)
141
142/* whine */
143static void
144feepout(char *msg)
145{
146    beep();
147    dialog_notify(msg);
148}
149
150/* Very basic IP address integrity check - could be drastically improved */
151static int
152verifyIP(char *ip)
153{
154    int a, b, c, d;
155
156    if (ip && sscanf(ip, "%d.%d.%d.%d", &a, &b, &c, &d) == 4 &&
157	_validByte(a) && _validByte(b) && _validByte(c) &&
158	_validByte(d))
159	return 1;
160    else
161	return 0;
162}
163
164/* Check for the settings on the screen - the per interface stuff is
165   moved to the main handling code now to do it on the fly - sigh */
166
167static int
168verifySettings(void)
169{
170    if (!hostname[0])
171	feepout("Must specify a host name of some sort!");
172    else if (gateway[0] && !verifyIP(gateway))
173	feepout("Invalid gateway IP address specified");
174    else if (nameserver[0] && !verifyIP(nameserver))
175	feepout("Invalid name server IP address specified");
176    else if (netmask[0] && (netmask[0] < '0' && netmask[0] > '3'))
177	feepout("Invalid netmask value");
178    else if (ipaddr[0] && !verifyIP(ipaddr))
179	feepout("Invalid IP address");
180    else
181	return 1;
182    return 0;
183}
184
185/* This is it - how to get TCP setup values */
186int
187tcpOpenDialog(Device *devp)
188{
189    WINDOW              *ds_win;
190    ComposeObj          *obj = NULL;
191    ComposeObj		*first, *last;
192    int                 n=0, quit=FALSE, cancel=FALSE, ret;
193    int			max;
194    char                *tmp;
195    char		help[FILENAME_MAX];
196    char		title[80];
197
198    /* We need a curses window */
199    ds_win = newwin(LINES, COLS, 0, 0);
200    if (ds_win == 0)
201	msgFatal("Cannot open TCP/IP dialog window!!");
202
203    /* Say where our help comes from */
204    systemHelpFile(TCP_HELPFILE, help);
205    use_helpfile(help);
206
207    /* Setup a nice screen for us to splat stuff onto */
208    draw_box(ds_win, TCP_DIALOG_Y, TCP_DIALOG_X, TCP_DIALOG_HEIGHT, TCP_DIALOG_WIDTH, dialog_attr, border_attr);
209    wattrset(ds_win, dialog_attr);
210    sprintf(title, " Interface %s ", devp->name);
211    mvwaddstr(ds_win, TCP_DIALOG_Y, TCP_DIALOG_X + 20, title);
212    draw_box(ds_win, TCP_DIALOG_Y + 9, TCP_DIALOG_X + 8, TCP_DIALOG_HEIGHT - 13, TCP_DIALOG_WIDTH - 17,
213	     dialog_attr, border_attr);
214    wattrset(ds_win, dialog_attr);
215    mvwaddstr(ds_win, TCP_DIALOG_Y + 9, TCP_DIALOG_X + 16, " Per Interface Configuration ");
216
217    /* Initialise vars from previous device values */
218    if (devp->private) {
219	DevInfo *di = (DevInfo *)devp->private;
220
221	strcpy(ipaddr, di->ipaddr);
222	strcpy(netmask, di->netmask);
223	strcpy(extras, di->extras);
224    }
225    else
226	ipaddr[0] = netmask[0] = extras[0] = '\0';
227
228    /* Look up values already recorded with the system, or blank the string variables ready to accept some new data */
229    tmp = getenv(VAR_HOSTNAME);
230    if (tmp)
231	strcpy(hostname, tmp);
232    else
233	bzero(hostname, sizeof(hostname));
234    tmp = getenv(VAR_DOMAINNAME);
235    if (tmp)
236	strcpy(domainname, tmp);
237    else
238	bzero(domainname, sizeof(domainname));
239    tmp = getenv(VAR_GATEWAY);
240    if (tmp)
241	strcpy(gateway, tmp);
242    else
243	bzero(gateway, sizeof(gateway));
244    tmp = getenv(VAR_NAMESERVER);
245    if (tmp)
246	strcpy(nameserver, tmp);
247    else
248	bzero(nameserver, sizeof(nameserver));
249
250    /* Loop over the layout list, create the objects, and add them
251       onto the chain of objects that dialog uses for traversal*/
252    n = 0;
253#define lt layout[n]
254    while (lt.help != NULL) {
255	switch (lt.type) {
256	case STRINGOBJ:
257	    lt.obj = NewStringObj(ds_win, lt.prompt, lt.var,
258				  lt.y + TCP_DIALOG_Y, lt.x + TCP_DIALOG_X,
259				  lt.len, lt.maxlen);
260	    break;
261
262	case BUTTONOBJ:
263	    lt.obj = NewButtonObj(ds_win, lt.prompt, lt.var,
264				  lt.y + TCP_DIALOG_Y, lt.x + TCP_DIALOG_X);
265	    break;
266
267	default:
268	    msgFatal("Don't support this object yet!");
269	}
270	AddObj(&obj, lt.type, (void *) lt.obj);
271	n++;
272    }
273    max = n - 1;
274
275    /* Find the last object we can traverse to */
276    last = obj;
277    while (last->next)
278	last = last->next;
279
280    /* Find the first object in the list */
281    first = obj;
282    while (first->prev)
283	first = first->prev;
284
285    /* Some more initialisation before we go into the main input loop */
286    n = 0;
287    cancelbutton = okbutton = 0;
288
289    /* Incoming user data - DUCK! */
290    while (!quit) {
291	char help_line[80];
292	int i, len = strlen(lt.help);
293
294	/* Display the help line at the bottom of the screen */
295	for (i = 0; i < 79; i++)
296	    help_line[i] = (i < len) ? lt.help[i] : ' ';
297	help_line[i] = '\0';
298	use_helpline(help_line);
299	display_helpline(ds_win, LINES - 1, COLS - 1);
300
301	/* Ask for libdialog to do its stuff */
302	ret = PollObj(&obj);
303
304	/* We are in the Hostname field - calculate the domainname */
305	if (n == 0) {
306	    if ((tmp = index(hostname, '.')) != NULL) {
307		strncpy(domainname, tmp + 1, strlen(tmp + 1));
308		domainname[strlen(tmp+1)] = '\0';
309		RefreshStringObj(layout[1].obj);
310	    }
311	}
312
313	/* Handle special case stuff that libdialog misses. Sigh */
314	switch (ret) {
315	    /* Bail out */
316	case SEL_ESC:
317	    quit = TRUE, cancel=TRUE;
318	    break;
319
320	    /* This doesn't work for list dialogs. Oh well. Perhaps
321	       should special case the move from the OK button ``up''
322	       to make it go to the interface list, but then it gets
323	       awkward for the user to go back and correct screw up's
324	       in the per-interface section */
325
326	case KEY_UP:
327	    if (obj->prev !=NULL ) {
328		obj = obj->prev;
329		--n;
330	    } else {
331		obj = last;
332		n = max;
333	    }
334	    break;
335
336	case KEY_DOWN:
337	    if (obj->next != NULL) {
338		obj = obj->next;
339		++n;
340	    } else {
341		obj = first;
342		n = 0;
343	    }
344	    break;
345
346	case SEL_TAB:
347	    if (n < max)
348		++n;
349	    else
350		n = 0;
351	    break;
352
353	    /* The user has pressed enter over a button object */
354	case SEL_BUTTON:
355 	    if (cancelbutton)
356		cancel = TRUE, quit = TRUE;
357	    else {
358		if (verifySettings())
359		    quit = TRUE;
360	    }
361	    break;
362
363	    /* Generic CR handler */
364	case SEL_CR:
365	    if (n < max)
366		++n;
367	    else
368		n = 0;
369	    break;
370
371	case SEL_BACKTAB:
372	    if (n)
373		--n;
374	    else
375		n = max;
376	    break;
377
378	case KEY_F(1):
379	    display_helpfile();
380
381	    /* They tried some key combination we don't support - tell them! */
382	default:
383	    beep();
384	}
385
386	/* BODGE ALERT! */
387	if (((tmp = index(hostname, '.')) != NULL) && (strlen(domainname)==0)) {
388	    strncpy(domainname, tmp + 1, strlen(tmp + 1));
389	    domainname[strlen(tmp+1)] = '\0';
390	    RefreshStringObj(layout[1].obj);
391	}
392    }
393
394    /* Clear this crap off the screen */
395    dialog_clear();
396    refresh();
397    use_helpfile(NULL);
398
399    /* We actually need to inform the rest of sysinstall about this
400       data now - if the user hasn't selected cancel, save the stuff
401       out to the environment via the variable_set layers */
402
403    if (!cancel) {
404	DevInfo *di;
405	char temp[512], ifn[64];
406
407	variable_set2(VAR_HOSTNAME, hostname);
408	variable_set2(VAR_DOMAINNAME, domainname);
409	if (gateway[0])
410	    variable_set2(VAR_GATEWAY, gateway);
411	if (nameserver[0])
412	    variable_set2(VAR_NAMESERVER, nameserver);
413
414	if (!devp->private)
415	    devp->private = (DevInfo *)malloc(sizeof(DevInfo));
416	di = devp->private;
417	strcpy(di->ipaddr, ipaddr);
418	strcpy(di->netmask, netmask);
419	strcpy(di->extras, extras);
420
421	sprintf(temp, "inet %s %s netmask %s", ipaddr, extras, netmask);
422	sprintf(ifn, "%s%s", VAR_IFCONFIG, devp->name);
423	variable_set2(ifn, temp);
424	sprintf(ifn, "%s %s", devp->name, getenv(VAR_INTERFACES) ? getenv(VAR_INTERFACES) : "");
425	variable_set2(VAR_INTERFACES, ifn);
426	if (ipaddr[0])
427	    variable_set2(VAR_IPADDR, ipaddr);
428	return 0;
429    }
430    return 1;
431}
432
433static int
434netHook(char *str)
435{
436    Device **devs;
437
438    /* Clip garbage off the ends */
439    string_prune(str);
440    str = string_skipwhite(str);
441    if (!*str)
442	return 0;
443    devs = deviceFind(str, DEVICE_TYPE_NETWORK);
444    if (devs) {
445	tcpOpenDialog(devs[0]);
446	mediaDevice = devs[0];
447    }
448    return devs ? 1 : 0;
449}
450
451/* Get a network device */
452int
453tcpDeviceSelect(char *str)
454{
455    DMenu *menu;
456
457    menu = deviceCreateMenu(&MenuNetworkDevice, DEVICE_TYPE_NETWORK, netHook);
458    if (!menu)
459	msgFatal("Unable to create network device menu!  Argh!");
460    dmenuOpenSimple(menu);
461    free(menu);
462    return 0;
463}
464
465/* Start PPP on the 3rd screen */
466Boolean
467tcpStartPPP(Device *devp)
468{
469    int fd;
470    FILE *fp;
471    char *val;
472    char myaddr[16], provider[16];
473
474    fd = open("/dev/ttyv2", O_RDWR);
475    if (fd == -1)
476	return FALSE;
477    Mkdir("/var/log", NULL);
478    Mkdir("/var/spool/lock", NULL);
479    Mkdir("/etc/ppp", NULL);
480    vsystem("touch /etc/ppp/ppp.linkup; chmod +x /etc/ppp/ppp.linkup");
481    vsystem("touch /etc/ppp/ppp.secret; chmod +x /etc/ppp/ppp.secret");
482    fp = fopen("/etc/ppp/ppp.conf", "w");
483    if (!fp) {
484	msgConfirm("Couldn't open /etc/ppp/ppp.conf file!  This isn't going to work");
485	return FALSE;
486    }
487    fprintf(fp, "default:\n");
488    fprintf(fp, " set device %s\n", devp->devname);
489    val = msgGetInput("115200",
490"Enter baud rate for your modem - this can be higher than the actual\nmaximum data rate since most modems can talk at one speed to the\ncomputer and at another speed to the remote end.\n\nIf you're not sure what to put here, just select the default.");
491    if (!val)
492	val = "115200";
493    fprintf(fp, " set speed %s\n", val);
494    if (getenv(VAR_GATEWAY))
495	strcpy(provider, getenv(VAR_GATEWAY));
496    else
497	strcpy(provider, "0");
498    val = msgGetInput(provider, "Enter the IP address of your service provider or 0 if you\ndon't know it and would prefer to negotiate it dynamically.");
499    if (!val)
500	val = "0";
501    if (devp->private && ((DevInfo *)devp->private)->ipaddr[0])
502	strcpy(myaddr, ((DevInfo *)devp->private)->ipaddr);
503    else
504	strcpy(myaddr, "0");
505    fprintf(fp, " set ifaddr %s %s\n", myaddr, val);
506    fclose(fp);
507    if (!fork()) {
508	dup2(fd, 0);
509	dup2(fd, 1);
510	dup2(fd, 2);
511	execl("/stand/ppp", "/stand/ppp", (char *)NULL);
512	exit(1);
513    }
514    msgConfirm("The PPP command is now started on screen 3 (type ALT-F3 to\ninteract with it, ALT-F1 to switch back here). The only command\nyou'll probably want or need to use is the \"term\" command\nwhich starts a terminal emulator you can use to talk to your\nmodem and dial the service provider.  Once you're connected,\ncome back to this screen and hit return.  DO NOT PRESS RETURN\nHERE UNTIL THE CONNECTION IS FULLY ESTABLISHED!");
515    return TRUE;
516}
517