1 /* qmail-users.c - qmail users/cdb lookup routines
2 * Copyright (C) 2010 Bruce Guenter <bruce@untroubled.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18 #include <bglibs/sysdeps.h>
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <pwd.h>
22 #include <string.h>
23 #include <sys/stat.h>
24 #include <unistd.h>
25
26 #include <bglibs/cdb.h>
27 #include <bglibs/cdb.h>
28 #include <bglibs/iobuf.h>
29 #include <bglibs/str.h>
30
31 #include "qmail.h"
32
33 static str users_path;
34 static int users_fd = -1;
35 static struct cdb users_cdb;
36 static struct stat users_stat;
37
qmail_users_reinit(void)38 int qmail_users_reinit(void)
39 {
40 struct stat s;
41 /* If we can see the users CDB file... */
42 if (stat(users_path.s, &s) != -1) {
43 /* If it was either not open or has changed since the last open... */
44 if (users_fd == -1 ||
45 s.st_ino != users_stat.st_ino ||
46 s.st_mtime != users_stat.st_mtime ||
47 s.st_size != users_stat.st_size) {
48 /* If it was previously open, close it */
49 if (users_fd != -1) {
50 close(users_fd);
51 cdb_free(&users_cdb);
52 }
53 /* And re-open it */
54 if ((users_fd = open(users_path.s, O_RDONLY)) != -1) {
55 fstat(users_fd, &users_stat);
56 cdb_init(&users_cdb, users_fd);
57 }
58 }
59 }
60 else if (users_fd != -1) {
61 close(users_fd);
62 cdb_free(&users_cdb);
63 users_fd = -1;
64 }
65 return 0;
66 }
67
qmail_users_init(void)68 int qmail_users_init(void)
69 {
70 if (!str_copy2s(&users_path, qmail_root, "/users/cdb"))
71 return -1;
72 return qmail_users_reinit();
73 }
74
lookup_userscdb(struct qmail_user * u,str * name,char dash)75 static int lookup_userscdb(struct qmail_user* u,
76 str* name, char dash)
77 {
78 char* ptr;
79 const char* end;
80 const char* user;
81 const char* home;
82 int i;
83
84 if (!str_spliceb(name, 0, 0, "!", 1)
85 || (name->len > 1 && !str_catc(name, dash))) {
86 errno = ENOMEM;
87 return -1;
88 }
89
90 if ((i = cdb_get(&users_cdb, name, name)) <= 0)
91 return i;
92
93 /* name now contains:
94 * user NUL uid NUL gid NUL home NUL dash NUL ext
95 */
96 errno = EDOM;
97 ptr = name->s;
98 end = name->s + name->len;
99 user = ptr;
100 if ((ptr += strlen(ptr) + 1) >= end) return -1;
101 u->uid = strtoul(ptr, &ptr, 10);
102 if (*ptr++ != 0 || ptr >= end) return -1;
103 u->gid = strtoul(ptr, &ptr, 10);
104 if (*ptr++ != 0 || ptr >= end) return -1;
105 home = ptr;
106 if ((ptr += strlen(ptr) + 1) >= end) return -1;
107 if ((u->dash = *ptr) != 0) ++ptr;
108 if (*ptr++ != 0 || ptr > end) return -1;
109
110 if (!str_copys(&u->user, user)
111 || !str_copys(&u->homedir, home)
112 || !str_copyb(&u->ext, ptr, end-ptr)) {
113 errno = ENOMEM;
114 return -1;
115 }
116
117 return 1;
118 }
119
lookup_passwd(struct qmail_user * u,const str * namestr,char dash)120 static int lookup_passwd(struct qmail_user* u, const str* namestr, char dash)
121 {
122 const struct passwd* pw;
123 const char* name;
124
125 if (*(name = namestr->s) == 0)
126 name = "alias";
127 if ((pw = getpwnam(name)) == 0)
128 return (errno == ETXTBSY) ? -1 : 0;
129
130 if (!str_copys(&u->user, pw->pw_name)
131 || !str_copys(&u->homedir, pw->pw_dir)
132 || !str_copys(&u->ext, "")) {
133 errno = ENOMEM;
134 return -1;
135 }
136 u->uid = pw->pw_uid;
137 u->gid = pw->pw_gid;
138 u->dash = dash;
139 return 1;
140 }
141
qmail_users_lookup(struct qmail_user * u,const char * name,char dash)142 int qmail_users_lookup(struct qmail_user* u, const char* name, char dash)
143 {
144 static str lname;
145 if (!str_copys(&lname, name)){
146 errno = ENOMEM;
147 return -1;
148 }
149 str_lower(&lname);
150 if (users_fd != -1) {
151 switch (lookup_userscdb(u, &lname, dash)) {
152 case -1: return -1;
153 case 0: break;
154 default: return 1;
155 }
156 if (!str_copys(&lname, name)){
157 errno = ENOMEM;
158 return -1;
159 }
160 }
161 return lookup_passwd(u, &lname, dash);
162 }
163
qmail_users_lookup_split(struct qmail_user * u,const char * name,str * local,str * ext)164 int qmail_users_lookup_split(struct qmail_user* u, const char* name,
165 str* local, str* ext)
166 {
167 static str account;
168 int i;
169
170 /* Check if the name is a base UNIX user. */
171 if (!str_copys(local, name)) return -1;
172 if (!str_copys(ext, "")) return -1;
173 switch (qmail_users_lookup(u, name, 0)) {
174 case -1: return -1;
175 case 0: break;
176 default: return 1;
177 }
178
179 /* Now, look for increasingly shorter base-ext pairs */
180 if (!str_copy(&account, local)) return -1;
181 i = account.len;
182 while (i > 0 && (i = str_findprev(&account, '-', i-1)) != -1) {
183 if (!str_copyb(local, account.s, i)) return -1;
184 if (!str_copyb(ext, account.s+i+1, account.len-i-1)) return -1;
185 switch (qmail_users_lookup(u, local->s, '-')) {
186 case -1: return -1;
187 case 0: continue;
188 default: return 1;
189 }
190 }
191
192 switch (qmail_users_lookup(u, "", '-')) {
193 case -1: return -1;
194 case 0: return 0;
195 }
196 str_copyb(local, "", 0);
197 if (!str_copy(ext, &account)) return -1;
198 return 1;
199 }
200