/* * User authentication & authorization * * Copyright 2010 Krzysztof Piotr Oledzki * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * */ #ifdef CONFIG_HAP_CRYPT /* This is to have crypt() defined on Linux */ #define _GNU_SOURCE #ifdef NEED_CRYPT_H /* some platforms such as Solaris need this */ #include #endif #endif /* CONFIG_HAP_CRYPT */ #include #include #include #include #include #include #include #include struct userlist *userlist = NULL; /* list of all existing userlists */ /* find targets for selected gropus. The function returns pointer to * the userlist struct ot NULL if name is NULL/empty or unresolvable. */ struct userlist * auth_find_userlist(char *name) { struct userlist *l; if (!name || !*name) return NULL; for (l = userlist; l; l = l->next) if (!strcmp(l->name, name)) return l; return NULL; } /* find group_mask for selected gropus. The function returns 1 if OK or nothing to do, * 0 if case of unresolved groupname. * WARING: the function destroys the list (strtok), so it can only be used once. */ unsigned int auth_resolve_groups(struct userlist *l, char *groups) { char *group = NULL; unsigned int g, group_mask = 0; if (!groups || !*groups) return 0; while ((group = strtok(group?NULL:groups," "))) { for (g = 0; g < l->grpcnt; g++) if (!strcmp(l->groups[g], group)) break; if (g == l->grpcnt) { Alert("No such group '%s' in userlist '%s'.\n", group, l->name); return 0; } group_mask |= (1 << g); } return group_mask; } struct req_acl_rule * parse_auth_cond(const char **args, const char *file, int linenum, struct proxy *proxy) { struct req_acl_rule *req_acl; int cur_arg; req_acl = (struct req_acl_rule*)calloc(1, sizeof(struct req_acl_rule)); if (!req_acl) { Alert("parsing [%s:%d]: out of memory.\n", file, linenum); return NULL; } if (!*args[0]) { goto req_error_parsing; } else if (!strcmp(args[0], "allow")) { req_acl->action = PR_REQ_ACL_ACT_ALLOW; cur_arg = 1; } else if (!strcmp(args[0], "deny")) { req_acl->action = PR_REQ_ACL_ACT_DENY; cur_arg = 1; } else if (!strcmp(args[0], "auth")) { req_acl->action = PR_REQ_ACL_ACT_HTTP_AUTH; cur_arg = 1; while(*args[cur_arg]) { if (!strcmp(args[cur_arg], "realm")) { req_acl->http_auth.realm = strdup(args[cur_arg + 1]); cur_arg+=2; continue; } else break; } } else { req_error_parsing: Alert("parsing [%s:%d]: %s '%s', expects 'allow', 'deny', 'auth'.\n", file, linenum, *args[1]?"unknown parameter":"missing keyword in", args[*args[1]?1:0]); return NULL; } if (strcmp(args[cur_arg], "if") == 0 || strcmp(args[cur_arg], "unless") == 0) { struct acl_cond *cond; if ((cond = build_acl_cond(file, linenum, proxy, args+cur_arg)) == NULL) { Alert("parsing [%s:%d] : error detected while parsing an 'http-request %s' condition.\n", file, linenum, args[0]); return NULL; } req_acl->cond = cond; } else if (*args[cur_arg]) { Alert("parsing [%s:%d]: 'http-request %s' expects 'realm' for 'auth' or" " either 'if' or 'unless' followed by a condition but found '%s'.\n", file, linenum, args[0], args[cur_arg]); return NULL; } return req_acl; } void userlist_free(struct userlist *ul) { struct userlist *tul; struct auth_users *au, *tau; int i; while (ul) { au = ul->users; while (au) { tau = au; au = au->next; free(tau->user); free(tau->pass); free(tau); } tul = ul; ul = ul->next; for (i = 0; i < tul->grpcnt; i++) free(tul->groups[i]); free(tul->name); free(tul); }; } void req_acl_free(struct list *r) { struct req_acl_rule *tr, *pr; list_for_each_entry_safe(pr, tr, r, list) { LIST_DEL(&pr->list); if (pr->action == PR_REQ_ACL_ACT_HTTP_AUTH) free(pr->http_auth.realm); free(pr); } } /* * Authenticate and authorize user; return 1 if OK, 0 if case of error. */ int check_user(struct userlist *ul, unsigned int group_mask, const char *user, const char *pass) { struct auth_users *u; const char *ep; #ifdef DEBUG_AUTH fprintf(stderr, "req: userlist=%s, user=%s, pass=%s, group_mask=%u\n", ul->name, user, pass, group_mask); #endif for (u = ul->users; u; u = u->next) if (!strcmp(user, u->user)) break; if (!u) return 0; #ifdef DEBUG_AUTH fprintf(stderr, "cfg: user=%s, pass=%s, group_mask=%u, flags=%X", u->user, u->pass, u->group_mask, u->flags); #endif /* * if user matches but group does not, * it makes no sens to check passwords */ if (group_mask && !(group_mask & u->u.group_mask)) return 0; if (!(u->flags & AU_O_INSECURE)) { #ifdef CONFIG_HAP_CRYPT ep = crypt(pass, u->pass); #else return 0; #endif } else ep = pass; #ifdef DEBUG_AUTH fprintf(stderr, ", crypt=%s\n", ep); #endif if (!strcmp(ep, u->pass)) return 1; else return 0; } int acl_match_auth(struct acl_test *test, struct acl_pattern *pattern) { struct userlist *ul = test->ctx.a[0]; char *user = test->ctx.a[1]; char *pass = test->ctx.a[2]; unsigned int group_mask; if (pattern) group_mask = pattern->val.group_mask; else group_mask = 0; if (check_user(ul, group_mask, user, pass)) return ACL_PAT_PASS; else return ACL_PAT_FAIL; }