rev |
line source |
yuuji@0
|
1 /* ========================================================================
|
yuuji@0
|
2 * Copyright 1988-2008 University of Washington
|
yuuji@0
|
3 *
|
yuuji@0
|
4 * Licensed under the Apache License, Version 2.0 (the "License");
|
yuuji@0
|
5 * you may not use this file except in compliance with the License.
|
yuuji@0
|
6 * You may obtain a copy of the License at
|
yuuji@0
|
7 *
|
yuuji@0
|
8 * http://www.apache.org/licenses/LICENSE-2.0
|
yuuji@0
|
9 *
|
yuuji@0
|
10 *
|
yuuji@0
|
11 * ========================================================================
|
yuuji@0
|
12 */
|
yuuji@0
|
13
|
yuuji@0
|
14 /*
|
yuuji@0
|
15 * Program: Amiga environment routines
|
yuuji@0
|
16 *
|
yuuji@0
|
17 * Author: Mark Crispin
|
yuuji@0
|
18 * UW Technology
|
yuuji@0
|
19 * Seattle, WA 98195
|
yuuji@0
|
20 * Internet: MRC@Washington.EDU
|
yuuji@0
|
21 *
|
yuuji@0
|
22 * Date: 1 August 1988
|
yuuji@0
|
23 * Last Edited: 15 May 2008
|
yuuji@0
|
24 */
|
yuuji@0
|
25
|
yuuji@0
|
26 #include <grp.h>
|
yuuji@0
|
27 #include <signal.h>
|
yuuji@0
|
28 #include <sys/wait.h>
|
yuuji@0
|
29
|
yuuji@0
|
30 /* c-client environment parameters */
|
yuuji@0
|
31
|
yuuji@0
|
32 static char *myUserName = NIL; /* user name */
|
yuuji@0
|
33 static char *myHomeDir = NIL; /* home directory name */
|
yuuji@0
|
34 static char *myMailboxDir = NIL;/* mailbox directory name */
|
yuuji@0
|
35 static char *myLocalHost = NIL; /* local host name */
|
yuuji@0
|
36 static char *myNewsrc = NIL; /* newsrc file name */
|
yuuji@0
|
37 static char *mailsubdir = NIL; /* mail subdirectory name */
|
yuuji@0
|
38 static char *sysInbox = NIL; /* system inbox name */
|
yuuji@0
|
39 static char *newsActive = NIL; /* news active file */
|
yuuji@0
|
40 static char *newsSpool = NIL; /* news spool */
|
yuuji@0
|
41 /* anonymous home directory */
|
yuuji@0
|
42 static char *anonymousHome = NIL;
|
yuuji@0
|
43 static char *ftpHome = NIL; /* ftp export home directory */
|
yuuji@0
|
44 static char *publicHome = NIL; /* public home directory */
|
yuuji@0
|
45 static char *sharedHome = NIL; /* shared home directory */
|
yuuji@0
|
46 static short anonymous = NIL; /* is anonymous */
|
yuuji@0
|
47 static short restrictBox = NIL; /* is a restricted box */
|
yuuji@0
|
48 static short has_no_life = NIL; /* is a cretin with no life */
|
yuuji@0
|
49 /* block environment init */
|
yuuji@0
|
50 static short block_env_init = NIL;
|
yuuji@0
|
51 static short hideDotFiles = NIL;/* hide files whose names start with . */
|
yuuji@0
|
52 /* advertise filesystem root */
|
yuuji@0
|
53 static short advertisetheworld = NIL;
|
yuuji@0
|
54 /* disable automatic shared namespaces */
|
yuuji@0
|
55 static short noautomaticsharedns = NIL;
|
yuuji@0
|
56 static short no822tztext = NIL; /* disable RFC [2]822 timezone text */
|
yuuji@0
|
57 static short netfsstatbug = NIL;/* compensate for broken stat() on network
|
yuuji@0
|
58 * filesystems (AFS and old NFS). Don't do
|
yuuji@0
|
59 * this unless you really have to!
|
yuuji@0
|
60 */
|
yuuji@0
|
61 /* 1 = disable plaintext, 2 = if not SSL */
|
yuuji@0
|
62 static long disablePlaintext = NIL;
|
yuuji@0
|
63 static long list_max_level = 20;/* maximum level of list recursion */
|
yuuji@0
|
64 /* default file protection */
|
yuuji@0
|
65 static long mbx_protection = 0600;
|
yuuji@0
|
66 /* default directory protection */
|
yuuji@0
|
67 static long dir_protection = 0700;
|
yuuji@0
|
68 /* default lock file protection */
|
yuuji@0
|
69 static long lock_protection = MANDATORYLOCKPROT;
|
yuuji@0
|
70 /* default ftp file protection */
|
yuuji@0
|
71 static long ftp_protection = 0644;
|
yuuji@0
|
72 static long ftp_dir_protection = 0755;
|
yuuji@0
|
73 /* default public file protection */
|
yuuji@0
|
74 static long public_protection = 0666;
|
yuuji@0
|
75 static long public_dir_protection = 0777;
|
yuuji@0
|
76 /* default shared file protection */
|
yuuji@0
|
77 static long shared_protection = 0660;
|
yuuji@0
|
78 static long shared_dir_protection = 0770;
|
yuuji@0
|
79 static long locktimeout = 5; /* default lock timeout */
|
yuuji@0
|
80 /* default prototypes */
|
yuuji@0
|
81 static MAILSTREAM *createProto = NIL;
|
yuuji@0
|
82 static MAILSTREAM *appendProto = NIL;
|
yuuji@0
|
83 /* default user flags */
|
yuuji@0
|
84 static char *userFlags[NUSERFLAGS] = {NIL};
|
yuuji@0
|
85 static NAMESPACE *nslist[3]; /* namespace list */
|
yuuji@0
|
86 static int logtry = 3; /* number of server login tries */
|
yuuji@0
|
87 /* block notification */
|
yuuji@0
|
88 static blocknotify_t mailblocknotify = mm_blocknotify;
|
yuuji@0
|
89
|
yuuji@0
|
90 /* Amiga namespaces */
|
yuuji@0
|
91
|
yuuji@0
|
92 /* personal mh namespace */
|
yuuji@0
|
93 static NAMESPACE nsmhf = {"#mh/",'/',NIL,NIL};
|
yuuji@0
|
94 static NAMESPACE nsmh = {"#mhinbox",NIL,NIL,&nsmhf};
|
yuuji@0
|
95 /* home namespace */
|
yuuji@0
|
96 static NAMESPACE nshome = {"",'/',NIL,&nsmh};
|
yuuji@0
|
97 /* Amiga other user namespace */
|
yuuji@0
|
98 static NAMESPACE nsamigaother = {"~",'/',NIL,NIL};
|
yuuji@0
|
99 /* public (anonymous OK) namespace */
|
yuuji@0
|
100 static NAMESPACE nspublic = {"#public/",'/',NIL,NIL};
|
yuuji@0
|
101 /* netnews namespace */
|
yuuji@0
|
102 static NAMESPACE nsnews = {"#news.",'.',NIL,&nspublic};
|
yuuji@0
|
103 /* FTP export namespace */
|
yuuji@0
|
104 static NAMESPACE nsftp = {"#ftp/",'/',NIL,&nsnews};
|
yuuji@0
|
105 /* shared (no anonymous) namespace */
|
yuuji@0
|
106 static NAMESPACE nsshared = {"#shared/",'/',NIL,&nsftp};
|
yuuji@0
|
107 /* world namespace */
|
yuuji@0
|
108 static NAMESPACE nsworld = {"/",'/',NIL,&nsshared};
|
yuuji@0
|
109
|
yuuji@0
|
110 #include "write.c" /* include safe writing routines */
|
yuuji@0
|
111 #include "pmatch.c" /* include wildcard pattern matcher */
|
yuuji@0
|
112
|
yuuji@0
|
113 /* Get all authenticators */
|
yuuji@0
|
114
|
yuuji@0
|
115 #include "auths.c"
|
yuuji@0
|
116
|
yuuji@0
|
117 /* Environment manipulate parameters
|
yuuji@0
|
118 * Accepts: function code
|
yuuji@0
|
119 * function-dependent value
|
yuuji@0
|
120 * Returns: function-dependent return value
|
yuuji@0
|
121 */
|
yuuji@0
|
122
|
yuuji@0
|
123 void *env_parameters (long function,void *value)
|
yuuji@0
|
124 {
|
yuuji@0
|
125 void *ret = NIL;
|
yuuji@0
|
126 switch ((int) function) {
|
yuuji@0
|
127 case GET_NAMESPACE:
|
yuuji@0
|
128 ret = (void *) nslist;
|
yuuji@0
|
129 break;
|
yuuji@0
|
130 case SET_USERNAME:
|
yuuji@0
|
131 if (myUserName) fs_give ((void **) &myUserName);
|
yuuji@0
|
132 myUserName = cpystr ((char *) value);
|
yuuji@0
|
133 case GET_USERNAME:
|
yuuji@0
|
134 ret = (void *) myUserName;
|
yuuji@0
|
135 break;
|
yuuji@0
|
136 case SET_HOMEDIR:
|
yuuji@0
|
137 if (myHomeDir) fs_give ((void **) &myHomeDir);
|
yuuji@0
|
138 myHomeDir = cpystr ((char *) value);
|
yuuji@0
|
139 case GET_HOMEDIR:
|
yuuji@0
|
140 ret = (void *) myHomeDir;
|
yuuji@0
|
141 break;
|
yuuji@0
|
142 case SET_LOCALHOST:
|
yuuji@0
|
143 if (myLocalHost) fs_give ((void **) &myLocalHost);
|
yuuji@0
|
144 myLocalHost = cpystr ((char *) value);
|
yuuji@0
|
145 case GET_LOCALHOST:
|
yuuji@0
|
146 ret = (void *) myLocalHost;
|
yuuji@0
|
147 break;
|
yuuji@0
|
148 case SET_NEWSRC:
|
yuuji@0
|
149 if (myNewsrc) fs_give ((void **) &myNewsrc);
|
yuuji@0
|
150 myNewsrc = cpystr ((char *) value);
|
yuuji@0
|
151 case GET_NEWSRC:
|
yuuji@0
|
152 ret = (void *) myNewsrc;
|
yuuji@0
|
153 break;
|
yuuji@0
|
154 case SET_NEWSACTIVE:
|
yuuji@0
|
155 if (newsActive) fs_give ((void **) &newsActive);
|
yuuji@0
|
156 newsActive = cpystr ((char *) value);
|
yuuji@0
|
157 case GET_NEWSACTIVE:
|
yuuji@0
|
158 ret = (void *) newsActive;
|
yuuji@0
|
159 break;
|
yuuji@0
|
160 case SET_NEWSSPOOL:
|
yuuji@0
|
161 if (newsSpool) fs_give ((void **) &newsSpool);
|
yuuji@0
|
162 newsSpool = cpystr ((char *) value);
|
yuuji@0
|
163 case GET_NEWSSPOOL:
|
yuuji@0
|
164 ret = (void *) newsSpool;
|
yuuji@0
|
165 break;
|
yuuji@0
|
166
|
yuuji@0
|
167 case SET_ANONYMOUSHOME:
|
yuuji@0
|
168 if (anonymousHome) fs_give ((void **) &anonymousHome);
|
yuuji@0
|
169 anonymousHome = cpystr ((char *) value);
|
yuuji@0
|
170 case GET_ANONYMOUSHOME:
|
yuuji@0
|
171 if (!anonymousHome) anonymousHome = cpystr (ANONYMOUSHOME);
|
yuuji@0
|
172 ret = (void *) anonymousHome;
|
yuuji@0
|
173 break;
|
yuuji@0
|
174 case SET_FTPHOME:
|
yuuji@0
|
175 if (ftpHome) fs_give ((void **) &ftpHome);
|
yuuji@0
|
176 ftpHome = cpystr ((char *) value);
|
yuuji@0
|
177 case GET_FTPHOME:
|
yuuji@0
|
178 ret = (void *) ftpHome;
|
yuuji@0
|
179 break;
|
yuuji@0
|
180 case SET_PUBLICHOME:
|
yuuji@0
|
181 if (publicHome) fs_give ((void **) &publicHome);
|
yuuji@0
|
182 publicHome = cpystr ((char *) value);
|
yuuji@0
|
183 case GET_PUBLICHOME:
|
yuuji@0
|
184 ret = (void *) publicHome;
|
yuuji@0
|
185 break;
|
yuuji@0
|
186 case SET_SHAREDHOME:
|
yuuji@0
|
187 if (sharedHome) fs_give ((void **) &sharedHome);
|
yuuji@0
|
188 sharedHome = cpystr ((char *) value);
|
yuuji@0
|
189 case GET_SHAREDHOME:
|
yuuji@0
|
190 ret = (void *) sharedHome;
|
yuuji@0
|
191 break;
|
yuuji@0
|
192 case SET_SYSINBOX:
|
yuuji@0
|
193 if (sysInbox) fs_give ((void **) &sysInbox);
|
yuuji@0
|
194 sysInbox = cpystr ((char *) value);
|
yuuji@0
|
195 case GET_SYSINBOX:
|
yuuji@0
|
196 ret = (void *) sysInbox;
|
yuuji@0
|
197 break;
|
yuuji@0
|
198 case SET_LISTMAXLEVEL:
|
yuuji@0
|
199 list_max_level = (long) value;
|
yuuji@0
|
200 case GET_LISTMAXLEVEL:
|
yuuji@0
|
201 ret = (void *) list_max_level;
|
yuuji@0
|
202 break;
|
yuuji@0
|
203
|
yuuji@0
|
204 case SET_MBXPROTECTION:
|
yuuji@0
|
205 mbx_protection = (long) value;
|
yuuji@0
|
206 case GET_MBXPROTECTION:
|
yuuji@0
|
207 ret = (void *) mbx_protection;
|
yuuji@0
|
208 break;
|
yuuji@0
|
209 case SET_DIRPROTECTION:
|
yuuji@0
|
210 dir_protection = (long) value;
|
yuuji@0
|
211 case GET_DIRPROTECTION:
|
yuuji@0
|
212 ret = (void *) dir_protection;
|
yuuji@0
|
213 break;
|
yuuji@0
|
214 case SET_LOCKPROTECTION:
|
yuuji@0
|
215 lock_protection = (long) value;
|
yuuji@0
|
216 case GET_LOCKPROTECTION:
|
yuuji@0
|
217 ret = (void *) lock_protection;
|
yuuji@0
|
218 break;
|
yuuji@0
|
219 case SET_FTPPROTECTION:
|
yuuji@0
|
220 ftp_protection = (long) value;
|
yuuji@0
|
221 case GET_FTPPROTECTION:
|
yuuji@0
|
222 ret = (void *) ftp_protection;
|
yuuji@0
|
223 break;
|
yuuji@0
|
224 case SET_PUBLICPROTECTION:
|
yuuji@0
|
225 public_protection = (long) value;
|
yuuji@0
|
226 case GET_PUBLICPROTECTION:
|
yuuji@0
|
227 ret = (void *) public_protection;
|
yuuji@0
|
228 break;
|
yuuji@0
|
229 case SET_SHAREDPROTECTION:
|
yuuji@0
|
230 shared_protection = (long) value;
|
yuuji@0
|
231 case GET_SHAREDPROTECTION:
|
yuuji@0
|
232 ret = (void *) shared_protection;
|
yuuji@0
|
233 break;
|
yuuji@0
|
234 case SET_FTPDIRPROTECTION:
|
yuuji@0
|
235 ftp_dir_protection = (long) value;
|
yuuji@0
|
236 case GET_FTPDIRPROTECTION:
|
yuuji@0
|
237 ret = (void *) ftp_dir_protection;
|
yuuji@0
|
238 break;
|
yuuji@0
|
239 case SET_PUBLICDIRPROTECTION:
|
yuuji@0
|
240 public_dir_protection = (long) value;
|
yuuji@0
|
241 case GET_PUBLICDIRPROTECTION:
|
yuuji@0
|
242 ret = (void *) public_dir_protection;
|
yuuji@0
|
243 break;
|
yuuji@0
|
244 case SET_SHAREDDIRPROTECTION:
|
yuuji@0
|
245 shared_dir_protection = (long) value;
|
yuuji@0
|
246 case GET_SHAREDDIRPROTECTION:
|
yuuji@0
|
247 ret = (void *) shared_dir_protection;
|
yuuji@0
|
248 break;
|
yuuji@0
|
249
|
yuuji@0
|
250 case SET_LOCKTIMEOUT:
|
yuuji@0
|
251 locktimeout = (long) value;
|
yuuji@0
|
252 case GET_LOCKTIMEOUT:
|
yuuji@0
|
253 ret = (void *) locktimeout;
|
yuuji@0
|
254 break;
|
yuuji@0
|
255 case SET_HIDEDOTFILES:
|
yuuji@0
|
256 hideDotFiles = value ? T : NIL;
|
yuuji@0
|
257 case GET_HIDEDOTFILES:
|
yuuji@0
|
258 ret = (void *) (hideDotFiles ? VOIDT : NIL);
|
yuuji@0
|
259 break;
|
yuuji@0
|
260 case SET_DISABLEPLAINTEXT:
|
yuuji@0
|
261 disablePlaintext = (long) value;
|
yuuji@0
|
262 case GET_DISABLEPLAINTEXT:
|
yuuji@0
|
263 ret = (void *) disablePlaintext;
|
yuuji@0
|
264 break;
|
yuuji@0
|
265 case SET_ADVERTISETHEWORLD:
|
yuuji@0
|
266 advertisetheworld = value ? T : NIL;
|
yuuji@0
|
267 case GET_ADVERTISETHEWORLD:
|
yuuji@0
|
268 ret = (void *) (advertisetheworld ? VOIDT : NIL);
|
yuuji@0
|
269 break;
|
yuuji@0
|
270 case SET_DISABLEAUTOSHAREDNS:
|
yuuji@0
|
271 noautomaticsharedns = value ? T : NIL;
|
yuuji@0
|
272 case GET_DISABLEAUTOSHAREDNS:
|
yuuji@0
|
273 ret = (void *) (noautomaticsharedns ? VOIDT : NIL);
|
yuuji@0
|
274 break;
|
yuuji@0
|
275 case SET_DISABLE822TZTEXT:
|
yuuji@0
|
276 no822tztext = value ? T : NIL;
|
yuuji@0
|
277 case GET_DISABLE822TZTEXT:
|
yuuji@0
|
278 ret = (void *) (no822tztext ? VOIDT : NIL);
|
yuuji@0
|
279 break;
|
yuuji@0
|
280 case SET_USERHASNOLIFE:
|
yuuji@0
|
281 has_no_life = value ? T : NIL;
|
yuuji@0
|
282 case GET_USERHASNOLIFE:
|
yuuji@0
|
283 ret = (void *) (has_no_life ? VOIDT : NIL);
|
yuuji@0
|
284 break;
|
yuuji@0
|
285 case SET_NETFSSTATBUG:
|
yuuji@0
|
286 netfsstatbug = value ? T : NIL;
|
yuuji@0
|
287 case GET_NETFSSTATBUG:
|
yuuji@0
|
288 ret = (void *) (netfsstatbug ? VOIDT : NIL);
|
yuuji@0
|
289 break;
|
yuuji@0
|
290 case SET_BLOCKENVINIT:
|
yuuji@0
|
291 block_env_init = value ? T : NIL;
|
yuuji@0
|
292 case GET_BLOCKENVINIT:
|
yuuji@0
|
293 ret = (void *) (block_env_init ? VOIDT : NIL);
|
yuuji@0
|
294 break;
|
yuuji@0
|
295 case SET_BLOCKNOTIFY:
|
yuuji@0
|
296 mailblocknotify = (blocknotify_t) value;
|
yuuji@0
|
297 case GET_BLOCKNOTIFY:
|
yuuji@0
|
298 ret = (void *) mailblocknotify;
|
yuuji@0
|
299 break;
|
yuuji@0
|
300 }
|
yuuji@0
|
301 return ret;
|
yuuji@0
|
302 }
|
yuuji@0
|
303
|
yuuji@0
|
304 /* Write current time
|
yuuji@0
|
305 * Accepts: destination string
|
yuuji@0
|
306 * optional format of day-of-week prefix
|
yuuji@0
|
307 * format of date and time
|
yuuji@0
|
308 * flag whether to append symbolic timezone
|
yuuji@0
|
309 */
|
yuuji@0
|
310
|
yuuji@0
|
311 static void do_date (char *date,char *prefix,char *fmt,int suffix)
|
yuuji@0
|
312 {
|
yuuji@0
|
313 time_t tn = time (0);
|
yuuji@0
|
314 struct tm *t = gmtime (&tn);
|
yuuji@0
|
315 int zone = t->tm_hour * 60 + t->tm_min;
|
yuuji@0
|
316 int julian = t->tm_yday;
|
yuuji@0
|
317 t = localtime (&tn); /* get local time now */
|
yuuji@0
|
318 /* minus UTC minutes since midnight */
|
yuuji@0
|
319 zone = t->tm_hour * 60 + t->tm_min - zone;
|
yuuji@0
|
320 /* julian can be one of:
|
yuuji@0
|
321 * 36x local time is December 31, UTC is January 1, offset -24 hours
|
yuuji@0
|
322 * 1 local time is 1 day ahead of UTC, offset +24 hours
|
yuuji@0
|
323 * 0 local time is same day as UTC, no offset
|
yuuji@0
|
324 * -1 local time is 1 day behind UTC, offset -24 hours
|
yuuji@0
|
325 * -36x local time is January 1, UTC is December 31, offset +24 hours
|
yuuji@0
|
326 */
|
yuuji@0
|
327 if (julian = t->tm_yday -julian)
|
yuuji@0
|
328 zone += ((julian < 0) == (abs (julian) == 1)) ? -24*60 : 24*60;
|
yuuji@0
|
329 if (prefix) { /* want day of week? */
|
yuuji@0
|
330 sprintf (date,prefix,days[t->tm_wday]);
|
yuuji@0
|
331 date += strlen (date); /* make next sprintf append */
|
yuuji@0
|
332 }
|
yuuji@0
|
333 /* output the date */
|
yuuji@0
|
334 sprintf (date,fmt,t->tm_mday,months[t->tm_mon],t->tm_year+1900,
|
yuuji@0
|
335 t->tm_hour,t->tm_min,t->tm_sec,zone/60,abs (zone) % 60);
|
yuuji@0
|
336 /* append timezone suffix if desired */
|
yuuji@0
|
337 if (suffix) rfc822_timezone (date,(void *) t);
|
yuuji@0
|
338 }
|
yuuji@0
|
339
|
yuuji@0
|
340 /* Write current time in RFC 822 format
|
yuuji@0
|
341 * Accepts: destination string
|
yuuji@0
|
342 */
|
yuuji@0
|
343
|
yuuji@0
|
344 void rfc822_date (char *date)
|
yuuji@0
|
345 {
|
yuuji@0
|
346 do_date (date,"%s, ","%d %s %d %02d:%02d:%02d %+03d%02d",
|
yuuji@0
|
347 no822tztext ? NIL : T);
|
yuuji@0
|
348 }
|
yuuji@0
|
349
|
yuuji@0
|
350
|
yuuji@0
|
351 /* Write current time in fixed-width RFC 822 format
|
yuuji@0
|
352 * Accepts: destination string
|
yuuji@0
|
353 */
|
yuuji@0
|
354
|
yuuji@0
|
355 void rfc822_fixed_date (char *date)
|
yuuji@0
|
356 {
|
yuuji@0
|
357 do_date (date,NIL,"%02d %s %4d %02d:%02d:%02d %+03d%02d",NIL);
|
yuuji@0
|
358 }
|
yuuji@0
|
359
|
yuuji@0
|
360
|
yuuji@0
|
361 /* Write current time in internal format
|
yuuji@0
|
362 * Accepts: destination string
|
yuuji@0
|
363 */
|
yuuji@0
|
364
|
yuuji@0
|
365 void internal_date (char *date)
|
yuuji@0
|
366 {
|
yuuji@0
|
367 do_date (date,NIL,"%02d-%s-%d %02d:%02d:%02d %+03d%02d",NIL);
|
yuuji@0
|
368 }
|
yuuji@0
|
369
|
yuuji@0
|
370 /* Initialize server
|
yuuji@0
|
371 * Accepts: server name for syslog or NIL
|
yuuji@0
|
372 * /etc/services service name or NIL
|
yuuji@0
|
373 * alternate /etc/services service name or NIL
|
yuuji@0
|
374 * clock interrupt handler
|
yuuji@0
|
375 * kiss-of-death interrupt handler
|
yuuji@0
|
376 * hangup interrupt handler
|
yuuji@0
|
377 * termination interrupt handler
|
yuuji@0
|
378 */
|
yuuji@0
|
379
|
yuuji@0
|
380 void server_init (char *server,char *service,char *sslservice,
|
yuuji@0
|
381 void *clkint,void *kodint,void *hupint,void *trmint,
|
yuuji@0
|
382 void *staint)
|
yuuji@0
|
383 {
|
yuuji@0
|
384 int onceonly = server && service && sslservice;
|
yuuji@0
|
385 if (onceonly) { /* set server name in syslog */
|
yuuji@0
|
386 int mask;
|
yuuji@0
|
387 openlog (myServerName = cpystr (server),LOG_PID,syslog_facility);
|
yuuji@0
|
388 fclose (stderr); /* possibly save a process ID */
|
yuuji@0
|
389
|
yuuji@0
|
390 switch (mask = umask (022)){/* check old umask */
|
yuuji@0
|
391 case 0: /* definitely unreasonable */
|
yuuji@0
|
392 case 022: /* don't need to change it */
|
yuuji@0
|
393 break;
|
yuuji@0
|
394 default: /* already was a reasonable value */
|
yuuji@0
|
395 umask (mask); /* so change it back */
|
yuuji@0
|
396 }
|
yuuji@0
|
397 }
|
yuuji@0
|
398 arm_signal (SIGALRM,clkint); /* prepare for clock interrupt */
|
yuuji@0
|
399 arm_signal (SIGUSR2,kodint); /* prepare for Kiss Of Death */
|
yuuji@0
|
400 arm_signal (SIGHUP,hupint); /* prepare for hangup */
|
yuuji@0
|
401 arm_signal (SIGPIPE,hupint); /* alternative hangup */
|
yuuji@0
|
402 arm_signal (SIGTERM,trmint); /* prepare for termination */
|
yuuji@0
|
403 /* status dump */
|
yuuji@0
|
404 if (staint) arm_signal (SIGUSR1,staint);
|
yuuji@0
|
405 if (onceonly) { /* set up network and maybe SSL */
|
yuuji@0
|
406 long port;
|
yuuji@0
|
407 struct servent *sv;
|
yuuji@0
|
408 /* Use SSL if SSL service, or if server starts with "s" and not service */
|
yuuji@0
|
409 if (((port = tcp_serverport ()) >= 0)) {
|
yuuji@0
|
410 if ((sv = getservbyname (service,"tcp")) && (port == ntohs (sv->s_port)))
|
yuuji@0
|
411 syslog (LOG_DEBUG,"%s service init from %s",service,tcp_clientaddr ());
|
yuuji@0
|
412 else if ((sv = getservbyname (sslservice,"tcp")) &&
|
yuuji@0
|
413 (port == ntohs (sv->s_port))) {
|
yuuji@0
|
414 syslog (LOG_DEBUG,"%s SSL service init from %s",sslservice,
|
yuuji@0
|
415 tcp_clientaddr ());
|
yuuji@0
|
416 ssl_server_init (server);
|
yuuji@0
|
417 }
|
yuuji@0
|
418 else { /* not service or SSL service port */
|
yuuji@0
|
419 syslog (LOG_DEBUG,"port %ld service init from %s",port,
|
yuuji@0
|
420 tcp_clientaddr ());
|
yuuji@0
|
421 if (*server == 's') ssl_server_init (server);
|
yuuji@0
|
422 }
|
yuuji@0
|
423 }
|
yuuji@0
|
424 }
|
yuuji@0
|
425 }
|
yuuji@0
|
426
|
yuuji@0
|
427 /* Wait for stdin input
|
yuuji@0
|
428 * Accepts: timeout in seconds
|
yuuji@0
|
429 * Returns: T if have input on stdin, else NIL
|
yuuji@0
|
430 */
|
yuuji@0
|
431
|
yuuji@0
|
432 long server_input_wait (long seconds)
|
yuuji@0
|
433 {
|
yuuji@0
|
434 fd_set rfd,efd;
|
yuuji@0
|
435 struct timeval tmo;
|
yuuji@0
|
436 FD_ZERO (&rfd);
|
yuuji@0
|
437 FD_ZERO (&efd);
|
yuuji@0
|
438 FD_SET (0,&rfd);
|
yuuji@0
|
439 FD_SET (0,&efd);
|
yuuji@0
|
440 tmo.tv_sec = seconds; tmo.tv_usec = 0;
|
yuuji@0
|
441 return select (1,&rfd,0,&efd,&tmo) ? LONGT : NIL;
|
yuuji@0
|
442 }
|
yuuji@0
|
443
|
yuuji@0
|
444 /* Return Amiga password entry for user name
|
yuuji@0
|
445 * Accepts: user name string
|
yuuji@0
|
446 * Returns: password entry
|
yuuji@0
|
447 *
|
yuuji@0
|
448 * Tries all-lowercase form of user name if given user name fails
|
yuuji@0
|
449 */
|
yuuji@0
|
450
|
yuuji@0
|
451 static struct passwd *pwuser (unsigned char *user)
|
yuuji@0
|
452 {
|
yuuji@0
|
453 unsigned char *s;
|
yuuji@0
|
454 struct passwd *pw = getpwnam (user);
|
yuuji@0
|
455 if (!pw) { /* failed, see if any uppercase characters */
|
yuuji@0
|
456 for (s = user; *s && ((*s < 'A') || (*s > 'Z')); s++);
|
yuuji@0
|
457 if (*s) { /* yes, try all lowercase form */
|
yuuji@0
|
458 pw = getpwnam (s = lcase (cpystr (user)));
|
yuuji@0
|
459 fs_give ((void **) &s);
|
yuuji@0
|
460 }
|
yuuji@0
|
461 }
|
yuuji@0
|
462 return pw;
|
yuuji@0
|
463 }
|
yuuji@0
|
464
|
yuuji@0
|
465
|
yuuji@0
|
466 /* Validate password for user name
|
yuuji@0
|
467 * Accepts: user name string
|
yuuji@0
|
468 * password string
|
yuuji@0
|
469 * argument count
|
yuuji@0
|
470 * argument vector
|
yuuji@0
|
471 * Returns: password entry if validated
|
yuuji@0
|
472 *
|
yuuji@0
|
473 * Tries password+1 if password fails and starts with space
|
yuuji@0
|
474 */
|
yuuji@0
|
475
|
yuuji@0
|
476 static struct passwd *valpwd (char *user,char *pwd,int argc,char *argv[])
|
yuuji@0
|
477 {
|
yuuji@0
|
478 char *s;
|
yuuji@0
|
479 struct passwd *pw;
|
yuuji@0
|
480 struct passwd *ret = NIL;
|
yuuji@0
|
481 if (auth_md5.server) { /* using CRAM-MD5 authentication? */
|
yuuji@0
|
482 if (s = auth_md5_pwd (user)) {
|
yuuji@0
|
483 if (!strcmp (s,pwd) || ((*pwd == ' ') && pwd[1] && !strcmp (s,pwd+1)))
|
yuuji@0
|
484 ret = pwuser (user); /* validated, get passwd entry for user */
|
yuuji@0
|
485 memset (s,0,strlen (s)); /* erase sensitive information */
|
yuuji@0
|
486 fs_give ((void **) &s);
|
yuuji@0
|
487 }
|
yuuji@0
|
488 }
|
yuuji@0
|
489 else if (pw = pwuser (user)) {/* can get user? */
|
yuuji@0
|
490 s = cpystr (pw->pw_name); /* copy returned name in case we need it */
|
yuuji@0
|
491 if (*pwd && !(ret = checkpw (pw,pwd,argc,argv)) &&
|
yuuji@0
|
492 (*pwd == ' ') && pwd[1] && (ret = pwuser (s)))
|
yuuji@0
|
493 ret = checkpw (pw,pwd+1,argc,argv);
|
yuuji@0
|
494 fs_give ((void **) &s); /* don't need copy of name any more */
|
yuuji@0
|
495 }
|
yuuji@0
|
496 return ret;
|
yuuji@0
|
497 }
|
yuuji@0
|
498
|
yuuji@0
|
499 /* Server log in
|
yuuji@0
|
500 * Accepts: user name string
|
yuuji@0
|
501 * password string
|
yuuji@0
|
502 * authenticating user name string
|
yuuji@0
|
503 * argument count
|
yuuji@0
|
504 * argument vector
|
yuuji@0
|
505 * Returns: T if password validated, NIL otherwise
|
yuuji@0
|
506 */
|
yuuji@0
|
507
|
yuuji@0
|
508 long server_login (char *user,char *pwd,char *authuser,int argc,char *argv[])
|
yuuji@0
|
509 {
|
yuuji@0
|
510 struct passwd *pw = NIL;
|
yuuji@0
|
511 int level = LOG_NOTICE;
|
yuuji@0
|
512 char *err = "failed";
|
yuuji@0
|
513 /* cretins still haven't given up */
|
yuuji@0
|
514 if ((strlen (user) >= NETMAXUSER) ||
|
yuuji@0
|
515 (authuser && (strlen (authuser) >= NETMAXUSER))) {
|
yuuji@0
|
516 level = LOG_ALERT; /* escalate this alert */
|
yuuji@0
|
517 err = "SYSTEM BREAK-IN ATTEMPT";
|
yuuji@0
|
518 logtry = 0; /* render this session useless */
|
yuuji@0
|
519 }
|
yuuji@0
|
520 else if (logtry-- <= 0) err = "excessive login failures";
|
yuuji@0
|
521 else if (disablePlaintext) err = "disabled";
|
yuuji@0
|
522 else if (!(authuser && *authuser)) pw = valpwd (user,pwd,argc,argv);
|
yuuji@0
|
523 else if (valpwd (authuser,pwd,argc,argv)) pw = pwuser (user);
|
yuuji@0
|
524 if (pw && pw_login (pw,authuser,pw->pw_name,NIL,argc,argv)) return T;
|
yuuji@0
|
525 syslog (level|LOG_AUTH,"Login %s user=%.64s auth=%.64s host=%.80s",err,
|
yuuji@0
|
526 user,(authuser && *authuser) ? authuser : user,tcp_clienthost ());
|
yuuji@0
|
527 sleep (3); /* slow down possible cracker */
|
yuuji@0
|
528 return NIL;
|
yuuji@0
|
529 }
|
yuuji@0
|
530
|
yuuji@0
|
531 /* Authenticated server log in
|
yuuji@0
|
532 * Accepts: user name string
|
yuuji@0
|
533 * authenticating user name string
|
yuuji@0
|
534 * argument count
|
yuuji@0
|
535 * argument vector
|
yuuji@0
|
536 * Returns: T if password validated, NIL otherwise
|
yuuji@0
|
537 */
|
yuuji@0
|
538
|
yuuji@0
|
539 long authserver_login (char *user,char *authuser,int argc,char *argv[])
|
yuuji@0
|
540 {
|
yuuji@0
|
541 return pw_login (pwuser (user),authuser,user,NIL,argc,argv);
|
yuuji@0
|
542 }
|
yuuji@0
|
543
|
yuuji@0
|
544
|
yuuji@0
|
545 /* Log in as anonymous daemon
|
yuuji@0
|
546 * Accepts: argument count
|
yuuji@0
|
547 * argument vector
|
yuuji@0
|
548 * Returns: T if successful, NIL if error
|
yuuji@0
|
549 */
|
yuuji@0
|
550
|
yuuji@0
|
551 long anonymous_login (int argc,char *argv[])
|
yuuji@0
|
552 {
|
yuuji@0
|
553 /* log in Mr. A. N. Onymous */
|
yuuji@0
|
554 return pw_login (getpwnam (ANONYMOUSUSER),NIL,NIL,
|
yuuji@0
|
555 (char *) mail_parameters (NIL,GET_ANONYMOUSHOME,NIL),
|
yuuji@0
|
556 argc,argv);
|
yuuji@0
|
557 }
|
yuuji@0
|
558
|
yuuji@0
|
559 /* Finish log in and environment initialization
|
yuuji@0
|
560 * Accepts: passwd struct for loginpw()
|
yuuji@0
|
561 * optional authentication user name
|
yuuji@0
|
562 * user name (NIL for anonymous)
|
yuuji@0
|
563 * home directory (NIL to use directory from passwd struct)
|
yuuji@0
|
564 * argument count
|
yuuji@0
|
565 * argument vector
|
yuuji@0
|
566 * Returns: T if successful, NIL if error
|
yuuji@0
|
567 */
|
yuuji@0
|
568
|
yuuji@0
|
569 long pw_login (struct passwd *pw,char *auser,char *user,char *home,int argc,
|
yuuji@0
|
570 char *argv[])
|
yuuji@0
|
571 {
|
yuuji@0
|
572 struct group *gr;
|
yuuji@0
|
573 char **t;
|
yuuji@0
|
574 long ret = NIL;
|
yuuji@0
|
575 if (pw && pw->pw_uid) { /* must have passwd struct for non-UID 0 */
|
yuuji@0
|
576 /* make safe copies of user and home */
|
yuuji@0
|
577 if (user) user = cpystr (pw->pw_name);
|
yuuji@0
|
578 home = cpystr (home ? home : pw->pw_dir);
|
yuuji@0
|
579 /* authorization ID .NE. authentication ID? */
|
yuuji@0
|
580 if (user && auser && *auser && compare_cstring (auser,user)) {
|
yuuji@0
|
581 /* scan list of mail administrators */
|
yuuji@0
|
582 if ((gr = getgrnam (ADMINGROUP)) && (t = gr->gr_mem)) while (*t && !ret)
|
yuuji@0
|
583 if (!compare_cstring (auser,*t++))
|
yuuji@0
|
584 ret = pw_login (pw,NIL,user,home,argc,argv);
|
yuuji@0
|
585 syslog (LOG_NOTICE|LOG_AUTH,"%s %.80s override of user=%.80s host=%.80s",
|
yuuji@0
|
586 ret ? "Admin" : "Failed",auser,user,tcp_clienthost ());
|
yuuji@0
|
587 }
|
yuuji@0
|
588 /* normal login */
|
yuuji@0
|
589 else if (((pw->pw_uid == geteuid ()) || loginpw (pw,argc,argv)) &&
|
yuuji@0
|
590 (ret = env_init (user,home))) chdir (myhomedir ());
|
yuuji@0
|
591 fs_give ((void **) &home); /* clean up */
|
yuuji@0
|
592 if (user) fs_give ((void **) &user);
|
yuuji@0
|
593 }
|
yuuji@0
|
594 return ret; /* return status */
|
yuuji@0
|
595 }
|
yuuji@0
|
596
|
yuuji@0
|
597 /* Initialize environment
|
yuuji@0
|
598 * Accepts: user name (NIL for anonymous)
|
yuuji@0
|
599 * home directory name
|
yuuji@0
|
600 * Returns: T, always
|
yuuji@0
|
601 */
|
yuuji@0
|
602
|
yuuji@0
|
603 long env_init (char *user,char *home)
|
yuuji@0
|
604 {
|
yuuji@0
|
605 extern MAILSTREAM CREATEPROTO;
|
yuuji@0
|
606 extern MAILSTREAM EMPTYPROTO;
|
yuuji@0
|
607 struct passwd *pw;
|
yuuji@0
|
608 struct stat sbuf;
|
yuuji@0
|
609 char tmp[MAILTMPLEN];
|
yuuji@0
|
610 /* don't init if blocked */
|
yuuji@0
|
611 if (block_env_init) return LONGT;
|
yuuji@0
|
612 if (myUserName) fatal ("env_init called twice!");
|
yuuji@0
|
613 /* set up user name */
|
yuuji@0
|
614 myUserName = cpystr (user ? user : ANONYMOUSUSER);
|
yuuji@0
|
615 if (user) { /* remember user name and home directory */
|
yuuji@0
|
616 nslist[0] = &nshome; /* home namespace */
|
yuuji@0
|
617 nslist[1] = &nsamigaother;
|
yuuji@0
|
618 nslist[2] = advertisetheworld ? &nsworld : &nsshared;
|
yuuji@0
|
619 }
|
yuuji@0
|
620 else { /* anonymous user */
|
yuuji@0
|
621 nslist[0] = nslist[1] = NIL,nslist[2] = &nsftp;
|
yuuji@0
|
622 sprintf (tmp,"%s/INBOX",
|
yuuji@0
|
623 home = (char *) mail_parameters (NIL,GET_ANONYMOUSHOME,NIL));
|
yuuji@0
|
624 sysInbox = cpystr (tmp); /* make system INBOX */
|
yuuji@0
|
625 anonymous = T; /* flag as anonymous */
|
yuuji@0
|
626 }
|
yuuji@0
|
627 myHomeDir = cpystr (home); /* set home directory */
|
yuuji@0
|
628 if (!noautomaticsharedns) {
|
yuuji@0
|
629 /* #ftp namespace */
|
yuuji@0
|
630 if (!ftpHome && (pw = getpwnam ("ftp"))) ftpHome = cpystr (pw->pw_dir);
|
yuuji@0
|
631 /* #public namespace */
|
yuuji@0
|
632 if (!publicHome && (pw = getpwnam ("imappublic")))
|
yuuji@0
|
633 publicHome = cpystr (pw->pw_dir);
|
yuuji@0
|
634 /* #shared namespace */
|
yuuji@0
|
635 if (!anonymous && !sharedHome && (pw = getpwnam ("imapshared")))
|
yuuji@0
|
636 sharedHome = cpystr (pw->pw_dir);
|
yuuji@0
|
637 }
|
yuuji@0
|
638 if (!myLocalHost) mylocalhost ();
|
yuuji@0
|
639 if (!myNewsrc) myNewsrc = cpystr(strcat (strcpy (tmp,myHomeDir),"/.newsrc"));
|
yuuji@0
|
640 if (!newsActive) newsActive = cpystr (ACTIVEFILE);
|
yuuji@0
|
641 if (!newsSpool) newsSpool = cpystr (NEWSSPOOL);
|
yuuji@0
|
642 /* force default prototype to be set */
|
yuuji@0
|
643 if (!createProto) createProto = &CREATEPROTO;
|
yuuji@0
|
644 if (!appendProto) appendProto = &EMPTYPROTO;
|
yuuji@0
|
645 /* re-do open action to get flags */
|
yuuji@0
|
646 (*createProto->dtb->open) (NIL);
|
yuuji@0
|
647 endpwent (); /* close pw database */
|
yuuji@0
|
648 return T;
|
yuuji@0
|
649 }
|
yuuji@0
|
650
|
yuuji@0
|
651 /* Return my user name
|
yuuji@0
|
652 * Accepts: pointer to optional flags
|
yuuji@0
|
653 * Returns: my user name
|
yuuji@0
|
654 */
|
yuuji@0
|
655
|
yuuji@0
|
656 char *myusername_full (unsigned long *flags)
|
yuuji@0
|
657 {
|
yuuji@0
|
658 struct passwd *pw;
|
yuuji@0
|
659 struct stat sbuf;
|
yuuji@0
|
660 char *s;
|
yuuji@0
|
661 unsigned long euid;
|
yuuji@0
|
662 char *ret = UNLOGGEDUSER;
|
yuuji@0
|
663 /* no user name yet and not root? */
|
yuuji@0
|
664 if (!myUserName && (euid = geteuid ())) {
|
yuuji@0
|
665 /* yes, look up getlogin() user name or EUID */
|
yuuji@0
|
666 if (((s = (char *) getlogin ()) && *s && (strlen (s) < NETMAXUSER) &&
|
yuuji@0
|
667 (pw = getpwnam (s)) && (pw->pw_uid == euid)) ||
|
yuuji@0
|
668 (pw = getpwuid (euid))) {
|
yuuji@0
|
669 if (block_env_init) { /* don't env_init if blocked */
|
yuuji@0
|
670 if (flags) *flags = MU_LOGGEDIN;
|
yuuji@0
|
671 return pw->pw_name;
|
yuuji@0
|
672 }
|
yuuji@0
|
673 env_init (pw->pw_name,
|
yuuji@0
|
674 ((s = getenv ("HOME")) && *s && (strlen (s) < NETMAXMBX) &&
|
yuuji@0
|
675 !stat (s,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFDIR)) ?
|
yuuji@0
|
676 s : pw->pw_dir);
|
yuuji@0
|
677 }
|
yuuji@0
|
678 else fatal ("Unable to look up user name");
|
yuuji@0
|
679 }
|
yuuji@0
|
680 if (myUserName) { /* logged in? */
|
yuuji@0
|
681 if (flags) *flags = anonymous ? MU_ANONYMOUS : MU_LOGGEDIN;
|
yuuji@0
|
682 ret = myUserName; /* return user name */
|
yuuji@0
|
683 }
|
yuuji@0
|
684 else if (flags) *flags = MU_NOTLOGGEDIN;
|
yuuji@0
|
685 return ret;
|
yuuji@0
|
686 }
|
yuuji@0
|
687 /* Return my local host name
|
yuuji@0
|
688 * Returns: my local host name
|
yuuji@0
|
689 */
|
yuuji@0
|
690
|
yuuji@0
|
691 char *mylocalhost ()
|
yuuji@0
|
692 {
|
yuuji@0
|
693 char tmp[MAILTMPLEN];
|
yuuji@0
|
694 struct hostent *host_name;
|
yuuji@0
|
695 if (!myLocalHost) myLocalHost = cpystr (gethostname (tmp,MAILTMPLEN-1) ?
|
yuuji@0
|
696 "random-pc" : tcp_canonical (tmp));
|
yuuji@0
|
697 return myLocalHost;
|
yuuji@0
|
698 }
|
yuuji@0
|
699
|
yuuji@0
|
700 /* Return my home directory name
|
yuuji@0
|
701 * Returns: my home directory name
|
yuuji@0
|
702 */
|
yuuji@0
|
703
|
yuuji@0
|
704 char *myhomedir ()
|
yuuji@0
|
705 {
|
yuuji@0
|
706 if (!myHomeDir) myusername ();/* initialize if first time */
|
yuuji@0
|
707 return myHomeDir ? myHomeDir : "";
|
yuuji@0
|
708 }
|
yuuji@0
|
709
|
yuuji@0
|
710
|
yuuji@0
|
711 /* Return my home mailbox name
|
yuuji@0
|
712 * Returns: my home directory name
|
yuuji@0
|
713 */
|
yuuji@0
|
714
|
yuuji@0
|
715 static char *mymailboxdir ()
|
yuuji@0
|
716 {
|
yuuji@0
|
717 char *home = myhomedir ();
|
yuuji@0
|
718 if (!myMailboxDir && home) { /* initialize if first time */
|
yuuji@0
|
719 if (mailsubdir) {
|
yuuji@0
|
720 char tmp[MAILTMPLEN];
|
yuuji@0
|
721 sprintf (tmp,"%s/%s",home,mailsubdir);
|
yuuji@0
|
722 myMailboxDir = cpystr (tmp);/* use pre-defined subdirectory of home */
|
yuuji@0
|
723 }
|
yuuji@0
|
724 else myMailboxDir = cpystr (home);
|
yuuji@0
|
725 }
|
yuuji@0
|
726 return myMailboxDir ? myMailboxDir : "";
|
yuuji@0
|
727 }
|
yuuji@0
|
728
|
yuuji@0
|
729
|
yuuji@0
|
730 /* Return system standard INBOX
|
yuuji@0
|
731 * Accepts: buffer string
|
yuuji@0
|
732 */
|
yuuji@0
|
733
|
yuuji@0
|
734 char *sysinbox ()
|
yuuji@0
|
735 {
|
yuuji@0
|
736 char tmp[MAILTMPLEN];
|
yuuji@0
|
737 if (!sysInbox) { /* initialize if first time */
|
yuuji@0
|
738 sprintf (tmp,"%s/%s",MAILSPOOL,myusername ());
|
yuuji@0
|
739 sysInbox = cpystr (tmp); /* system inbox is from mail spool */
|
yuuji@0
|
740 }
|
yuuji@0
|
741 return sysInbox;
|
yuuji@0
|
742 }
|
yuuji@0
|
743
|
yuuji@0
|
744 /* Return mailbox directory name
|
yuuji@0
|
745 * Accepts: destination buffer
|
yuuji@0
|
746 * directory prefix
|
yuuji@0
|
747 * name in directory
|
yuuji@0
|
748 * Returns: file name or NIL if error
|
yuuji@0
|
749 */
|
yuuji@0
|
750
|
yuuji@0
|
751 char *mailboxdir (char *dst,char *dir,char *name)
|
yuuji@0
|
752 {
|
yuuji@0
|
753 char tmp[MAILTMPLEN];
|
yuuji@0
|
754 if (dir || name) { /* if either argument provided */
|
yuuji@0
|
755 if (dir) {
|
yuuji@0
|
756 if (strlen (dir) > NETMAXMBX) return NIL;
|
yuuji@0
|
757 strcpy (tmp,dir); /* write directory prefix */
|
yuuji@0
|
758 }
|
yuuji@0
|
759 else tmp[0] = '\0'; /* otherwise null string */
|
yuuji@0
|
760 if (name) {
|
yuuji@0
|
761 if (strlen (name) > NETMAXMBX) return NIL;
|
yuuji@0
|
762 strcat (tmp,name); /* write name in directory */
|
yuuji@0
|
763 }
|
yuuji@0
|
764 /* validate name, return its name */
|
yuuji@0
|
765 if (!mailboxfile (dst,tmp)) return NIL;
|
yuuji@0
|
766 }
|
yuuji@0
|
767 /* no arguments, wants mailbox directory */
|
yuuji@0
|
768 else strcpy (dst,mymailboxdir ());
|
yuuji@0
|
769 return dst; /* return the name */
|
yuuji@0
|
770 }
|
yuuji@0
|
771
|
yuuji@0
|
772 /* Return mailbox file name
|
yuuji@0
|
773 * Accepts: destination buffer
|
yuuji@0
|
774 * mailbox name
|
yuuji@0
|
775 * Returns: file name or empty string for driver-selected INBOX or NIL if error
|
yuuji@0
|
776 */
|
yuuji@0
|
777
|
yuuji@0
|
778 char *mailboxfile (char *dst,char *name)
|
yuuji@0
|
779 {
|
yuuji@0
|
780 struct passwd *pw;
|
yuuji@0
|
781 char *s;
|
yuuji@0
|
782 if (!name || !*name || (*name == '{') || (strlen (name) > NETMAXMBX) ||
|
yuuji@0
|
783 ((anonymous || restrictBox || (*name == '#')) &&
|
yuuji@0
|
784 (strstr (name,"..") || strstr (name,"//") || strstr (name,"/~"))))
|
yuuji@0
|
785 dst = NIL; /* invalid name */
|
yuuji@0
|
786 else switch (*name) { /* determine mailbox type based upon name */
|
yuuji@0
|
787 case '#': /* namespace name */
|
yuuji@0
|
788 /* #ftp/ namespace */
|
yuuji@0
|
789 if (((name[1] == 'f') || (name[1] == 'F')) &&
|
yuuji@0
|
790 ((name[2] == 't') || (name[2] == 'T')) &&
|
yuuji@0
|
791 ((name[3] == 'p') || (name[3] == 'P')) &&
|
yuuji@0
|
792 (name[4] == '/') && ftpHome) sprintf (dst,"%s/%s",ftpHome,name+5);
|
yuuji@0
|
793 /* #public/ and #shared/ namespaces */
|
yuuji@0
|
794 else if ((((name[1] == 'p') || (name[1] == 'P')) &&
|
yuuji@0
|
795 ((name[2] == 'u') || (name[2] == 'U')) &&
|
yuuji@0
|
796 ((name[3] == 'b') || (name[3] == 'B')) &&
|
yuuji@0
|
797 ((name[4] == 'l') || (name[4] == 'L')) &&
|
yuuji@0
|
798 ((name[5] == 'i') || (name[5] == 'I')) &&
|
yuuji@0
|
799 ((name[6] == 'c') || (name[6] == 'C')) &&
|
yuuji@0
|
800 (name[7] == '/') && (s = publicHome)) ||
|
yuuji@0
|
801 (!anonymous && ((name[1] == 's') || (name[1] == 'S')) &&
|
yuuji@0
|
802 ((name[2] == 'h') || (name[2] == 'H')) &&
|
yuuji@0
|
803 ((name[3] == 'a') || (name[3] == 'A')) &&
|
yuuji@0
|
804 ((name[4] == 'r') || (name[4] == 'R')) &&
|
yuuji@0
|
805 ((name[5] == 'e') || (name[5] == 'E')) &&
|
yuuji@0
|
806 ((name[6] == 'd') || (name[6] == 'D')) &&
|
yuuji@0
|
807 (name[7] == '/') && (s = sharedHome)))
|
yuuji@0
|
808 sprintf (dst,"%s/%s",s,compare_cstring (name,"INBOX") ? name : "INBOX");
|
yuuji@0
|
809 else dst = NIL; /* unknown namespace */
|
yuuji@0
|
810 break;
|
yuuji@0
|
811
|
yuuji@0
|
812 case '/': /* root access */
|
yuuji@0
|
813 if (anonymous) dst = NIL; /* anonymous forbidden to do this */
|
yuuji@0
|
814 else if ((restrictBox & RESTRICTROOT) && strcmp (name,sysinbox ()))
|
yuuji@0
|
815 dst = NIL; /* restricted and not access to sysinbox */
|
yuuji@0
|
816 else strcpy (dst,name); /* unrestricted, copy root name */
|
yuuji@0
|
817 break;
|
yuuji@0
|
818 case '~': /* other user access */
|
yuuji@0
|
819 /* bad syntax or anonymous can't win */
|
yuuji@0
|
820 if (!*++name || anonymous) dst = NIL;
|
yuuji@0
|
821 /* ~/ equivalent to ordinary name */
|
yuuji@0
|
822 else if (*name == '/') sprintf (dst,"%s/%s",mymailboxdir (),name+1);
|
yuuji@0
|
823 /* other user forbidden if restricted */
|
yuuji@0
|
824 else if (restrictBox & RESTRICTOTHERUSER) dst = NIL;
|
yuuji@0
|
825 else { /* clear box other user */
|
yuuji@0
|
826 /* copy user name */
|
yuuji@0
|
827 for (s = dst; *name && (*name != '/'); *s++ = *name++);
|
yuuji@0
|
828 *s++ = '\0'; /* tie off user name, look up in passwd file */
|
yuuji@0
|
829 if ((pw = getpwnam (dst)) && pw->pw_dir) {
|
yuuji@0
|
830 if (*name) name++; /* skip past the slash */
|
yuuji@0
|
831 /* canonicalize case of INBOX */
|
yuuji@0
|
832 if (!compare_cstring (name,"INBOX")) name = "INBOX";
|
yuuji@0
|
833 /* remove trailing / from directory */
|
yuuji@0
|
834 if ((s = strrchr (pw->pw_dir,'/')) && !s[1]) *s = '\0';
|
yuuji@0
|
835 /* don't allow ~root/ if restricted root */
|
yuuji@0
|
836 if ((restrictBox & RESTRICTROOT) && !*pw->pw_dir) dst = NIL;
|
yuuji@0
|
837 /* build final name w/ subdir if needed */
|
yuuji@0
|
838 else if (mailsubdir) sprintf (dst,"%s/%s/%s",pw->pw_dir,mailsubdir,name);
|
yuuji@0
|
839 else sprintf (dst,"%s/%s",pw->pw_dir,name);
|
yuuji@0
|
840 }
|
yuuji@0
|
841 else dst = NIL; /* no such user */
|
yuuji@0
|
842 }
|
yuuji@0
|
843 break;
|
yuuji@0
|
844 case 'I': case 'i': /* possible INBOX */
|
yuuji@0
|
845 if (!compare_cstring (name+1,"NBOX")) {
|
yuuji@0
|
846 /* if anonymous, use INBOX in mailbox dir */
|
yuuji@0
|
847 if (anonymous) sprintf (dst,"%s/INBOX",mymailboxdir ());
|
yuuji@0
|
848 else *dst = '\0'; /* otherwise driver selects the name */
|
yuuji@0
|
849 break;
|
yuuji@0
|
850 }
|
yuuji@0
|
851 /* drop into to ordinary name case */
|
yuuji@0
|
852 default: /* ordinary name is easy */
|
yuuji@0
|
853 sprintf (dst,"%s/%s",mymailboxdir (),name);
|
yuuji@0
|
854 break;
|
yuuji@0
|
855 }
|
yuuji@0
|
856 return dst; /* return final name */
|
yuuji@0
|
857 }
|
yuuji@0
|
858
|
yuuji@0
|
859 /* Dot-lock file locker
|
yuuji@0
|
860 * Accepts: file name to lock
|
yuuji@0
|
861 * destination buffer for lock file name
|
yuuji@0
|
862 * open file description on file name to lock
|
yuuji@0
|
863 * Returns: T if success, NIL if failure
|
yuuji@0
|
864 */
|
yuuji@0
|
865
|
yuuji@0
|
866 long dotlock_lock (char *file,DOTLOCK *base,int fd)
|
yuuji@0
|
867 {
|
yuuji@0
|
868 int i = locktimeout * 60;
|
yuuji@0
|
869 int j,mask,retry,pi[2],po[2];
|
yuuji@0
|
870 char *s,tmp[MAILTMPLEN];
|
yuuji@0
|
871 struct stat sb;
|
yuuji@0
|
872 /* flush absurd file name */
|
yuuji@0
|
873 if (strlen (file) > 512) return NIL;
|
yuuji@0
|
874 /* build lock filename */
|
yuuji@0
|
875 sprintf (base->lock,"%s.lock",file);
|
yuuji@0
|
876 /* assume no pipe */
|
yuuji@0
|
877 base->pipei = base->pipeo = -1;
|
yuuji@0
|
878 do { /* make sure not symlink */
|
yuuji@0
|
879 if (!(j = chk_notsymlink (base->lock,&sb))) return NIL;
|
yuuji@0
|
880 /* time out if file older than 5 minutes */
|
yuuji@0
|
881 if ((j > 0) && ((time (0)) >= (sb.st_ctime + locktimeout * 60))) i = 0;
|
yuuji@0
|
882 /* try to create the lock */
|
yuuji@0
|
883 if ((j = open (name,O_WRONLY|O_CREAT|O_EXCL,(int) lock_protection)) >= 0) {
|
yuuji@0
|
884 close (i); /* make the file, now close it */
|
yuuji@0
|
885 chmod (base->lock,(int) lock_protection);
|
yuuji@0
|
886 return LONGT;
|
yuuji@0
|
887 }
|
yuuji@0
|
888 if (errno == EEXIST) { /* already locked? */
|
yuuji@0
|
889 retry = -1; /* can try again */
|
yuuji@0
|
890 if (!(i%15)) { /* time to notify? */
|
yuuji@0
|
891 sprintf (tmp,"Mailbox %.80s is locked, will override in %d seconds...",
|
yuuji@0
|
892 file,i);
|
yuuji@0
|
893 mm_log (tmp,WARN);
|
yuuji@0
|
894 }
|
yuuji@0
|
895 sleep (1); /* wait 1 second before next try */
|
yuuji@0
|
896 }
|
yuuji@0
|
897 else retry = i = 0; /* hard failure, no more retries */
|
yuuji@0
|
898 } while (i--); /* until out of retries */
|
yuuji@0
|
899 if (retry < 0) { /* still returning retry after locktimeout? */
|
yuuji@0
|
900 if (!(j = chk_notsymlink (base->lock,&sb))) return NIL;
|
yuuji@0
|
901 if ((j > 0) && ((time (0)) < (sb.st_ctime + locktimeout * 60))) {
|
yuuji@0
|
902 sprintf (tmp,"Mailbox vulnerable - seizing %ld second old lock",
|
yuuji@0
|
903 (long) (time (0) - sb.st_ctime));
|
yuuji@0
|
904 mm_log (tmp,WARN);
|
yuuji@0
|
905 }
|
yuuji@0
|
906 mask = umask (0);
|
yuuji@0
|
907 unlink (base->lock); /* try to remove the old file */
|
yuuji@0
|
908 /* seize the lock */
|
yuuji@0
|
909 if ((i = open (base->lock,O_WRONLY|O_CREAT,(int) lock_protection)) >= 0) {
|
yuuji@0
|
910 close (i); /* don't need descriptor any more */
|
yuuji@0
|
911 sprintf (tmp,"Mailbox %.80s lock overridden",file);
|
yuuji@0
|
912 mm_log (tmp,NIL);
|
yuuji@0
|
913 chmod (base->lock,(int) lock_protection);
|
yuuji@0
|
914 umask (mask) /* restore old umask */
|
yuuji@0
|
915 return LONGT;
|
yuuji@0
|
916 }
|
yuuji@0
|
917 umask (mask) /* restore old umask */
|
yuuji@0
|
918 }
|
yuuji@0
|
919
|
yuuji@0
|
920 if (fd >= 0) switch (errno) {
|
yuuji@0
|
921 case EACCES: /* protection failure? */
|
yuuji@0
|
922 /* make command pipes */
|
yuuji@0
|
923 if (!stat (LOCKPGM,&sb) && (pipe (pi) >= 0)) {
|
yuuji@0
|
924 /* if input pipes usable create output pipes */
|
yuuji@0
|
925 if ((pi[0] < FD_SETSIZE) && (pi[1] < FD_SETSIZE) && (pipe (po) >= 0)) {
|
yuuji@0
|
926 /* make sure output pipes are usable */
|
yuuji@0
|
927 if ((po[0] >= FD_SETSIZE) || (po[1] >= FD_SETSIZE));
|
yuuji@0
|
928 /* all is good, make inferior process */
|
yuuji@0
|
929 else if (!(j = fork ())) {
|
yuuji@0
|
930 if (!fork ()) { /* make grandchild so it's inherited by init */
|
yuuji@0
|
931 long cf; /* don't change caller vars in case vfork() */
|
yuuji@0
|
932 char *argv[4],arg[20];
|
yuuji@0
|
933 /* prepare argument vector */
|
yuuji@0
|
934 sprintf (arg,"%d",fd);
|
yuuji@0
|
935 argv[0] = LOCKPGM; argv[1] = arg;
|
yuuji@0
|
936 argv[2] = file; argv[3] = NIL;
|
yuuji@0
|
937 /* set parent's I/O to my O/I */
|
yuuji@0
|
938 dup2 (pi[1],1); dup2 (pi[1],2); dup2 (po[0],0);
|
yuuji@0
|
939 /* close all unnecessary descriptors */
|
yuuji@0
|
940 for (cf = max (20,max (max (pi[0],pi[1]),max(po[0],po[1])));
|
yuuji@0
|
941 cf >= 3; --cf) if (cf != fd) close (cf);
|
yuuji@0
|
942 /* be our own process group */
|
yuuji@0
|
943 setpgrp (0,getpid ());
|
yuuji@0
|
944 /* now run it */
|
yuuji@0
|
945 _exit (execv (argv[0],argv));
|
yuuji@0
|
946 }
|
yuuji@0
|
947 _exit (1); /* child is done */
|
yuuji@0
|
948 }
|
yuuji@0
|
949 else if (j > 0) { /* parent process */
|
yuuji@0
|
950 fd_set rfd;
|
yuuji@0
|
951 struct timeval tmo;
|
yuuji@0
|
952 FD_ZERO (&rfd);
|
yuuji@0
|
953 FD_SET (pi[0],&rfd);
|
yuuji@0
|
954 tmo.tv_sec = locktimeout * 60;
|
yuuji@0
|
955 grim_pid_reap (j,NIL);/* reap child; grandchild now owned by init */
|
yuuji@0
|
956 /* read response from locking program */
|
yuuji@0
|
957 if (select (pi[0]+1,&rfd,0,0,&tmo) &&
|
yuuji@0
|
958 (read (pi[0],tmp,1) == 1) && (tmp[0] == '+')) {
|
yuuji@0
|
959 /* success, record pipes */
|
yuuji@0
|
960 base->pipei = pi[0]; base->pipeo = po[1];
|
yuuji@0
|
961 /* close child's side of the pipes */
|
yuuji@0
|
962 close (pi[1]); close (po[0]);
|
yuuji@0
|
963 return LONGT;
|
yuuji@0
|
964 }
|
yuuji@0
|
965 }
|
yuuji@0
|
966 close (po[0]); close (po[1]);
|
yuuji@0
|
967 }
|
yuuji@0
|
968 close (pi[0]); close (pi[1]);
|
yuuji@0
|
969 }
|
yuuji@0
|
970 /* find directory/file delimiter */
|
yuuji@0
|
971 if (s = strrchr (base->lock,'/')) {
|
yuuji@0
|
972 *s = '\0'; /* tie off at directory */
|
yuuji@0
|
973 sprintf(tmp, /* generate default message */
|
yuuji@0
|
974 "Mailbox vulnerable - directory %.80s must have 1777 protection",
|
yuuji@0
|
975 base->lock);
|
yuuji@0
|
976 /* definitely not 1777 if can't stat */
|
yuuji@0
|
977 mask = stat (base->lock,&sb) ? 0 : (sb.st_mode & 1777);
|
yuuji@0
|
978 *s = '/'; /* restore lock name */
|
yuuji@0
|
979 if (mask != 1777) { /* default warning if not 1777 */
|
yuuji@0
|
980 MM_LOG (tmp,WARN);
|
yuuji@0
|
981 break;
|
yuuji@0
|
982 }
|
yuuji@0
|
983 }
|
yuuji@0
|
984 default:
|
yuuji@0
|
985 sprintf (tmp,"Mailbox vulnerable - error creating %.80s: %s",
|
yuuji@0
|
986 base->lock,strerror (errno));
|
yuuji@0
|
987 mm_log (tmp,WARN); /* this is probably not good */
|
yuuji@0
|
988 break;
|
yuuji@0
|
989 }
|
yuuji@0
|
990 base->lock[0] = '\0'; /* don't use lock files */
|
yuuji@0
|
991 return NIL;
|
yuuji@0
|
992 }
|
yuuji@0
|
993
|
yuuji@0
|
994 /* Dot-lock file unlocker
|
yuuji@0
|
995 * Accepts: lock file name
|
yuuji@0
|
996 * Returns: T if success, NIL if failure
|
yuuji@0
|
997 */
|
yuuji@0
|
998
|
yuuji@0
|
999 long dotlock_unlock (DOTLOCK *base)
|
yuuji@0
|
1000 {
|
yuuji@0
|
1001 long ret = LONGT;
|
yuuji@0
|
1002 if (base && base->lock[0]) {
|
yuuji@0
|
1003 if (base->pipei >= 0) { /* if running through a pipe unlocker */
|
yuuji@0
|
1004 ret = (write (base->pipeo,"+",1) == 1);
|
yuuji@0
|
1005 /* nuke the pipes */
|
yuuji@0
|
1006 close (base->pipei); close (base->pipeo);
|
yuuji@0
|
1007 }
|
yuuji@0
|
1008 else ret = !unlink (base->lock);
|
yuuji@0
|
1009 }
|
yuuji@0
|
1010 return ret;
|
yuuji@0
|
1011 }
|
yuuji@0
|
1012
|
yuuji@0
|
1013 /* Lock file name
|
yuuji@0
|
1014 * Accepts: scratch buffer
|
yuuji@0
|
1015 * file name
|
yuuji@0
|
1016 * type of locking operation (LOCK_SH or LOCK_EX)
|
yuuji@0
|
1017 * pointer to return PID of locker
|
yuuji@0
|
1018 * Returns: file descriptor of lock or negative if error
|
yuuji@0
|
1019 */
|
yuuji@0
|
1020
|
yuuji@0
|
1021 int lockname (char *lock,char *fname,int op,long *pid)
|
yuuji@0
|
1022 {
|
yuuji@0
|
1023 struct stat sbuf;
|
yuuji@0
|
1024 *pid = 0; /* no locker PID */
|
yuuji@0
|
1025 return stat (fname,&sbuf) ? -1 : lock_work (lock,&sbuf,op,pid);
|
yuuji@0
|
1026 }
|
yuuji@0
|
1027
|
yuuji@0
|
1028
|
yuuji@0
|
1029 /* Lock file descriptor
|
yuuji@0
|
1030 * Accepts: file descriptor
|
yuuji@0
|
1031 * lock file name buffer
|
yuuji@0
|
1032 * type of locking operation (LOCK_SH or LOCK_EX)
|
yuuji@0
|
1033 * Returns: file descriptor of lock or negative if error
|
yuuji@0
|
1034 */
|
yuuji@0
|
1035
|
yuuji@0
|
1036 int lockfd (int fd,char *lock,int op)
|
yuuji@0
|
1037 {
|
yuuji@0
|
1038 struct stat sbuf;
|
yuuji@0
|
1039 return fstat (fd,&sbuf) ? -1 : lock_work (lock,&sbuf,op,NIL);
|
yuuji@0
|
1040 }
|
yuuji@0
|
1041
|
yuuji@0
|
1042 /* Lock file name worker
|
yuuji@0
|
1043 * Accepts: lock file name
|
yuuji@0
|
1044 * pointer to stat() buffer
|
yuuji@0
|
1045 * type of locking operation (LOCK_SH or LOCK_EX)
|
yuuji@0
|
1046 * pointer to return PID of locker
|
yuuji@0
|
1047 * Returns: file descriptor of lock or negative if error
|
yuuji@0
|
1048 */
|
yuuji@0
|
1049
|
yuuji@0
|
1050 int lock_work (char *lock,void *sb,int op,long *pid)
|
yuuji@0
|
1051 {
|
yuuji@0
|
1052 struct stat lsb,fsb;
|
yuuji@0
|
1053 struct stat *sbuf = (struct stat *) sb;
|
yuuji@0
|
1054 char tmp[MAILTMPLEN];
|
yuuji@0
|
1055 long i;
|
yuuji@0
|
1056 int fd;
|
yuuji@0
|
1057 int mask = umask (0);
|
yuuji@0
|
1058 if (pid) *pid = 0; /* initialize return PID */
|
yuuji@0
|
1059 /* make temporary lock file name */
|
yuuji@0
|
1060 sprintf (lock,"%s/.%lx.%lx","/tmp",
|
yuuji@0
|
1061 (unsigned long) sbuf->st_dev,(unsigned long) sbuf->st_ino);
|
yuuji@0
|
1062 while (T) { /* until get a good lock */
|
yuuji@0
|
1063 do switch ((int) chk_notsymlink (lock,&lsb)) {
|
yuuji@0
|
1064 case 1: /* exists just once */
|
yuuji@0
|
1065 if (((fd = open (lock,O_RDWR,lock_protection)) >= 0) ||
|
yuuji@0
|
1066 (errno != ENOENT) || (chk_notsymlink (lock,&lsb) >= 0)) break;
|
yuuji@0
|
1067 case -1: /* name doesn't exist */
|
yuuji@0
|
1068 fd = open (lock,O_RDWR|O_CREAT|O_EXCL,lock_protection);
|
yuuji@0
|
1069 break;
|
yuuji@0
|
1070 default: /* multiple hard links */
|
yuuji@0
|
1071 mm_log ("hard link to lock name",ERROR);
|
yuuji@0
|
1072 syslog (LOG_CRIT,"SECURITY PROBLEM: hard link to lock name: %.80s",lock);
|
yuuji@0
|
1073 case 0: /* symlink (already did syslog) */
|
yuuji@0
|
1074 umask (mask); /* restore old mask */
|
yuuji@0
|
1075 return -1; /* fail: no lock file */
|
yuuji@0
|
1076 } while ((fd < 0) && (errno == EEXIST));
|
yuuji@0
|
1077 if (fd < 0) { /* failed to get file descriptor */
|
yuuji@0
|
1078 syslog (LOG_INFO,"Mailbox lock file %s open failure: %s",lock,
|
yuuji@0
|
1079 strerror (errno));
|
yuuji@0
|
1080 if (stat ("/tmp",&lsb))
|
yuuji@0
|
1081 syslog (LOG_CRIT,"SYSTEM ERROR: no /tmp: %s",strerror (errno));
|
yuuji@0
|
1082 else if ((lsb.st_mode & 01777) != 01777)
|
yuuji@0
|
1083 mm_log ("Can't lock for write: /tmp must have 1777 protection",WARN);
|
yuuji@0
|
1084 umask (mask); /* restore old mask */
|
yuuji@0
|
1085 return -1; /* fail: can't open lock file */
|
yuuji@0
|
1086 }
|
yuuji@0
|
1087
|
yuuji@0
|
1088 /* non-blocking form */
|
yuuji@0
|
1089 if (op & LOCK_NB) i = flock (fd,op);
|
yuuji@0
|
1090 else { /* blocking form */
|
yuuji@0
|
1091 (*mailblocknotify) (BLOCK_FILELOCK,NIL);
|
yuuji@0
|
1092 i = flock (fd,op);
|
yuuji@0
|
1093 (*mailblocknotify) (BLOCK_NONE,NIL);
|
yuuji@0
|
1094 }
|
yuuji@0
|
1095 if (i) { /* failed, get other process' PID */
|
yuuji@0
|
1096 if (pid && !fstat (fd,&fsb) && (i = min (fsb.st_size,MAILTMPLEN-1)) &&
|
yuuji@0
|
1097 (read (fd,tmp,i) == i) && !(tmp[i] = 0) && ((i = atol (tmp)) > 0))
|
yuuji@0
|
1098 *pid = i;
|
yuuji@0
|
1099 close (fd); /* failed, give up on lock */
|
yuuji@0
|
1100 umask (mask); /* restore old mask */
|
yuuji@0
|
1101 return -1; /* fail: can't lock */
|
yuuji@0
|
1102 }
|
yuuji@0
|
1103 /* make sure this lock is good for us */
|
yuuji@0
|
1104 if (!lstat (lock,&lsb) && ((lsb.st_mode & S_IFMT) != S_IFLNK) &&
|
yuuji@0
|
1105 !fstat (fd,&fsb) && (lsb.st_dev == fsb.st_dev) &&
|
yuuji@0
|
1106 (lsb.st_ino == fsb.st_ino) && (fsb.st_nlink == 1)) break;
|
yuuji@0
|
1107 close (fd); /* lock not right, drop fd and try again */
|
yuuji@0
|
1108 }
|
yuuji@0
|
1109 /* make sure mode OK (don't use fchmod()) */
|
yuuji@0
|
1110 chmod (lock,(int) lock_protection);
|
yuuji@0
|
1111 umask (mask); /* restore old mask */
|
yuuji@0
|
1112 return fd; /* success */
|
yuuji@0
|
1113 }
|
yuuji@0
|
1114
|
yuuji@0
|
1115 /* Check to make sure not a symlink
|
yuuji@0
|
1116 * Accepts: file name
|
yuuji@0
|
1117 * stat buffer
|
yuuji@0
|
1118 * Returns: -1 if doesn't exist, NIL if symlink, else number of hard links
|
yuuji@0
|
1119 */
|
yuuji@0
|
1120
|
yuuji@0
|
1121 long chk_notsymlink (char *name,void *sb)
|
yuuji@0
|
1122 {
|
yuuji@0
|
1123 struct stat *sbuf = (struct stat *) sb;
|
yuuji@0
|
1124 /* name exists? */
|
yuuji@0
|
1125 if (lstat (name,sbuf)) return -1;
|
yuuji@0
|
1126 /* forbid symbolic link */
|
yuuji@0
|
1127 if ((sbuf->st_mode & S_IFMT) == S_IFLNK) {
|
yuuji@0
|
1128 mm_log ("symbolic link on lock name",ERROR);
|
yuuji@0
|
1129 syslog (LOG_CRIT,"SECURITY PROBLEM: symbolic link on lock name: %.80s",
|
yuuji@0
|
1130 name);
|
yuuji@0
|
1131 return NIL;
|
yuuji@0
|
1132 }
|
yuuji@0
|
1133 return (long) sbuf->st_nlink; /* return number of hard links */
|
yuuji@0
|
1134 }
|
yuuji@0
|
1135
|
yuuji@0
|
1136
|
yuuji@0
|
1137 /* Unlock file descriptor
|
yuuji@0
|
1138 * Accepts: file descriptor
|
yuuji@0
|
1139 * lock file name from lockfd()
|
yuuji@0
|
1140 */
|
yuuji@0
|
1141
|
yuuji@0
|
1142 void unlockfd (int fd,char *lock)
|
yuuji@0
|
1143 {
|
yuuji@0
|
1144 /* delete the file if no sharers */
|
yuuji@0
|
1145 if (!flock (fd,LOCK_EX|LOCK_NB)) unlink (lock);
|
yuuji@0
|
1146 flock (fd,LOCK_UN); /* unlock it */
|
yuuji@0
|
1147 close (fd); /* close it */
|
yuuji@0
|
1148 }
|
yuuji@0
|
1149
|
yuuji@0
|
1150 /* Set proper file protection for mailbox
|
yuuji@0
|
1151 * Accepts: mailbox name
|
yuuji@0
|
1152 * actual file path name
|
yuuji@0
|
1153 * Returns: T, always
|
yuuji@0
|
1154 */
|
yuuji@0
|
1155
|
yuuji@0
|
1156 long set_mbx_protections (char *mailbox,char *path)
|
yuuji@0
|
1157 {
|
yuuji@0
|
1158 struct stat sbuf;
|
yuuji@0
|
1159 int mode = (int) mbx_protection;
|
yuuji@0
|
1160 if (*mailbox == '#') { /* possible namespace? */
|
yuuji@0
|
1161 if (((mailbox[1] == 'f') || (mailbox[1] == 'F')) &&
|
yuuji@0
|
1162 ((mailbox[2] == 't') || (mailbox[2] == 'T')) &&
|
yuuji@0
|
1163 ((mailbox[3] == 'p') || (mailbox[3] == 'P')) &&
|
yuuji@0
|
1164 (mailbox[4] == '/')) mode = (int) ftp_protection;
|
yuuji@0
|
1165 else if (((mailbox[1] == 'p') || (mailbox[1] == 'P')) &&
|
yuuji@0
|
1166 ((mailbox[2] == 'u') || (mailbox[2] == 'U')) &&
|
yuuji@0
|
1167 ((mailbox[3] == 'b') || (mailbox[3] == 'B')) &&
|
yuuji@0
|
1168 ((mailbox[4] == 'l') || (mailbox[4] == 'L')) &&
|
yuuji@0
|
1169 ((mailbox[5] == 'i') || (mailbox[5] == 'I')) &&
|
yuuji@0
|
1170 ((mailbox[6] == 'c') || (mailbox[6] == 'C')) &&
|
yuuji@0
|
1171 (mailbox[7] == '/')) mode = (int) public_protection;
|
yuuji@0
|
1172 else if (((mailbox[1] == 's') || (mailbox[1] == 'S')) &&
|
yuuji@0
|
1173 ((mailbox[2] == 'h') || (mailbox[2] == 'H')) &&
|
yuuji@0
|
1174 ((mailbox[3] == 'a') || (mailbox[3] == 'A')) &&
|
yuuji@0
|
1175 ((mailbox[4] == 'r') || (mailbox[4] == 'R')) &&
|
yuuji@0
|
1176 ((mailbox[5] == 'e') || (mailbox[5] == 'E')) &&
|
yuuji@0
|
1177 ((mailbox[6] == 'd') || (mailbox[6] == 'D')) &&
|
yuuji@0
|
1178 (mailbox[7] == '/')) mode = (int) shared_protection;
|
yuuji@0
|
1179 }
|
yuuji@0
|
1180 /* if a directory */
|
yuuji@0
|
1181 if (!stat (path,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFDIR)) {
|
yuuji@0
|
1182 /* set owner search if allow read or write */
|
yuuji@0
|
1183 if (mode & 0600) mode |= 0100;
|
yuuji@0
|
1184 if (mode & 060) mode |= 010;/* set group search if allow read or write */
|
yuuji@0
|
1185 if (mode & 06) mode |= 01; /* set world search if allow read or write */
|
yuuji@0
|
1186 /* preserve directory SGID bit */
|
yuuji@0
|
1187 if (sbuf.st_mode & S_ISGID) mode |= S_ISGID;
|
yuuji@0
|
1188 }
|
yuuji@0
|
1189 chmod (path,mode); /* set the new protection, ignore failure */
|
yuuji@0
|
1190 return LONGT;
|
yuuji@0
|
1191 }
|
yuuji@0
|
1192
|
yuuji@0
|
1193 /* Get proper directory protection
|
yuuji@0
|
1194 * Accepts: mailbox name
|
yuuji@0
|
1195 * Returns: directory mode, always
|
yuuji@0
|
1196 */
|
yuuji@0
|
1197
|
yuuji@0
|
1198 long get_dir_protection (char *mailbox)
|
yuuji@0
|
1199 {
|
yuuji@0
|
1200 if (*mailbox == '#') { /* possible namespace? */
|
yuuji@0
|
1201 if (((mailbox[1] == 'f') || (mailbox[1] == 'F')) &&
|
yuuji@0
|
1202 ((mailbox[2] == 't') || (mailbox[2] == 'T')) &&
|
yuuji@0
|
1203 ((mailbox[3] == 'p') || (mailbox[3] == 'P')) &&
|
yuuji@0
|
1204 (mailbox[4] == '/')) return ftp_dir_protection;
|
yuuji@0
|
1205 else if (((mailbox[1] == 'p') || (mailbox[1] == 'P')) &&
|
yuuji@0
|
1206 ((mailbox[2] == 'u') || (mailbox[2] == 'U')) &&
|
yuuji@0
|
1207 ((mailbox[3] == 'b') || (mailbox[3] == 'B')) &&
|
yuuji@0
|
1208 ((mailbox[4] == 'l') || (mailbox[4] == 'L')) &&
|
yuuji@0
|
1209 ((mailbox[5] == 'i') || (mailbox[5] == 'I')) &&
|
yuuji@0
|
1210 ((mailbox[6] == 'c') || (mailbox[6] == 'C')) &&
|
yuuji@0
|
1211 (mailbox[7] == '/')) return public_dir_protection;
|
yuuji@0
|
1212 else if (((mailbox[1] == 's') || (mailbox[1] == 'S')) &&
|
yuuji@0
|
1213 ((mailbox[2] == 'h') || (mailbox[2] == 'H')) &&
|
yuuji@0
|
1214 ((mailbox[3] == 'a') || (mailbox[3] == 'A')) &&
|
yuuji@0
|
1215 ((mailbox[4] == 'r') || (mailbox[4] == 'R')) &&
|
yuuji@0
|
1216 ((mailbox[5] == 'e') || (mailbox[5] == 'E')) &&
|
yuuji@0
|
1217 ((mailbox[6] == 'd') || (mailbox[6] == 'D')) &&
|
yuuji@0
|
1218 (mailbox[7] == '/')) return shared_dir_protection;
|
yuuji@0
|
1219 }
|
yuuji@0
|
1220 return dir_protection;
|
yuuji@0
|
1221 }
|
yuuji@0
|
1222
|
yuuji@0
|
1223 /* Determine default prototype stream to user
|
yuuji@0
|
1224 * Accepts: type (NIL for create, T for append)
|
yuuji@0
|
1225 * Returns: default prototype stream
|
yuuji@0
|
1226 */
|
yuuji@0
|
1227
|
yuuji@0
|
1228 MAILSTREAM *default_proto (long type)
|
yuuji@0
|
1229 {
|
yuuji@0
|
1230 myusername (); /* make sure initialized */
|
yuuji@0
|
1231 /* return default driver's prototype */
|
yuuji@0
|
1232 return type ? appendProto : createProto;
|
yuuji@0
|
1233 }
|
yuuji@0
|
1234
|
yuuji@0
|
1235
|
yuuji@0
|
1236 /* Set up user flags for stream
|
yuuji@0
|
1237 * Accepts: MAIL stream
|
yuuji@0
|
1238 * Returns: MAIL stream with user flags set up
|
yuuji@0
|
1239 */
|
yuuji@0
|
1240
|
yuuji@0
|
1241 MAILSTREAM *user_flags (MAILSTREAM *stream)
|
yuuji@0
|
1242 {
|
yuuji@0
|
1243 int i;
|
yuuji@0
|
1244 myusername (); /* make sure initialized */
|
yuuji@0
|
1245 for (i = 0; i < NUSERFLAGS && userFlags[i]; ++i)
|
yuuji@0
|
1246 if (!stream->user_flags[i]) stream->user_flags[i] = cpystr (userFlags[i]);
|
yuuji@0
|
1247 return stream;
|
yuuji@0
|
1248 }
|
yuuji@0
|
1249
|
yuuji@0
|
1250
|
yuuji@0
|
1251 /* Return nth user flag
|
yuuji@0
|
1252 * Accepts: user flag number
|
yuuji@0
|
1253 * Returns: flag
|
yuuji@0
|
1254 */
|
yuuji@0
|
1255
|
yuuji@0
|
1256 char *default_user_flag (unsigned long i)
|
yuuji@0
|
1257 {
|
yuuji@0
|
1258 myusername (); /* make sure initialized */
|
yuuji@0
|
1259 return userFlags[i];
|
yuuji@0
|
1260 }
|
yuuji@0
|
1261
|
yuuji@0
|
1262 /* Default block notify routine
|
yuuji@0
|
1263 * Accepts: reason for calling
|
yuuji@0
|
1264 * data
|
yuuji@0
|
1265 * Returns: data
|
yuuji@0
|
1266 */
|
yuuji@0
|
1267
|
yuuji@0
|
1268 void *mm_blocknotify (int reason,void *data)
|
yuuji@0
|
1269 {
|
yuuji@0
|
1270 void *ret = data;
|
yuuji@0
|
1271 switch (reason) {
|
yuuji@0
|
1272 case BLOCK_SENSITIVE: /* entering sensitive code */
|
yuuji@0
|
1273 ret = (void *) alarm (0);
|
yuuji@0
|
1274 break;
|
yuuji@0
|
1275 case BLOCK_NONSENSITIVE: /* exiting sensitive code */
|
yuuji@0
|
1276 if ((unsigned int) data) alarm ((unsigned int) data);
|
yuuji@0
|
1277 break;
|
yuuji@0
|
1278 default: /* ignore all other reasons */
|
yuuji@0
|
1279 break;
|
yuuji@0
|
1280 }
|
yuuji@0
|
1281 return ret;
|
yuuji@0
|
1282 }
|