1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
29
30 /*
31 * Portions of this source code were derived from Berkeley 4.3 BSD
32 * under license from the Regents of the University of California.
33 */
34
35 #include "mt.h"
36 #include "../rpc/rpc_mt.h" /* for MT declarations only */
37 #include <rpc/types.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <ctype.h>
42 #include <netconfig.h>
43 #include <malloc.h>
44 #include <libintl.h>
45 #include <syslog.h>
46 #include "netcspace.h"
47
48 #define FAILURE (unsigned)(-1)
49
50 /*
51 * Local routines used by the library procedures
52 */
53
54 static int blank(char *);
55 static int comment(char *);
56 static struct netconfig *fgetnetconfig(FILE *, char *);
57 static void netconfig_free(struct netconfig *);
58 static unsigned int getflag(char *);
59 static char **getlookups(char *);
60 static struct netconfig **getnetlist(void);
61 static unsigned int getnlookups(char *);
62 static char *gettoken(char *, int);
63 static unsigned int getvalue(char *, struct nc_data nc_data[]);
64 static void shift1left(char *);
65 static void netlist_free(struct netconfig ***);
66 static void free_entry(void *);
67 static struct netconfig *netconfig_dup(struct netconfig *);
68
69 extern const char __nsl_dom[];
70
71 /*
72 * Static global variables used by the library procedures:
73 *
74 * netpp - points to the beginning of the list of netconfig
75 * entries used by setnetconfig() and setnetpath().
76 * Once netpp is initialized, that memory is *never*
77 * released. This was necessary to improve performance.
78 *
79 * linenum - the current line number of the /etc/netconfig
80 * file (used for debugging and for nc_perror()).
81 *
82 * fieldnum - the current field number of the current line
83 * of /etc/netconfig (used for debugging and for
84 * nc_perror()).
85 *
86 * nc_error - the error condition encountered.
87 */
88
89 static struct netconfig **netpp = NULL;
90 mutex_t netpp_mutex = DEFAULTMUTEX;
91 /*
92 * The following two variables are used by the /etc/netconfig parsing
93 * routines, which will always be executed once, and within the netpp_mutex.
94 * They are global to allow the nc_sperror routine to provide better
95 * information to the user about /etc/netconfig file problems.
96 */
97 static int linenum = 0; /* "owned" by getnetlist() */
98 static int fieldnum = 0; /* "owned" by fgetnetconfig() */
99
100
101 static int *
__nc_error(void)102 __nc_error(void)
103 {
104 static pthread_key_t nc_error_key = PTHREAD_ONCE_KEY_NP;
105 static int nc_error = NC_NOERROR;
106 int *ret;
107
108 if (thr_main())
109 return (&nc_error);
110 ret = thr_get_storage(&nc_error_key, sizeof (int), free);
111 /* if thr_get_storage fails we return the address of nc_error */
112 return (ret ? ret : &nc_error);
113 }
114 #define nc_error (*(__nc_error()))
115
116 /*
117 * setnetconfig() has the effect of "initializing" the
118 * network configuration database. It reads in the
119 * netcf entries (if not already read in).
120 */
121
122 void *
setnetconfig(void)123 setnetconfig(void)
124 {
125 NCONF_HANDLE *retp;
126
127 (void) mutex_lock(&netpp_mutex);
128 if ((netpp == NULL) && ((netpp = getnetlist()) == NULL)) {
129 (void) mutex_unlock(&netpp_mutex);
130 return (NULL);
131 }
132 (void) mutex_unlock(&netpp_mutex);
133 if ((retp = malloc(sizeof (NCONF_HANDLE))) == NULL) {
134 nc_error = NC_NOMEM;
135 return (NULL);
136 }
137 nc_error = NC_NOERROR;
138 retp->nc_head = retp->nc_curr = netpp;
139 return ((void *)retp);
140 }
141
142 /*
143 * endnetconfig() frees up all data allocated by setnetconfig()
144 */
145
146 int
endnetconfig(void * vdata)147 endnetconfig(void *vdata)
148 {
149 NCONF_HANDLE *nconf_handlep = (NCONF_HANDLE *)vdata;
150
151 (void) mutex_lock(&netpp_mutex);
152 if (netpp == NULL || nconf_handlep == NULL) {
153 nc_error = NC_NOSET;
154 (void) mutex_unlock(&netpp_mutex);
155 return (-1);
156 }
157 (void) mutex_unlock(&netpp_mutex);
158
159 nc_error = NC_NOERROR;
160 free(nconf_handlep);
161 return (0);
162 }
163
164 /*
165 * getnetconfig() returns the current entry in the list
166 * of netconfig structures. It uses the nconf_handlep argument
167 * to determine the current entry. If setnetconfig() was not
168 * called previously to set up the list, return failure.
169 * It also check if ipv6 interface is present(ipv6_present) and
170 * skips udp6 & tcp6 entries if ipv6 is not supported.
171 */
172
173 struct netconfig *
getnetconfig(void * vdata)174 getnetconfig(void *vdata)
175 {
176 NCONF_HANDLE *nconf_handlep = (NCONF_HANDLE *)vdata;
177 struct netconfig *retp; /* holds the return value */
178 int ipv6_present = -1;
179
180 (void) mutex_lock(&netpp_mutex);
181 if ((netpp == NULL) || (nconf_handlep == NULL)) {
182 nc_error = NC_NOSET;
183 (void) mutex_unlock(&netpp_mutex);
184 return (NULL);
185 }
186 (void) mutex_unlock(&netpp_mutex);
187 for (;;) {
188 retp = *(nconf_handlep->nc_curr);
189 if (retp && (strcmp(retp->nc_netid, "udp6") == 0 ||
190 strcmp(retp->nc_netid, "tcp6") == 0)) {
191 if (ipv6_present == -1)
192 ipv6_present = __can_use_af(AF_INET6);
193 if (!ipv6_present) {
194 ++(nconf_handlep->nc_curr);
195 continue;
196 }
197 }
198 break;
199 }
200 if (retp != NULL) {
201 ++(nconf_handlep->nc_curr);
202 nc_error = NC_NOERROR;
203 } else {
204 nc_error = NC_NOMOREENTRIES;
205 }
206 return (retp);
207 }
208
209 /*
210 * getnetconfig() searches the netconfig database for a
211 * given network id. Returns a pointer to the netconfig
212 * structure or a NULL if not found.
213 * It also check if ipv6 interface is present(ipv6_present) and
214 * skips udp6 & tcp6 entries if ipv6 is not supported.
215 */
216
217 struct netconfig *
getnetconfigent(const char * netid)218 getnetconfigent(const char *netid)
219 {
220 struct netconfig **tpp;
221 int ipv6_present;
222
223 (void) mutex_lock(&netpp_mutex);
224 if ((netpp == NULL) && ((netpp = getnetlist()) == NULL)) {
225 (void) mutex_unlock(&netpp_mutex);
226 return (NULL);
227 }
228 (void) mutex_unlock(&netpp_mutex);
229 for (tpp = netpp; *tpp; tpp++) {
230 if (strcmp((*tpp)->nc_netid, netid) == 0) {
231 if (*tpp && (strcmp((*tpp)->nc_netid, "udp6") == 0 ||
232 strcmp((*tpp)->nc_netid, "tcp6") == 0)) {
233 ipv6_present = __can_use_af(AF_INET6);
234 if (!ipv6_present) {
235 nc_error = NC_NOTFOUND;
236 return (NULL);
237 }
238 }
239 return (netconfig_dup(*tpp));
240 }
241 }
242 nc_error = NC_NOTFOUND;
243 return (NULL);
244 }
245
246 /*
247 * freenetconfigent frees the data allocated by getnetconfigent()
248 */
249
250 void
freenetconfigent(struct netconfig * netp)251 freenetconfigent(struct netconfig *netp)
252 {
253 netconfig_free(netp);
254 }
255
256 /*
257 * getnetlist() reads the netconfig file and creates a
258 * NULL-terminated list of entries.
259 * Returns the pointer to the head of the list or a NULL
260 * on failure.
261 */
262
263 static struct netconfig **
getnetlist(void)264 getnetlist(void)
265 {
266 char line[BUFSIZ]; /* holds each line of NETCONFIG */
267 FILE *fp; /* file stream for NETCONFIG */
268 struct netconfig **listpp; /* the beginning of the netconfig list */
269 struct netconfig **tpp; /* used to traverse the netconfig list */
270 int count; /* the number of entries in file */
271
272 if ((fp = fopen(NETCONFIG, "rF")) == NULL) {
273 nc_error = NC_OPENFAIL;
274 return (NULL);
275 }
276
277 count = 0;
278 while (fgets(line, BUFSIZ, fp)) {
279 if (!(blank(line) || comment(line))) {
280 ++count;
281 }
282 }
283 rewind(fp);
284
285 if (count == 0) {
286 nc_error = NC_NOTFOUND;
287 (void) fclose(fp);
288 return (NULL);
289 }
290 if ((listpp = malloc((count + 1) *
291 sizeof (struct netconfig *))) == NULL) {
292 nc_error = NC_NOMEM;
293 (void) fclose(fp);
294 return (NULL);
295 }
296
297 /*
298 * The following loop fills in the list (loops until
299 * fgetnetconfig() returns a NULL) and counts the
300 * number of entries placed in the list. Note that
301 * when the loop is completed, the last entry in the
302 * list will contain a NULL (signifying the end of
303 * the list).
304 */
305 linenum = 0;
306 for (tpp = listpp; *tpp = fgetnetconfig(fp, NULL); tpp++)
307 ;
308 (void) fclose(fp);
309
310 if (nc_error != NC_NOMOREENTRIES) /* Something is screwed up */
311 netlist_free(&listpp);
312 return (listpp);
313 }
314
315 /*
316 * fgetnetconfig() parses a line of the netconfig file into
317 * a netconfig structure. It returns a pointer to the
318 * structure of success and a NULL on failure or EOF.
319 */
320
321 static struct netconfig *
fgetnetconfig(FILE * fp,char * netid)322 fgetnetconfig(FILE *fp, char *netid)
323 {
324 char linep[BUFSIZ]; /* pointer to a line in the file */
325 struct netconfig *netconfigp; /* holds the new netconfig structure */
326 char *tok1, *tok2, *tok3; /* holds a token from the line */
327 char *retvalp; /* the return value of fgets() */
328 char *entnetid; /* netid for the current entry */
329
330 /* skip past blank lines and comments. */
331 while (retvalp = fgets(linep, BUFSIZ, fp)) {
332 linenum++;
333 if (!(blank(linep) || comment(linep))) {
334 break;
335 }
336 retvalp = NULL;
337 }
338 if (retvalp == NULL) {
339 nc_error = NC_NOMOREENTRIES;
340 return (NULL);
341 }
342 fieldnum = 0;
343 if ((entnetid = gettoken(linep, FALSE)) == NULL) {
344 nc_error = NC_BADLINE;
345 return (NULL);
346 }
347 if (netid && (strcmp(netid, entnetid) != 0)) {
348 free(entnetid);
349 nc_error = NC_NOTFOUND;
350 return (NULL);
351 }
352 if ((netconfigp = calloc(1, sizeof (struct netconfig))) == NULL) {
353 free(entnetid);
354 nc_error = NC_NOMEM;
355 return (NULL);
356 }
357
358 tok1 = tok2 = tok3 = NULL;
359 netconfigp->nc_netid = entnetid;
360 if (((tok1 = gettoken(NULL, FALSE)) == NULL) ||
361 ((netconfigp->nc_semantics =
362 getvalue(tok1, nc_semantics)) == FAILURE) ||
363 ((tok2 = gettoken(NULL, FALSE)) == NULL) ||
364 ((netconfigp->nc_flag = getflag(tok2)) == FAILURE) ||
365 ((netconfigp->nc_protofmly = gettoken(NULL, FALSE)) == NULL) ||
366 ((netconfigp->nc_proto = gettoken(NULL, FALSE)) == NULL) ||
367 ((netconfigp->nc_device = gettoken(NULL, FALSE)) == NULL) ||
368 ((tok3 = gettoken(NULL, TRUE)) == NULL) ||
369 (((netconfigp->nc_nlookups = getnlookups(tok3)) != 0) &&
370 ((netconfigp->nc_lookups = getlookups(tok3)) == NULL))) {
371 netconfig_free(netconfigp);
372 nc_error = NC_BADLINE;
373 netconfigp = NULL;
374 }
375 free(tok1);
376 free(tok2);
377 free(tok3);
378 return (netconfigp);
379 }
380
381 /*
382 * setnetpath() has the effect of "initializing" the
383 * NETPATH variable. It reads in the netcf entries (if not
384 * already read in), creates a list corresponding to the entries
385 * in the NETPATH variable (or the "visible" entries og netconfig
386 * if NETPATH is not set).
387 */
388
389 void *
setnetpath(void)390 setnetpath(void)
391 {
392 int count; /* the number of entries in NETPATH */
393 char valid_netpath[BUFSIZ]; /* holds the valid entries if NETPATH */
394 char templine[BUFSIZ]; /* has value of NETPATH when scanning */
395 struct netconfig **curr_pp; /* scans the list from NETPATH */
396 struct netconfig **tpp; /* scans the list from netconfig file */
397 struct netconfig **rnetpp; /* the list of entries from NETPATH */
398 char *netpath; /* value of NETPATH from environment */
399 char *netid; /* holds a component of NETPATH */
400 char *tp; /* used to scan NETPATH string */
401 NCONF_HANDLE *retp; /* the return value */
402
403 /*
404 * Read in the netconfig database if not already read in
405 */
406 (void) mutex_lock(&netpp_mutex);
407 if ((netpp == NULL) && ((netpp = getnetlist()) == NULL)) {
408 (void) mutex_unlock(&netpp_mutex);
409 return (NULL);
410 }
411 (void) mutex_unlock(&netpp_mutex);
412
413 if ((retp = malloc(sizeof (NCONF_HANDLE))) == NULL) {
414 nc_error = NC_NOMEM;
415 return (NULL);
416 }
417
418 /*
419 * Get the valid entries of the NETPATH variable (and
420 * count the number of entries while doing it).
421 *
422 * This is done every time the procedure is called just
423 * in case NETPATH has changed from call to call.
424 *
425 * If NETPATH is too long, we ignore it altogether as
426 * it can only be a buffer overflow attack.
427 * Since we add one colon for each entry, but colons only
428 * need to exist between entries, we have to subtract one.
429 */
430 count = 0;
431 valid_netpath[0] = '\0';
432 if ((netpath = getenv(NETPATH)) == NULL ||
433 strlen(netpath) >= sizeof (templine) - 1) {
434 /*
435 * If NETPATH variable is not set or invalid,
436 * the valid NETPATH consist of all "visible"
437 * netids from the netconfig database.
438 */
439
440 for (tpp = netpp; *tpp; tpp++) {
441 if ((*tpp)->nc_flag & NC_VISIBLE) {
442 (void) strcat(valid_netpath, (*tpp)->nc_netid);
443 (void) strcat(valid_netpath, ":");
444 count++;
445 }
446 }
447 } else {
448
449 /*
450 * Copy the value of NETPATH (since '\0's will be
451 * put into the string) and create the valid NETPATH
452 * (by throwing away all netids not in the database).
453 * If an entry appears more than one, it *will* be
454 * listed twice in the list of valid netpath entries.
455 */
456
457 (void) strcpy(templine, netpath);
458 tp = templine;
459
460 while (*tp) {
461 /* Skip all leading ':'s */
462 while (*tp && *tp == ':')
463 tp++;
464 if (*tp == '\0')
465 break; /* last one */
466 netid = tp;
467 while (*tp && *tp != ':')
468 tp++;
469 if (*tp)
470 *tp++ = '\0'; /* isolate netid */
471
472 for (tpp = netpp; *tpp; tpp++) {
473 if (strcmp(netid, (*tpp)->nc_netid) == 0) {
474 (void) strcat(valid_netpath,
475 (*tpp)->nc_netid);
476 (void) strcat(valid_netpath, ":");
477 count++;
478 break;
479 }
480 }
481 }
482 }
483
484 /* Get space to hold the valid list (+1 for the NULL) */
485
486 if ((rnetpp = malloc((count + 1) *
487 sizeof (struct netconfig *))) == NULL) {
488 free(retp);
489 nc_error = NC_NOMEM;
490 return (NULL);
491 }
492
493 /*
494 * Populate the NETPATH list, ending it with a NULL.
495 * Each entry in the list points to the structure in the
496 * "netpp" list (the entry must exist in the list, otherwise
497 * it wouldn't appear in valid_netpath[]).
498 */
499
500 curr_pp = rnetpp;
501 netid = tp = valid_netpath;
502 while (*tp) {
503 netid = tp;
504 while (*tp && *tp != ':')
505 tp++;
506 if (*tp)
507 *tp++ = '\0';
508 for (tpp = netpp; *tpp; tpp++) {
509 if (strcmp(netid, (*tpp)->nc_netid) == 0) {
510 *curr_pp++ = *tpp;
511 break;
512 }
513 }
514 }
515 *curr_pp = NULL;
516
517 retp->nc_curr = retp->nc_head = rnetpp;
518 return ((void *)retp);
519 }
520
521 /*
522 * endnetpath() frees up all of the memory allocated by setnetpath().
523 * It returns -1 (error) if setnetpath was never called.
524 */
525
526 int
endnetpath(void * vdata)527 endnetpath(void *vdata)
528 {
529 /* The argument is really a NCONF_HANDLE; cast it here */
530 NCONF_HANDLE *nconf_handlep = (NCONF_HANDLE *)vdata;
531
532 (void) mutex_lock(&netpp_mutex);
533 if (netpp == NULL || nconf_handlep == NULL) {
534 nc_error = NC_NOSET;
535 (void) mutex_unlock(&netpp_mutex);
536 return (-1);
537 }
538 (void) mutex_unlock(&netpp_mutex);
539
540 free(nconf_handlep->nc_head);
541 free(nconf_handlep);
542 return (0);
543 }
544
545 /*
546 * getnetpath() returns the current entry in the list
547 * from the NETPATH variable. If setnetpath() was not called
548 * previously to set up the list, return NULL.
549 */
550
551 struct netconfig *
getnetpath(void * vdata)552 getnetpath(void *vdata)
553 {
554 /* The argument is really a NCONF_HANDLE; cast it here */
555 NCONF_HANDLE *nconf_handlep = (NCONF_HANDLE *)vdata;
556 struct netconfig *retp; /* holds the return value */
557 int ipv6_present = -1;
558
559 (void) mutex_lock(&netpp_mutex);
560 if (netpp == NULL) {
561 nc_error = NC_NOSET;
562 (void) mutex_unlock(&netpp_mutex);
563 return (NULL);
564 }
565 (void) mutex_unlock(&netpp_mutex);
566 for (;;) {
567 retp = *(nconf_handlep->nc_curr);
568 if (retp && (strcmp(retp->nc_netid, "udp6") == 0 ||
569 strcmp(retp->nc_netid, "tcp6") == 0)) {
570 if (ipv6_present == -1)
571 ipv6_present = __can_use_af(AF_INET6);
572 if (!ipv6_present) {
573 ++(nconf_handlep->nc_curr);
574 continue;
575 }
576 }
577 break;
578 }
579 if (retp) {
580 ++(nconf_handlep->nc_curr);
581 nc_error = NC_NOERROR;
582 } else {
583 nc_error = NC_NOMOREENTRIES;
584 }
585
586 return (retp);
587 }
588
589 /*
590 * blank() returns true if the line is a blank line, 0 otherwise
591 */
592
593 static int
blank(char * cp)594 blank(char *cp)
595 {
596 while (*cp && isspace(*cp)) {
597 cp++;
598 }
599 return (*cp == '\0');
600 }
601
602 /*
603 * comment() returns true if the line is a comment, 0 otherwise.
604 */
605
606 static int
comment(char * cp)607 comment(char *cp)
608 {
609 while (*cp && isspace(*cp)) {
610 cp++;
611 }
612 return (*cp == '#');
613 }
614
615 /*
616 * getvalue() searches for the given string in the given array,
617 * and return the integer value associated with the string.
618 */
619
620 static unsigned int
getvalue(char * cp,struct nc_data nc_data[])621 getvalue(char *cp, struct nc_data nc_data[])
622 {
623 int i; /* used to index through the given struct nc_data array */
624
625 for (i = 0; nc_data[i].string; i++) {
626 if (strcmp(nc_data[i].string, cp) == 0) {
627 break;
628 }
629 }
630 return (nc_data[i].value);
631 }
632
633 /*
634 * getflag() creates a bitmap of the one-character flags in
635 * the given string. It uses nc_flags array to get the values.
636 */
637
638 static unsigned int
getflag(char * cp)639 getflag(char *cp)
640 {
641 int i; /* indexs through the nc_flag array */
642 unsigned int mask = 0; /* holds bitmask of flags */
643
644 while (*cp) {
645 for (i = 0; nc_flag[i].string; i++) {
646 if (*nc_flag[i].string == *cp) {
647 mask |= nc_flag[i].value;
648 break;
649 }
650 }
651 cp++;
652 }
653 return (mask);
654 }
655
656 /*
657 * getlookups() creates and returns an array of string representing
658 * the directory lookup libraries, given as a comma-seperated list
659 * in the argument "cp".
660 */
661
662 static char **
getlookups(char * cp)663 getlookups(char *cp)
664 {
665 unsigned int num; /* holds the number of entries in the list */
666 char **listpp; /* the beginning of the list of dir routines */
667 char **tpp; /* traverses the list, populating it */
668 char *start;
669
670 num = getnlookups(cp);
671 if (num == 0)
672 return (NULL);
673 if ((listpp = malloc((num + 1) * sizeof (char *))) == NULL)
674 return (NULL);
675
676 tpp = listpp;
677 while (num--) {
678 start = cp;
679
680 /*
681 * Traverse the string looking for the next entry
682 * of the list (i.e, where the ',' or end of the
683 * string appears). If a "\" is found, shift the
684 * token over 1 to the left (taking the next char
685 * literally).
686 */
687
688 while (*cp && *cp != ',') {
689 if (*cp == '\\' && *(cp + 1)) {
690 shift1left(cp);
691 }
692 cp++;
693 }
694 if (*cp)
695 *cp++ = '\0';
696 if ((*tpp++ = strdup(start)) == NULL) {
697 for (tpp = listpp; *tpp; tpp++)
698 free(*tpp);
699 free(listpp);
700 return (NULL);
701 }
702 }
703 *tpp = NULL;
704 return (listpp);
705 }
706
707 /*
708 * getnlookups() returns the number of entries in a comma-separated
709 * string of tokens. A "-" means no strings are present.
710 */
711
712 static unsigned int
getnlookups(char * cp)713 getnlookups(char *cp)
714 {
715 unsigned int count; /* the number of tokens in the string */
716
717 if (strcmp(cp, "-") == 0)
718 return (0);
719
720 count = 1;
721 while (*cp) {
722 if (*cp == ',') {
723 count++;
724 }
725
726 /*
727 * If a "\" is in the string, take the next character
728 * literally. Onlly skip the character if "\" is
729 * not the last character of the token.
730 */
731 if (*cp == '\\' && *(cp + 1)) {
732 cp++;
733 }
734 cp++;
735 }
736 return (count);
737 }
738
739 /*
740 * gettoken() behaves much like strtok(), except that
741 * it knows about escaped space characters (i.e., space characters
742 * preceeded by a '\' are taken literally).
743 */
744
745 static char *
gettoken(char * cp,int skip)746 gettoken(char *cp, int skip)
747 {
748 static char *savep; /* the place where we left off */
749 char *p; /* the beginning of the new token */
750 char *retp; /* the token to be returned */
751
752 fieldnum++;
753
754 /* Determine if first or subsequent call */
755 p = (cp == NULL)? savep: cp;
756
757 /* Return if no tokens remain. */
758 if (p == 0)
759 return (NULL);
760
761 while (isspace(*p))
762 p++;
763
764 if (*p == '\0')
765 return (NULL);
766
767 /*
768 * Save the location of the token and then skip past it
769 */
770
771 retp = p;
772 while (*p) {
773 if (isspace(*p))
774 if (skip == TRUE) {
775 shift1left(p);
776 continue;
777 } else
778 break;
779 /*
780 * Only process the escape of the space seperator;
781 * since the token may contain other separators,
782 * let the other routines handle the escape of
783 * specific characters in the token.
784 */
785
786 if (*p == '\\' && *(p + 1) != '\n' && isspace(*(p + 1))) {
787 shift1left(p);
788 }
789 p++;
790 }
791 if (*p == '\0') {
792 savep = 0; /* indicate this is last token */
793 } else {
794 *p = '\0';
795 savep = ++p;
796 }
797 return (strdup(retp));
798 }
799
800 /*
801 * shift1left() moves all characters in the string over 1 to
802 * the left.
803 */
804
805 static void
shift1left(char * p)806 shift1left(char *p)
807 {
808 for (; *p; p++)
809 *p = *(p + 1);
810 }
811
812 char *
nc_sperror(void)813 nc_sperror(void)
814 {
815 static char buf_main[BUFSIZ];
816 static pthread_key_t perror_key = PTHREAD_ONCE_KEY_NP;
817 char *retstr = thr_main()?
818 buf_main :
819 thr_get_storage(&perror_key, BUFSIZ, free);
820
821 if (retstr == NULL) {
822 syslog(LOG_WARNING,
823 "nc_sperror: malloc failed when trying to create buffer\n");
824 return (NULL);
825 }
826
827 switch (nc_error) {
828 case NC_NOERROR:
829 (void) strlcpy(retstr, dgettext(__nsl_dom, "no error"), BUFSIZ);
830 break;
831 case NC_NOMEM:
832 (void) strlcpy(retstr, dgettext(__nsl_dom, "out of memory"),
833 BUFSIZ);
834 break;
835 case NC_NOSET:
836 (void) strlcpy(retstr, dgettext(__nsl_dom,
837 "routine called before calling \
838 setnetpath() or setnetconfig()"), BUFSIZ);
839 break;
840 case NC_OPENFAIL:
841 (void) strlcpy(retstr,
842 dgettext(__nsl_dom, "cannot open /etc/netconfig"),
843 BUFSIZ);
844 break;
845 case NC_BADLINE:
846 (void) snprintf(retstr, BUFSIZ, dgettext(__nsl_dom,
847 "error in /etc/netconfig: field %d of line %d\n"),
848 fieldnum, linenum);
849 break;
850 case NC_NOTFOUND:
851 (void) snprintf(retstr, BUFSIZ,
852 dgettext(__nsl_dom,
853 "netid not found in /etc/netconfig"));
854 break;
855 case NC_NOMOREENTRIES:
856 (void) snprintf(retstr, BUFSIZ,
857 dgettext(__nsl_dom,
858 "no more entries in /etc/netconfig"));
859 break;
860 default:
861 (void) strlcpy(retstr, dgettext(__nsl_dom, "unknown error"),
862 BUFSIZ);
863 break;
864 }
865 return (retstr);
866 }
867
868 void
nc_perror(const char * string)869 nc_perror(const char *string)
870 {
871 if (string)
872 (void) fprintf(stderr, "%s: %s\n", string, nc_sperror());
873 else
874 (void) fprintf(stderr, "%s\n", nc_sperror());
875 }
876
877 static void
netlist_free(struct netconfig *** netppp)878 netlist_free(struct netconfig ***netppp)
879 {
880 struct netconfig **tpp;
881
882 for (tpp = *netppp; *tpp; tpp++) {
883 netconfig_free(*tpp);
884 }
885 free(*netppp);
886 *netppp = NULL;
887 }
888
889 static void
netconfig_free(struct netconfig * netconfigp)890 netconfig_free(struct netconfig *netconfigp)
891 {
892 int i;
893
894 if (netconfigp == NULL)
895 return;
896 free_entry(netconfigp->nc_netid);
897 free_entry(netconfigp->nc_protofmly);
898 free_entry(netconfigp->nc_proto);
899 free_entry(netconfigp->nc_device);
900 if (netconfigp->nc_lookups)
901 for (i = 0; i < netconfigp->nc_nlookups; i++)
902 free_entry(netconfigp->nc_lookups[i]);
903 free_entry(netconfigp->nc_lookups);
904 free(netconfigp);
905 }
906
907 static struct netconfig *
netconfig_dup(struct netconfig * netconfigp)908 netconfig_dup(struct netconfig *netconfigp)
909 {
910 struct netconfig *nconf;
911 int i;
912
913 nconf = calloc(1, sizeof (struct netconfig));
914 if (nconf == NULL) {
915 nc_error = NC_NOMEM;
916 return (NULL);
917 }
918 nconf->nc_netid = strdup(netconfigp->nc_netid);
919 nconf->nc_protofmly = strdup(netconfigp->nc_protofmly);
920 nconf->nc_proto = strdup(netconfigp->nc_proto);
921 nconf->nc_device = strdup(netconfigp->nc_device);
922 nconf->nc_lookups = malloc((netconfigp->nc_nlookups + 1)
923 * sizeof (char *));
924 if (!(nconf->nc_lookups && nconf->nc_netid &&
925 nconf->nc_protofmly && nconf->nc_proto &&
926 nconf->nc_device)) {
927 nc_error = NC_NOMEM;
928 netconfig_free(nconf);
929 return (NULL);
930 }
931
932 for (i = 0; i < netconfigp->nc_nlookups; i++) {
933 nconf->nc_lookups[i] = strdup(netconfigp->nc_lookups[i]);
934 if (nconf->nc_lookups[i] == NULL) {
935 nconf->nc_nlookups = i;
936 netconfig_free(nconf);
937 nc_error = NC_NOMEM;
938 return (NULL);
939 }
940 }
941 nconf->nc_lookups[i] = NULL;
942 nconf->nc_nlookups = netconfigp->nc_nlookups;
943 nconf->nc_flag = netconfigp->nc_flag;
944 nconf->nc_semantics = netconfigp->nc_semantics;
945 return (nconf);
946 }
947
948 static void
free_entry(void * foo)949 free_entry(void *foo)
950 {
951 if (foo)
952 free(foo);
953 }
954