--- libaitcfg/src/pwd.c 2012/09/19 13:46:46 1.1 +++ libaitcfg/src/pwd.c 2012/09/19 15:22:32 1.2 @@ -0,0 +1,336 @@ +/************************************************************************* +* (C) 2010 AITNET ltd - Sofia/Bulgaria - +* by Michael Pounov +* +* $Author: misho $ +* $Id: pwd.c,v 1.2 2012/09/19 15:22:32 misho Exp $ +* +************************************************************************** +The ELWIX and AITNET software is distributed under the following +terms: + +All of the documentation and software included in the ELWIX and AITNET +Releases is copyrighted by ELWIX - Sofia/Bulgaria + +Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 + by Michael Pounov . All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. All advertising materials mentioning features or use of this software + must display the following acknowledgement: +This product includes software developed by Michael Pounov +ELWIX - Embedded LightWeight unIX and its contributors. +4. Neither the name of AITNET nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. +*/ +#include "global.h" +#include "aitpwd.h" + + +#pragma GCC visibility push(hidden) + +inline int +pwd_tree_cmp(struct tagUser *a, struct tagUser *b) +{ + assert(a && b); + + return strcmp(AIT_GET_STR(&a->usr_name), AIT_GET_STR(&b->usr_name)); +} + +RB_GENERATE(tagPWD, tagUser, usr_node, pwd_tree_cmp); + +#pragma GCC visibility pop + +static inline void +_invertQueue(pwd_root_t * __restrict pwd) +{ + struct tagUser *item, *next, *prev = NULL; + + SLIST_FOREACH_SAFE(item, pwd, usr_next, next) { + item->usr_next.sle_next = prev; + prev = item; + } + pwd->slh_first = prev; +} + + +/* + * cfgReadPasswd() - Read file and add new item at password root + * + * @f = File resource + * @pwd = Password root + * return: -1 error or 0 ok + */ +int +cfgReadPasswd(FILE *f, pwd_root_t * __restrict pwd) +{ + char line[BUFSIZ], *pos, *items[PWD_MAX_FIELDS]; + struct tagUser *u; + register int i; + + if (!f || !pwd) { + cfg_SetErr(EINVAL, "Invalid parameter(s)"); + return -1; + } + + while (!feof(f)) { + memset(line, 0, sizeof line); + fgets(line, sizeof line - 1, f); + if (!(pos = strpbrk(line, "\r\n"))) { + /* skip line, too long */ + continue; + } else { + *pos = 0; + io_TrimStr(line); + } + + /* *NEW USER* alloc new element */ + u = io_malloc(sizeof(struct tagUser)); + if (!u) { + cfg_SetErr(io_GetErrno(), "%s", io_GetError()); + return -1; + } else { + memset(u, 0, sizeof(struct tagUser)); + PWD_LOCK(pwd); + SLIST_INSERT_HEAD(pwd, u, usr_next); + PWD_UNLOCK(pwd); + } + + /* check for comment or empty line */ + if (!*line || *line == '#' || *line == ';') { + AIT_SET_STR(&u->usr_realm, line); + continue; + } + + /* count & parse elements */ + memset(items, 0, sizeof items); + for (i = 0, items[i] = pos = line; pos && i < (PWD_MAX_FIELDS - 2);) + if ((pos = strchr(pos, PWD_DELIM))) { + *pos++ = 0; + items[++i] = pos; + } + u->usr_fields = i; + AIT_SET_U32(&u->usr_uid, 0); + AIT_SET_U32(&u->usr_gid, 0); + + /* parse elements */ + for (i = 0; i < (u->usr_fields + 1); i++) { + switch (i) { + case 0: + AIT_SET_STR(&u->usr_name, items[i]); + break; + case 1: + AIT_SET_STR(&u->usr_pass, items[i]); + break; + case 2: + AIT_SET_U32(&u->usr_uid, strtol(items[i], NULL, 10)); + break; + case 3: + AIT_SET_U32(&u->usr_gid, strtol(items[i], NULL, 10)); + break; + case 4: + AIT_SET_STR(&u->usr_class, items[i]); + break; + case 5: + AIT_SET_U32(&u->usr_change, strtol(items[i], NULL, 10)); + break; + case 6: + AIT_SET_U32(&u->usr_expire, strtol(items[i], NULL, 10)); + break; + case 7: + AIT_SET_STR(&u->usr_realm, items[i]); + break; + case 8: + AIT_SET_STR(&u->usr_home, items[i]); + break; + case 9: + AIT_SET_STR(&u->usr_shell, items[i]); + break; + } + } + + /* add to tree */ + AIT_KEY(&u->usr_name) = crcFletcher16(AIT_GET_LIKE(&u->usr_name, u_short*), + io_align(AIT_LEN(&u->usr_name) - 1, 2) / 2); + + PWD_LOCK(pwd); + RB_INSERT(tagPWD, pwd, u); + PWD_UNLOCK(pwd); + } + + return 0; +} + +/* + * cfgWritePasswd() - Write passwords from memory + * + * @f = File handle + * @pwd = Password root + * return: -1 error or 0 ok + */ +int +cfgWritePasswd(FILE *f, pwd_root_t * __restrict pwd) +{ + struct tagUser *u; + char line[BUFSIZ]; + int len = 0; + register int i; + + if (!f || !pwd) { + cfg_SetErr(EINVAL, "Invalid parameter(s)"); + return -1; + } + + PWD_LOCK(pwd); + _invertQueue(pwd); + SLIST_FOREACH(u, pwd, usr_next) { + /* build line */ + memset(line, 0, sizeof line); + /* comment or other senseless line */ + if (AIT_ISEMPTY(&u->usr_name)) + strlcpy(line, AIT_GET_STRZ(&u->usr_realm), sizeof line); + else { + for (i = 0; i < u->usr_fields + 1; i++) { + switch (i) { + case 0: + len = strlcpy(line, AIT_GET_STR(&u->usr_name), sizeof line); + break; + case 1: + len += snprintf(line + len, sizeof line, "%c%s", PWD_DELIM, + AIT_GET_STRZ(&u->usr_pass)); + break; + case 2: + len += snprintf(line + len, sizeof line, "%c%u", PWD_DELIM, + AIT_GET_U32(&u->usr_uid)); + break; + case 3: + len += snprintf(line + len, sizeof line, "%c%u", PWD_DELIM, + AIT_GET_U32(&u->usr_gid)); + break; + case 4: + len += snprintf(line + len, sizeof line, "%c%s", PWD_DELIM, + AIT_GET_STRZ(&u->usr_class)); + break; + case 5: + len += snprintf(line + len, sizeof line, "%c%u", PWD_DELIM, + AIT_GET_U32(&u->usr_change)); + break; + case 6: + len += snprintf(line + len, sizeof line, "%c%u", PWD_DELIM, + AIT_GET_U32(&u->usr_expire)); + break; + case 7: + len += snprintf(line + len, sizeof line, "%c%s", PWD_DELIM, + AIT_GET_STRZ(&u->usr_realm)); + break; + case 8: + len += snprintf(line + len, sizeof line, "%c%s", PWD_DELIM, + AIT_GET_STRZ(&u->usr_home)); + break; + case 9: + len += snprintf(line + len, sizeof line, "%c%s", PWD_DELIM, + AIT_GET_STRZ(&u->usr_shell)); + break; + } + } + } + + /* write */ + if (!cfg_Write(f, "%s\n", line)) { + LOGERR; + _invertQueue(pwd); + PWD_UNLOCK(pwd); + return -1; + } + } + _invertQueue(pwd); + PWD_UNLOCK(pwd); + + return 0; +} + +/* + * cfgConcatPasswd() - Concat two password roots into one + * + * @pwd = Password root + * @add_pwd = Concated password root will be destroy after merge + * return: -1 error or 0 ok + */ +int +cfgConcatPasswd(pwd_root_t * __restrict pwd, pwd_root_t * __restrict add_pwd) +{ + struct tagUser *item; + + if (!pwd || !add_pwd) + return -1; + + PWD_LOCK(add_pwd); + PWD_LOCK(pwd); + + /* concat items at the end */ + for (item = SLIST_FIRST(pwd); SLIST_NEXT(item, usr_next); item = SLIST_NEXT(item, usr_next)); + SLIST_NEXT(item, usr_next) = SLIST_FIRST(add_pwd); + + /* concat red-black trees */ + SLIST_FOREACH(item, add_pwd, usr_next) + RB_INSERT(tagPWD, pwd, item); + + PWD_UNLOCK(pwd); + + add_pwd->slh_first = NULL; + add_pwd->rbh_root = NULL; + PWD_UNLOCK(add_pwd); + pthread_mutex_destroy(&add_pwd->pwd_mtx); + return 0; +} + +/* + * cfgAuthPasswd() - Authenticate user against passwords db + * + * @pwd = Password root + * @csName = Username + * @csPass = Password + * return: =NULL deny or !=NULL allow + */ +const struct tagUser * +cfgAuthPasswd(pwd_root_t * __restrict pwd, const char *csName, const char *csPass) +{ + const struct tagUser *u; + + if (!pwd || !csName) + return NULL; + + u = cfg_getPasswd(pwd, PWD_CRIT_NAME, csName); + if (u) { + if (!csPass) { + if (!AIT_ADDR(&u->usr_pass)) + return u; /* allow */ + } else { + if (AIT_ADDR(&u->usr_pass) && + !strcmp(AIT_GET_STR(&u->usr_pass), csPass)) + return u; /* allow */ + } + } + + return NULL; /* deny */ +}