masqmail

diff src/local.c @ 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 fc1c6425c024
children 41958685480d
line diff
     1.1 --- a/src/local.c	Sat Aug 27 16:19:07 2011 +0200
     1.2 +++ b/src/local.c	Sat Aug 27 16:21:17 2011 +0200
     1.3 @@ -54,94 +54,93 @@
     1.4  {
     1.5  	struct passwd *pw;
     1.6  	gboolean ok = FALSE;
     1.7 +	uid_t saved_uid = geteuid();
     1.8 +	gid_t saved_gid = getegid();
     1.9 +	gboolean uid_ok = TRUE, gid_ok = TRUE;
    1.10 +	gchar *filename;
    1.11 +	FILE *out;
    1.12  
    1.13  	/* headers may be special for a local delivery */
    1.14 -	if (hdr_list == NULL)
    1.15 +	if (!hdr_list)
    1.16  		hdr_list = msg->hdr_list;
    1.17  
    1.18 -	if ((pw = getpwnam(user))) {
    1.19 -		uid_t saved_uid = geteuid();
    1.20 -		gid_t saved_gid = getegid();
    1.21 -		gboolean uid_ok = TRUE, gid_ok = TRUE;
    1.22 -
    1.23 -		if (!conf.run_as_user) {
    1.24 -			uid_ok = (seteuid(0) == 0);
    1.25 -			if (uid_ok) {
    1.26 -				gid_ok = (setegid(conf.mail_gid) == 0);
    1.27 -				uid_ok = (seteuid(pw->pw_uid) == 0);
    1.28 -			}
    1.29 -		}
    1.30 -
    1.31 -		DEBUG(5) debugf("running as euid %d, egid %d\n", geteuid(), getegid());
    1.32 -
    1.33 -		if (uid_ok && gid_ok) {
    1.34 -			gchar *filename;
    1.35 -			FILE *out;
    1.36 -
    1.37 -			filename = g_strdup_printf("%s/%s", conf.mail_dir, user);
    1.38 -			if ((out = fopen(filename, "a"))) {
    1.39 -#ifdef USE_LIBLOCKFILE
    1.40 -				gint err;
    1.41 -				/* lock file using liblockfile */
    1.42 -				err = maillock(user, 3);
    1.43 -				if (err == 0) {
    1.44 -#else
    1.45 -				/* lock file: */
    1.46 -				struct flock lock;
    1.47 -				lock.l_type = F_WRLCK;
    1.48 -				lock.l_whence = SEEK_END;
    1.49 -				lock.l_start = lock.l_len = 0;
    1.50 -				if (fcntl(fileno(out), F_SETLK, &lock) != -1) {
    1.51 -#endif
    1.52 -					fchmod(fileno(out), 0600);
    1.53 -					message_stream(out, msg, hdr_list, MSGSTR_FROMLINE | MSGSTR_FROMHACK);
    1.54 -					ok = TRUE;
    1.55 -
    1.56 -					/* close when still user */
    1.57 -					fclose(out);
    1.58 -#ifdef USE_LIBLOCKFILE
    1.59 -					mailunlock();
    1.60 -#endif
    1.61 -				} else {
    1.62 -					fclose(out);
    1.63 -#ifdef USE_LIBLOCKFILE
    1.64 -					DEBUG(3) debugf("could not lock file %s: error %d\n", filename, err);
    1.65 -				}  /* XEmacs indenting convenience... */
    1.66 -#else
    1.67 -					DEBUG(3) debugf("could not lock file %s: %s\n", filename, strerror(errno));
    1.68 -				}
    1.69 -#endif
    1.70 -			} else {
    1.71 -				logwrite(LOG_ALERT, "could not open file %s: %s\n", filename, strerror(errno));
    1.72 -			}
    1.73 -			g_free(filename);
    1.74 -
    1.75 -			if (!conf.run_as_user) {
    1.76 -				uid_ok = (seteuid(0) == 0);
    1.77 -				if (uid_ok) {
    1.78 -					gid_ok = (setegid(saved_gid) == 0);
    1.79 -					uid_ok = (seteuid(saved_uid) == 0);
    1.80 -				}
    1.81 -			}
    1.82 -
    1.83 -			if (!uid_ok || !gid_ok) {
    1.84 -				/* FIXME: if this fails we HAVE to exit, because we shall not run
    1.85 -				   with some users id. But we do not return, and so this message
    1.86 -				   will not be finished, so the user will get the message again
    1.87 -				   next time a delivery is attempted... */
    1.88 -				logwrite(LOG_ALERT, "could not set back uid or gid after local delivery: %s\n", strerror(errno));
    1.89 -				logwrite(LOG_ALERT, "uid=%d, gid=%d, euid=%d, egid=%d, want = %d, %d\n",
    1.90 -				         getuid(), getgid(), geteuid(), getegid(), saved_uid, saved_gid);
    1.91 -				exit(1);
    1.92 -			}
    1.93 -		} else {
    1.94 -			logwrite(LOG_ALERT, "could not set uid or gid for local delivery, uid = %d: %s\n", pw->pw_uid, strerror(errno));
    1.95 -		}
    1.96 -	} else {
    1.97 +	if (!(pw = getpwnam(user))) {
    1.98  		logwrite(LOG_ALERT, "could not find password entry for user %s\n", user);
    1.99  		errno = ENOENT;  /* getpwnam does not set errno correctly */
   1.100 +		return FALSE;
   1.101  	}
   1.102  
   1.103 +	if (!conf.run_as_user) {
   1.104 +		uid_ok = (seteuid(0) == 0);
   1.105 +		if (uid_ok) {
   1.106 +			gid_ok = (setegid(conf.mail_gid) == 0);
   1.107 +			uid_ok = (seteuid(pw->pw_uid) == 0);
   1.108 +		}
   1.109 +		if (!uid_ok || !gid_ok) {
   1.110 +			logwrite(LOG_ALERT, "could not set uid or gid for local delivery, uid = %d: %s\n", pw->pw_uid, strerror(errno));
   1.111 +			return FALSE;
   1.112 +		}
   1.113 +	}
   1.114 +
   1.115 +	DEBUG(5) debugf("running as euid %d, egid %d\n", geteuid(), getegid());
   1.116 +
   1.117 +	filename = g_strdup_printf("%s/%s", conf.mail_dir, user);
   1.118 +	if (!(out = fopen(filename, "a"))) {
   1.119 +		logwrite(LOG_ALERT, "could not open file %s: %s\n", filename, strerror(errno));
   1.120 +	} else {
   1.121 +#ifdef USE_LIBLOCKFILE
   1.122 +		gint err;
   1.123 +		/* lock file using liblockfile */
   1.124 +		err = maillock(user, 3);
   1.125 +		if (err == 0) {
   1.126 +#else
   1.127 +		/* lock file: */
   1.128 +		struct flock lock;
   1.129 +		lock.l_type = F_WRLCK;
   1.130 +		lock.l_whence = SEEK_END;
   1.131 +		lock.l_start = lock.l_len = 0;
   1.132 +		if (fcntl(fileno(out), F_SETLK, &lock) != -1) {
   1.133 +#endif
   1.134 +			fchmod(fileno(out), 0600);
   1.135 +			message_stream(out, msg, hdr_list, MSGSTR_FROMLINE | MSGSTR_FROMHACK);
   1.136 +			ok = TRUE;
   1.137 +
   1.138 +			/* close when still user */
   1.139 +			fclose(out);
   1.140 +#ifdef USE_LIBLOCKFILE
   1.141 +			mailunlock();
   1.142 +#endif
   1.143 +		} else {
   1.144 +			fclose(out);
   1.145 +#ifdef USE_LIBLOCKFILE
   1.146 +			DEBUG(3) debugf("could not lock file %s: error %d\n", filename, err);
   1.147 +		}  /* XEmacs indenting convenience... */
   1.148 +#else
   1.149 +			DEBUG(3) debugf("could not lock file %s: %s\n", filename, strerror(errno));
   1.150 +		}
   1.151 +#endif
   1.152 +	}
   1.153 +	g_free(filename);
   1.154 +
   1.155 +	if (!conf.run_as_user) {
   1.156 +		uid_ok = (seteuid(0) == 0);
   1.157 +		if (uid_ok) {
   1.158 +			gid_ok = (setegid(saved_gid) == 0);
   1.159 +			uid_ok = (seteuid(saved_uid) == 0);
   1.160 +		}
   1.161 +	}
   1.162 +
   1.163 +	if (!uid_ok || !gid_ok) {
   1.164 +		/* FIXME: if this fails we HAVE to exit, because we shall not run
   1.165 +		   with some users id. But we do not return, and so this message
   1.166 +		   will not be finished, so the user will get the message again
   1.167 +		   next time a delivery is attempted... */
   1.168 +		logwrite(LOG_ALERT, "could not set back uid or gid after local delivery: %s\n", strerror(errno));
   1.169 +		logwrite(LOG_ALERT, "uid=%d, gid=%d, euid=%d, egid=%d, want = %d, %d\n",
   1.170 +		         getuid(), getgid(), geteuid(), getegid(), saved_uid, saved_gid);
   1.171 +		logwrite(LOG_ALERT, "In case of trouble, see local.c:append_file() for details.\n", strerror(errno));
   1.172 +		exit(1);
   1.173 +	}
   1.174  	return ok;
   1.175  }
   1.176  
   1.177 @@ -157,6 +156,7 @@
   1.178  	pid_t pid;
   1.179  	void (*old_signal) (int);
   1.180  	int status;
   1.181 +	address *ancestor = addr_find_ancestor(rcpt);
   1.182  
   1.183  	/* set uid and gid to the mail ids */
   1.184  	if (!conf.run_as_user) {
   1.185 @@ -164,33 +164,30 @@
   1.186  	}
   1.187  
   1.188  	/* set environment */
   1.189 -	{
   1.190 -		gint i = 0;
   1.191 -		address *ancestor = addr_find_ancestor(rcpt);
   1.192 +	n = 0;
   1.193 +	envp[n++] = g_strdup_printf("SENDER=%s@%s", msg->return_path->local_part, msg->return_path->domain);
   1.194 +	envp[n++] = g_strdup_printf("SENDER_DOMAIN=%s", msg->return_path->domain);
   1.195 +	envp[n++] = g_strdup_printf("SENDER_LOCAL=%s", msg->return_path->local_part);
   1.196 +	envp[n++] = g_strdup_printf("RECEIVED_HOST=%s", msg->received_host ? msg->received_host : "");
   1.197  
   1.198 -		envp[i++] = g_strdup_printf("SENDER=%s@%s", msg->return_path->local_part, msg->return_path->domain);
   1.199 -		envp[i++] = g_strdup_printf("SENDER_DOMAIN=%s", msg->return_path->domain);
   1.200 -		envp[i++] = g_strdup_printf("SENDER_LOCAL=%s", msg->return_path->local_part);
   1.201 -		envp[i++] = g_strdup_printf("RECEIVED_HOST=%s", msg->received_host ? msg->received_host : "");
   1.202 +	envp[n++] = g_strdup_printf("RETURN_PATH=%s@%s", msg->return_path->local_part, msg->return_path->domain);
   1.203 +	envp[n++] = g_strdup_printf("DOMAIN=%s", ancestor->domain);
   1.204  
   1.205 -		envp[i++] = g_strdup_printf("RETURN_PATH=%s@%s", msg->return_path->local_part, msg->return_path->domain);
   1.206 -		envp[i++] = g_strdup_printf("DOMAIN=%s", ancestor->domain);
   1.207 +	envp[n++] = g_strdup_printf("LOCAL_PART=%s", ancestor->local_part);
   1.208 +	envp[n++] = g_strdup_printf("USER=%s", ancestor->local_part);
   1.209 +	envp[n++] = g_strdup_printf("LOGNAME=%s", ancestor->local_part);
   1.210  
   1.211 -		envp[i++] = g_strdup_printf("LOCAL_PART=%s", ancestor->local_part);
   1.212 -		envp[i++] = g_strdup_printf("USER=%s", ancestor->local_part);
   1.213 -		envp[i++] = g_strdup_printf("LOGNAME=%s", ancestor->local_part);
   1.214 +	envp[n++] = g_strdup_printf("MESSAGE_ID=%s", msg->uid);
   1.215 +	envp[n++] = g_strdup_printf("QUALIFY_DOMAIN=%s", conf.host_name);
   1.216  
   1.217 -		envp[i++] = g_strdup_printf("MESSAGE_ID=%s", msg->uid);
   1.218 -		envp[i++] = g_strdup_printf("QUALIFY_DOMAIN=%s", conf.host_name);
   1.219 -
   1.220 -		envp[i] = NULL;
   1.221 -		n = i;
   1.222 -	}
   1.223 +	envp[n] = NULL;
   1.224  
   1.225  	old_signal = signal(SIGCHLD, SIG_DFL);
   1.226  
   1.227  	out = peidopen(cmd, "w", envp, &pid, conf.mail_uid, conf.mail_gid);
   1.228 -	if (out != NULL) {
   1.229 +	if (!out) {
   1.230 +		logwrite(LOG_ALERT, "could not open pipe '%s': %s\n", cmd, strerror(errno));
   1.231 +	} else {
   1.232  		message_stream(out, msg, hdr_list, flags);
   1.233  
   1.234  		fclose(out);
   1.235 @@ -206,8 +203,7 @@
   1.236  		} else
   1.237  			ok = TRUE;
   1.238  
   1.239 -	} else
   1.240 -		logwrite(LOG_ALERT, "could not open pipe '%s': %s\n", cmd, strerror(errno));
   1.241 +	}
   1.242  
   1.243  	signal(SIGCHLD, old_signal);
   1.244