summaryrefslogtreecommitdiffstats
path: root/crypto/heimdal/appl/su/su.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/heimdal/appl/su/su.c')
-rw-r--r--crypto/heimdal/appl/su/su.c183
1 files changed, 127 insertions, 56 deletions
diff --git a/crypto/heimdal/appl/su/su.c b/crypto/heimdal/appl/su/su.c
index 757f39d..e8e4783 100644
--- a/crypto/heimdal/appl/su/su.c
+++ b/crypto/heimdal/appl/su/su.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999 - 2003 Kungliga Tekniska Högskolan
+ * Copyright (c) 1999 - 2007 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* All rights reserved.
*
@@ -36,7 +36,7 @@
#include <config.h>
-RCSID("$Id: su.c,v 1.26.2.1 2003/05/06 12:06:44 joda Exp $");
+RCSID("$Id: su.c 21988 2007-10-19 05:36:54Z lha $");
#include <stdio.h>
#include <stdlib.h>
@@ -53,6 +53,9 @@ RCSID("$Id: su.c,v 1.26.2.1 2003/05/06 12:06:44 joda Exp $");
#endif
#include <pwd.h>
+#ifdef HAVE_CRYPT_H
+#include <crypt.h>
+#endif
#include "crypto-headers.h"
#ifdef KRB5
@@ -66,13 +69,7 @@ RCSID("$Id: su.c,v 1.26.2.1 2003/05/06 12:06:44 joda Exp $");
#include <roken.h>
#include <getarg.h>
-#ifndef _PATH_DEFPATH
-#define _PATH_DEFPATH "/usr/bin:/bin"
-#endif
-
-#ifndef _PATH_BSHELL
-#define _PATH_BSHELL "/bin/sh"
-#endif
+#include "supaths.h"
int kerberos_flag = 1;
int csh_f_flag;
@@ -175,7 +172,9 @@ krb5_verify(const struct passwd *login_info,
{
krb5_error_code ret;
krb5_principal p;
+ krb5_realm *realms, *r;
char *login_name = NULL;
+ int user_ok = 0;
#if defined(HAVE_GETLOGIN) && !defined(POSIX_GETLOGIN)
login_name = getlogin();
@@ -188,50 +187,63 @@ krb5_verify(const struct passwd *login_info,
return 1;
}
- if (login_name == NULL || strcmp (login_name, "root") == 0)
- login_name = login_info->pw_name;
- if (strcmp (su_info->pw_name, "root") == 0)
- ret = krb5_make_principal(context, &p, NULL,
- login_name,
- kerberos_instance,
- NULL);
- else
- ret = krb5_make_principal(context, &p, NULL,
- su_info->pw_name,
- NULL);
- if(ret)
+ ret = krb5_get_default_realms(context, &realms);
+ if (ret)
return 1;
+
+ /* Check all local realms */
+ for (r = realms; *r != NULL && !user_ok; r++) {
+
+ if (login_name == NULL || strcmp (login_name, "root") == 0)
+ login_name = login_info->pw_name;
+ if (strcmp (su_info->pw_name, "root") == 0)
+ ret = krb5_make_principal(context, &p, *r,
+ login_name,
+ kerberos_instance,
+ NULL);
+ else
+ ret = krb5_make_principal(context, &p, *r,
+ su_info->pw_name,
+ NULL);
+ if (ret) {
+ krb5_free_host_realm(context, realms);
+ return 1;
+ }
- if(su_info->pw_uid != 0 || krb5_kuserok(context, p, su_info->pw_name)) {
+ /* if we are su-ing too root, check with krb5_kuserok */
+ if (su_info->pw_uid == 0 && !krb5_kuserok(context, p, su_info->pw_name))
+ continue;
+
ret = krb5_cc_gen_new(context, &krb5_mcc_ops, &ccache);
if(ret) {
-#if 1
- krb5_warn(context, ret, "krb5_cc_gen_new");
-#endif
+ krb5_free_host_realm(context, realms);
krb5_free_principal (context, p);
return 1;
}
- ret = krb5_verify_user_lrealm(context, p, ccache, NULL, TRUE, NULL);
+ ret = krb5_verify_user(context, p, ccache, NULL, TRUE, NULL);
krb5_free_principal (context, p);
- if(ret) {
+ switch (ret) {
+ case 0:
+ user_ok = 1;
+ break;
+ case KRB5_LIBOS_PWDINTR :
krb5_cc_destroy(context, ccache);
- switch (ret) {
- case KRB5_LIBOS_PWDINTR :
- break;
- case KRB5KRB_AP_ERR_BAD_INTEGRITY:
- case KRB5KRB_AP_ERR_MODIFIED:
- krb5_warnx(context, "Password incorrect");
- break;
- default :
- krb5_warn(context, ret, "krb5_verify_user");
- break;
- }
- return 1;
+ break;
+ case KRB5KRB_AP_ERR_BAD_INTEGRITY:
+ case KRB5KRB_AP_ERR_MODIFIED:
+ krb5_cc_destroy(context, ccache);
+ krb5_warnx(context, "Password incorrect");
+ break;
+ default :
+ krb5_cc_destroy(context, ccache);
+ krb5_warn(context, ret, "krb5_verify_user");
+ break;
}
- return 0;
}
- krb5_free_principal (context, p);
- return 1;
+ krb5_free_host_realm(context, realms);
+ if (!user_ok)
+ return 1;
+ return 0;
}
static int
@@ -249,8 +261,10 @@ krb5_start_session(void)
ret = krb5_cc_copy_cache(context, ccache, ccache2);
- asprintf(&cc_name, "%s:%s", krb5_cc_get_type(context, ccache2),
- krb5_cc_get_name(context, ccache2));
+ ret = asprintf(&cc_name, "%s:%s", krb5_cc_get_type(context, ccache2),
+ krb5_cc_get_name(context, ccache2));
+ if (ret == -1)
+ errx(1, "malloc - out of memory");
esetenv("KRB5CCNAME", cc_name, 1);
/* we want to export this even if we don't directly support KRB4 */
@@ -300,10 +314,12 @@ krb_verify(const struct passwd *login_info,
krb_kuserok(name, instance, realm, su_info->pw_name) == 0) {
char password[128];
char *prompt;
- asprintf (&prompt,
+ ret = asprintf (&prompt,
"%s's Password: ",
krb_unparse_name_long (name, instance, realm));
- if (des_read_pw_string (password, sizeof (password), prompt, 0)) {
+ if (ret == -1)
+ return (1);
+ if (UI_UTIL_read_pw_string (password, sizeof (password), prompt, 0)) {
memset (password, 0, sizeof (password));
free(prompt);
return (1);
@@ -341,8 +357,29 @@ krb_start_session(void)
}
#endif
+#define GROUP_MEMBER 0
+#define GROUP_MISSING 1
+#define GROUP_EMPTY 2
+#define GROUP_NOT_MEMBER 3
+
+static int
+group_member_p(const char *group, const char *user)
+{
+ struct group *g;
+ int i;
+ g = getgrnam(group);
+ if(g == NULL)
+ return GROUP_MISSING;
+ if(g->gr_mem[0] == NULL)
+ return GROUP_EMPTY;
+ for(i = 0; g->gr_mem[i] != NULL; i++)
+ if(strcmp(user, g->gr_mem[i]) == 0)
+ return GROUP_MEMBER;
+ return GROUP_NOT_MEMBER;
+}
+
static int
-verify_unix(struct passwd *su)
+verify_unix(struct passwd *login, struct passwd *su)
{
char prompt[128];
char pw_buf[1024];
@@ -350,13 +387,31 @@ verify_unix(struct passwd *su)
int r;
if(su->pw_passwd != NULL && *su->pw_passwd != '\0') {
snprintf(prompt, sizeof(prompt), "%s's password: ", su->pw_name);
- r = des_read_pw_string(pw_buf, sizeof(pw_buf), prompt, 0);
+ r = UI_UTIL_read_pw_string(pw_buf, sizeof(pw_buf), prompt, 0);
if(r != 0)
exit(0);
pw = crypt(pw_buf, su->pw_passwd);
memset(pw_buf, 0, sizeof(pw_buf));
- if(strcmp(pw, su->pw_passwd) != 0)
+ if(strcmp(pw, su->pw_passwd) != 0) {
+ syslog (LOG_ERR | LOG_AUTH, "%s to %s: incorrect password",
+ login->pw_name, su->pw_name);
+ return 1;
+ }
+ }
+ /* if su:ing to root, check membership of group wheel or root; if
+ that group doesn't exist, or is empty, allow anyone to su
+ root */
+ if(su->pw_uid == 0) {
+#ifndef ROOT_GROUP
+#define ROOT_GROUP "wheel"
+#endif
+ int gs = group_member_p(ROOT_GROUP, login->pw_name);
+ if(gs == GROUP_NOT_MEMBER) {
+ syslog (LOG_ERR | LOG_AUTH, "%s to %s: not in group %s",
+ login->pw_name, su->pw_name, ROOT_GROUP);
return 1;
+ }
+ return 0;
}
return 0;
}
@@ -398,6 +453,9 @@ main(int argc, char **argv)
else
su_user = argv[optind++];
+ if (!issuid() && getuid() != 0)
+ warnx("Not setuid and you are root, expect this to fail");
+
pwd = k_getpwnam(su_user);
if(pwd == NULL)
errx (1, "unknown login %s", su_user);
@@ -434,7 +492,7 @@ main(int argc, char **argv)
ok = 4;
#endif
- if(ok == 0 && login_info->pw_uid && verify_unix(su_info) != 0) {
+ if(ok == 0 && login_info->pw_uid && verify_unix(login_info, su_info) != 0) {
printf("Sorry!\n");
exit(1);
}
@@ -473,7 +531,7 @@ main(int argc, char **argv)
#endif
{
char *tty = ttyname (STDERR_FILENO);
- syslog (LOG_NOTICE | LOG_AUTH, tty ? "%s to %s" : "%s to %s on %s",
+ syslog (LOG_NOTICE | LOG_AUTH, tty ? "%s to %s on %s" : "%s to %s",
login_info->pw_name, su_info->pw_name, tty);
}
@@ -481,11 +539,23 @@ main(int argc, char **argv)
if(!env_flag) {
if(full_login) {
char *t = getenv ("TERM");
-
- environ = malloc (10 * sizeof (char *));
+ char **newenv = NULL;
+ int i, j;
+
+ i = read_environment(_PATH_ETC_ENVIRONMENT, &newenv);
+
+ environ = malloc ((10 + i) * sizeof (char *));
if (environ == NULL)
err (1, "malloc");
environ[0] = NULL;
+
+ for (j = 0; j < i; j++) {
+ char *p = strchr(newenv[j], '=');
+ *p++ = 0;
+ esetenv (newenv[j], p, 1);
+ }
+ free(newenv);
+
esetenv ("PATH", _PATH_DEFPATH, 1);
if (t)
esetenv ("TERM", t, 1);
@@ -516,9 +586,10 @@ main(int argc, char **argv)
if (args == NULL)
err (1, "malloc");
i = 0;
- if(full_login)
- asprintf(&args[i++], "-%s", p);
- else
+ if(full_login) {
+ if (asprintf(&args[i++], "-%s", p) == -1)
+ errx (1, "malloc");
+ } else
args[i++] = p;
if (cmd) {
args[i++] = "-c";
OpenPOWER on IntegriCloud