root/usr/src/cmd/cmd-inet/usr.bin/ftp/ruserpass.c
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 *      Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 *      Use is subject to license terms.
 */

/*      Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T     */
/*      All Rights Reserved     */

/*
 *      University Copyright- Copyright (c) 1982, 1986, 1988
 *      The Regents of the University of California
 *      All Rights Reserved
 *
 *      University Acknowledgment- Portions of this document are derived from
 *      software developed by the University of California, Berkeley, and its
 *      contributors.
 */

#include "ftp_var.h"

static  FILE *cfile;

static int rnetrc(char *host, char **aname, char **apass, char **aacct);
static int token(void);

int
ruserpass(char *host, char **aname, char **apass, char **aacct)
{
#if 0
        renv(host, aname, apass, aacct);
        if (*aname == 0 || *apass == 0)
#endif
                return (rnetrc(host, aname, apass, aacct));
}

#define DEFAULT 1
#define LOGIN   2
#define PASSWD  3
#define ACCOUNT 4
#define MACDEF  5
#define SKIPSYST        6
#define ID      10
#define MACHINE 11

static char tokval[100];

static struct toktab {
        char *tokstr;
        int tval;
} toktab[] = {
        "default",      DEFAULT,
        "login",        LOGIN,
        "password",     PASSWD,
        "account",      ACCOUNT,
        "machine",      MACHINE,
        "macdef",       MACDEF,
        "skipsyst",     SKIPSYST,
        0,              0
};

