22 require Digest
::SHA
::PurePerl
;
23 Digest
::SHA
::PurePerl
->import(
26 die "One of Digest::SHA or Digest::SHA1 or Digest::SHA::PurePerl "
27 . "must be available\n";
32 filedb_atomic_append
(jailed_file
('/etc/passwd'),
33 join(':', $self->{name
}, 'x', '\i', 65534, $self->{email
}, '/', '/bin/git-shell'));
38 filedb_atomic_edit
(jailed_file
('/etc/passwd'),
42 if ($self->{name
} eq (split /:/)[0]) {
43 # preserve all but login name and comment field
44 my @fields=split(/:/, $_, -1);
45 $fields[0] = $self->{name
};
46 $fields[4] = $self->{email
};
47 return join(':', @fields)."\n";
57 '/etc/sshkeys/'.$self->{name
};
62 open F
, "<".jailed_file
($self->_sshkey_path) or die "sshkey load failed: $!";
67 if (/^ssh-(?:dss|rsa) /) {
69 } elsif (/^# REPOAUTH ([0-9a-f]+) (\d+)/) {
71 $auth = $1 unless (time >= $expire);
75 my $keys = join("\n", @keys); chomp $keys;
81 open F
, ">".jailed_file
($self->_sshkey_path) or die "sshkey failed: $!";
82 if (defined($self->{auth
}) && $self->{auth
}) {
83 my $expire = time + 24 * 3600;
84 print F
"# REPOAUTH $self->{auth} $expire\n";
86 print F
$self->{keys}."\n";
88 chmod 0664, jailed_file
($self->_sshkey_path);
91 # private constructor, do not use
95 Girocco
::User
::valid_name
($name) or die "refusing to create user with invalid name ($name)!";
96 my $proj = { name
=> $name };
101 # public constructor #0
102 # creates a virtual user not connected to disk record
103 # you can conjure() it later to disk
107 my $self = $class->_new($name);
111 # public constructor #1
116 open F
, jailed_file
("/etc/passwd") or die "user load failed: $!";
120 next unless (shift eq $name);
122 my $self = $class->_new($name);
124 (undef, $self->{uid
}, undef, $self->{email
}) = @_;
125 ($self->{keys}, $self->{auth
}) = $self->_sshkey_load;
133 # public constructor #2
138 open F
, jailed_file
("/etc/passwd") or die "user load failed: $!";
142 next unless ($_[2] eq $uid);
144 my $self = $class->_new($_[0]);
146 (undef, undef, $self->{uid
}, undef, $self->{email
}) = @_;
147 ($self->{keys}, $self->{auth
}) = $self->_sshkey_load;
155 # $user may not be in sane state if this returns false!
159 my $cgi = $gcgi->cgi;
161 $self->{name
} = $gcgi->wparam('name');
162 Girocco
::User
::valid_name
($self->{name
})
163 or $gcgi->err("Name contains invalid characters.");
165 $self->{email
} = $gcgi->wparam('email');
166 valid_email
($self->{email
})
167 or $gcgi->err("Your email sure looks weird...?");
169 $self->keys_fill($gcgi);
175 foreach (split /\r\n|\r|\n/, $keys) {
176 next if /^[ \t]*$/ || /^[ \t]*#/;
179 return join("\n", @lines);
185 my $email = shift || '';
187 if (valid_email
($email)) {
188 $self->{email
} = $email;
189 $self->_passwd_update;
191 $gcgi->err("Your email sure looks weird...?");
194 not $gcgi->err_check;
200 my $cgi = $gcgi->cgi;
202 $self->{keys} = _trimkeys
($cgi->param('keys'));
203 length($self->{keys}) <= 4096
204 or $gcgi->err("The list of keys is more than 4kb. Do you really need that much?");
205 foreach (split /\r?\n/, $self->{keys}) {
207 /^ssh-(?:dss|rsa) [0-9A-Za-z+\/=]+ \S
+@\S
+$/
208 or $keyval=CGI
::escapeHTML
($_),$gcgi->err(<<EOT);
209 Your ssh key ("$keyval") appears to have an invalid format
210 (does not start with ssh-dss or ssh-rsa or does not end with <tt>\@</tt>-identifier) -
211 maybe your browser has split a single key onto multiple lines?
215 not $gcgi->err_check;
227 $self->{auth
} = sha1_hex
(time . $$ . rand() . $self->{keys});
235 delete $self->{auth
};
249 /^[a-zA-Z0-9+._-]+$/;
254 Girocco
::User
::valid_name
($name) or die "tried to query for user with invalid name $name!";
255 (-e jailed_file
("/etc/sshkeys/$name"));
260 $Girocco::Config
::chrooted
and undef; # TODO for ACLs within chroot
261 scalar(getpwnam($name));