Julien ÉLIE julien at
Tue Aug 26 19:20:41 UTC 2008

Hi Russ,

>> Or maybe I am totally wrong and do not understand PERMpass?
> I think you're not understanding AUTHINFO GENERIC.  It's used to hold the
> password returned by the external program so that it can be compared
> against a password provided by the user, as near as I can tell.

I still do not understand the logic behind.
AUTHINFO GENERIC is enough to authenticate; no need to use AUTHINFO USER (?)

If AUTHINFO GENERIC succeeds, it is fine.  But PERMpass is never used
(indeed, one cannot send other AUTHINFO commands).

If AUTHINFO GENERIC fails, then PERMpass exists and people have
to use AUTHINFO USER and AUTHINFO PASS afterwards.  And the password
has to be PERMpass.

Is it the way it works?  Double authentication?!?  (A failed one with
AUTHINFO GENERIC and a successful one afterwards?)

Code follows to explains what I have just wrote:

static int
PERMgeneric(char *av[], char *accesslist, size_t size)

// spawn, etc. etc.

    PERMcanread = strchr(fields[1], 'R') != NULL;
    PERMcanpost = strchr(fields[1], 'P') != NULL;
    PERMaccessconf->allowapproved = strchr(fields[1], 'A') != NULL;
    PERMaccessconf->locpost = strchr(fields[1], 'L') != NULL;
    PERMaccessconf->allowihave = strchr(fields[1], 'I') != NULL;
    if (strchr(fields[1], 'N') != NULL) PERMaccessconf->allownewnews = true;
    snprintf(PERMuser, sizeof(PERMuser), "%s@%s", fields[2], fields[0]);
    strlcpy(PERMpass, fields[3], sizeof(PERMpass));
    strlcpy(accesslist, fields[4], size);

So PERMgeneric() sets up useful stuff for the reader.

CMDauthinfo(int ac, char *av[])
    if (strcasecmp(av[1], "generic") == 0) {
        switch (PERMgeneric(av, accesslist, sizeof(accesslist))) {
            case 1:
                Reply("%d Authentication succeeded\r\n", NNTP_OK_AUTHINFO);
                PERMneedauth = false;
                PERMauthorized = true;
                PERMcanauthenticate = false;
            case 0:
                Reply("%d Authentication failed\r\n", NNTP_ERR_ACCESS);
    } else if (strcasecmp(av[1], "sasl") == 0) {
        SASLauth(ac, av);
    } else {
        /* Each time AUTHINFO USER is used, the new username is cached. */
        if (strcasecmp(av[1], "user") == 0) {
            strlcpy(User, av[2], sizeof(User));
            Reply("%d PASS required\r\n", NNTP_CONT_AUTHINFO);

        /* If it is not AUTHINFO PASS, we do not support the provided subcommand. */
        if (strcasecmp(av[1], "pass") != 0) {
            Reply("%d bad authinfo param\r\n", NNTP_ERR_COMMAND);
        if (User[0] == '\0') {
            Reply("%d USER required\r\n", NNTP_FAIL_AUTHINFO_REJECT);

        /* There is a cached username and a password is provided. */
        strlcpy(Password, av[2], sizeof(Password));

        if (strcmp(User, PERMuser) == 0 && strcmp(Password, PERMpass) == 0) {
            syslog(L_NOTICE, "%s user %s",, PERMuser);
            if (LLOGenable) {
                fprintf(locallog, "%s user (%s):%s\n",, Username, PERMuser);
            Reply("%d Ok\r\n", NNTP_OK_AUTHINFO);
            PERMneedauth = false;
            PERMauthorized = true;
            PERMcanauthenticate = false;

So PERMpass is used within the code used by AUTHINFO PASS?

Very strange authenticating system (I do not see such an explanation in RFC 2980).

Julien ÉLIE

« C'est le vin des vins ! il est pétillant, et on s'en sert
  pour les grandes occasions ! Baptiser les galères par exemple... » (Astérix)

More information about the inn-workers mailing list