1: /*************************************************************************
2: * (C) 2010 AITNET ltd - Sofia/Bulgaria - <misho@aitbg.com>
3: * by Michael Pounov <misho@openbsd-bg.org>
4: *
5: * $Author: misho $
6: * $Id: pwd.c,v 1.2 2012/09/19 15:22:32 misho Exp $
7: *
8: **************************************************************************
9: The ELWIX and AITNET software is distributed under the following
10: terms:
11:
12: All of the documentation and software included in the ELWIX and AITNET
13: Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>
14:
15: Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
16: by Michael Pounov <misho@elwix.org>. All rights reserved.
17:
18: Redistribution and use in source and binary forms, with or without
19: modification, are permitted provided that the following conditions
20: are met:
21: 1. Redistributions of source code must retain the above copyright
22: notice, this list of conditions and the following disclaimer.
23: 2. Redistributions in binary form must reproduce the above copyright
24: notice, this list of conditions and the following disclaimer in the
25: documentation and/or other materials provided with the distribution.
26: 3. All advertising materials mentioning features or use of this software
27: must display the following acknowledgement:
28: This product includes software developed by Michael Pounov <misho@elwix.org>
29: ELWIX - Embedded LightWeight unIX and its contributors.
30: 4. Neither the name of AITNET nor the names of its contributors
31: may be used to endorse or promote products derived from this software
32: without specific prior written permission.
33:
34: THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND
35: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37: ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
38: FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40: OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42: LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43: OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44: SUCH DAMAGE.
45: */
46: #include "global.h"
47: #include "aitpwd.h"
48:
49:
50: #pragma GCC visibility push(hidden)
51:
52: inline int
53: pwd_tree_cmp(struct tagUser *a, struct tagUser *b)
54: {
55: assert(a && b);
56:
57: return strcmp(AIT_GET_STR(&a->usr_name), AIT_GET_STR(&b->usr_name));
58: }
59:
60: RB_GENERATE(tagPWD, tagUser, usr_node, pwd_tree_cmp);
61:
62: #pragma GCC visibility pop
63:
64: static inline void
65: _invertQueue(pwd_root_t * __restrict pwd)
66: {
67: struct tagUser *item, *next, *prev = NULL;
68:
69: SLIST_FOREACH_SAFE(item, pwd, usr_next, next) {
70: item->usr_next.sle_next = prev;
71: prev = item;
72: }
73: pwd->slh_first = prev;
74: }
75:
76:
77: /*
78: * cfgReadPasswd() - Read file and add new item at password root
79: *
80: * @f = File resource
81: * @pwd = Password root
82: * return: -1 error or 0 ok
83: */
84: int
85: cfgReadPasswd(FILE *f, pwd_root_t * __restrict pwd)
86: {
87: char line[BUFSIZ], *pos, *items[PWD_MAX_FIELDS];
88: struct tagUser *u;
89: register int i;
90:
91: if (!f || !pwd) {
92: cfg_SetErr(EINVAL, "Invalid parameter(s)");
93: return -1;
94: }
95:
96: while (!feof(f)) {
97: memset(line, 0, sizeof line);
98: fgets(line, sizeof line - 1, f);
99: if (!(pos = strpbrk(line, "\r\n"))) {
100: /* skip line, too long */
101: continue;
102: } else {
103: *pos = 0;
104: io_TrimStr(line);
105: }
106:
107: /* *NEW USER* alloc new element */
108: u = io_malloc(sizeof(struct tagUser));
109: if (!u) {
110: cfg_SetErr(io_GetErrno(), "%s", io_GetError());
111: return -1;
112: } else {
113: memset(u, 0, sizeof(struct tagUser));
114: PWD_LOCK(pwd);
115: SLIST_INSERT_HEAD(pwd, u, usr_next);
116: PWD_UNLOCK(pwd);
117: }
118:
119: /* check for comment or empty line */
120: if (!*line || *line == '#' || *line == ';') {
121: AIT_SET_STR(&u->usr_realm, line);
122: continue;
123: }
124:
125: /* count & parse elements */
126: memset(items, 0, sizeof items);
127: for (i = 0, items[i] = pos = line; pos && i < (PWD_MAX_FIELDS - 2);)
128: if ((pos = strchr(pos, PWD_DELIM))) {
129: *pos++ = 0;
130: items[++i] = pos;
131: }
132: u->usr_fields = i;
133: AIT_SET_U32(&u->usr_uid, 0);
134: AIT_SET_U32(&u->usr_gid, 0);
135:
136: /* parse elements */
137: for (i = 0; i < (u->usr_fields + 1); i++) {
138: switch (i) {
139: case 0:
140: AIT_SET_STR(&u->usr_name, items[i]);
141: break;
142: case 1:
143: AIT_SET_STR(&u->usr_pass, items[i]);
144: break;
145: case 2:
146: AIT_SET_U32(&u->usr_uid, strtol(items[i], NULL, 10));
147: break;
148: case 3:
149: AIT_SET_U32(&u->usr_gid, strtol(items[i], NULL, 10));
150: break;
151: case 4:
152: AIT_SET_STR(&u->usr_class, items[i]);
153: break;
154: case 5:
155: AIT_SET_U32(&u->usr_change, strtol(items[i], NULL, 10));
156: break;
157: case 6:
158: AIT_SET_U32(&u->usr_expire, strtol(items[i], NULL, 10));
159: break;
160: case 7:
161: AIT_SET_STR(&u->usr_realm, items[i]);
162: break;
163: case 8:
164: AIT_SET_STR(&u->usr_home, items[i]);
165: break;
166: case 9:
167: AIT_SET_STR(&u->usr_shell, items[i]);
168: break;
169: }
170: }
171:
172: /* add to tree */
173: AIT_KEY(&u->usr_name) = crcFletcher16(AIT_GET_LIKE(&u->usr_name, u_short*),
174: io_align(AIT_LEN(&u->usr_name) - 1, 2) / 2);
175:
176: PWD_LOCK(pwd);
177: RB_INSERT(tagPWD, pwd, u);
178: PWD_UNLOCK(pwd);
179: }
180:
181: return 0;
182: }
183:
184: /*
185: * cfgWritePasswd() - Write passwords from memory
186: *
187: * @f = File handle
188: * @pwd = Password root
189: * return: -1 error or 0 ok
190: */
191: int
192: cfgWritePasswd(FILE *f, pwd_root_t * __restrict pwd)
193: {
194: struct tagUser *u;
195: char line[BUFSIZ];
196: int len = 0;
197: register int i;
198:
199: if (!f || !pwd) {
200: cfg_SetErr(EINVAL, "Invalid parameter(s)");
201: return -1;
202: }
203:
204: PWD_LOCK(pwd);
205: _invertQueue(pwd);
206: SLIST_FOREACH(u, pwd, usr_next) {
207: /* build line */
208: memset(line, 0, sizeof line);
209: /* comment or other senseless line */
210: if (AIT_ISEMPTY(&u->usr_name))
211: strlcpy(line, AIT_GET_STRZ(&u->usr_realm), sizeof line);
212: else {
213: for (i = 0; i < u->usr_fields + 1; i++) {
214: switch (i) {
215: case 0:
216: len = strlcpy(line, AIT_GET_STR(&u->usr_name), sizeof line);
217: break;
218: case 1:
219: len += snprintf(line + len, sizeof line, "%c%s", PWD_DELIM,
220: AIT_GET_STRZ(&u->usr_pass));
221: break;
222: case 2:
223: len += snprintf(line + len, sizeof line, "%c%u", PWD_DELIM,
224: AIT_GET_U32(&u->usr_uid));
225: break;
226: case 3:
227: len += snprintf(line + len, sizeof line, "%c%u", PWD_DELIM,
228: AIT_GET_U32(&u->usr_gid));
229: break;
230: case 4:
231: len += snprintf(line + len, sizeof line, "%c%s", PWD_DELIM,
232: AIT_GET_STRZ(&u->usr_class));
233: break;
234: case 5:
235: len += snprintf(line + len, sizeof line, "%c%u", PWD_DELIM,
236: AIT_GET_U32(&u->usr_change));
237: break;
238: case 6:
239: len += snprintf(line + len, sizeof line, "%c%u", PWD_DELIM,
240: AIT_GET_U32(&u->usr_expire));
241: break;
242: case 7:
243: len += snprintf(line + len, sizeof line, "%c%s", PWD_DELIM,
244: AIT_GET_STRZ(&u->usr_realm));
245: break;
246: case 8:
247: len += snprintf(line + len, sizeof line, "%c%s", PWD_DELIM,
248: AIT_GET_STRZ(&u->usr_home));
249: break;
250: case 9:
251: len += snprintf(line + len, sizeof line, "%c%s", PWD_DELIM,
252: AIT_GET_STRZ(&u->usr_shell));
253: break;
254: }
255: }
256: }
257:
258: /* write */
259: if (!cfg_Write(f, "%s\n", line)) {
260: LOGERR;
261: _invertQueue(pwd);
262: PWD_UNLOCK(pwd);
263: return -1;
264: }
265: }
266: _invertQueue(pwd);
267: PWD_UNLOCK(pwd);
268:
269: return 0;
270: }
271:
272: /*
273: * cfgConcatPasswd() - Concat two password roots into one
274: *
275: * @pwd = Password root
276: * @add_pwd = Concated password root will be destroy after merge
277: * return: -1 error or 0 ok
278: */
279: int
280: cfgConcatPasswd(pwd_root_t * __restrict pwd, pwd_root_t * __restrict add_pwd)
281: {
282: struct tagUser *item;
283:
284: if (!pwd || !add_pwd)
285: return -1;
286:
287: PWD_LOCK(add_pwd);
288: PWD_LOCK(pwd);
289:
290: /* concat items at the end */
291: for (item = SLIST_FIRST(pwd); SLIST_NEXT(item, usr_next); item = SLIST_NEXT(item, usr_next));
292: SLIST_NEXT(item, usr_next) = SLIST_FIRST(add_pwd);
293:
294: /* concat red-black trees */
295: SLIST_FOREACH(item, add_pwd, usr_next)
296: RB_INSERT(tagPWD, pwd, item);
297:
298: PWD_UNLOCK(pwd);
299:
300: add_pwd->slh_first = NULL;
301: add_pwd->rbh_root = NULL;
302: PWD_UNLOCK(add_pwd);
303: pthread_mutex_destroy(&add_pwd->pwd_mtx);
304: return 0;
305: }
306:
307: /*
308: * cfgAuthPasswd() - Authenticate user against passwords db
309: *
310: * @pwd = Password root
311: * @csName = Username
312: * @csPass = Password
313: * return: =NULL deny or !=NULL allow
314: */
315: const struct tagUser *
316: cfgAuthPasswd(pwd_root_t * __restrict pwd, const char *csName, const char *csPass)
317: {
318: const struct tagUser *u;
319:
320: if (!pwd || !csName)
321: return NULL;
322:
323: u = cfg_getPasswd(pwd, PWD_CRIT_NAME, csName);
324: if (u) {
325: if (!csPass) {
326: if (!AIT_ADDR(&u->usr_pass))
327: return u; /* allow */
328: } else {
329: if (AIT_ADDR(&u->usr_pass) &&
330: !strcmp(AIT_GET_STR(&u->usr_pass), csPass))
331: return u; /* allow */
332: }
333: }
334:
335: return NULL; /* deny */
336: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>