PUBLIC bool websVerifyPassword(Webs *wp) { char passbuf[BIT_LIMIT_PASSWORD * 3 + 3]; bool success; assure(wp); if (!wp->encoded) { fmt(passbuf, sizeof(passbuf), "%s:%s:%s", wp->username, BIT_REALM, wp->password); wfree(wp->password); wp->password = websMD5(passbuf); wp->encoded = 1; } if (!wp->user && (wp->user = websLookupUser(wp->username)) == 0) { trace(5, "verifyUser: Unknown user \"%s\"", wp->username); return 0; } /* Verify the password */ if (wp->digest) { success = smatch(wp->password, wp->digest); } else { success = smatch(wp->password, wp->user->password); } if (success) { trace(5, "User \"%s\" authenticated", wp->username); } else { trace(5, "Password for user \"%s\" failed to authenticate", wp->username); } return success; }
PUBLIC bool websVerifyPasswordFromFile(Webs *wp) { char passbuf[ME_GOAHEAD_LIMIT_PASSWORD * 3 + 3]; bool success; assert(wp); if (!wp->user && (wp->user = websLookupUser(wp->username)) == 0) { trace(5, "verifyUser: Unknown user \"%s\"", wp->username); return 0; } /* Verify the password. If using Digest auth, we compare the digest of the password. Otherwise we encode the plain-text password and compare that */ if (!wp->encoded) { fmt(passbuf, sizeof(passbuf), "%s:%s:%s", wp->username, ME_GOAHEAD_REALM, wp->password); wfree(wp->password); wp->password = websMD5(passbuf); wp->encoded = 1; } if (wp->digest) { success = smatch(wp->password, wp->digest); } else { success = smatch(wp->password, wp->user->password); } if (success) { trace(5, "User \"%s\" authenticated", wp->username); } else { trace(5, "Password for user \"%s\" failed to authenticate", wp->username); } return success; }
PUBLIC bool websVerifyPamPassword(Webs *wp) { WebsBuf abilities; pam_handle_t *pamh; UserInfo info; struct pam_conv conv = { pamChat, &info }; struct group *gp; int res, i; assure(wp); assure(wp->username && wp->username); assure(wp->password); assure(!wp->encoded); info.name = (char*) wp->username; info.password = (char*) wp->password; pamh = NULL; if ((res = pam_start("login", info.name, &conv, &pamh)) != PAM_SUCCESS) { return 0; } if ((res = pam_authenticate(pamh, PAM_DISALLOW_NULL_AUTHTOK)) != PAM_SUCCESS) { pam_end(pamh, PAM_SUCCESS); trace(5, "httpPamVerifyUser failed to verify %s", wp->username); return 0; } pam_end(pamh, PAM_SUCCESS); trace(5, "httpPamVerifyUser verified %s", wp->username); if (!wp->user) { wp->user = websLookupUser(wp->username); } if (!wp->user) { Gid groups[32]; int ngroups; /* Create a temporary user with a abilities set to the groups */ ngroups = sizeof(groups) / sizeof(Gid); if ((i = getgrouplist(wp->username, 99999, groups, &ngroups)) >= 0) { bufCreate(&abilities, 128, -1); for (i = 0; i < ngroups; i++) { if ((gp = getgrgid(groups[i])) != 0) { bufPutStr(&abilities, gp->gr_name); bufPutc(&abilities, ' '); } } bufAddNull(&abilities); trace(5, "Create temp user \"%s\" with abilities: %s", wp->username, abilities.servp); if ((wp->user = websAddUser(wp->username, 0, abilities.servp)) == 0) { return 0; } computeUserAbilities(wp->user); } } return 1; }
PUBLIC int websSetUserPassword(char *username, char *password) { WebsUser *user; assert(username); if ((user = websLookupUser(username)) == 0) { return -1; } wfree(user->password); user->password = sclone(password); return 0; }
PUBLIC int websSetUserRoles(char *username, char *roles) { WebsUser *user; assure(username &&*username); if ((user = websLookupUser(username)) == 0) { return -1; } wfree(user->roles); user->roles = sclone(roles); computeUserAbilities(user); return 0; }
WebsUser *websAddUser(char *username, char *password, char *roles) { WebsUser *user; if (!username) { error("User is missing name"); return 0; } if (websLookupUser(username)) { error("User %s already exists", username); /* Already exists */ return 0; } if ((user = createUser(username, password, roles)) == 0) { return 0; } if (hashEnter(users, username, valueSymbol(user), 0) == 0) { return 0; } return user; }
static bool parseDigestDetails(Webs *wp) { WebsTime when; char *value, *tok, *key, *dp, *sp, *secret, *realm; int seenComma; assure(wp); key = sclone(wp->authDetails); while (*key) { while (*key && isspace((uchar) *key)) { key++; } tok = key; while (*tok && !isspace((uchar) *tok) && *tok != ',' && *tok != '=') { tok++; } *tok++ = '\0'; while (isspace((uchar) *tok)) { tok++; } seenComma = 0; if (*tok == '\"') { value = ++tok; while (*tok != '\"' && *tok != '\0') { tok++; } } else { value = tok; while (*tok != ',' && *tok != '\0') { tok++; } seenComma++; } *tok++ = '\0'; /* Handle back-quoting */ if (strchr(value, '\\')) { for (dp = sp = value; *sp; sp++) { if (*sp == '\\') { sp++; } *dp++ = *sp++; } *dp = '\0'; } /* user, response, oqaque, uri, realm, nonce, nc, cnonce, qop */ switch (tolower((uchar) *key)) { case 'a': if (scaselesscmp(key, "algorithm") == 0) { break; } else if (scaselesscmp(key, "auth-param") == 0) { break; } break; case 'c': if (scaselesscmp(key, "cnonce") == 0) { wp->cnonce = sclone(value); } break; case 'd': if (scaselesscmp(key, "domain") == 0) { break; } break; case 'n': if (scaselesscmp(key, "nc") == 0) { wp->nc = sclone(value); } else if (scaselesscmp(key, "nonce") == 0) { wp->nonce = sclone(value); } break; case 'o': if (scaselesscmp(key, "opaque") == 0) { wp->opaque = sclone(value); } break; case 'q': if (scaselesscmp(key, "qop") == 0) { wp->qop = sclone(value); } break; case 'r': if (scaselesscmp(key, "realm") == 0) { wp->realm = sclone(value); } else if (scaselesscmp(key, "response") == 0) { /* Store the response digest in the password field. This is MD5(user:realm:password) */ wp->password = sclone(value); wp->encoded = 1; } break; case 's': if (scaselesscmp(key, "stale") == 0) { break; } case 'u': if (scaselesscmp(key, "uri") == 0) { wp->digestUri = sclone(value); } else if (scaselesscmp(key, "username") == 0 || scaselesscmp(key, "user") == 0) { wp->username = sclone(value); } break; default: /* Just ignore keywords we don't understand */ ; } key = tok; if (!seenComma) { while (*key && *key != ',') { key++; } if (*key) { key++; } } } if (wp->username == 0 || wp->realm == 0 || wp->nonce == 0 || wp->route == 0 || wp->password == 0) { return 0; } if (wp->qop && (wp->cnonce == 0 || wp->nc == 0)) { return 0; } if (wp->qop == 0) { wp->qop = sclone(""); } /* Validate the nonce value - prevents replay attacks */ when = 0; secret = 0; realm = 0; parseDigestNonce(wp->nonce, &secret, &realm, &when); if (!smatch(secret, secret)) { trace(2, "Access denied: Nonce mismatch\n"); return 0; } else if (!smatch(realm, BIT_REALM)) { trace(2, "Access denied: Realm mismatch\n"); return 0; } else if (!smatch(wp->qop, "auth")) { trace(2, "Access denied: Bad qop\n"); return 0; } else if ((when + (5 * 60)) < time(0)) { trace(2, "Access denied: Nonce is stale\n"); return 0; } if (!wp->user) { if ((wp->user = websLookupUser(wp->username)) == 0) { trace(2, "Access denied: user is unknown\n"); return 0; } } wp->digest = calcDigest(wp, 0, wp->user->password); return 1; }