X-Git-Url: https://diplodocus.org/git/nmh/blobdiff_plain/52a236230220232fd632b5aa88eb9bb31dba346e..1e03ea3338cc5ccd9ddf4feaaacfeda1998689cc:/sbr/ruserpass.c?ds=inline diff --git a/sbr/ruserpass.c b/sbr/ruserpass.c index f5ef74a4..55694c82 100644 --- a/sbr/ruserpass.c +++ b/sbr/ruserpass.c @@ -1,4 +1,5 @@ -/* +/* ruserpass.c -- parse .netrc-format file. + * * Portions of this code are * Copyright (c) 1985 Regents of the University of California. * All rights reserved. @@ -20,13 +21,17 @@ * distribution for complete copyright information. */ -#include -#include +#include "h/mh.h" +#include "getpass.h" +#include "ruserpass.h" +#include "credentials.h" +#include "error.h" +#include "h/utils.h" #include -#include static FILE *cfile; +#define TOK_EOF 0 #define DEFAULT 1 #define LOGIN 2 #define PASSWD 3 @@ -35,7 +40,7 @@ static FILE *cfile; #define ID 10 #define MACH 11 -static char tokval[100]; +#define MAX_TOKVAL_SIZE 1024 /* Including terminating NUL. */ struct toktab { char *tokstr; @@ -43,6 +48,7 @@ struct toktab { }; static struct toktab toktabs[] = { + { "", TOK_EOF }, { "default", DEFAULT }, { "login", LOGIN }, { "password", PASSWD }, @@ -56,13 +62,13 @@ static struct toktab toktabs[] = { /* * prototypes */ -static int token(void); +static int token(char *); void -ruserpass(char *host, char **aname, char **apass) +ruserpass(const char *host, char **aname, char **apass, int flags) { - int t, usedefault = 0; + int t; struct stat stb; init_credentials_file (); @@ -72,15 +78,19 @@ ruserpass(char *host, char **aname, char **apass) if (errno != ENOENT) perror (credentials_file); } else { - while ((t = token())) { + char tokval[MAX_TOKVAL_SIZE]; + tokval[0] = '\0'; + + bool usedefault = false; + while ((t = token(tokval))) { switch(t) { case DEFAULT: - usedefault = 1; - /* FALL THROUGH */ + usedefault = true; + /* FALLTHRU */ case MACH: if (!usedefault) { - if (token() != ID) + if (token(tokval) != ID) continue; /* * Allow match either for user's host name. @@ -90,29 +100,26 @@ ruserpass(char *host, char **aname, char **apass) continue; } match: - while ((t = token()) && t != MACH && t != DEFAULT) { + while ((t = token(tokval)) && t != MACH && t != DEFAULT) { switch(t) { case LOGIN: - if (token() && *aname == 0) { - *aname = mh_xmalloc((size_t) strlen(tokval) + 1); - strcpy(*aname, tokval); - } + if (token(tokval) && *aname == 0) + *aname = mh_xstrdup(tokval); break; case PASSWD: - if (fstat(fileno(cfile), &stb) >= 0 && + if (!credentials_no_perm_check && + fstat(fileno(cfile), &stb) >= 0 && (stb.st_mode & 077) != 0) { /* We make this a fatal error to force the user to correct it. */ - advise(NULL, "Error - file %s must not be world or " - "group readable.", credentials_file); - adios(NULL, "Remove password or correct file " + inform("group or other permissions, %#o, " + "forbidden: %s", stb.st_mode, credentials_file); + die("Remove password or correct file " "permissions."); } - if (token() && *apass == 0) { - *apass = mh_xmalloc((size_t) strlen(tokval) + 1); - strcpy(*apass, tokval); - } + if (token(tokval) && *apass == 0) + *apass = mh_xstrdup(tokval); break; case ACCOUNT: @@ -134,7 +141,7 @@ ruserpass(char *host, char **aname, char **apass) } } - if (!*aname) { + if (!*aname && ! (flags & RUSERPASS_NO_PROMPT_USER)) { char tmp[80]; char *myname; @@ -146,68 +153,77 @@ ruserpass(char *host, char **aname, char **apass) } printf("Name (%s:%s): ", host, myname); - fgets(tmp, sizeof(tmp) - 1, stdin); - tmp[strlen(tmp) - 1] = '\0'; - if (*tmp != '\0') { + if (fgets(tmp, sizeof tmp, stdin) == NULL) { + advise ("tmp", "fgets"); + } + trim_suffix_c(tmp, '\n'); + if (*tmp != '\0' || myname == NULL) { myname = tmp; } - *aname = mh_xmalloc((size_t) strlen(myname) + 1); - strcpy (*aname, myname); + *aname = mh_xstrdup(myname); } - if (!*apass) { + if (!*apass && ! (flags & RUSERPASS_NO_PROMPT_PASSWORD)) { char prompt[256]; char *mypass; snprintf(prompt, sizeof(prompt), "Password (%s:%s): ", host, *aname); mypass = nmh_getpass(prompt); - + if (*mypass == '\0') { mypass = *aname; } - *apass = mh_xmalloc((size_t) strlen(mypass) + 1); - strcpy (*apass, mypass); + *aname = mh_xstrdup(mypass); } } static int -token(void) +token(char *tokval) { - char *cp; int c; + const char normalStop[] = "\t\n ,"; /* Each breaks a word. */ + const char *stop; + char *cp; struct toktab *t; - if (feof(cfile)) - return (0); - while ((c = getc(cfile)) != EOF && - (c == '\n' || c == '\t' || c == ' ' || c == ',')) - continue; + if (feof(cfile) || ferror(cfile)) + return TOK_EOF; + + stop = normalStop; + while ((c = getc(cfile)) != EOF && c && strchr(stop, c)) + ; if (c == EOF) - return (0); + return TOK_EOF; + cp = tokval; - if (c == '"') { - while ((c = getc(cfile)) != EOF && c != '"') { - if (c == '\\') - c = getc(cfile); - *cp++ = c; - } - } else { - *cp++ = c; - while ((c = getc(cfile)) != EOF - && c != '\n' && c != '\t' && c != ' ' && c != ',') { - if (c == '\\') - c = getc(cfile); - *cp++ = c; - } + if (c == '"') + /* FIXME: Where is the quoted-string syntax of netrc documented? + * This code treats «"foo""bar"» as two tokens without further + * separators. */ + stop = "\""; + else + /* Might be backslash. Get it again later. It's handled then. */ + if (ungetc(c, cfile) == EOF) + return TOK_EOF; + + while ((c = getc(cfile)) != EOF && c && !strchr(stop, c)) { + if (c == '\\' && (c = getc(cfile)) == EOF) + return TOK_EOF; /* Discard whole token. */ + + *cp++ = c; + if (cp - tokval > MAX_TOKVAL_SIZE-1) { + die("credential tokens restricted to length %d", + MAX_TOKVAL_SIZE - 1); + } } - *cp = 0; - if (tokval[0] == 0) - return (0); + *cp = '\0'; + for (t = toktabs; t->tokstr; t++) if (!strcmp(t->tokstr, tokval)) - return (t->tval); - return (ID); + return t->tval; + + return ID; }