tcpip.c revision 8780
1/*
2 * $Id: tcpip.c,v 1.20 1995/05/26 21:37:53 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
197    /* We need a curses window */
198    ds_win = newwin(LINES, COLS, 0, 0);
199    if (ds_win == 0)
200	msgFatal("Cannot open TCP/IP dialog window!!");
201
202    /* Say where our help comes from */
203    systemHelpFile(TCP_HELPFILE, help);
204    use_helpfile(help);
205
206    /* Setup a nice screen for us to splat stuff onto */
207    draw_box(ds_win, TCP_DIALOG_Y, TCP_DIALOG_X, TCP_DIALOG_HEIGHT, TCP_DIALOG_WIDTH, dialog_attr, border_attr);
208    wattrset(ds_win, dialog_attr);
209    mvwaddstr(ds_win, TCP_DIALOG_Y, TCP_DIALOG_X + 20, " Network Configuration ");
210
211    draw_box(ds_win, TCP_DIALOG_Y + 9, TCP_DIALOG_X + 8, TCP_DIALOG_HEIGHT - 13, TCP_DIALOG_WIDTH - 17,
212	     dialog_attr, border_attr);
213    wattrset(ds_win, dialog_attr);
214    mvwaddstr(ds_win, TCP_DIALOG_Y + 9, TCP_DIALOG_X + 16, " Per Interface Configuration ");
215
216    /* Initialise vars from previous device values */
217    if (devp->private) {
218	DevInfo *di = (DevInfo *)devp->private;
219
220	strcpy(ipaddr, di->ipaddr);
221	strcpy(netmask, di->netmask);
222	strcpy(extras, di->extras);
223    }
224    else
225	ipaddr[0] = netmask[0] = extras[0] = '\0';
226
227    /* Look up values already recorded with the system, or blank the string variables ready to accept some new data */
228    tmp = getenv(VAR_HOSTNAME);
229    if (tmp)
230	strcpy(hostname, tmp);
231    else
232	bzero(hostname, sizeof(hostname));
233    tmp = getenv(VAR_DOMAINNAME);
234    if (tmp)
235	strcpy(domainname, tmp);
236    else
237	bzero(domainname, sizeof(domainname));
238    tmp = getenv(VAR_GATEWAY);
239    if (tmp)
240	strcpy(gateway, tmp);
241    else
242	bzero(gateway, sizeof(gateway));
243    tmp = getenv(VAR_NAMESERVER);
244    if (tmp)
245	strcpy(nameserver, tmp);
246    else
247	bzero(nameserver, sizeof(nameserver));
248
249    /* Loop over the layout list, create the objects, and add them
250       onto the chain of objects that dialog uses for traversal*/
251    n = 0;
252#define lt layout[n]
253    while (lt.help != NULL) {
254	switch (lt.type) {
255	case STRINGOBJ:
256	    lt.obj = NewStringObj(ds_win, lt.prompt, lt.var,
257				  lt.y + TCP_DIALOG_Y, lt.x + TCP_DIALOG_X,
258				  lt.len, lt.maxlen);
259	    break;
260
261	case BUTTONOBJ:
262	    lt.obj = NewButtonObj(ds_win, lt.prompt, lt.var,
263				  lt.y + TCP_DIALOG_Y, lt.x + TCP_DIALOG_X);
264	    break;
265
266	default:
267	    msgFatal("Don't support this object yet!");
268	}
269	AddObj(&obj, lt.type, (void *) lt.obj);
270	n++;
271    }
272    max = n - 1;
273
274    /* Find the last object we can traverse to */
275    last = obj;
276    while (last->next)
277	last = last->next;
278
279    /* Find the first object in the list */
280    first = obj;
281    while (first->prev)
282	first = first->prev;
283
284    /* Some more initialisation before we go into the main input loop */
285    n = 0;
286    cancelbutton = okbutton = 0;
287
288    /* Incoming user data - DUCK! */
289    while (!quit) {
290	char help_line[80];
291	int i, len = strlen(lt.help);
292
293	/* Display the help line at the bottom of the screen */
294	for (i = 0; i < 79; i++)
295	    help_line[i] = (i < len) ? lt.help[i] : ' ';
296	help_line[i] = '\0';
297	use_helpline(help_line);
298	display_helpline(ds_win, LINES - 1, COLS - 1);
299
300	/* Ask for libdialog to do its stuff */
301	ret = PollObj(&obj);
302
303	/* We are in the Hostname field - calculate the domainname */
304	if (n == 0) {
305	    if ((tmp = index(hostname, '.')) != NULL) {
306		strncpy(domainname, tmp + 1, strlen(tmp + 1));
307		domainname[strlen(tmp+1)] = '\0';
308		RefreshStringObj(layout[1].obj);
309	    }
310	}
311
312	/* Handle special case stuff that libdialog misses. Sigh */
313	switch (ret) {
314	    /* Bail out */
315	case SEL_ESC:
316	    quit = TRUE, cancel=TRUE;
317	    break;
318
319	    /* This doesn't work for list dialogs. Oh well. Perhaps
320	       should special case the move from the OK button ``up''
321	       to make it go to the interface list, but then it gets
322	       awkward for the user to go back and correct screw up's
323	       in the per-interface section */
324
325	case KEY_UP:
326	    if (obj->prev !=NULL ) {
327		obj = obj->prev;
328		--n;
329	    } else {
330		obj = last;
331		n = max;
332	    }
333	    break;
334
335	case KEY_DOWN:
336	    if (obj->next != NULL) {
337		obj = obj->next;
338		++n;
339	    } else {
340		obj = first;
341		n = 0;
342	    }
343	    break;
344
345	case SEL_TAB:
346	    if (n < max)
347		++n;
348	    else
349		n = 0;
350	    break;
351
352	    /* The user has pressed enter over a button object */
353	case SEL_BUTTON:
354 	    if (cancelbutton)
355		cancel = TRUE, quit = TRUE;
356	    else {
357		if (verifySettings())
358		    quit = TRUE;
359	    }
360	    break;
361
362	    /* Generic CR handler */
363	case SEL_CR:
364	    if (n < max)
365		++n;
366	    else
367		n = 0;
368	    break;
369
370	case SEL_BACKTAB:
371	    if (n)
372		--n;
373	    else
374		n = max;
375	    break;
376
377	case KEY_F(1):
378	    display_helpfile();
379
380	    /* They tried some key combination we don't support - tell them! */
381	default:
382	    beep();
383	}
384
385	/* BODGE ALERT! */
386	if (((tmp = index(hostname, '.')) != NULL) && (strlen(domainname)==0)) {
387	    strncpy(domainname, tmp + 1, strlen(tmp + 1));
388	    domainname[strlen(tmp+1)] = '\0';
389	    RefreshStringObj(layout[1].obj);
390	}
391    }
392
393    /* Clear this crap off the screen */
394    dialog_clear();
395    refresh();
396    use_helpfile(NULL);
397
398    /* We actually need to inform the rest of sysinstall about this
399       data now - if the user hasn't selected cancel, save the stuff
400       out to the environment via the variable_set layers */
401
402    if (!cancel) {
403	DevInfo *di;
404	char temp[512], ifn[64];
405
406	variable_set2(VAR_HOSTNAME, hostname);
407	variable_set2(VAR_DOMAINNAME, domainname);
408	if (gateway[0])
409	    variable_set2(VAR_GATEWAY, gateway);
410	if (nameserver[0])
411	    variable_set2(VAR_NAMESERVER, nameserver);
412
413	if (!devp->private)
414	    devp->private = (DevInfo *)malloc(sizeof(DevInfo));
415	di = devp->private;
416	strcpy(di->ipaddr, ipaddr);
417	strcpy(di->netmask, netmask);
418	strcpy(di->extras, extras);
419
420	sprintf(temp, "inet %s %s netmask %s", ipaddr, extras, netmask);
421	sprintf(ifn, "%s%s", VAR_IFCONFIG, devp->name);
422	variable_set2(ifn, temp);
423	sprintf(ifn, "%s %s", devp->name, getenv(VAR_INTERFACES) ? getenv(VAR_INTERFACES) : "");
424	variable_set2(VAR_INTERFACES, ifn);
425	if (ipaddr[0])
426	    variable_set2(VAR_IPADDR, ipaddr);
427	return 0;
428    }
429    return 1;
430}
431
432static int
433netHook(char *str)
434{
435    Device **devs;
436
437    /* Clip garbage off the ends */
438    string_prune(str);
439    str = string_skipwhite(str);
440    if (!*str)
441	return 0;
442    devs = deviceFind(str, DEVICE_TYPE_NETWORK);
443    if (devs) {
444	tcpOpenDialog(devs[0]);
445	mediaDevice = devs[0];
446    }
447    return devs ? 1 : 0;
448}
449
450/* Get a network device */
451int
452tcpDeviceSelect(char *str)
453{
454    DMenu *menu;
455
456    menu = deviceCreateMenu(&MenuNetworkDevice, DEVICE_TYPE_NETWORK, netHook);
457    if (!menu)
458	msgFatal("Unable to create network device menu!  Argh!");
459    dmenuOpenSimple(menu);
460    free(menu);
461    return 0;
462}
463
464/* Start PPP on the 3rd screen */
465Boolean
466tcpStartPPP(Device *devp)
467{
468    int fd;
469    FILE *fp;
470    char *val;
471    char myaddr[16], provider[16];
472
473    fd = open("/dev/ttyv2", O_RDWR);
474    if (fd == -1)
475	return FALSE;
476    Mkdir("/var/log", NULL);
477    Mkdir("/var/spool/lock", NULL);
478    Mkdir("/etc/ppp", NULL);
479    vsystem("touch /etc/ppp/ppp.linkup; chmod +x /etc/ppp/ppp.linkup");
480    vsystem("touch /etc/ppp/ppp.secret; chmod +x /etc/ppp/ppp.secret");
481    fp = fopen("/etc/ppp/ppp.conf", "w");
482    if (!fp) {
483	msgConfirm("Couldn't open /etc/ppp/ppp.conf file!  This isn't going to work");
484	return FALSE;
485    }
486    fprintf(fp, "default:\n");
487    fprintf(fp, " set device %s\n", devp->devname);
488    val = msgGetInput("115200",
489"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.");
490    if (!val)
491	val = "115200";
492    fprintf(fp, " set speed %s\n", val);
493    if (getenv(VAR_GATEWAY))
494	strcpy(provider, getenv(VAR_GATEWAY));
495    else
496	strcpy(provider, "0");
497    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.");
498    if (!val)
499	val = "0";
500    if (devp->private && ((DevInfo *)devp->private)->ipaddr[0])
501	strcpy(myaddr, ((DevInfo *)devp->private)->ipaddr);
502    else
503	strcpy(myaddr, "0");
504    fprintf(fp, " set ifaddr %s %s\n", myaddr, val);
505    fclose(fp);
506    if (!fork()) {
507	dup2(fd, 0);
508	dup2(fd, 1);
509	dup2(fd, 2);
510	execl("/stand/ppp", "/stand/ppp", (char *)NULL);
511	exit(1);
512    }
513    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!");
514    return TRUE;
515}
516