masqmail

changeset 332:63efd381e27b

refactoring, partly also related to set_euidgid()
author markus schnalke <meillo@marmaro.de>
date Sat, 27 Aug 2011 16:21:17 +0200
parents e507c854a63e
children 0bd27f603910
files src/listen.c src/local.c
diffstat 2 files changed, 98 insertions(+), 109 deletions(-) [+]
line diff
     1.1 --- a/src/listen.c	Sat Aug 27 16:19:07 2011 +0200
     1.2 +++ b/src/listen.c	Sat Aug 27 16:21:17 2011 +0200
     1.3 @@ -131,14 +131,7 @@
     1.4  
     1.5  	/* now that we have our socket(s), we can give up root privileges */
     1.6  	if (!conf.run_as_user) {
     1.7 -		if (setegid(conf.mail_gid) != 0) {
     1.8 -			logwrite(LOG_ALERT, "could not change gid to %d: %s\n", conf.mail_gid, strerror(errno));
     1.9 -			exit(1);
    1.10 -		}
    1.11 -		if (seteuid(conf.mail_uid) != 0) {
    1.12 -			logwrite(LOG_ALERT, "could not change uid to %d: %s\n", conf.mail_uid, strerror(errno));
    1.13 -			exit(1);
    1.14 -		}
    1.15 +		set_euidgid(conf.mail_uid, conf.mail_gid, NULL, NULL);
    1.16  	}
    1.17  
    1.18  	/*  sel_ret = 0; */
     2.1 --- a/src/local.c	Sat Aug 27 16:19:07 2011 +0200
     2.2 +++ b/src/local.c	Sat Aug 27 16:21:17 2011 +0200
     2.3 @@ -54,94 +54,93 @@
     2.4  {
     2.5  	struct passwd *pw;
     2.6  	gboolean ok = FALSE;
     2.7 +	uid_t saved_uid = geteuid();
     2.8 +	gid_t saved_gid = getegid();
     2.9 +	gboolean uid_ok = TRUE, gid_ok = TRUE;
    2.10 +	gchar *filename;
    2.11 +	FILE *out;
    2.12  
    2.13  	/* headers may be special for a local delivery */
    2.14 -	if (hdr_list == NULL)
    2.15 +	if (!hdr_list)
    2.16  		hdr_list = msg->hdr_list;
    2.17  
    2.18 -	if ((pw = getpwnam(user))) {
    2.19 -		uid_t saved_uid = geteuid();
    2.20 -		gid_t saved_gid = getegid();
    2.21 -		gboolean uid_ok = TRUE, gid_ok = TRUE;
    2.22 -
    2.23 -		if (!conf.run_as_user) {
    2.24 -			uid_ok = (seteuid(0) == 0);
    2.25 -			if (uid_ok) {
    2.26 -				gid_ok = (setegid(conf.mail_gid) == 0);
    2.27 -				uid_ok = (seteuid(pw->pw_uid) == 0);
    2.28 -			}
    2.29 -		}
    2.30 -
    2.31 -		DEBUG(5) debugf("running as euid %d, egid %d\n", geteuid(), getegid());
    2.32 -
    2.33 -		if (uid_ok && gid_ok) {
    2.34 -			gchar *filename;
    2.35 -			FILE *out;
    2.36 -
    2.37 -			filename = g_strdup_printf("%s/%s", conf.mail_dir, user);
    2.38 -			if ((out = fopen(filename, "a"))) {
    2.39 -#ifdef USE_LIBLOCKFILE
    2.40 -				gint err;
    2.41 -				/* lock file using liblockfile */
    2.42 -				err = maillock(user, 3);
    2.43 -				if (err == 0) {
    2.44 -#else
    2.45 -				/* lock file: */
    2.46 -				struct flock lock;
    2.47 -				lock.l_type = F_WRLCK;
    2.48 -				lock.l_whence = SEEK_END;
    2.49 -				lock.l_start = lock.l_len = 0;
    2.50 -				if (fcntl(fileno(out), F_SETLK, &lock) != -1) {
    2.51 -#endif
    2.52 -					fchmod(fileno(out), 0600);
    2.53 -					message_stream(out, msg, hdr_list, MSGSTR_FROMLINE | MSGSTR_FROMHACK);
    2.54 -					ok = TRUE;
    2.55 -
    2.56 -					/* close when still user */
    2.57 -					fclose(out);
    2.58 -#ifdef USE_LIBLOCKFILE
    2.59 -					mailunlock();
    2.60 -#endif
    2.61 -				} else {
    2.62 -					fclose(out);
    2.63 -#ifdef USE_LIBLOCKFILE
    2.64 -					DEBUG(3) debugf("could not lock file %s: error %d\n", filename, err);
    2.65 -				}  /* XEmacs indenting convenience... */
    2.66 -#else
    2.67 -					DEBUG(3) debugf("could not lock file %s: %s\n", filename, strerror(errno));
    2.68 -				}
    2.69 -#endif
    2.70 -			} else {
    2.71 -				logwrite(LOG_ALERT, "could not open file %s: %s\n", filename, strerror(errno));
    2.72 -			}
    2.73 -			g_free(filename);
    2.74 -
    2.75 -			if (!conf.run_as_user) {
    2.76 -				uid_ok = (seteuid(0) == 0);
    2.77 -				if (uid_ok) {
    2.78 -					gid_ok = (setegid(saved_gid) == 0);
    2.79 -					uid_ok = (seteuid(saved_uid) == 0);
    2.80 -				}
    2.81 -			}
    2.82 -
    2.83 -			if (!uid_ok || !gid_ok) {
    2.84 -				/* FIXME: if this fails we HAVE to exit, because we shall not run
    2.85 -				   with some users id. But we do not return, and so this message
    2.86 -				   will not be finished, so the user will get the message again
    2.87 -				   next time a delivery is attempted... */
    2.88 -				logwrite(LOG_ALERT, "could not set back uid or gid after local delivery: %s\n", strerror(errno));
    2.89 -				logwrite(LOG_ALERT, "uid=%d, gid=%d, euid=%d, egid=%d, want = %d, %d\n",
    2.90 -				         getuid(), getgid(), geteuid(), getegid(), saved_uid, saved_gid);
    2.91 -				exit(1);
    2.92 -			}
    2.93 -		} else {
    2.94 -			logwrite(LOG_ALERT, "could not set uid or gid for local delivery, uid = %d: %s\n", pw->pw_uid, strerror(errno));
    2.95 -		}
    2.96 -	} else {
    2.97 +	if (!(pw = getpwnam(user))) {
    2.98  		logwrite(LOG_ALERT, "could not find password entry for user %s\n", user);
    2.99  		errno = ENOENT;  /* getpwnam does not set errno correctly */
   2.100 +		return FALSE;
   2.101  	}
   2.102  
   2.103 +	if (!conf.run_as_user) {
   2.104 +		uid_ok = (seteuid(0) == 0);
   2.105 +		if (uid_ok) {
   2.106 +			gid_ok = (setegid(conf.mail_gid) == 0);
   2.107 +			uid_ok = (seteuid(pw->pw_uid) == 0);
   2.108 +		}
   2.109 +		if (!uid_ok || !gid_ok) {
   2.110 +			logwrite(LOG_ALERT, "could not set uid or gid for local delivery, uid = %d: %s\n", pw->pw_uid, strerror(errno));
   2.111 +			return FALSE;
   2.112 +		}
   2.113 +	}
   2.114 +
   2.115 +	DEBUG(5) debugf("running as euid %d, egid %d\n", geteuid(), getegid());
   2.116 +
   2.117 +	filename = g_strdup_printf("%s/%s", conf.mail_dir, user);
   2.118 +	if (!(out = fopen(filename, "a"))) {
   2.119 +		logwrite(LOG_ALERT, "could not open file %s: %s\n", filename, strerror(errno));
   2.120 +	} else {
   2.121 +#ifdef USE_LIBLOCKFILE
   2.122 +		gint err;
   2.123 +		/* lock file using liblockfile */
   2.124 +		err = maillock(user, 3);
   2.125 +		if (err == 0) {
   2.126 +#else
   2.127 +		/* lock file: */
   2.128 +		struct flock lock;
   2.129 +		lock.l_type = F_WRLCK;
   2.130 +		lock.l_whence = SEEK_END;
   2.131 +		lock.l_start = lock.l_len = 0;
   2.132 +		if (fcntl(fileno(out), F_SETLK, &lock) != -1) {
   2.133 +#endif
   2.134 +			fchmod(fileno(out), 0600);
   2.135 +			message_stream(out, msg, hdr_list, MSGSTR_FROMLINE | MSGSTR_FROMHACK);
   2.136 +			ok = TRUE;
   2.137 +
   2.138 +			/* close when still user */
   2.139 +			fclose(out);
   2.140 +#ifdef USE_LIBLOCKFILE
   2.141 +			mailunlock();
   2.142 +#endif
   2.143 +		} else {
   2.144 +			fclose(out);
   2.145 +#ifdef USE_LIBLOCKFILE
   2.146 +			DEBUG(3) debugf("could not lock file %s: error %d\n", filename, err);
   2.147 +		}  /* XEmacs indenting convenience... */
   2.148 +#else
   2.149 +			DEBUG(3) debugf("could not lock file %s: %s\n", filename, strerror(errno));
   2.150 +		}
   2.151 +#endif
   2.152 +	}
   2.153 +	g_free(filename);
   2.154 +
   2.155 +	if (!conf.run_as_user) {
   2.156 +		uid_ok = (seteuid(0) == 0);
   2.157 +		if (uid_ok) {
   2.158 +			gid_ok = (setegid(saved_gid) == 0);
   2.159 +			uid_ok = (seteuid(saved_uid) == 0);
   2.160 +		}
   2.161 +	}
   2.162 +
   2.163 +	if (!uid_ok || !gid_ok) {
   2.164 +		/* FIXME: if this fails we HAVE to exit, because we shall not run
   2.165 +		   with some users id. But we do not return, and so this message
   2.166 +		   will not be finished, so the user will get the message again
   2.167 +		   next time a delivery is attempted... */
   2.168 +		logwrite(LOG_ALERT, "could not set back uid or gid after local delivery: %s\n", strerror(errno));
   2.169 +		logwrite(LOG_ALERT, "uid=%d, gid=%d, euid=%d, egid=%d, want = %d, %d\n",
   2.170 +		         getuid(), getgid(), geteuid(), getegid(), saved_uid, saved_gid);
   2.171 +		logwrite(LOG_ALERT, "In case of trouble, see local.c:append_file() for details.\n", strerror(errno));
   2.172 +		exit(1);
   2.173 +	}
   2.174  	return ok;
   2.175  }
   2.176  
   2.177 @@ -157,6 +156,7 @@
   2.178  	pid_t pid;
   2.179  	void (*old_signal) (int);
   2.180  	int status;
   2.181 +	address *ancestor = addr_find_ancestor(rcpt);
   2.182  
   2.183  	/* set uid and gid to the mail ids */
   2.184  	if (!conf.run_as_user) {
   2.185 @@ -164,33 +164,30 @@
   2.186  	}
   2.187  
   2.188  	/* set environment */
   2.189 -	{
   2.190 -		gint i = 0;
   2.191 -		address *ancestor = addr_find_ancestor(rcpt);
   2.192 +	n = 0;
   2.193 +	envp[n++] = g_strdup_printf("SENDER=%s@%s", msg->return_path->local_part, msg->return_path->domain);
   2.194 +	envp[n++] = g_strdup_printf("SENDER_DOMAIN=%s", msg->return_path->domain);
   2.195 +	envp[n++] = g_strdup_printf("SENDER_LOCAL=%s", msg->return_path->local_part);
   2.196 +	envp[n++] = g_strdup_printf("RECEIVED_HOST=%s", msg->received_host ? msg->received_host : "");
   2.197  
   2.198 -		envp[i++] = g_strdup_printf("SENDER=%s@%s", msg->return_path->local_part, msg->return_path->domain);
   2.199 -		envp[i++] = g_strdup_printf("SENDER_DOMAIN=%s", msg->return_path->domain);
   2.200 -		envp[i++] = g_strdup_printf("SENDER_LOCAL=%s", msg->return_path->local_part);
   2.201 -		envp[i++] = g_strdup_printf("RECEIVED_HOST=%s", msg->received_host ? msg->received_host : "");
   2.202 +	envp[n++] = g_strdup_printf("RETURN_PATH=%s@%s", msg->return_path->local_part, msg->return_path->domain);
   2.203 +	envp[n++] = g_strdup_printf("DOMAIN=%s", ancestor->domain);
   2.204  
   2.205 -		envp[i++] = g_strdup_printf("RETURN_PATH=%s@%s", msg->return_path->local_part, msg->return_path->domain);
   2.206 -		envp[i++] = g_strdup_printf("DOMAIN=%s", ancestor->domain);
   2.207 +	envp[n++] = g_strdup_printf("LOCAL_PART=%s", ancestor->local_part);
   2.208 +	envp[n++] = g_strdup_printf("USER=%s", ancestor->local_part);
   2.209 +	envp[n++] = g_strdup_printf("LOGNAME=%s", ancestor->local_part);
   2.210  
   2.211 -		envp[i++] = g_strdup_printf("LOCAL_PART=%s", ancestor->local_part);
   2.212 -		envp[i++] = g_strdup_printf("USER=%s", ancestor->local_part);
   2.213 -		envp[i++] = g_strdup_printf("LOGNAME=%s", ancestor->local_part);
   2.214 +	envp[n++] = g_strdup_printf("MESSAGE_ID=%s", msg->uid);
   2.215 +	envp[n++] = g_strdup_printf("QUALIFY_DOMAIN=%s", conf.host_name);
   2.216  
   2.217 -		envp[i++] = g_strdup_printf("MESSAGE_ID=%s", msg->uid);
   2.218 -		envp[i++] = g_strdup_printf("QUALIFY_DOMAIN=%s", conf.host_name);
   2.219 -
   2.220 -		envp[i] = NULL;
   2.221 -		n = i;
   2.222 -	}
   2.223 +	envp[n] = NULL;
   2.224  
   2.225  	old_signal = signal(SIGCHLD, SIG_DFL);
   2.226  
   2.227  	out = peidopen(cmd, "w", envp, &pid, conf.mail_uid, conf.mail_gid);
   2.228 -	if (out != NULL) {
   2.229 +	if (!out) {
   2.230 +		logwrite(LOG_ALERT, "could not open pipe '%s': %s\n", cmd, strerror(errno));
   2.231 +	} else {
   2.232  		message_stream(out, msg, hdr_list, flags);
   2.233  
   2.234  		fclose(out);
   2.235 @@ -206,8 +203,7 @@
   2.236  		} else
   2.237  			ok = TRUE;
   2.238  
   2.239 -	} else
   2.240 -		logwrite(LOG_ALERT, "could not open pipe '%s': %s\n", cmd, strerror(errno));
   2.241 +	}
   2.242  
   2.243  	signal(SIGCHLD, old_signal);
   2.244