summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNate Straz <nstraz@redhat.com>2005-08-24 21:50:03 +0000
committerNate Straz <nstraz@redhat.com>2005-08-24 21:50:03 +0000
commite48b3f4d5002deced980f5ef8e1c4fe3eb884fbc (patch)
treeef642b45b524974c76d35dd6ab1a34c1e1733932
parent0c59da8a7310e1e3811f873fd0106ccebdb53c53 (diff)
downloadqarsh-e48b3f4d5002deced980f5ef8e1c4fe3eb884fbc.tar.gz
qarsh-e48b3f4d5002deced980f5ef8e1c4fe3eb884fbc.tar.xz
qarsh-e48b3f4d5002deced980f5ef8e1c4fe3eb884fbc.zip
Add a new packet type "setuser" so we can become any user/group combination.
With this mod, `qarsh foo@host` should look the same as `ssh foo@host.`
-rw-r--r--qarsh/qarsh.c56
-rw-r--r--qarsh/qarsh_packet.c72
-rw-r--r--qarsh/qarsh_packet.h12
-rw-r--r--qarsh/qarshd.c36
4 files changed, 173 insertions, 3 deletions
diff --git a/qarsh/qarsh.c b/qarsh/qarsh.c
index 20e7023..0b91f5d 100644
--- a/qarsh/qarsh.c
+++ b/qarsh/qarsh.c
@@ -18,6 +18,7 @@
#include <netinet/in.h>
#include <netdb.h>
#include <syslog.h>
+#include <pwd.h>
#include "sockutil.h"
@@ -31,7 +32,7 @@ int qarsh_fd = -1; /* The control connection to qarshd */
void
usage()
{
- printf("Usage: qarsh hostname cmdline ...\n");
+ printf("qarsh: [user[.group]@]hostname cmdline ...\n");
}
char *
@@ -58,6 +59,25 @@ copyargs(char **argv)
return args;
}
+void
+set_remote_user(char *user, char *group)
+{
+ struct qa_packet *qp;
+
+ qp = make_qp_setuser(user, group);
+ qp->qp_seq = 1;
+ send_packet(qarsh_fd, qp);
+ qpfree(qp);
+ qp = recv_packet(qarsh_fd);
+ if (qp && qp->qp_type == QP_RETURNCODE
+ && qp->qp_returncode.qp_rc == -1) {
+
+ fprintf(stderr, "Remote side failed, %s\n",
+ qp->qp_returncode.qp_strerror);
+ close(qarsh_fd);
+ exit(125);
+ }
+}
int
run_remote_cmd(char *cmdline)
@@ -219,13 +239,22 @@ main(int argc, char *argv[])
int c;
int port = 5008;
char *host;
+ char *remuser = NULL;
+ char *remgroup = NULL;
char *args;
+ struct passwd *pw;
int ret;
openlog("qarsh", LOG_PID, LOG_DAEMON);
- while ((c = getopt(argc, argv, "+p:")) != -1) {
+ while ((c = getopt(argc, argv, "+p:l:g:")) != -1) {
switch (c) {
+ case 'l':
+ remuser = strdup(optarg);
+ break;
+ case 'g':
+ remgroup = strdup(optarg);
+ break;
case 'p':
port = atoi(optarg);
break;
@@ -240,6 +269,27 @@ main(int argc, char *argv[])
usage();
exit(1);
}
+ /* check for user and group in form [user[.group]@]hostname */
+ {
+ char *sp;
+
+ if ((sp = strchr(host, '@'))) {
+ remuser = host;
+ host = sp+1;
+ *sp = '\0';
+ }
+ if (remuser && (sp = strchr(remuser, '.'))) {
+ remgroup = sp+1;
+ *sp = '\0';
+ }
+ }
+ if (!(pw = getpwuid(getuid()))) {
+ fprintf(stderr, "qarsh: unknown user id.\n");
+ exit(1);
+ }
+ if (remuser == NULL) {
+ remuser = strdup(pw->pw_name);
+ }
argc -= optind;
argv += optind;
@@ -259,6 +309,8 @@ main(int argc, char *argv[])
return 127;
}
+ set_remote_user(remuser, remgroup);
+
ret = run_remote_cmd(args);
close(qarsh_fd);
free(args);
diff --git a/qarsh/qarsh_packet.c b/qarsh/qarsh_packet.c
index 929e204..cc4f082 100644
--- a/qarsh/qarsh_packet.c
+++ b/qarsh/qarsh_packet.c
@@ -16,21 +16,25 @@ int parse_qp_returncode(xmlXPathContextPtr ctxt, struct qa_packet *qp);
int parse_qp_ack(xmlXPathContextPtr ctxt, struct qa_packet *qp);
int parse_qp_runcmd(xmlXPathContextPtr ctxt, struct qa_packet *qp);
int parse_qp_cmdexit(xmlXPathContextPtr ctxt, struct qa_packet *qp);
+int parse_qp_setuser(xmlXPathContextPtr ctxt, struct qa_packet *qp);
void string_qp_hello(xmlNodePtr node, struct qa_packet *qp);
void string_qp_returncode(xmlNodePtr node, struct qa_packet *qp);
void string_qp_runcmd(xmlNodePtr node, struct qa_packet *qp);
void string_qp_ack(xmlNodePtr node, struct qa_packet *qp);
void string_qp_cmdexit(xmlNodePtr node, struct qa_packet *qp);
+void string_qp_setuser(xmlNodePtr node, struct qa_packet *qp);
void free_qp_hello(struct qa_packet *qp);
void free_qp_returncode(struct qa_packet *qp);
void free_qp_runcmd(struct qa_packet *qp);
+void free_qp_setuser(struct qa_packet *qp);
void dump_qp_ack(struct qa_packet *qp);
void dump_qp_runcmd(struct qa_packet *qp);
void dump_qp_returncode(struct qa_packet *qp);
void dump_qp_cmdexit(struct qa_packet *qp);
+void dump_qp_setuser(struct qa_packet *qp);
struct packet_internals {
@@ -76,6 +80,12 @@ struct packet_internals {
.pi_string = string_qp_cmdexit,
.pi_free = NULL,
.pi_dump = dump_qp_cmdexit
+ }, {
+ .pi_name = "setuser",
+ .pi_parse = parse_qp_setuser,
+ .pi_string = string_qp_setuser,
+ .pi_free = free_qp_setuser,
+ .pi_dump = dump_qp_setuser
}
};
@@ -177,6 +187,14 @@ parse_qp_cmdexit(xmlXPathContextPtr ctxt, struct qa_packet *qp)
free(s);
return 0;
}
+
+int
+parse_qp_setuser(xmlXPathContextPtr ctxt, struct qa_packet *qp)
+{
+ qp->qp_setuser.qp_user = get_xpath_string(ctxt, "param[@name='user']");
+ qp->qp_setuser.qp_group = get_xpath_string(ctxt, "param[@name='group']");
+ return 0;
+}
struct qa_packet *
parse_packet(xmlXPathContextPtr ctxt)
@@ -323,6 +341,14 @@ void string_qp_cmdexit(xmlNodePtr node, struct qa_packet *qp)
xmlAddChild(node, make_param("status", tmpstr));
}
+void string_qp_setuser(xmlNodePtr node, struct qa_packet *qp)
+{
+ xmlAddChild(node, make_param("user", qp->qp_setuser.qp_user));
+ if (qp->qp_setuser.qp_group) {
+ xmlAddChild(node, make_param("group", qp->qp_setuser.qp_group));
+ }
+}
+
/* Must pass in a pointer, but not a malloc'ed pointer */
char *
qptostr(struct qa_packet *qp, char **qpstr, int *qpsize)
@@ -372,6 +398,23 @@ make_qp_hello(char *greeting)
}
struct qa_packet *
+make_qp_returncode(int rc, int eno, char *strerr)
+{
+ struct qa_packet *qp;
+
+ qp = malloc(sizeof *qp);
+ assert(qp);
+ memset(qp, 0, sizeof *qp);
+
+ qp->qp_type = QP_RETURNCODE;
+ qp->qp_returncode.qp_rc = rc;
+ qp->qp_returncode.qp_errno = eno;
+ qp->qp_returncode.qp_strerror = strdup(strerr);
+
+ return qp;
+}
+
+struct qa_packet *
make_qp_ack(enum qa_packet_type t, int i)
{
struct qa_packet *qp;
@@ -418,6 +461,21 @@ make_qp_cmdexit(pid_t pid, int status)
return qp;
}
+struct qa_packet *
+make_qp_setuser(char *user, char *group)
+{
+ struct qa_packet *qp;
+ qp = malloc(sizeof *qp);
+ assert(qp);
+ memset(qp, 0, sizeof *qp);
+
+ qp->qp_type = QP_SETUSER;
+ qp->qp_setuser.qp_user = strdup(user);
+ if (group) qp->qp_setuser.qp_group = strdup(group);
+
+ return qp;
+}
+
/*
* Packet deallocation functions
*/
@@ -440,6 +498,13 @@ free_qp_runcmd(struct qa_packet *qp)
}
void
+free_qp_setuser(struct qa_packet *qp)
+{
+ condfree(qp->qp_setuser.qp_user);
+ condfree(qp->qp_setuser.qp_group);
+}
+
+void
qpfree(struct qa_packet *qp)
{
if (qp) {
@@ -488,6 +553,13 @@ dump_qp_cmdexit(struct qa_packet *qp)
}
void
+dump_qp_setuser(struct qa_packet *qp)
+{
+ printf("\tuser: %s\n", qp->qp_setuser.qp_user);
+ printf("\tgroup: %s\n", qp->qp_setuser.qp_group);
+}
+
+void
dump_qp(struct qa_packet *qp)
{
printf("%s #%d\n", QP_NAME(qp->qp_type), qp->qp_seq);
diff --git a/qarsh/qarsh_packet.h b/qarsh/qarsh_packet.h
index b21661b..b6d821b 100644
--- a/qarsh/qarsh_packet.h
+++ b/qarsh/qarsh_packet.h
@@ -11,7 +11,8 @@ enum qa_packet_type {
QP_RETURNCODE = 2,
QP_RUNCMD = 3,
QP_ACK = 4,
- QP_CMDEXIT = 5
+ QP_CMDEXIT = 5,
+ QP_SETUSER = 6
};
struct qp_hello_pkt {
@@ -42,6 +43,11 @@ struct qp_cmdexit_pkt {
int qp_status;
};
+struct qp_setuser_pkt {
+ char *qp_user;
+ char *qp_group;
+};
+
#define QP_VERSION 1
struct qa_packet {
@@ -53,6 +59,7 @@ struct qa_packet {
struct qp_runcmd_pkt runcmd;
struct qp_ack_pkt ack;
struct qp_cmdexit_pkt cmdexit;
+ struct qp_setuser_pkt setuser;
} qp_u;
};
@@ -61,14 +68,17 @@ struct qa_packet {
#define qp_runcmd qp_u.runcmd
#define qp_ack qp_u.ack
#define qp_cmdexit qp_u.cmdexit
+#define qp_setuser qp_u.setuser
/* Prototypes */
char *qp_packet_type(enum qa_packet_type t);
struct qa_packet *parse_packets(char *buf, int n);
struct qa_packet *make_qp_hello(char *greeting);
+struct qa_packet *make_qp_returncode(int rc, int eno, char *strerr);
struct qa_packet *make_qp_ack(enum qa_packet_type t, int i);
struct qa_packet *make_qp_runcmd(char *cmdline, int p_in, int p_out, int p_err);
struct qa_packet *make_qp_cmdexit(pid_t pid, int status);
+struct qa_packet *make_qp_setuser(char *user, char *group);
char *qptostr(struct qa_packet *qp, char **qpstr, int *qpsize);
void qpfree(struct qa_packet *qp);
void dump_qp(struct qa_packet *qp);
diff --git a/qarsh/qarshd.c b/qarsh/qarshd.c
index 9a90782..d443704 100644
--- a/qarsh/qarshd.c
+++ b/qarsh/qarshd.c
@@ -11,6 +11,9 @@
#include <sys/wait.h>
#include <sys/socket.h>
#include <arpa/inet.h>
+#include <pwd.h>
+#include <grp.h>
+
#include "sockutil.h"
#include "qarsh_packet.h"
@@ -23,6 +26,28 @@
/* Globals */
struct sockaddr_in peername;
+int
+setup_user(char *user, char *group)
+{
+ struct passwd *pw;
+ struct group *grp;
+
+ if ((pw = getpwnam(user)) == NULL) {
+ syslog(LOG_WARNING, "User \"%s\" not found\n", user);
+ return 0;
+ }
+
+ if (group && (grp = getgrnam(group))) {
+ setgid(grp->gr_gid);
+ initgroups(pw->pw_name, grp->gr_gid);
+ } else {
+ setgid(pw->pw_gid);
+ initgroups(pw->pw_name, pw->pw_gid);
+ }
+ /* setuid is last so we can still do setgid and initgroups */
+ setuid(pw->pw_uid);
+ return 1;
+}
pid_t
run_cmd(const char *cmd, int p_in, int p_out, int p_err)
@@ -109,6 +134,16 @@ handle_packets(int infd)
break;
}
switch (qp->qp_type) {
+ case QP_SETUSER:
+ if (setup_user(qp->qp_setuser.qp_user,
+ qp->qp_setuser.qp_group) == 0) {
+ rp = make_qp_returncode(-1, 0, "User not found");
+ } else {
+ rp = make_qp_ack(QP_SETUSER, 1);
+ }
+ send_packet(fileno(stdout), rp);
+ qpfree(rp);
+ break;
case QP_RUNCMD:
child_pid = run_cmd(qp->qp_runcmd.qp_cmdline,
qp->qp_runcmd.qp_stdin_port,
@@ -117,6 +152,7 @@ handle_packets(int infd)
waitpid(child_pid, &child_status, 0);
rp = make_qp_cmdexit(child_pid, child_status);
send_packet(fileno(stdout), rp);
+ qpfree(rp);
break;
default:
syslog(LOG_WARNING,