rebuild for hcoop
[hcoop/debian/courier-authlib.git] / authdaemon.c
1 /*
2 ** Copyright 2000-2015 Double Precision, Inc. See COPYING for
3 ** distribution information.
4 */
5
6 #include "auth.h"
7 #include "courierauthstaticlist.h"
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"
20 #include <sys/stat.h>
21 #include <pwd.h>
22 #include <sys/types.h>
23 #include <dirent.h>
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
60 rc=strcmp(authtype, "EXTERNAL") == 0
61 ? auth_getuserinfo(service, authdata, callback_func,
62 callback_arg)
63 : authdaemondo(buf, callback_func, callback_arg);
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 }
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 }