Move hcoop changes to quilt patch
[hcoop/debian/courier-authlib.git] / authdaemon.c
CommitLineData
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
25extern int authdaemondo(const char *authreq,
26 int (*func)(struct authinfo *, void *), void *arg);
27
28extern 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
38int 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
80int 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
118static 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
155static 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
177static 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
248static 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
263int 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
287int 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}