diff --git a/pppd/auth.c b/pppd/auth.c index 42a140b9..f017d406 100644 --- a/pppd/auth.c +++ b/pppd/auth.c @@ -297,7 +297,7 @@ static int scan_authfile(FILE *, char *, char *, char *, struct wordlist **, struct wordlist **, char *); static void free_wordlist (struct wordlist *); -static void auth_script (char *); +static void auth_script (char *, const char*); static void auth_script_done (void *); static void set_allowed_addrs (int, struct wordlist *, struct wordlist *); static int some_ip_ok (struct wordlist *); @@ -305,7 +305,6 @@ static int setupapfile (char **); static int privgroup (char **); static int set_noauth_addr (char **); static int set_permitted_number (char **); -static void check_access (int, const char *); static int wordlist_count (struct wordlist *); static void check_maxoctets (void *); @@ -516,6 +515,7 @@ setupapfile(char **argv) uid_t euid; char u[MAXNAMELEN], p[MAXSECRETLEN]; char *fname; + int check_res; lcp_allowoptions[0].neg_upap = 1; @@ -530,6 +530,7 @@ setupapfile(char **argv) return 0; } ufile = fopen(fname, "r"); + check_res = ufile && ppp_check_access(fileno(ufile), fname, PPP_FT_SECRET); if (seteuid(euid) == -1) fatal("unable to regain privileges: %m"); if (ufile == NULL) { @@ -537,7 +538,11 @@ setupapfile(char **argv) free(fname); return 0; } - check_access(fileno(ufile), fname); + if (!check_res) { + fclose(ufile); + free(fname); + return 0; + } uafname = fname; /* get username */ @@ -785,7 +790,7 @@ link_down(int unit) if (auth_script_state == s_up && auth_script_pid == 0) { ppp_get_link_stats(NULL); auth_script_state = s_down; - auth_script(path_auth_down); + auth_script(path_auth_down, "auth-up"); } } if (!mp_on()) @@ -933,7 +938,7 @@ network_phase(int unit) auth_state = s_up; if (auth_script_state == s_down && auth_script_pid == 0) { auth_script_state = s_up; - auth_script(path_auth_up); + auth_script(path_auth_up, "auth-up"); } } @@ -1551,12 +1556,11 @@ check_passwd(int unit, } else { int fd = fileno(f); - if (!ppp_check_access(fd, filename, 0)) { + if (!ppp_check_access(fd, filename, PPP_FT_SECRET)) { fclose(f); ppp_explicit_bzero(passwd, sizeof(passwd)); return UPAP_AUTHNAK; } - check_access(fd, filename); if (scan_authfile(f, user, our_name, secret, &addrs, &opts, filename) < 0) { warn("no PAP secret found for %s", user); } else { @@ -1657,11 +1661,10 @@ null_login(int unit) if (f == NULL) return 0; fd = fileno(f); - if (!ppp_check_access(fd, filename, 0)) { + if (!ppp_check_access(fd, filename, PPP_FT_SECRET)) { fclose(f); return 0; } - check_access(fd, filename); i = scan_authfile(f, "", our_name, secret, &addrs, &opts, filename); ret = i >= 0 && secret[0] == 0; @@ -1707,7 +1710,10 @@ get_pap_passwd(char *passwd) f = fopen(filename, "r"); if (f == NULL) return 0; - check_access(fileno(f), filename); + if (!ppp_check_access(fileno(f), filename, PPP_FT_SECRET)) { + fclose(f); + return 0; + } ret = scan_authfile(f, user, (remote_name[0]? remote_name: NULL), secret, NULL, NULL, filename); @@ -1745,7 +1751,7 @@ have_pap_secret(int *lacks_ipp) if (f == NULL) return 0; - if (!ppp_check_access(fileno(f), filename, 0)) { + if (!ppp_check_access(fileno(f), filename, PPP_FT_SECRET)) { fclose(f); return 0; } @@ -1791,7 +1797,7 @@ have_chap_secret(char *client, char *server, if (f == NULL) return 0; - if (!ppp_check_access(fileno(f), filename, 0)) { + if (!ppp_check_access(fileno(f), filename, PPP_FT_SECRET)) { fclose(f); return 0; } @@ -1853,11 +1859,10 @@ get_secret(int unit, char *client, char *server, } fd = fileno(f); - if (!ppp_check_access(fd, filename, 0)) { + if (!ppp_check_access(fd, filename, PPP_FT_SECRET)) { fclose(f); return 0; } - check_access(fd, filename); ret = scan_authfile(f, client, server, secbuf, &addrs, &opts, filename); fclose(f); @@ -2133,23 +2138,6 @@ auth_number(void) return 0; } -/* - * check_access - complain if a secret file has too-liberal permissions. - */ -static void -check_access(int fd, const char *filename) -{ - struct stat sbuf; - - if (fstat(fd, &sbuf) < 0) { - warn("cannot stat secret file %s: %m", filename); - } else if ((sbuf.st_mode & (S_IRWXG | S_IRWXO)) != 0) { - warn("Warning - secret file %s has world and/or group access", - filename); - } -} - - /* * scan_authfile - Scan an authorization file for a secret suitable * for authenticating `client' on `server'. The return value is -1 @@ -2246,11 +2234,10 @@ scan_authfile(FILE *f, char *client, char *server, continue; } fd = fileno(sf); - if (!ppp_check_access(fd, atfile, 0)) { + if (!ppp_check_access(fd, atfile, PPP_FT_SECRET)) { fclose(sf); continue; } - check_access(fd, atfile); if (!getword(sf, word, &xxx, atfile)) { warn("no secret in indirect secret file %s", atfile); fclose(sf); @@ -2358,13 +2345,13 @@ auth_script_done(void *arg) case s_up: if (auth_state == s_down) { auth_script_state = s_down; - auth_script(path_auth_down); + auth_script(path_auth_down, "auth-down"); } break; case s_down: if (auth_state == s_up) { auth_script_state = s_up; - auth_script(path_auth_up); + auth_script(path_auth_up, "auth-up"); } break; } @@ -2375,7 +2362,7 @@ auth_script_done(void *arg) * interface-name peer-name real-user tty speed */ static void -auth_script(char *script) +auth_script(char *script, const char* name) { char strspeed[32]; struct passwd *pw; @@ -2400,7 +2387,7 @@ auth_script(char *script) argv[6] = ipparam; argv[7] = NULL; - auth_script_pid = run_program(script, argv, 0, auth_script_done, NULL, 0); + auth_script_pid = run_program(script, argv, 0, auth_script_done, NULL, 0, name); } @@ -2423,7 +2410,7 @@ have_eaptls_secret_server(char *client, char *server, if (f == NULL) return 0; - if (!ppp_check_access(fileno(f), filename, 0)) { + if (!ppp_check_access(fileno(f), filename, PPP_FT_SECRET)) { fclose(f); return 0; } @@ -2707,11 +2694,10 @@ get_eaptls_secret(int unit, char *client, char *server, } fd = fileno(fp); - if (!ppp_check_access(fd, filename, 0)) { + if (!ppp_check_access(fd, filename, PPP_FT_SECRET)) { fclose(fp); return 0; } - check_access(fd, filename); ret = scan_authfile_eaptls(fp, client, server, clicertfile, servcertfile, cacertfile, pkfile, &addrs, &opts, filename); diff --git a/pppd/ipcp.c b/pppd/ipcp.c index e47e66cc..fed02904 100644 --- a/pppd/ipcp.c +++ b/pppd/ipcp.c @@ -294,7 +294,7 @@ struct protent ipcp_protent = { }; static void ipcp_clear_addrs (int, u_int32_t, u_int32_t); -static void ipcp_script (char *, int); /* Run an up/down script */ +static void ipcp_script (char *, int, const char *); /* Run an up/down script */ static void ipcp_script_done (void *); /* @@ -1822,7 +1822,7 @@ ip_demand_conf(int u) } if (!sifaddr(u, wo->ouraddr, wo->hisaddr, GetMask(wo->ouraddr))) return 0; - ipcp_script(path_ippreup, 1); + ipcp_script(path_ippreup, 1, "ip-pre-up"); if (!sifup(u)) return 0; if (!sifnpmode(u, PPP_IP, NPMODE_QUEUE)) @@ -1985,7 +1985,7 @@ ipcp_up(fsm *f) ifindex = if_nametoindex(ifname); /* run the pre-up script, if any, and wait for it to finish */ - ipcp_script(path_ippreup, 1); + ipcp_script(path_ippreup, 1, "ip-pre-up"); /* check if preup script renamed the interface */ if (!if_indextoname(ifindex, ifname)) { @@ -2048,7 +2048,7 @@ ipcp_up(fsm *f) */ if (ipcp_script_state == s_down && ipcp_script_pid == 0) { ipcp_script_state = s_up; - ipcp_script(path_ipup, 0); + ipcp_script(path_ipup, 0, "ip-up"); } } @@ -2097,7 +2097,7 @@ ipcp_down(fsm *f) /* Execute the ip-down script */ if (ipcp_script_state == s_up && ipcp_script_pid == 0) { ipcp_script_state = s_down; - ipcp_script(path_ipdown, 0); + ipcp_script(path_ipdown, 0, "ip-down"); } } @@ -2146,13 +2146,13 @@ ipcp_script_done(void *arg) case s_up: if (ipcp_fsm[0].state != OPENED) { ipcp_script_state = s_down; - ipcp_script(path_ipdown, 0); + ipcp_script(path_ipdown, 0, "ip-down"); } break; case s_down: if (ipcp_fsm[0].state == OPENED) { ipcp_script_state = s_up; - ipcp_script(path_ipup, 0); + ipcp_script(path_ipup, 0, "ip-down"); } break; } @@ -2164,7 +2164,7 @@ ipcp_script_done(void *arg) * interface-name tty-name speed local-IP remote-IP. */ static void -ipcp_script(char *script, int wait) +ipcp_script(char *script, int wait, const char* name) { char strspeed[32], strlocal[32], strremote[32]; char *argv[8]; @@ -2182,10 +2182,10 @@ ipcp_script(char *script, int wait) argv[6] = ipparam; argv[7] = NULL; if (wait) - run_program(script, argv, 0, NULL, NULL, 1); + run_program(script, argv, 0, NULL, NULL, 1, name); else ipcp_script_pid = run_program(script, argv, 0, ipcp_script_done, - NULL, 0); + NULL, 0, name); } /* diff --git a/pppd/ipv6cp.c b/pppd/ipv6cp.c index c8d88caa..7c6a0b5b 100644 --- a/pppd/ipv6cp.c +++ b/pppd/ipv6cp.c @@ -328,7 +328,7 @@ struct protent ipv6cp_protent = { }; static void ipv6cp_clear_addrs (int, eui64_t, eui64_t); -static void ipv6cp_script (char *); +static void ipv6cp_script (char *, const char *); static void ipv6cp_script_done (void *); /* @@ -1400,7 +1400,7 @@ ipv6cp_up(fsm *f) */ if (ipv6cp_script_state == s_down && ipv6cp_script_pid == 0) { ipv6cp_script_state = s_up; - ipv6cp_script(path_ipv6up); + ipv6cp_script(path_ipv6up, "ipv6-ip"); } } @@ -1451,7 +1451,7 @@ ipv6cp_down(fsm *f) /* Execute the ipv6-down script */ if (ipv6cp_script_state == s_up && ipv6cp_script_pid == 0) { ipv6cp_script_state = s_down; - ipv6cp_script(path_ipv6down); + ipv6cp_script(path_ipv6down, "ipv6-down"); } } @@ -1489,13 +1489,13 @@ ipv6cp_script_done(void *arg) case s_up: if (ipv6cp_fsm[0].state != OPENED) { ipv6cp_script_state = s_down; - ipv6cp_script(path_ipv6down); + ipv6cp_script(path_ipv6down, "ipv6-down"); } break; case s_down: if (ipv6cp_fsm[0].state == OPENED) { ipv6cp_script_state = s_up; - ipv6cp_script(path_ipv6up); + ipv6cp_script(path_ipv6up, "ipv6-up"); } break; } @@ -1507,7 +1507,7 @@ ipv6cp_script_done(void *arg) * interface-name tty-name speed local-LL remote-LL. */ static void -ipv6cp_script(char *script) +ipv6cp_script(char *script, const char* name) { char strspeed[32], strlocal[64], strremote[64]; char *argv[8]; @@ -1526,7 +1526,7 @@ ipv6cp_script(char *script) argv[7] = NULL; ipv6cp_script_pid = run_program(script, argv, 0, ipv6cp_script_done, - NULL, 0); + NULL, 0, name); } /* diff --git a/pppd/main.c b/pppd/main.c index 1de34096..fecf9a03 100644 --- a/pppd/main.c +++ b/pppd/main.c @@ -215,7 +215,7 @@ bool bundle_terminating; */ struct subprocess { pid_t pid; - char *prog; + const char *prog; void (*done)(void *); void *arg; int killable; @@ -244,7 +244,7 @@ static void holdoff_end(void *); static void forget_child(int pid, int status); static int reap_kids(void); static void childwait_end(void *); -static void run_net_script(char* script, int wait); +static void run_net_script(char* script, int wait, const char* name); #ifdef PPP_WITH_TDB static void update_db_entry(void); @@ -822,7 +822,8 @@ setup_signals(void) /* * net-* scripts to be run come through here. */ -void run_net_script(char* script, int wait) +static +void run_net_script(char* script, int wait, const char* name) { char strspeed[32]; char *argv[6]; @@ -836,7 +837,7 @@ void run_net_script(char* script, int wait) argv[4] = ipparam; argv[5] = NULL; - run_program(script, argv, 0, NULL, NULL, wait); + run_program(script, argv, 0, NULL, NULL, wait, name); } /* @@ -866,7 +867,7 @@ set_ifunit(int iskey) } if (*remote_number) ppp_script_setenv("REMOTENUMBER", remote_number, 0); - run_net_script(path_net_init, 1); + run_net_script(path_net_init, 1, "net-init"); } /* @@ -1276,7 +1277,7 @@ new_phase(ppp_phase_t p) if (phase <= PHASE_NETWORK) { char iftmpname[IFNAMSIZ]; int ifindex = if_nametoindex(ifname); - run_net_script(path_net_preup, 1); + run_net_script(path_net_preup, 1, "net-pre-up"); if (if_indextoname(ifindex, iftmpname) && strcmp(iftmpname, ifname)) { info("Detected interface name change from %s to %s.", ifname, iftmpname); strcpy(ifname, iftmpname); @@ -1284,7 +1285,7 @@ new_phase(ppp_phase_t p) } break; case PHASE_DISCONNECT: - run_net_script(path_net_down, 0); + run_net_script(path_net_down, 0, "net-down"); break; } @@ -1926,7 +1927,7 @@ update_script_environment(void) * reap_kids) iff the return value is > 0. */ pid_t -run_program(char *prog, char * const *args, int must_exist, void (*done)(void *), void *arg, int wait) +run_program(const char *prog, char * const *args, int must_exist, void (*done)(void *), void *arg, int wait, const char* name) { int fd, pid, status, ret; @@ -1946,7 +1947,7 @@ run_program(char *prog, char * const *args, int must_exist, void (*done)(void *) error("Can't access %s: %m", prog); return 0; } - if (!ppp_check_access(fd, prog, 1)) { + if (!ppp_check_access(fd, prog, PPP_FT_EXEC)) { close(fd); return 0; } @@ -1997,12 +1998,15 @@ run_program(char *prog, char * const *args, int must_exist, void (*done)(void *) warn("can't reset priority to 0: %m"); #endif + ppp_script_setenv("PPP_SCRIPT_INSTANCE", name, 0); + /* run the program */ update_script_environment(); + + if (strict_script_checks) { #ifdef HAVE_FEXECVE - fexecve(fd, args, script_env); + fexecve(fd, args, script_env); #else - { char fdpath[32]; snprintf(fdpath, sizeof(fdpath), "/dev/fd/%d", fd); @@ -2011,8 +2015,11 @@ run_program(char *prog, char * const *args, int must_exist, void (*done)(void *) snprintf(fdpath, sizeof(fdpath), "/proc/self/fd/%d", fd); execve(fdpath, args, script_env); } - } #endif + } else { + /* This is risky. Allows for certain TOCTAU issues, but usually we should be OKay */ + execve(prog, args, script_env); + } /* have to reopen the log, there's nowhere else for the message to go. */ reopen_log(); syslog(LOG_ERR, "Can't execute %s: %m", prog); @@ -2026,7 +2033,7 @@ run_program(char *prog, char * const *args, int must_exist, void (*done)(void *) * to use. */ void -record_child(int pid, char *prog, void (*done)(void *), void *arg, int killable) +record_child(int pid, const char *prog, void (*done)(void *), void *arg, int killable) { struct subprocess *chp; @@ -2207,7 +2214,7 @@ novm(const char *msg) * for scripts that we run (e.g. ip-up, auth-up, etc.) */ void -ppp_script_setenv(char *var, char *value, int iskey) +ppp_script_setenv(const char *var, const char *value, int iskey) { size_t varl = strlen(var); size_t vl = varl + strlen(value) + 2; diff --git a/pppd/options.c b/pppd/options.c index 6d6b227f..fec65edd 100644 --- a/pppd/options.c +++ b/pppd/options.c @@ -134,6 +134,7 @@ char req_ifname[IFNAMSIZ]; /* requested interface name */ char req_vrf[IFNAMSIZ]; /* VRF name to bind with PPP interface */ #endif bool multilink = 0; /* Enable multilink operation */ +bool strict_script_checks = 1; /* Whether strict script checks are enabled. */ char *bundle_name = NULL; /* bundle name for multilink */ bool dump_options; /* print out option values */ bool show_options; /* print all supported options and exit */ @@ -149,7 +150,7 @@ char path_ipv6down[MAXPATHLEN]; /* pathname of ipv6-down script */ unsigned int maxoctets = 0; /* default - no limit */ session_limit_dir_t maxoctets_dir = PPP_OCTETS_DIRECTION_SUM; /* default - sum of traffic */ -int maxoctets_timeout = 1; /* default 1 second */ +int maxoctets_timeout = 1; /* default 1 second */ extern struct option auth_options[]; @@ -417,6 +418,16 @@ struct option general_options[] = { { "mo-timeout", o_int, &maxoctets_timeout, "Check for traffic limit every N seconds", OPT_PRIO | OPT_LLIMIT | 1 }, + { "strict-script-checks", o_bool, &strict_script_checks, + "Enforce strict script TOCTAU checks.", OPT_PRIO | 1 }, + { "nostrict-script-checks", o_bool, &strict_script_checks, + "disables strict script TOCTAU checks.", OPT_PRIV|OPT_PRIO | 0 }, + + { "strict-secrets-files", o_bool, &strict_secrets_files, + "Enforce strict read checks on secrets files.", OPT_PRIO | 1 }, + { "nostrict-secrets-files", o_bool, &strict_secrets_files, + "Disabled strict read checks on secrets files.", OPT_PRIV|OPT_PRIO | 0 }, + /* Dummy option, does nothing */ { "noipx", o_bool, &noipx_opt, NULL, OPT_NOPRINT | 1 }, @@ -1710,7 +1721,7 @@ callfile(char **argv) free(fname); return 0; } - if (!ppp_check_access(fileno(f), fname, 0)) { + if (!ppp_check_access(fileno(f), fname, PPP_FT_DEFAULT)) { free(fname); fclose(f); return 0; @@ -1765,7 +1776,7 @@ setactivefilter(char **argv) #endif /* - * setdomain - Set domain name to append to hostname + * setdomain - Set domain name to append to hostname */ static int setdomain(char **argv) diff --git a/pppd/pppd-private.h b/pppd/pppd-private.h index 26c3f2c5..a518180c 100644 --- a/pppd/pppd-private.h +++ b/pppd/pppd-private.h @@ -219,6 +219,8 @@ extern char *current_option; /* the name of the option being parsed */ extern int privileged_option; /* set iff the current option came from root */ extern char *option_source; /* string saying where the option came from */ extern int option_priority; /* priority of current options */ +extern bool strict_script_checks; /* Whether to enforce strict checking on scripts */ +extern bool strict_secrets_files; /* Whether strict checks are enabled on secrets files. */ #ifdef PPP_WITH_IPV6CP extern char path_ipv6up[]; /* pathname of ipv6-up script */ @@ -310,11 +312,11 @@ void detach(void); /* Detach from controlling tty */ void die(int); /* Cleanup and exit */ void quit(void); /* like die(1) */ -void record_child(int, char *, void (*) (void *), void *, int); +void record_child(int, const char *, void (*) (void *), void *, int); int device_script(char *cmd, int in, int out, int dont_wait); /* Run `cmd' with given stdin and stdout */ -pid_t run_program(char *prog, char * const * args, int must_exist, - void (*done)(void *), void *arg, int wait); +pid_t run_program(const char *prog, char * const * args, int must_exist, + void (*done)(void *), void *arg, int wait, const char * name); /* Run program prog with args in child */ void reopen_log(void); /* (re)open the connection to syslog */ void print_link_stats(void); /* Print stats, if available */ diff --git a/pppd/pppd.8 b/pppd/pppd.8 index 67aee7de..e07a2524 100644 --- a/pppd/pppd.8 +++ b/pppd/pppd.8 @@ -909,6 +909,12 @@ traffic. .B nosendip Don't send our local IP address to peer during IP address negotiation. .TP +.B nostrict\-script\-checks +Disabled strict\-script\-checks. This option is privileged. +.TP +.B nostrict\-secrets\-files +Disabled strict\-secrets\-files. This option is privileged. +.TP .B notty Normally, pppd requires a terminal device. With this option, pppd will allocate itself a pseudo-tty master/slave pair and use the slave @@ -1143,6 +1149,22 @@ file any pseudonym offered by the peer during authentication. Set the number of stop bits for the serial port. Valid values are 1 or 2. The default value is 1. .TP +.B strict\-script\-checks +This option (which is on by default) will enforce stricter rules on scripts, +specifically they must be owned by root (or the effective id), and not be +writable by either group or other. The option is not privileged. The inverse +nostrict\-script\-checks to disable the checks however is. This switches from +using execve() when invoking scripts to using execveat() - which means we +perform the relevant checks on the file we are guaranteed to exec to, with the +caveat that if these are scripts with shebangs (#!) then $0 (argv[0]) will be +lost - your scripts should either know who/what they are - or rely on +PPP_SCRIPT_INSTANCE environment variable. +.TP +.B strict\-secrets\-files +This option (which is on be default) will refuse to operate using secrets files +that are group or world readable. This option is not privileged, but it's +inverse (nostrict\-secrets\-files) is. +.TP .B sync Use synchronous HDLC serial encoding instead of asynchronous. The device used by pppd with this option must have sync support. @@ -1779,6 +1801,10 @@ environment that is empty except for some environment variables that give information about the link. The environment variables that pppd sets are: .TP +.B PPP_SCRIPT_INSTANCE +The name of the intended script, as documented, not as referenced. For +example, even if you set ip\-up\-script /some/other/path this variable will +still be ip-up. .B DEVICE The name of the serial tty device being used. .TP diff --git a/pppd/pppd.h b/pppd/pppd.h index c34ba9ed..1c1b0a0b 100644 --- a/pppd/pppd.h +++ b/pppd/pppd.h @@ -114,6 +114,16 @@ typedef enum ppp_exit_code EXIT_CNID_AUTH_FAILED = 21 } ppp_exit_code_t; +/* + * Values for file types to be checked in pppd_check_access + */ +typedef enum +{ + PPP_FT_DEFAULT = 0, + PPP_FT_EXEC = 1, + PPP_FT_SECRET = 2, +} ppp_file_type_t; + /* * Type of notifier callbacks */ @@ -300,7 +310,7 @@ void pr_log(void *, char *, ...); void end_pr_log(void); /* Check that a file can safely be used */ -int ppp_check_access(int fd, const char *path, int exec); +int ppp_check_access(int fd, const char *path, ppp_file_type_t filetype); /* * Get the current exist status of pppd @@ -431,7 +441,7 @@ bool ppp_bad_ip_addr(uint32_t); /* * Expose an environment variable to scripts */ -void ppp_script_setenv(char *, char *, int); +void ppp_script_setenv(const char *, const char *, int); /* * Unexpose an environment variable to scripts diff --git a/pppd/utils.c b/pppd/utils.c index 44362aa5..2c08ee10 100644 --- a/pppd/utils.c +++ b/pppd/utils.c @@ -64,6 +64,9 @@ extern char *strerror(); #endif +/* check options.c for details */ +bool strict_secrets_files = 1; /* Whether strict checks are enabled on secrets files. */ + static void logit(int, const char *, va_list); static void log_write(int, char *); static void vslp_printer(void *, char *, ...); @@ -94,15 +97,13 @@ ppp_explicit_bzero(void *buf, size_t len) } /* - * Check that a file descriptor is owned by root, not writable by group or - * other. - * If exec is true, check for execute permission, otherwise for read - * permission. + * Check that a file descriptor is owned by root (Or the effective user), not + * writable by group or other. * Note: the path argument is only used for log messages. * Returns 1 if OK; if not, prints an error message and returns 0. */ int -ppp_check_access(int fd, const char *path, int exec) +ppp_check_access(int fd, const char *path, ppp_file_type_t filetype) { struct stat sbuf; int perm; @@ -117,8 +118,9 @@ ppp_check_access(int fd, const char *path, int exec) goto err; } - if (sbuf.st_uid != 0) { - error("Can't safely use %v because it is not owned by root", path); + if (sbuf.st_uid != 0 && sbuf.st_uid != geteuid()) { + + error("Can't safely use %v because it is not owned by root (or the effective uid).", path); goto err; } @@ -128,13 +130,22 @@ ppp_check_access(int fd, const char *path, int exec) goto err; } - perm = exec? S_IXUSR : S_IRUSR; + perm = (filetype == PPP_FT_EXEC) ? S_IXUSR : S_IRUSR; if ((sbuf.st_mode & perm) == 0) { error("Can't use %v: not %sable by root", path, - exec? "execut": "read"); + (filetype == PPP_FT_EXEC) ? "execute": "read"); goto err; } + if ((filetype == PPP_FT_SECRET) && (sbuf.st_mode & (S_IRWXG | S_IRWXO)) != 0) { + if (strict_secrets_files) { + error("Can't use %v: secret file has world and/or group access", path); + goto err; + } else { + warn("Warning - secret file %v has world and/or group access", path); + } + } + return 1; err: