1 /*
2  * $Id: util.c,v 1.10 2010/02/04 10:31:41 aland Exp $
3  *
4  * Copyright (c) 1998 The NetBSD Foundation, Inc.
5  *
6  * Copyright (C) 1995,1996,1997 Lars Fenneberg
7  *
8  * Copyright 1992 Livingston Enterprises, Inc.
9  *
10  * Copyright 1992,1993, 1994,1995 The Regents of the University of Michigan
11  * and Merit Network, Inc. All Rights Reserved
12  *
13  * See the file COPYRIGHT for the respective terms and conditions.
14  * If the file is missing contact me at lf@elemental.net
15  * and I'll send you a copy.
16  *
17  */
18 
19 #include <sys/time.h>
20 
21 #include <config.h>
22 #include <includes.h>
23 #include <freeradius-client.h>
24 
25 #define	RC_BUFSIZ	1024
26 
27 /*
28  * Function: rc_str2tm
29  *
30  * Purpose: Turns printable string into correct tm struct entries.
31  *
32  */
33 
34 static char const * months[] =
35 		{
36 			"Jan", "Feb", "Mar", "Apr", "May", "Jun",
37 			"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
38 		};
39 
rc_str2tm(char const * valstr,struct tm * tm)40 void rc_str2tm (char const *valstr, struct tm *tm)
41 {
42 	int             i;
43 
44 	/* Get the month */
45 	for (i = 0; i < 12; i++)
46 	{
47 		if (strncmp (months[i], valstr, 3) == 0)
48 		{
49 			tm->tm_mon = i;
50 			i = 13;
51 		}
52 	}
53 
54 	/* Get the Day */
55 	tm->tm_mday = atoi (&valstr[4]);
56 
57 	/* Now the year */
58 	tm->tm_year = atoi (&valstr[7]) - 1900;
59 }
60 
61 /*
62  * Function: rc_getifname
63  *
64  * Purpose: get the network interface name associated with this tty
65  *
66  */
67 
rc_getifname(rc_handle * rh,char const * tty)68 char *rc_getifname(rc_handle *rh, char const *tty)
69 {
70 #if defined(BSD4_4) || defined(linux)
71 	int		fd;
72 
73 	if ((fd = open(tty, O_RDWR|O_NDELAY)) < 0) {
74 		rc_log(LOG_ERR, "rc_getifname: can't open %s: %s", tty, strerror(errno));
75 		return NULL;
76 	}
77 #endif
78 
79 #ifdef BSD4_4
80 	strcpy(rh->ifname,ttyname(fd));
81 	if (strlen(rh->ifname) < 1) {
82 		rc_log(LOG_ERR, "rc_getifname: can't get attached interface of %s: %s", tty, strerror(errno));
83 		close(fd);
84 		return NULL;
85 	}
86 #elif linux
87 	if (ioctl(fd, SIOCGIFNAME, rh->ifname) < 0) {
88 		rc_log(LOG_ERR, "rc_getifname: can't ioctl %s: %s", tty, strerror(errno));
89 		close(fd);
90 		return NULL;
91 	}
92 #else
93 	return NULL;
94 #endif
95 
96 #if defined(BSD4_4) || defined(linux)
97 	close(fd);
98 	return rh->ifname;
99 #endif
100 }
101 
102 /*
103  * Function: rc_getstr
104  *
105  * Purpose: Reads in a string from the user (with or witout echo)
106  *
107  */
108 #ifndef _MSC_VER
rc_getstr(rc_handle * rh,char const * prompt,int do_echo)109 char *rc_getstr (rc_handle *rh, char const *prompt, int do_echo)
110 {
111 	int             in, out;
112 	char           *p;
113 	struct termios  term_old, term_new;
114 	int		is_term, flags, old_flags;
115 	char		c;
116 	int		flushed = 0;
117 	sigset_t        newset;
118 	sigset_t        oldset;
119 
120 	in = fileno(stdin);
121 	out = fileno(stdout);
122 
123 	(void) sigemptyset (&newset);
124 	(void) sigaddset (&newset, SIGINT);
125 	(void) sigaddset (&newset, SIGTSTP);
126 	(void) sigaddset (&newset, SIGQUIT);
127 
128 	(void) sigprocmask (SIG_BLOCK, &newset, &oldset);
129 
130 	if ((is_term = isatty(in)))
131 	{
132 
133 		(void) tcgetattr (in, &term_old);
134 		term_new = term_old;
135 		if (do_echo)
136 			term_new.c_lflag |= ECHO;
137 		else
138 			term_new.c_lflag &= ~ECHO;
139 
140 		if (tcsetattr (in, TCSAFLUSH, &term_new) == 0)
141 			flushed = 1;
142 
143 	}
144 	else
145 	{
146 		is_term = 0;
147 		if ((flags = fcntl(in, F_GETFL, 0)) >= 0) {
148 			old_flags = flags;
149 			flags |= O_NONBLOCK;
150 
151 			fcntl(in, F_SETFL, flags);
152 
153 			while (read(in, &c, 1) > 0)
154 				/* nothing */;
155 
156 			fcntl(in, F_SETFL, old_flags);
157 
158 			flushed = 1;
159 		}
160 	}
161 
162 	(void)write(out, prompt, strlen(prompt));
163 
164 	/* well, this looks ugly, but it handles the following end of line
165 	   markers: \r \r\0 \r\n \n \n\r, at least at a second pass */
166 
167 	p = rh->buf;
168 	for (;;)
169 	{
170 		if (read(in, &c, 1) <= 0)
171 			return NULL;
172 
173 		if (!flushed && ((c == '\0') || (c == '\r') || (c == '\n'))) {
174 			flushed = 1;
175 			continue;
176 		}
177 
178 		if ((c == '\r') || (c == '\n'))
179 			break;
180 
181 		flushed = 1;
182 
183 		if (p < rh->buf + GETSTR_LENGTH)
184 		{
185 			if (do_echo && !is_term)
186 				(void)write(out, &c, 1);
187 			*p++ = c;
188 		}
189 	}
190 
191 	*p = '\0';
192 
193 	if (!do_echo || !is_term) (void)write(out, "\r\n", 2);
194 
195 	if (is_term)
196 		tcsetattr (in, TCSAFLUSH, &term_old);
197 	else {
198 		if ((flags = fcntl(in, F_GETFL, 0)) >= 0) {
199 			old_flags = flags;
200 			flags |= O_NONBLOCK;
201 
202 			fcntl(in, F_SETFL, flags);
203 
204 			while (read(in, &c, 1) > 0)
205 				/* nothing */;
206 
207 			fcntl(in, F_SETFL, old_flags);
208 		}
209 	}
210 
211 	(void) sigprocmask (SIG_SETMASK, &oldset, NULL);
212 
213 	return rh->buf;
214 }
215 #endif
rc_mdelay(int msecs)216 void rc_mdelay(int msecs)
217 {
218 	struct timeval tv;
219 
220 	tv.tv_sec = (int) msecs / 1000;
221 	tv.tv_usec = (msecs % 1000) * 1000;
222 
223 	select(0, NULL, NULL, NULL, &tv);
224 }
225 
226 /*
227  * Function: rc_mksid
228  *
229  * Purpose: generate a quite unique string
230  *
231  * Remarks: not that unique at all...
232  *
233  */
234 
235 char *
rc_mksid(rc_handle * rh)236 rc_mksid (rc_handle *rh)
237 {
238   snprintf (rh->buf1, sizeof(rh->buf1), "%08lX%04X", (unsigned long int) time (NULL), (unsigned int) getpid ());
239   return rh->buf1;
240 }
241 
242 /*
243  * Function: rc_new
244  *
245  * Purpose: Initialises new Radius Client handle
246  *
247  */
248 
249 rc_handle *
rc_new(void)250 rc_new(void)
251 {
252 	rc_handle *rh;
253 
254 	rh = malloc(sizeof(*rh));
255 	if (rh == NULL) {
256                 rc_log(LOG_CRIT, "rc_new: out of memory");
257                 return NULL;
258         }
259 	memset(rh, 0, sizeof(*rh));
260 	return rh;
261 }
262 
263 /*
264  * Function: rc_destroy
265  *
266  * Purpose: Destroys Radius Client handle reclaiming all memory
267  *
268  */
269 
270 void
rc_destroy(rc_handle * rh)271 rc_destroy(rc_handle *rh)
272 {
273 
274 	rc_map2id_free(rh);
275 	rc_dict_free(rh);
276 	rc_config_free(rh);
277 	if (rh->this_host_bind_ipaddr != NULL)
278 		free(rh->this_host_bind_ipaddr);
279 	free(rh);
280 }
281 
282 /*
283  * Function: rc_fgetln
284  *
285  * Purpose: Get next line from the stream.
286  *
287  */
288 
289 char *
rc_fgetln(FILE * fp,size_t * len)290 rc_fgetln(FILE *fp, size_t *len)
291 {
292 	static char *buf = NULL;
293 	static size_t bufsiz = 0;
294 	char *ptr;
295 
296 	if (buf == NULL) {
297 		bufsiz = RC_BUFSIZ;
298 		if ((buf = malloc(bufsiz)) == NULL)
299 			return NULL;
300 	}
301 
302 	if (fgets(buf, (int)bufsiz, fp) == NULL)
303 		return NULL;
304 	*len = 0;
305 
306 	while ((ptr = strchr(&buf[*len], '\n')) == NULL) {
307 		size_t nbufsiz = bufsiz + RC_BUFSIZ;
308 		char *nbuf = realloc(buf, nbufsiz);
309 
310 		if (nbuf == NULL) {
311 			int oerrno = errno;
312 			free(buf);
313 			errno = oerrno;
314 			buf = NULL;
315 			return NULL;
316 		} else
317 			buf = nbuf;
318 
319 		*len = bufsiz;
320 		if (fgets(&buf[bufsiz], RC_BUFSIZ, fp) == NULL)
321 			return buf;
322 
323 		bufsiz = nbufsiz;
324 	}
325 
326 	*len = (ptr - buf) + 1;
327 	return buf;
328 }
329 
330 /*
331  * Function: rc_getctime
332  *
333  * Purpose: Get current time (seconds since epoch) expressed as
334  * double-precision floating point number.
335  *
336  */
337 
338 double
rc_getctime(void)339 rc_getctime(void)
340 {
341     struct timeval timev;
342 
343     if (gettimeofday(&timev, NULL) == -1)
344         return -1;
345 
346     return timev.tv_sec + ((double)timev.tv_usec) / 1000000.0;
347 }
348