Commit 59b5cfc3 by Scott Duckworth

import sshkey app from webhandin

parents
diff --git a/auth2-pubkey.c b/auth2-pubkey.c
index 3ff6faa..61cad6f 100644
--- a/auth2-pubkey.c
+++ b/auth2-pubkey.c
@@ -458,11 +458,11 @@ user_key_allowed2(struct passwd *pw, Key *key, char *file)
static int
user_key_command_allowed2(struct passwd *user_pw, Key *key)
{
- FILE *f;
+ FILE *f_out, *f_in;
int ok, found_key = 0;
struct passwd *pw;
struct stat st;
- int status, devnull, p[2], i;
+ int status, devnull, pipe_in[2], pipe_out[2], i;
pid_t pid;
char *username, errmsg[512];
@@ -499,8 +499,15 @@ user_key_command_allowed2(struct passwd *user_pw, Key *key)
goto out;
}
- if (pipe(p) != 0) {
+ if (pipe(pipe_in) != 0) {
+ error("%s: pipe: %s", __func__, strerror(errno));
+ goto out;
+ }
+
+ if (pipe(pipe_out) != 0) {
error("%s: pipe: %s", __func__, strerror(errno));
+ close(pipe_in[0]);
+ close(pipe_in[1]);
goto out;
}
@@ -516,21 +523,18 @@ user_key_command_allowed2(struct passwd *user_pw, Key *key)
switch ((pid = fork())) {
case -1: /* error */
error("%s: fork: %s", __func__, strerror(errno));
- close(p[0]);
- close(p[1]);
+ close(pipe_in[0]);
+ close(pipe_in[1]);
+ close(pipe_out[0]);
+ close(pipe_out[1]);
return 0;
case 0: /* child */
for (i = 0; i < NSIG; i++)
signal(i, SIG_DFL);
- if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) {
- error("%s: open %s: %s", __func__, _PATH_DEVNULL,
- strerror(errno));
- _exit(1);
- }
/* Keep stderr around a while longer to catch errors */
- if (dup2(devnull, STDIN_FILENO) == -1 ||
- dup2(p[1], STDOUT_FILENO) == -1) {
+ if (dup2(pipe_in[0], STDIN_FILENO) == -1 ||
+ dup2(pipe_out[1], STDOUT_FILENO) == -1) {
error("%s: dup2: %s", __func__, strerror(errno));
_exit(1);
}
@@ -547,11 +551,16 @@ user_key_command_allowed2(struct passwd *user_pw, Key *key)
strerror(errno));
_exit(1);
}
- /* stdin is pointed to /dev/null at this point */
- if (dup2(STDIN_FILENO, STDERR_FILENO) == -1) {
+ if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) {
+ error("%s: open %s: %s", __func__, _PATH_DEVNULL,
+ strerror(errno));
+ _exit(1);
+ }
+ if (dup2(devnull, STDERR_FILENO) == -1) {
error("%s: dup2: %s", __func__, strerror(errno));
_exit(1);
}
+ close(devnull);
execl(options.authorized_keys_command,
options.authorized_keys_command, user_pw->pw_name, NULL);
@@ -565,18 +574,32 @@ user_key_command_allowed2(struct passwd *user_pw, Key *key)
temporarily_use_uid(pw);
- close(p[1]);
- if ((f = fdopen(p[0], "r")) == NULL) {
+ close(pipe_in[0]);
+ close(pipe_out[1]);
+ if ((f_in = fdopen(pipe_in[1], "w")) == NULL) {
error("%s: fdopen: %s", __func__, strerror(errno));
- close(p[0]);
+ close(pipe_in[1]);
+ close(pipe_out[0]);
/* Don't leave zombie child */
kill(pid, SIGTERM);
while (waitpid(pid, NULL, 0) == -1 && errno == EINTR)
;
goto out;
}
- ok = check_authkeys_file(f, options.authorized_keys_command, key, pw);
- fclose(f);
+ if ((f_out = fdopen(pipe_out[0], "r")) == NULL) {
+ error("%s: fdopen: %s", __func__, strerror(errno));
+ fclose(f_in);
+ close(pipe_out[0]);
+ /* Don't leave zombie child */
+ kill(pid, SIGTERM);
+ while (waitpid(pid, NULL, 0) == -1 && errno == EINTR)
+ ;
+ goto out;
+ }
+ key_write(key, f_in);
+ fclose(f_in);
+ ok = check_authkeys_file(f_out, options.authorized_keys_command, key, pw);
+ fclose(f_out);
while (waitpid(pid, &status, 0) == -1) {
if (errno != EINTR) {
from django.contrib import admin
from sshkey.models import UserKey
class UserKeyAdmin(admin.ModelAdmin):
search_fields = [
'user__username',
]
admin.site.register(UserKey, UserKeyAdmin)
#!/usr/bin/env python
import sshkey.util
import sys
sshkey.util.lookup_command(sys.argv[1:])
#!/bin/bash
url="$1"
if [ $# -eq 1 ]; then
read line
fingerprint=$(ssh-keygen -lf /dev/stdin <<< $line | cut -f2 -d' ')
exec curl -G "$url" --data-urlencode "fingerprint=${fingerprint}"
elif [ $# -eq 2 ]; then
username="$2"
exec curl -G "$url" --data-urlencode "username=${username}"
else
echo "Invalid number of arguments" >&2
exit 2
fi
from django.core.management.base import BaseCommand, CommandError
from django.conf import settings
from sshkey.models import sshkey_fingerprint, UserKey
import base64
import hashlib
import sys
class Command(BaseCommand):
args = '[<username>]'
def handle(self, *args, **options):
if len(args) == 0:
line = sys.stdin.readline()
if not line:
raise CommandError('no input given')
fingerprint = sshkey_fingerprint(line)
keys = UserKey.objects.filter(fingerprint=fingerprint)
elif len(args) == 1:
keys = UserKey.objects.filter(user__username=args[0])
else:
raise CommandError('invalid number of arguments')
status = 1
for key in keys:
status = 0
try:
options = 'command="%s" ' % (
settings.SSHKEY_AUTHORIZED_KEYS_COMMAND.format(username=key.user.username).replace('"', r'\"')
)
except AttributeError:
options = ''
print(options + key.key)
return status
from django.db import models
from django.dispatch import receiver
from django.db.models.signals import pre_save
from django.contrib.auth.models import User
from sshkey.util import sshkey_fingerprint
class UserKey(models.Model):
user = models.ForeignKey(User, db_index=True)
name = models.CharField(max_length=50)
key = models.TextField(max_length=2000)
fingerprint = models.CharField(max_length=47, unique=True, blank=True, db_index=True)
class Meta:
unique_together = [
('user', 'name'),
]
def __unicode__(self):
return unicode(self.user) + u': ' + self.name
@receiver(pre_save, sender=UserKey, dispatch_uid=__name__ + '.set_fingerprint')
def set_fingerprint(sender, instance, **kwargs):
instance.fingerprint = sshkey_fingerprint(instance.key)
"""
This file demonstrates writing tests using the unittest module. These will pass
when you run "manage.py test".
Replace this with more appropriate tests for your application.
"""
from django.test import TestCase
class SimpleTest(TestCase):
def test_basic_addition(self):
"""
Tests that 1 + 1 always equals 2.
"""
self.assertEqual(1 + 1, 2)
from django.conf.urls.defaults import patterns, url
urlpatterns = patterns('sshkey.views',
url(r'^lookup$', 'lookup'),
)
import base64
import hashlib
import re
sshkey_re = re.compile(r'\s*(?:(?P<options>.*?)\s+)?(?P<type>ssh-\w+)\s+(?P<key>\S+)(?:\s+(?P<comment>\S+))?\s*$')
def sshkey_fingerprint(key_line):
match = sshkey_re.match(key_line)
if not match:
return None
key = base64.b64decode(match.group('key'))
fp_plain = hashlib.md5(key).hexdigest()
return ':'.join(a+b for a,b in zip(fp_plain[::2], fp_plain[1::2]))
def lookup_command(args):
import sys
import urllib
if len(args) == 1:
url = args[0]
line = sys.stdin.readline()
if not line:
sys.stderr.write('no input given\n')
sys.exit(2)
fingerprint = sshkey_fingerprint(line)
url += '?fingerprint=' + urllib.quote_plus(fingerprint)
elif len(args) == 2:
url, username = args
url += '?username=' + urllib.quote_plus(username)
else:
sys.stderr.write('Invalid number of arguments\n')
sys.exit(2)
response = urllib.urlopen(url)
status = 1
for line in response.readlines():
status = 0
sys.stdout.write(line)
sys.exit(status)
from django.http import HttpResponse
from django.conf import settings
from sshkey.models import UserKey
def lookup(request):
try:
fingerprint = request.GET['fingerprint']
keys = UserKey.objects.filter(fingerprint=fingerprint)
except KeyError:
try:
username = request.GET['username']
keys = UserKey.objects.filter(user__username=username)
except KeyError:
keys = UserKey.objects.iterator()
response = ''
for key in keys:
try:
options = 'command="%s" ' % (
settings.SSHKEY_AUTHORIZED_KEYS_COMMAND
.format(username=key.user.username)
.replace('"', r'\"')
)
except AttributeError:
options = ''
response += options + key.key + '\n'
return HttpResponse(response, mimetype='text/plain')
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment