50#define SRP_INIT_MARKER 0x0001
51#define SRP_CLIENT_PROOF 0x0003
52#define SRP_SERVER_PROOF 0x0004
54#define SRP_SESSION_KEY_LEN 40
57#define SRP_AUTH_FAILURE (-6754)
78 size_t len,
size_t *out_len)
80 while (len > 1 && *
buf == 0) {
98 unsigned char *out,
size_t out_len)
100 unsigned char counter_be[4];
103 uint32_t counter = 0;
105 while (pos < out_len) {
106 counter_be[0] = (counter >> 24) & 0xFF;
107 counter_be[1] = (counter >> 16) & 0xFF;
108 counter_be[2] = (counter >> 8) & 0xFF;
109 counter_be[3] = counter & 0xFF;
112 if (gcry_md_open(&hd, GCRY_MD_SHA1, 0) != 0) {
116 gcry_md_write(hd,
seed, seed_len);
117 gcry_md_write(hd, counter_be, 4);
118 memcpy(hash, gcry_md_read(hd, GCRY_MD_SHA1),
SRP_SHA1_LEN);
120 size_t to_copy = out_len - pos;
126 memcpy(out + pos, hash, to_copy);
148 gcry_error_t err = gcry_md_open(&hd, GCRY_MD_SHA1, 0);
157 const unsigned char *
data = va_arg(ap,
const unsigned char *);
163 size_t len = va_arg(ap,
size_t);
164 gcry_md_write(hd,
data, len);
168 memcpy(out, gcry_md_read(hd, GCRY_MD_SHA1),
SRP_SHA1_LEN);
183 memset(
buf, 0, nbytes);
184 gcry_mpi_print(GCRYMPI_FMT_USG,
buf, nbytes, &nwritten, m);
186 if (nwritten < nbytes) {
187 memmove(
buf + nbytes - nwritten,
buf, nwritten);
188 memset(
buf, 0, nbytes - nwritten);
200 (*p)[0] = (val >> 8) & 0xFF;
201 (*p)[1] = val & 0xFF;
213 uint16_t val = (uint16_t)((*p)[0] << 8 | (*p)[1]);
220#define unhex(x) (isdigit(x) ? (x) - '0' : toupper(x) + 10 - 'A')
249 const char *username,
251 unsigned char *salt_out,
256 char uid_name[3 *
sizeof(uid_t) + 1];
260 int dirfd = -1, fd = -1;
263 if (!srp_valid_username(username)) {
267 int uid_len = snprintf(uid_name,
sizeof(uid_name),
"%ju", (uintmax_t)uid);
269 if (uid_len < 0 || uid_len >= (
int)
sizeof(uid_name)) {
273 dirfd = open(
path, O_RDONLY | O_DIRECTORY | O_CLOEXEC | O_NOFOLLOW);
275 if (dirfd < 0 ||
fstat(dirfd, &st) < 0 || !
S_ISDIR(st.st_mode) ||
276 st.st_uid != 0 || (st.st_mode & (S_IWGRP | S_IWOTH))) {
277 if (dirfd < 0 && lstat(
path, &st) == 0 && S_ISREG(st.st_mode)) {
279 "srp_lookup_verifier: %s is a legacy flat SRP verifier file; stop afpd and run 'afppasswd -m'",
283 "srp_lookup_verifier: unsafe or unavailable verifier directory %s",
291 fd = openat(dirfd, uid_name, O_RDONLY | O_CLOEXEC | O_NOFOLLOW);
294 if (errno != ENOENT) {
296 "srp_lookup_verifier: can't open verifier %s/%s: %s",
path,
297 uid_name, strerror(errno));
304 if (
fstat(fd, &st) < 0) {
306 "srp_lookup_verifier: can't stat verifier %s/%s: %s",
path,
307 uid_name, strerror(errno));
312 if (!S_ISREG(st.st_mode)) {
314 "srp_lookup_verifier: verifier %s/%s for user %s is not a regular file",
315 path, uid_name, username);
320 if ((st.st_uid != uid && st.st_uid != 0) ||
321 !srp_verifier_mode_is_safe(st.st_mode) || st.st_nlink != 1) {
323 "srp_lookup_verifier: unsafe verifier %s/%s for user %s: "
324 "owner uid %ju (expected %ju), mode %04o (must not grant group "
325 "or other access), link count %ju (expected 1)",
326 path, uid_name, username, (uintmax_t)st.st_uid, (uintmax_t)uid,
327 (
unsigned int)(st.st_mode & 07777), (uintmax_t)st.st_nlink);
332 fp = fdopen(fd,
"r");
336 "srp_lookup_verifier: can't open verifier stream %s/%s: %s",
337 path, uid_name, strerror(errno));
344 if (fgets(line,
sizeof(line), fp) ==
NULL || fgetc(fp) != EOF) {
346 "srp_lookup_verifier: invalid verifier %s/%s for user %s: must contain exactly one record",
347 path, uid_name, username);
352 p = strchr(line,
':');
354 if (p ==
NULL || (
size_t)(p - line) != ulen ||
355 strncmp(line, username, ulen) != 0) {
357 "srp_lookup_verifier: invalid verifier %s/%s for user %s: username does not match",
358 path, uid_name, username);
365 if (!srp_valid_fields(p)) {
367 "srp_lookup_verifier: invalid verifier %s/%s for user %s: malformed fields",
368 path, uid_name, username);
379 if (st.st_uid != uid) {
381 "srp_lookup_verifier: unsafe active verifier %s/%s for user %s: "
382 "owner uid %ju (expected %ju)",
path, uid_name, username,
383 (uintmax_t)st.st_uid, (uintmax_t)uid);
389 salt_out[i] = (
unsigned char)((
unhex(p[0]) << 4) |
unhex(p[1]));
397 v_bytes[i] = (
unsigned char)((
unhex(p[0]) << 4) |
unhex(p[1]));
401 if (gcry_mpi_scan(v_out, GCRYMPI_FMT_USG, v_bytes,
SRP_NBYTES,
406 "srp_lookup_verifier: invalid verifier %s/%s for user %s",
407 path, uid_name, username);
463static int srp_setup(
void *obj,
char *ibuf _U_,
size_t ibuflen _U_,
464 char *rbuf,
size_t *rbuflen)
466 char *verifier_path =
NULL;
468 unsigned char *b_binary =
NULL;
477 (
void *)&verifier_path, &len) < 0) {
479 "srp_setup: can't get SRP verifier path option");
483 if (!verifier_path || len == 0) {
485 "srp_setup: SRP verifier path not configured");
491 gcry_mpi_scan(&
session_g, GCRYMPI_FMT_USG, &srp_g_byte, 1,
NULL);
499 switch (verifier_status) {
507 "srp_setup: user %s is not enrolled (root-owned disabled verifier)",
513 "srp_setup: SRP verifier is disabled for user %s",
524 "srp_setup: unknown verifier state for user %s",
533 unsigned char *rbufp = (
unsigned char *)rbuf;
543 if (b_binary ==
NULL) {
550 kv = gcry_mpi_new(0);
567 gcry_mpi_t gb = gcry_mpi_new(0);
570 gcry_randomize(b_binary,
SRP_NBYTES, GCRY_STRONG_RANDOM);
578 }
while (gcry_mpi_cmp_ui(
session_B, 0) == 0);
580 gcry_mpi_release(gb);
588 unsigned char *p = (
unsigned char *)rbuf;
608 *rbuflen = p - (
unsigned char *)rbuf;
612 gcry_mpi_release(kv);
617 gcry_mpi_release(kv);
628static int srp_login(
void *obj,
struct passwd **uam_pwd _U_,
629 char *ibuf,
size_t ibuflen,
630 char *rbuf,
size_t *rbuflen)
642 (
void *)&username, &ulen) < 0) {
646 len = (
unsigned char) * ibuf++;
649 if (len > ulen || len > ibuflen) {
653 memcpy(username, ibuf, len);
655 username[len] =
'\0';
657 if ((
unsigned long)ibuf & 1) {
673 return srp_setup(obj, ibuf, ibuflen, rbuf, rbuflen);
682static int srp_login_ext(
void *obj,
char *uname,
struct passwd **uam_pwd _U_,
683 char *ibuf,
size_t ibuflen,
684 char *rbuf,
size_t *rbuflen)
693 (
void *)&username, &ulen) < 0) {
702 memcpy(&temp16, uname,
sizeof(temp16));
705 if (!len || len > ulen) {
709 memcpy(username, uname + 2, len);
710 username[len] =
'\0';
724 return srp_setup(obj, ibuf, ibuflen, rbuf, rbuflen);
737 char *ibuf,
size_t ibuflen,
738 char *rbuf,
size_t *rbuflen)
743 unsigned char *S_binary =
NULL;
755 unsigned char *d = (
unsigned char *)ibuf;
756 const unsigned char *end = d + ibuflen;
791 const unsigned char *A_raw = d;
792 gcry_mpi_scan(&A, GCRYMPI_FMT_USG, d, A_len,
NULL);
795 tmp = gcry_mpi_new(0);
798 if (gcry_mpi_cmp_ui(tmp, 0) == 0) {
815 const unsigned char *M1_received = d;
820 memcpy(A_buf +
SRP_NBYTES - A_len, A_raw, A_len);
838 if (gcry_mpi_cmp_ui(u, 0) == 0) {
844 vu = gcry_mpi_new(0);
845 Avu = gcry_mpi_new(0);
853 if (S_binary ==
NULL) {
859 size_t S_stripped_len;
863 if (
mgf1_sha1(S_stripped, S_stripped_len,
K,
sizeof(
K)) != 0) {
873 size_t N_stripped_len;
895 xor_ng[i] = H_N[i] ^ H_g[i];
928 size_t A_stripped_len, B_stripped_len;
939 A_stripped, A_stripped_len,
940 B_stripped, B_stripped_len,
958 A_stripped, A_stripped_len,
967 unsigned char *p = (
unsigned char *)rbuf;
972 *rbuflen = p - (
unsigned char *)rbuf;
982 gcry_mpi_release(vu);
983 gcry_mpi_release(Avu);
984 gcry_mpi_release(tmp);
996 "SRP: unable to initialize libgcrypt");
#define AFPERR_PARAM
Definition afp.h:73
#define AFPERR_NOTAUTH
Definition afp.h:77
#define AFP_OK
Definition afp.h:51
#define AFPERR_AUTHCONT
Definition afp.h:55
#define AFPERR_MISC
Definition afp.h:68
int uam_checkuser(void *private, const struct passwd *pwd)
Definition afpd/uam.c:316
int uam_afpserver_option(void *private, const int what, void *option, size_t *len)
Definition afpd/uam.c:402
int uam_register(const int type, const char *path, const char *name,...)
Definition afpd/uam.c:114
struct passwd * uam_getname(void *private, char *name, const int len)
helper functions for plugin uams
Definition afpd/uam.c:219
void uam_unregister(const int type, const char *name)
Definition afpd/uam.c:194
static char buf[MAXPATHLEN+1]
Definition afppasswd.c:85
void explicit_bzero(void *s, size_t n)
Definition explicit_bzero.c:32
size_t strlcpy(char *, const char *, size_t)
Definition strlcpy.c:36
size_t strnlen(const char *s, size_t n)
Definition misc.c:19
int seed(struct interface *iface, char **av)
Definition config.c:522
int atalk_ct_memcmp(const void *, const void *, size_t)
Constant-time memory equality check.
Definition constant_time.c:27
#define data
Definition hash.c:52
#define LOG(log_level, type,...)
Definition logger.h:148
#define UAM_MODULE_EXPORT
Definition logger.h:14
@ logtype_uams
Definition logger.h:41
@ log_error
Definition logger.h:20
@ log_info
Definition logger.h:23
#define S_ISDIR(s)
Definition megatron.h:96
#define SRP_USERNAME_MAX_LEN
Definition srp.h:14
#define SRP_NBYTES
Definition srp.h:11
#define SRP_GROUP_INDEX
Definition srp.h:13
#define SRP_SALT_LEN
Definition srp.h:10
#define SRP_SHA1_LEN
Definition srp.h:12
#define SRP_DISABLED_CHAR
Definition srp.h:15
#define SRP_FORMAT_LEN
Definition srp.h:23
Definition include/atalk/directory.h:140
#define fstat
Definition test_afppasswd.c:44
#define UAM_SERVER_LOGIN_EXT
Definition uam.h:30
#define UAM_USERNAMELEN
Definition uam.h:57
#define UAM_NEED_LIBGCRYPT_VERSION
Definition uam.h:24
#define UAM_OPTION_PASSWDOPT
Definition uam.h:35
#define UAM_OPTION_USERNAME
Definition uam.h:33
#define UAM_MODULE_VERSION
Definition uam.h:21
#define UAM_SERVER_LOGIN
Definition uam.h:27
#define UAM_MODULE_SERVER
Definition uam.h:17
#define UAM_PASSWD_SRP_VERIFIER_PATH
Definition uam.h:53
gcry_mpi_t K
Definition uams_dhx_pam.c:46
static gcry_mpi_t session_g
Definition uams_srp.c:62
static struct passwd * srppwd
Definition uams_srp.c:69
static uint16_t read_uint16_be(unsigned char **p)
Read a 2-byte big-endian unsigned integer and advance the pointer.
Definition uams_srp.c:211
static void write_uint16_be(unsigned char **p, uint16_t val)
Write a 2-byte big-endian unsigned integer and advance the pointer.
Definition uams_srp.c:198
#define unhex(x)
Definition uams_srp.c:220
srp_verifier_status
Definition uams_srp.c:222
@ SRP_VERIFIER_NOT_ENROLLED
Definition uams_srp.c:225
@ SRP_VERIFIER_INVALID
Definition uams_srp.c:228
@ SRP_VERIFIER_DISABLED
Definition uams_srp.c:226
@ SRP_VERIFIER_OK
Definition uams_srp.c:223
@ SRP_VERIFIER_MISSING
Definition uams_srp.c:224
@ SRP_VERIFIER_UNSAFE
Definition uams_srp.c:227
static int mgf1_sha1(const unsigned char *seed, size_t seed_len, unsigned char *out, size_t out_len)
MGF1 mask generation function (PKCS#1 v2.1) with SHA-1.
Definition uams_srp.c:97
static unsigned char session_B_buf[SRP_NBYTES]
Definition uams_srp.c:67
#define SRP_SERVER_PROOF
Definition uams_srp.c:52
static enum srp_verifier_status srp_lookup_verifier(const char *path, const char *username, uid_t uid, unsigned char *salt_out, gcry_mpi_t *v_out)
Look up a user's salt and verifier from their SRP verifier file.
Definition uams_srp.c:248
static unsigned char session_salt[SRP_SALT_LEN]
Definition uams_srp.c:66
#define SRP_INIT_MARKER
Definition uams_srp.c:50
#define SRP_CLIENT_PROOF
Definition uams_srp.c:51
static gcry_mpi_t session_N
Definition uams_srp.c:61
#define SRP_SESSION_KEY_LEN
Definition uams_srp.c:54
UAM_MODULE_EXPORT struct uam_export uams_srp
Definition uams_srp.c:1013
static gcry_mpi_t session_v
Definition uams_srp.c:63
static void mpi_to_padded_buf(unsigned char *buf, size_t nbytes, gcry_mpi_t m)
Write an MPI to a buffer as a big-endian integer, zero-padded.
Definition uams_srp.c:180
static int sha1_multi(unsigned char *out,...)
Compute SHA-1 incrementally from multiple buffers.
Definition uams_srp.c:144
static void srp_session_free(void)
Release all per-session SRP state and zero sensitive buffers.
Definition uams_srp.c:436
#define SRP_AUTH_FAILURE
Definition uams_srp.c:57
static gcry_mpi_t session_b
Definition uams_srp.c:64
static int srp_login(void *obj, struct passwd **uam_pwd, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
FPLogin handler for SRP UAM.
Definition uams_srp.c:628
static int uam_setup(void *obj, const char *path)
Definition uams_srp.c:991
static const unsigned char * strip_leading_zeros(const unsigned char *buf, size_t len, size_t *out_len)
Strip leading zero bytes from a big-endian integer buffer.
Definition uams_srp.c:77
static char session_username[UAM_USERNAMELEN+1]
Definition uams_srp.c:68
static int srp_login_ext(void *obj, char *uname, struct passwd **uam_pwd, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
FPLoginExt handler for SRP UAM.
Definition uams_srp.c:682
static void uam_cleanup(void)
Definition uams_srp.c:1008
static int srp_logincont(void *obj, struct passwd **uam_pwd, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
SRP Round 2: FPLoginCont handler.
Definition uams_srp.c:736
static gcry_mpi_t session_B
Definition uams_srp.c:65
static int srp_setup(void *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
SRP Round 1 setup.
Definition uams_srp.c:463
#define NULL
Definition utf8util.c:47