static int
rnetrc(char *host, char **aname, char **apass, char **aacct)
{
        char *hdir, buf[PATH_MAX+1], *tmp;
        int t, i, c;
        struct stat stb;
        extern int errno;

        hdir = getenv("HOME");
        if (hdir == NULL)
                hdir = ".";
        if (snprintf(buf, sizeof (buf), "%s/.netrc", hdir) >= sizeof (buf)) {
                fprintf(stderr, ".netrc: %s\n", strerror(ENAMETOOLONG));
                exit(1);
        }

        cfile = fopen(buf, "r");
        if (cfile == NULL) {
                if (errno != ENOENT)
                        perror(buf);
                return (0);
        }
next:
        while ((t = token()))
                switch (t) {

        case MACHINE:
                if (token() != ID || strcmp(host, tokval))
                        continue;
                /* "machine name" matches host */
                /* FALLTHROUGH */

        case DEFAULT:
                /* "default" matches any host */
                while (((t = token()) != 0) && t != MACHINE && t != DEFAULT)
                        switch (t) {

                case LOGIN:
                        if (token())
                                if (*aname == 0) {
                                        *aname = malloc((unsigned)
                                            strlen(tokval) + 1);
                                        if (*aname == NULL) {
                                                fprintf(stderr,
                                                    "Error - out of VM\n");
                                                exit(1);
                                        }
                                        (void) strcpy(*aname, tokval);
                                } else {
                                        if (strcmp(*aname, tokval))
                                                goto next;
                                }
                        break;
                case PASSWD:
                        if (fstat(fileno(cfile), &stb) >= 0 &&
                            (stb.st_mode & 077) != 0) {
                                fprintf(stderr, "Error - .netrc file not "
                                    "correct mode.\n");
                                fprintf(stderr, "Remove password or correct "
                                    "mode.\n");
                                return (-1);
                        }
                        if (token() && *apass == 0) {
                                *apass = malloc((unsigned)strlen(tokval) + 1);
                                if (*apass == NULL) {
                                        fprintf(stderr, "Error - out of VM\n");
                                        exit(1);
                                }
                                (void) strcpy(*apass, tokval);
                        }
                        break;
                case ACCOUNT:
                        if (fstat(fileno(cfile), &stb) >= 0 &&
                            (stb.st_mode & 077) != 0) {
                                fprintf(stderr, "Error - .netrc file not "
                                    "correct mode.\n");
                                fprintf(stderr, "Remove account or correct "
                                    "mode.\n");
                                return (-1);
                        }
                        if (token() && *aacct == 0) {
                                *aacct = malloc((unsigned)strlen(tokval) + 1);
                                if (*aacct == NULL) {
                                        fprintf(stderr, "Error - out of VM\n");
                                        exit(1);
                                }
                                (void) strcpy(*aacct, tokval);
                        }
                        break;
                case MACDEF:
                        if (proxy) {
                                return (0);
                        }
                        while ((c = getc(cfile)) != EOF && c == ' ' ||
                            c == '\t');
                        if (c == EOF || c == '\n') {
                                printf("Missing macdef name argument.\n");
                                return (-1);
                        }
                        if (macnum == 16) {
                                printf("Limit of 16 macros have already "
                                    "been defined\n");
                                return (-1);
                        }
                        tmp = macros[macnum].mac_name;
                        *tmp++ = c;
                        for (i = 0; i < 8 && (c = getc(cfile)) != EOF &&
                            !isspace(c); ++i) {
                                *tmp++ = c;
                        }
                        if (c == EOF) {
                                printf("Macro definition for `%s` missing "
                                    "null line terminator.\n",
                                    macros[macnum].mac_name);
                                return (-1);
                        }
                        *tmp = '\0';
                        if (c != '\n') {
                                while ((c = getc(cfile)) != EOF && c != '\n');
                        }
                        if (c == EOF) {
                                printf("Macro definition for `%s` missing "
                                    "null line terminator.\n",
                                    macros[macnum].mac_name);
                                return (-1);
                        }
                        if (macnum == 0) {
                                macros[macnum].mac_start = macbuf;
                        } else {
                                macros[macnum].mac_start =
                                    macros[macnum-1].mac_end + 1;
                        }
                        tmp = macros[macnum].mac_start;
                        while (tmp != macbuf + 4096) {
                                if ((c = getc(cfile)) == EOF) {
                                printf("Macro definition for `%s` missing "
                                    "null line terminator.\n",
                                    macros[macnum].mac_name);
                                        return (-1);
                                }
                                *tmp = c;
                                if (*tmp == '\n') {
                                        if (*(tmp-1) == '\0') {
                                                macros[macnum++].mac_end =
                                                    tmp - 1;
                                                break;
                                        }
                                        *tmp = '\0';
                                }
                                tmp++;
                        }
                        if (tmp == macbuf + 4096) {
                                printf("4K macro buffer exceeded\n");
                                return (-1);
                        }
                        if (*macros[macnum - 1].mac_start == '\n') {
                                printf("Macro definition for `%s` is empty, "
                                    "macro not stored.\n",
                                        macros[--macnum].mac_name);
                        }
                        break;
                case SKIPSYST:
                        skipsyst = 1;
                        break;
                default:
                        fprintf(stderr, "Unknown .netrc keyword %s\n", tokval);
                        break;
                }
                goto done;
        }
done:
        (void) fclose(cfile);
        return (0);
}

static int
token(void)
{
        char *cp;
        int c;
        struct toktab *t;
        int     len;

        if (feof(cfile))
                return (0);
        while ((c = fgetwc(cfile)) != EOF &&
            (c == '\n' || c == '\t' || c == ' ' || c == ','))
                continue;
        if (c == EOF)
                return (0);
        cp = tokval;
        if (c == '"') {
                while ((c = fgetwc(cfile)) != EOF && c != '"') {
                        if (c == '\\')
                                c = fgetwc(cfile);
                        if ((len = wctomb(cp, c)) <= 0) {
                                len = 1;
                                *cp = (unsigned char)c;
                        }
                        cp += len;
                }
        } else {
                if ((len = wctomb(cp, c)) <= 0) {
                        *cp = (unsigned char)c;
                        len = 1;
                }
                cp += len;
                while ((c = fgetwc(cfile)) != EOF && c != '\n' && c != '\t' &&
                    c != ' ' && c != ',') {
                        if (c == '\\')
                                c = fgetwc(cfile);
                        if ((len = wctomb(cp, c)) <= 0) {
                                len = 1;
                                *cp = (unsigned char)c;
                        }
                        cp += len;
                }
        }
        *cp = 0;
        if (tokval[0] == 0)
                return (0);
        for (t = toktab; t->tokstr; t++)
                if (strcmp(t->tokstr, tokval) == 0)
                        return (t->tval);
        return (ID);
}