Commit | Line | Data |
---|---|---|
d9898ee8 | 1 | /* |
d50284c4 | 2 | ** Copyright 2000-2015 Double Precision, Inc. See COPYING for |
d9898ee8 | 3 | ** distribution information. |
4 | */ | |
5 | ||
6 | #include "auth.h" | |
b0322a85 | 7 | #include "courierauthstaticlist.h" |
d9898ee8 | 8 | #include "courierauthsasl.h" |
9 | #include "authwait.h" | |
10 | #include "courierauthdebug.h" | |
11 | #include <stdlib.h> | |
12 | #include <stdio.h> | |
13 | #include <string.h> | |
14 | #include <signal.h> | |
15 | #include <unistd.h> | |
16 | #include <errno.h> | |
17 | #include <sys/time.h> | |
18 | #include <sys/select.h> | |
19 | #include "numlib/numlib.h" | |
d50284c4 CE |
20 | #include <sys/stat.h> |
21 | #include <pwd.h> | |
22 | #include <sys/types.h> | |
23 | #include <dirent.h> | |
d9898ee8 | 24 | |
25 | extern int authdaemondo(const char *authreq, | |
26 | int (*func)(struct authinfo *, void *), void *arg); | |
27 | ||
28 | extern void auth_daemon_enumerate( void(*cb_func)(const char *name, | |
29 | uid_t uid, | |
30 | gid_t gid, | |
31 | const char *homedir, | |
32 | const char *maildir, | |
33 | const char *options, | |
34 | void *void_arg), | |
35 | void *void_arg); | |
36 | ||
37 | ||
38 | int auth_generic(const char *service, | |
39 | const char *authtype, | |
40 | char *authdata, | |
41 | int (*callback_func)(struct authinfo *, void *), | |
42 | void *callback_arg) | |
43 | { | |
44 | char tbuf[NUMBUFSIZE]; | |
45 | size_t l=strlen(service)+strlen(authtype)+strlen(authdata)+2; | |
46 | char *n=libmail_str_size_t(l, tbuf); | |
47 | char *buf=malloc(strlen(n)+l+20); | |
48 | int rc; | |
49 | ||
50 | courier_authdebug_login_init(); | |
51 | ||
52 | if (!buf) | |
53 | return 1; | |
54 | ||
55 | strcat(strcat(strcpy(buf, "AUTH "), n), "\n"); | |
56 | strcat(strcat(buf, service), "\n"); | |
57 | strcat(strcat(buf, authtype), "\n"); | |
58 | strcat(buf, authdata); | |
59 | ||
ac40fd9e | 60 | rc=strcmp(authtype, "EXTERNAL") == 0 |
61 | ? auth_getuserinfo(service, authdata, callback_func, | |
62 | callback_arg) | |
63 | : authdaemondo(buf, callback_func, callback_arg); | |
d9898ee8 | 64 | free(buf); |
65 | ||
66 | if (courier_authdebug_login_level) | |
67 | { | |
68 | struct timeval t; | |
69 | ||
70 | /* short delay to try and allow authdaemond's courierlogger | |
71 | to finish writing; otherwise items can appear out of order */ | |
72 | t.tv_sec = 0; | |
73 | t.tv_usec = 100000; | |
74 | select(0, 0, 0, 0, &t); | |
75 | } | |
76 | ||
77 | return rc; | |
78 | } | |
79 | ||
80 | int auth_callback_default(struct authinfo *ainfo) | |
81 | { | |
82 | if (ainfo->address == NULL) | |
83 | { | |
84 | fprintf(stderr, "WARN: No address!!\n"); | |
85 | return (-1); | |
86 | } | |
87 | ||
88 | if (ainfo->sysusername) | |
89 | libmail_changeusername(ainfo->sysusername, | |
90 | &ainfo->sysgroupid); | |
91 | else if (ainfo->sysuserid) | |
92 | libmail_changeuidgid(*ainfo->sysuserid, | |
93 | ainfo->sysgroupid); | |
94 | else | |
95 | { | |
96 | fprintf(stderr, "WARN: %s: No UID/GID!!\n", ainfo->address); | |
97 | return (-1); | |
98 | } | |
99 | ||
100 | if (!ainfo->homedir) | |
101 | { | |
102 | errno=EINVAL; | |
103 | fprintf(stderr, "WARN: %s: No homedir!!\n", ainfo->address); | |
104 | return (1); | |
105 | } | |
106 | ||
107 | if (chdir(ainfo->homedir)) | |
108 | { | |
109 | fprintf(stderr, "WARN: %s: chdir(%s) failed!!\n", | |
110 | ainfo->address, ainfo->homedir); | |
111 | perror("WARN: error"); | |
112 | return (1); | |
113 | } | |
114 | ||
115 | return 0; | |
116 | } | |
d50284c4 CE |
117 | |
118 | static void do_copy(const char *from, | |
119 | const char *to, | |
120 | struct stat *stat_buf, | |
121 | uid_t uid, | |
122 | gid_t gid) | |
123 | { | |
124 | FILE *fp=fopen(from, "r"); | |
125 | FILE *fp2; | |
126 | int c; | |
127 | ||
128 | if (!fp) | |
129 | { | |
130 | fprintf(stderr, "WARN: %s: %s!!\n", from, strerror(errno)); | |
131 | return; | |
132 | } | |
133 | ||
134 | fp2=fopen(to, "w"); | |
135 | ||
136 | if (!fp2) | |
137 | { | |
138 | fprintf(stderr, "WARN: %s: %s!!\n", to, strerror(errno)); | |
139 | fclose(fp); | |
140 | return; | |
141 | } | |
142 | ||
143 | while ((c=getc(fp)) != EOF) | |
144 | putc(c, fp2); | |
145 | fclose(fp); | |
146 | fclose(fp2); | |
147 | ||
148 | if (chmod(to, stat_buf->st_mode & ~S_IFMT) || | |
149 | chown(to, uid, gid) < 0) | |
150 | { | |
151 | fprintf(stderr, "WARN: %s: %s!!\n", to, strerror(errno)); | |
152 | } | |
153 | } | |
154 | ||
155 | static void do_symlink(const char *from, | |
156 | const char *to, | |
157 | uid_t uid, | |
158 | gid_t gid) | |
159 | { | |
160 | char buf[1024]; | |
161 | ssize_t l=readlink(from, buf, sizeof(buf)-1); | |
162 | ||
163 | if (l < 0) | |
164 | { | |
165 | fprintf(stderr, "WARN: %s: %s!!\n", from, strerror(errno)); | |
166 | return; | |
167 | } | |
168 | buf[l]=0; | |
169 | ||
170 | if (symlink(buf, to) < 0 || lchown(to, uid, gid) < 0) | |
171 | { | |
172 | fprintf(stderr, "WARN: %s: %s!!\n", from, strerror(errno)); | |
173 | return; | |
174 | } | |
175 | } | |
176 | ||
177 | static int do_mkhomedir(const char *skeldir, | |
178 | const char *homedir, | |
179 | uid_t uid, | |
180 | gid_t gid) | |
181 | { | |
182 | struct stat stat_buf; | |
183 | DIR *d; | |
184 | struct dirent *de; | |
185 | ||
186 | mkdir(homedir, 0); | |
187 | ||
188 | if (stat(skeldir, &stat_buf) < 0 || | |
189 | chmod(homedir, stat_buf.st_mode & ~S_IFMT) || | |
190 | chown(homedir, uid, gid) < 0) | |
191 | { | |
192 | fprintf(stderr, "WARN: %s: %s!!\n", skeldir, strerror(errno)); | |
193 | return 0; | |
194 | } | |
195 | ||
196 | if ((d=opendir(skeldir)) != NULL) | |
197 | { | |
198 | while ((de=readdir(d)) != NULL) | |
199 | { | |
200 | char *fskeldir, *fhomedir; | |
201 | ||
202 | if (strcmp(de->d_name, ".") == 0) | |
203 | continue; | |
204 | if (strcmp(de->d_name, "..") == 0) | |
205 | continue; | |
206 | ||
207 | fskeldir=malloc(strlen(skeldir)+2+strlen(de->d_name)); | |
208 | fhomedir=malloc(strlen(homedir)+2+strlen(de->d_name)); | |
209 | ||
210 | if (fskeldir && fhomedir) | |
211 | { | |
212 | strcat(strcat(strcpy(fskeldir, skeldir), "/"), | |
213 | de->d_name); | |
214 | strcat(strcat(strcpy(fhomedir, homedir), "/"), | |
215 | de->d_name); | |
216 | ||
217 | if (lstat(fskeldir, &stat_buf) == 0) | |
218 | { | |
219 | if (S_ISDIR(stat_buf.st_mode)) | |
220 | { | |
221 | do_mkhomedir(fskeldir, fhomedir, | |
222 | uid, gid); | |
223 | } | |
224 | else if (S_ISLNK(stat_buf.st_mode)) | |
225 | { | |
226 | do_symlink(fskeldir, fhomedir, | |
227 | uid, gid); | |
228 | } | |
229 | else if (S_ISREG(stat_buf.st_mode)) | |
230 | { | |
231 | do_copy(fskeldir, fhomedir, | |
232 | &stat_buf, | |
233 | uid, gid); | |
234 | } | |
235 | } | |
236 | } | |
237 | ||
238 | if (fskeldir) | |
239 | free(fskeldir); | |
240 | if (fhomedir) | |
241 | free(fhomedir); | |
242 | } | |
243 | closedir(d); | |
244 | } | |
245 | return 0; | |
246 | } | |
247 | ||
248 | static int mkhomedir(struct authinfo *ainfo, | |
249 | const char *skel) | |
250 | { | |
251 | if (ainfo->sysusername) | |
252 | { | |
253 | struct passwd *pw=getpwnam(ainfo->sysusername); | |
254 | return do_mkhomedir(skel, ainfo->homedir, | |
255 | pw->pw_uid, | |
256 | pw->pw_gid); | |
257 | } | |
258 | ||
259 | return do_mkhomedir(skel, ainfo->homedir, | |
260 | *ainfo->sysuserid, ainfo->sysgroupid); | |
261 | } | |
262 | ||
263 | int auth_mkhomedir(struct authinfo *ainfo) | |
264 | { | |
265 | struct stat stat_buf; | |
266 | ||
267 | const char *p=getenv("AUTH_MKHOMEDIR_SKEL"); | |
268 | ||
269 | if (p && *p && ainfo->address && | |
270 | (ainfo->sysusername || ainfo->sysuserid) && | |
271 | ainfo->homedir && stat(ainfo->homedir, &stat_buf) < 0 && | |
272 | errno == ENOENT && stat(p, &stat_buf) == 0) | |
273 | { | |
274 | int rc; | |
275 | mode_t old_umask=umask(0777); | |
276 | ||
277 | rc=mkhomedir(ainfo, p); | |
278 | ||
279 | umask(old_umask); | |
280 | ||
281 | if (rc) | |
282 | return rc; | |
283 | } | |
284 | return 0; | |
285 | } | |
286 | ||
287 | int auth_callback_default_autocreate(struct authinfo *ainfo) | |
288 | { | |
289 | int rc=auth_mkhomedir(ainfo); | |
290 | ||
291 | if (rc) | |
292 | return rc; | |
293 | ||
294 | return auth_callback_default(ainfo); | |
295 | } |