[WIP] user: skip malformed and empty lines#230
Conversation
1b8a8f3 to
36088f5
Compare
706f6e5 to
15f6695
Compare
| ok, err := parseLine(line, &p.Name, &p.Pass, &p.Uid, &p.Gid, &p.Gecos, &p.Home, &p.Shell) | ||
| if err != nil || !ok { | ||
| // Skip malformed and empty lines, and don't consider them. | ||
| continue | ||
| } |
There was a problem hiding this comment.
Possibly also skip zero-records;
if p == (User{}) {
continue
}| ok, err := parseLine(line, &p.Name, &p.Pass, &p.Gid, &p.List) | ||
| if err != nil || !ok { | ||
| // Skip malformed and empty lines, and don't consider them. | ||
| continue | ||
| } | ||
|
|
||
| if filter == nil || filter(p) { | ||
| out = append(out, p) |
There was a problem hiding this comment.
Here as well, but Group is not comparable (due to the List []string)
ffef6e5 to
752b6ed
Compare
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Return an error when failing to parse numeric values instead of silently discarding them. Co-authored-by: Mickael Emirkanian <mickael.emirkanian@docker.com> Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
| p := User{} | ||
| parseLine(line, &p.Name, &p.Pass, &p.Uid, &p.Gid, &p.Gecos, &p.Home, &p.Shell) | ||
| if err := parseLine(line, &p.Name, &p.Pass, &p.Uid, &p.Gid, &p.Gecos, &p.Home, &p.Shell); err != nil { | ||
| return nil, fmt.Errorf("invalid line (%q): %w", string(line), err) |
There was a problem hiding this comment.
nit: you have both () and "" around line, which seems excessive.
| return nil, fmt.Errorf("invalid line (%q): %w", string(line), err) | |
| return nil, fmt.Errorf("invalid line %q: %w", string(line), err) |
There was a problem hiding this comment.
Ah, yes, I think I was going back-and-forth on %q or (%s) - %q isn't always great due to escaping nested quotes if they can be expected.
| p := Group{} | ||
| parseLine(line, &p.Name, &p.Pass, &p.Gid, &p.List) | ||
| if err := parseLine(line, &p.Name, &p.Pass, &p.Gid, &p.List); err != nil { | ||
| return nil, fmt.Errorf("invalid line (%q): %w", string(line), err) |
kolyshkin
left a comment
There was a problem hiding this comment.
The second patch seems problematic: while it says "skip malformed and empty lines", in fact it returns an error where previously it was ignored.
I think we should merely skip lines that do not conform to the specification, otherwise there will be regressions.
Yes, I need to clean-up my patch set; temporarily pushed, because I think the second (add error return) patch needed updates to the tests.
This was the topic of discussion (so was reordering the patches to make the "skip" last); Old code wasn't good, because it would silently discard invalid UID/GID (numeric) values; it would use The trickier question is what to do if the file contains malformed line(s)? Currently (see above) we "half" ignore them (bad). Which, even with this patch, may still be true; We silently ignore truncated lines; // Ignore cases where we don't have enough fields to populate the arguments.
// Some configuration files like to misbehave.
if len(v) <= i {
break
}So a line like And we still consider empty fields; case *int64:
if len(p) != 0 {
n, err := strconv.ParseInt(string(p), 10, 64)
if err != nil {
return true, fmt.Errorf("parsing integer field %d: %w", i, err)
}
*e = n
}So The slightly less problematic case is ignoring completely malformed lines, and it's less problematic if such a record was not the one we were looking for (i.e., we wouldn't use it anyway), but of course, if it's malformed, it COULD have been the line we were looking for, and I think we pick "first match", so the malformed (or incoplete) line would shadow the valid one; If we skip such lines or error out, that would prevent that (but probably needs more than this patch). |
|
Looks like getent skips over malformed lines; if (ret == EINVAL)
/* Skip over malformed lines. */
continue;Older implementations; } while (*p == '\0' || *p == '#' /* Ignore empty and comment lines. */
/* Parse the line. If it is invalid, loop to
get the next line of the file to parse. */
|| ! parse_line (p, resbuf, (void *) buffer, buflen, &errno));But it looks like it does reject lines with empty numeric columns; INT_FIELD (result->pw_uid, ISCOLON, 0, 10,)
INT_FIELD (result->pw_gid, ISCOLON, 0, 10,)Except for STRING_FIELD (result->pw_name, ISCOLON, 0);
if (line[0] == '\0'
&& (result->pw_name[0] == '+' || result->pw_name[0] == '-'))
{
/* This a special case. We allow lines containing only a `+' sign
since this is used for nss_compat. All other services will
reject this entry later. Initialize all other fields now. */
result->pw_passwd = NULL;
result->pw_uid = 0;
result->pw_gid = 0;
result->pw_gecos = NULL;
result->pw_dir = NULL;
result->pw_shell = NULL;
} |
|
Quick AI summary;
So the overall behavior is:
That's a fairly common pattern in libc: the iteration APIs ( I think that's a strong precedent for |
|
And for the
|
No description provided.