1254 lines
36 KiB
C
1254 lines
36 KiB
C
/*
|
|
NDS client for ncpfs
|
|
Copyright (C) 1997 Arne de Bruijn
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
|
|
#define RANDBUF /* if defined: read random data once from /dev/urandom */
|
|
/*#define ERR_MSG*/ /* if defined: show error messages in nds_login_auth */
|
|
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <ctype.h>
|
|
#ifdef ERR_MSG
|
|
#include <stdio.h>
|
|
#endif
|
|
#include <unistd.h>
|
|
#include <sys/time.h>
|
|
#ifdef RANDBUF
|
|
#include <fcntl.h>
|
|
#endif
|
|
#include "ncplib.h"
|
|
#include "ncplib_err.h"
|
|
#include "ndslib.h"
|
|
#include "ndscrypt.h"
|
|
|
|
#define USUALS
|
|
typedef u_int32_t word32;
|
|
typedef u_int16_t word16;
|
|
typedef unsigned char boolean;
|
|
|
|
#include "mpilib.h"
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include "kernel/ipx.h"
|
|
#include <errno.h>
|
|
#include "ndslib.h"
|
|
|
|
int bindery_only = 0;
|
|
|
|
static int buf_get_dword_lh(char **buf, char *bufend, u_int32_t *v) {
|
|
if ((*buf) + 4 <= bufend) {
|
|
if (v)
|
|
*v = DVAL_LH(*buf, 0);
|
|
(*buf) += 4;
|
|
return 0;
|
|
} else
|
|
return -1;
|
|
}
|
|
|
|
static int buf_get_lbuf(char **buf, char *bufend, char *out, int outmax,
|
|
int *outlen) {
|
|
int i, j;
|
|
|
|
if ((!buf_get_dword_lh(buf, bufend, &i)) && (*buf + i <= bufend)) {
|
|
j = i;
|
|
if (out) {
|
|
if (j > outmax) j = outmax;
|
|
memcpy(out, *buf, j);
|
|
}
|
|
if (outlen) *outlen = j;
|
|
*buf += (i + 3) & (~3);
|
|
return 0;
|
|
} else
|
|
return -1;
|
|
}
|
|
|
|
static int buf_put_word_lh2(char **buf, char *bufend, u_int16_t v) {
|
|
if ((*buf) + 2 <= bufend) {
|
|
WSET_LH(*buf, 0, v);
|
|
*buf += 2;
|
|
return 0;
|
|
} else
|
|
return -1;
|
|
}
|
|
|
|
static int buf_put_dword_lh(char **buf, char *bufend, u_int32_t v) {
|
|
if ((buf) && ((*buf) + 4 <= bufend)) {
|
|
DSET_LH(*buf, 0, v);
|
|
*buf += 4;
|
|
return 0;
|
|
} else
|
|
return -1;
|
|
}
|
|
|
|
static int buf_put_dword_hl(char **buf, char *bufend, u_int32_t v) {
|
|
if ((*buf) + 4 <= bufend) {
|
|
DSET_HL(*buf, 0, v);
|
|
*buf += 4;
|
|
return 0;
|
|
} else
|
|
return -1;
|
|
}
|
|
|
|
static int buf_put_lbuf(char **buf, char *bufend, const char *databuf,
|
|
size_t buflen) {
|
|
if ((!buf_put_dword_lh(buf, bufend, buflen)) &&
|
|
(*buf + buflen <= bufend)) {
|
|
if (!buflen) return 0; /* explicitly allow {NULL, 0} buffer */
|
|
if (!databuf) return -1;
|
|
memcpy(*buf, databuf, buflen);
|
|
(*buf) += buflen;
|
|
while (buflen++ & 3)
|
|
*(*buf)++ = 0;
|
|
return 0;
|
|
} else
|
|
return -1;
|
|
}
|
|
|
|
static int buf_put_buf(char **buf, char *bufend, const char *databuf,
|
|
size_t buflen) {
|
|
if ((databuf) && (*buf + buflen <= bufend)) {
|
|
memcpy(*buf, databuf, buflen);
|
|
(*buf) += buflen;
|
|
while (buflen++ & 3)
|
|
*(*buf)++ = 0;
|
|
return 0;
|
|
} else
|
|
return -1;
|
|
}
|
|
|
|
static int buf_put_unistr(char **buf, char *bufend, const uni_char *str) {
|
|
int i = (strlen_u(str) + 1) * 2;
|
|
|
|
if ((str) && (!buf_put_dword_lh(buf, bufend, i)) &&
|
|
(*buf + i <= bufend)) {
|
|
memcpy(*buf, str, i);
|
|
(*buf) += i;
|
|
while (i++ & 3)
|
|
*(*buf)++ = 0;
|
|
return 0;
|
|
} else
|
|
return -1;
|
|
}
|
|
|
|
static int buf_get_dword_hl(char **buf, char *bufend, u_int32_t *v) {
|
|
if ((*buf) + 4 <= bufend) {
|
|
if (v) {
|
|
*v = DVAL_HL(*buf, 0);
|
|
}
|
|
(*buf) += 4;
|
|
return 0;
|
|
} else
|
|
return -1;
|
|
}
|
|
|
|
static int buf_get_word_lh(char **buf, char *bufend, u_int16_t *v) {
|
|
if (((*buf) + 2 <= bufend)) {
|
|
if (v) {
|
|
*v = WVAL_LH(*buf, 0);
|
|
}
|
|
(*buf) += 4;
|
|
return 0;
|
|
} else
|
|
return -1;
|
|
}
|
|
|
|
static int buf_get_word_lh2(char **buf, char *bufend, u_int16_t *v) {
|
|
if (((*buf) + 2 <= bufend)) {
|
|
if (v) {
|
|
*v = WVAL_LH(*buf, 0);
|
|
}
|
|
(*buf) += 2;
|
|
return 0;
|
|
} else
|
|
return -1;
|
|
}
|
|
|
|
static int buf_get_lbuf_alloc(char **buf, char *bufend,
|
|
char **outbuf, int *bufsize) {
|
|
int i, err = 0;
|
|
|
|
if ((!buf_get_dword_lh(buf, bufend, &i)) && (*buf + i <= bufend)) {
|
|
if (outbuf) {
|
|
if (((*outbuf) = malloc(i)))
|
|
memcpy(*outbuf, *buf, i);
|
|
else
|
|
err = ENOMEM;
|
|
}
|
|
(*buf) += (i + 3) & (~3);
|
|
if (bufsize) *bufsize = i;
|
|
return err;
|
|
} else {
|
|
if (outbuf) *outbuf = NULL;
|
|
if (bufsize) *bufsize = 0;
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
static int buf_get_buf(char **buf, char *bufend, char *outbuf, size_t bufsize) {
|
|
if (*buf + bufsize <= bufend) {
|
|
if (outbuf) memcpy(outbuf, *buf, bufsize);
|
|
*buf += (bufsize + 3) & (~3);
|
|
return 0;
|
|
} else
|
|
return -1;
|
|
}
|
|
|
|
int strlen_u(const uni_char *s) {
|
|
int i = 0;
|
|
while (*s++) i++;
|
|
return i;
|
|
}
|
|
|
|
void strcpy_uc(char *d, const uni_char *s) {
|
|
while ((*d++ = *s++));
|
|
}
|
|
|
|
void strcpy_cu(uni_char *d, const char *s) {
|
|
while ((*d++ = *s++));
|
|
}
|
|
|
|
long nds_get_server_name(struct ncp_conn *conn, uni_char **server_name) {
|
|
long err;
|
|
int outlen;
|
|
char *p, *pend, *outbuf;
|
|
|
|
if (!(outbuf = malloc(4096)))
|
|
return ENOMEM;
|
|
if (server_name) *server_name = NULL;
|
|
if ((err = ncp_send_nds_frag(conn, 53, NULL, 0,
|
|
outbuf, 4096, &outlen)) == 0) {
|
|
pend = (p = outbuf) + outlen;
|
|
if (buf_get_dword_lh(&p, pend, &outlen))
|
|
err = NCPL_ET_REPLY_FORMAT;
|
|
else {
|
|
if (!((*server_name) = malloc(outlen)))
|
|
err = ENOMEM;
|
|
else
|
|
memcpy(*server_name, p, outlen);
|
|
}
|
|
}
|
|
free(outbuf);
|
|
return err;
|
|
}
|
|
|
|
long nds_get_tree_name(struct ncp_conn *conn, char *name, int name_buf_len) {
|
|
char buf[128];
|
|
int size;
|
|
long err;
|
|
char *p, *pend;
|
|
|
|
if (bindery_only) return -1;
|
|
|
|
if (!(err = ncp_send_nds(conn, 1, "\0\0\0", 3, buf, sizeof(buf),
|
|
&size))) {
|
|
p = buf + 4;
|
|
pend = buf + size;
|
|
if (buf_get_lbuf(&p, pend, name, name_buf_len, &size))
|
|
return NCPL_ET_REPLY_FORMAT;
|
|
if (name) {
|
|
p = name + size - 1;
|
|
while ((p >= name) && (!*p))
|
|
p--;
|
|
while ((p >= name) && (*p == '_'))
|
|
p--;
|
|
*(p + 1) = 0;
|
|
}
|
|
}
|
|
return err;
|
|
}
|
|
|
|
/* for login */
|
|
long nds_resolve_name(struct ncp_conn *conn, int flags, uni_char *entry_name,
|
|
int *entry_id, int *remote, struct sockaddr *serv_addr, size_t *addr_len) {
|
|
char *buf, *p, *pend, addr_buf[12];
|
|
long err;
|
|
int i;
|
|
|
|
if (!(buf = malloc(4096)))
|
|
return ENOMEM;
|
|
pend = (p = buf) + 2048;
|
|
buf_put_dword_lh(&p, pend, 0);
|
|
buf_put_dword_lh(&p, pend, flags);
|
|
buf_put_dword_lh(&p, pend, 0);
|
|
buf_put_unistr(&p, pend, entry_name);
|
|
buf_put_dword_lh(&p, pend, 1);
|
|
buf_put_dword_lh(&p, pend, 0);
|
|
buf_put_dword_lh(&p, pend, 1);
|
|
buf_put_dword_lh(&p, pend, 0);
|
|
if ((err = ncp_send_nds_frag(conn, 1, buf, p - buf, buf + 2048, 2048,
|
|
&i)) == 0) {
|
|
pend = (p = buf + 2048) + i;
|
|
if (buf_get_dword_lh(&p, pend, &i) || (i < 0) || (i > 2))
|
|
err = NCPL_ET_REPLY_FORMAT;
|
|
else if (i == 1) {
|
|
if (remote) *remote = 0;
|
|
if (buf_get_dword_hl(&p, pend, entry_id))
|
|
err = NCPL_ET_REPLY_FORMAT;
|
|
} else {
|
|
if (remote) *remote = 1;
|
|
if ((!serv_addr) || (!addr_len)) {
|
|
free(buf);
|
|
return 0;
|
|
}
|
|
if (buf_get_dword_hl(&p, pend, entry_id) ||
|
|
buf_get_dword_lh(&p, pend, &i) || (i != 0) ||
|
|
buf_get_dword_lh(&p, pend, &i) || (i == 0) ||
|
|
buf_get_dword_lh(&p, pend, &i))
|
|
err = NCPL_ET_REPLY_FORMAT;
|
|
else if (i != 0) /* no ipx? */
|
|
err = NCPL_ET_TRANSPORT_UNKNOWN;
|
|
else if (buf_get_dword_lh(&p, pend, &i) || (i != 12) ||
|
|
buf_get_buf(&p, pend, addr_buf, 12))
|
|
err = NCPL_ET_REPLY_FORMAT;
|
|
else if (*addr_len < sizeof(struct sockaddr_ipx))
|
|
err = EINVAL;
|
|
else {
|
|
((struct sockaddr_ipx *)serv_addr)->sipx_family = AF_IPX;
|
|
((struct sockaddr_ipx *)serv_addr)->sipx_type = NCP_PTYPE;
|
|
/* buf and addr both in network order */
|
|
memcpy(&((struct sockaddr_ipx *)serv_addr)->sipx_network,
|
|
addr_buf, 4);
|
|
memcpy(((struct sockaddr_ipx *)serv_addr)->sipx_node,
|
|
addr_buf + 4, 6);
|
|
memcpy(&((struct sockaddr_ipx *)serv_addr)->sipx_port,
|
|
addr_buf + 10, 2);
|
|
*addr_len = sizeof(struct sockaddr_ipx);
|
|
}
|
|
}
|
|
}
|
|
free(buf);
|
|
return err;
|
|
}
|
|
|
|
long nds_readentryname(struct ncp_conn *conn, int obj_id,
|
|
uni_char **name, int *namelen) {
|
|
char reqbuf[16], *p, *pend, *buf;
|
|
uni_char *p2;
|
|
long err;
|
|
int outlen;
|
|
|
|
if (name) *name = NULL;
|
|
if (namelen) *namelen = 0;
|
|
pend = (p = reqbuf) + 16;
|
|
buf_put_dword_lh(&p, pend, 2);
|
|
buf_put_dword_lh(&p, pend, 0);
|
|
buf_put_dword_lh(&p, pend, 0x281d);
|
|
buf_put_dword_hl(&p, pend, obj_id);
|
|
if (!(buf = malloc(4096)))
|
|
return ENOMEM;
|
|
if ((err = ncp_send_nds_frag(conn, 2, reqbuf, 16, buf, 4096, &outlen))) {
|
|
free(buf);
|
|
return err;
|
|
}
|
|
pend = (p = buf) + outlen;
|
|
p += 16;
|
|
buf_get_lbuf(&p, pend, NULL, 0, NULL);
|
|
if ((buf_get_dword_lh(&p, pend, &outlen)) ||
|
|
(outlen > pend - p)) {
|
|
free(buf);
|
|
return NCPL_ET_REPLY_FORMAT;
|
|
}
|
|
if (name) {
|
|
if (!(p2 = malloc(outlen))) {
|
|
free(buf);
|
|
return ENOMEM;
|
|
}
|
|
memcpy(p2, p, outlen);
|
|
*name = p2;
|
|
}
|
|
if (namelen) *namelen = outlen;
|
|
free(buf);
|
|
return 0;
|
|
}
|
|
|
|
long nds_read(struct ncp_conn *conn, int obj_id, uni_char *propname,
|
|
char **outbuf, int *outlen) {
|
|
long err;
|
|
char *buf, *p, *pend;
|
|
int n1, n2, n3, n4, n5;
|
|
|
|
if (outbuf) *outbuf = NULL;
|
|
if (outlen) *outlen = 0;
|
|
if (!(buf = malloc(4096)))
|
|
return ENOMEM;
|
|
pend = (p = buf) + 2048;
|
|
buf_put_dword_lh(&p, pend, 0);
|
|
buf_put_dword_lh(&p, pend, -1L);
|
|
buf_put_dword_hl(&p, pend, obj_id);
|
|
buf_put_dword_lh(&p, pend, 1);
|
|
buf_put_dword_lh(&p, pend, 0);
|
|
buf_put_dword_lh(&p, pend, 1);
|
|
buf_put_unistr(&p, pend, propname);
|
|
if (!(err = ncp_send_nds_frag(conn, 3, buf, p - buf,
|
|
buf + 2048, 2048, &n1))) {
|
|
pend = (p = (buf + 2048)) + n1;
|
|
if (!(err = buf_get_dword_lh(&p, pend, &n1)) &&
|
|
!(err = buf_get_dword_lh(&p, pend, &n2)) &&
|
|
!(err = buf_get_dword_lh(&p, pend, &n3)) &&
|
|
!(err = buf_get_dword_lh(&p, pend, &n4)) &&
|
|
!(err = buf_get_lbuf(&p, pend, NULL, 0, NULL)) &&
|
|
!(err = buf_get_dword_lh(&p, pend, &n5))) {
|
|
if ((n1 != -1) || (n2 != 1) || (n3 != 1) ||
|
|
(n4 != 9) || (n5 != 1))
|
|
err = -1;
|
|
else
|
|
err = buf_get_lbuf_alloc(&p, pend, outbuf, outlen);
|
|
}
|
|
}
|
|
free(buf);
|
|
return err;
|
|
}
|
|
|
|
#ifdef RANDBUF
|
|
#define RANDBUFSIZE 1236 /* total size of all fillrandom's for login+auth */
|
|
char global_randbuf[RANDBUFSIZE];
|
|
char *g_rndp = global_randbuf + RANDBUFSIZE;
|
|
|
|
void fillrandom(char *buf, int buflen) {
|
|
int fh,i;
|
|
|
|
do {
|
|
if (g_rndp == global_randbuf + RANDBUFSIZE) {
|
|
if ((fh = open("/dev/urandom", O_RDONLY)) >=0) {
|
|
read(fh, global_randbuf, RANDBUFSIZE);
|
|
close(fh);
|
|
} else {
|
|
g_rndp = global_randbuf;
|
|
while (g_rndp - global_randbuf < RANDBUFSIZE)
|
|
*(g_rndp++) = rand() / ((((unsigned)RAND_MAX)+255) / 256);
|
|
}
|
|
g_rndp = global_randbuf;
|
|
}
|
|
if ((i = RANDBUFSIZE - (g_rndp - global_randbuf)) > buflen) i = buflen;
|
|
memcpy(buf, g_rndp, i);
|
|
buf += i;
|
|
g_rndp += i;
|
|
buflen -= i;
|
|
} while (buflen);
|
|
}
|
|
#else
|
|
void fillrandom(char *buf, int buflen) {
|
|
int fh;
|
|
char *p;
|
|
|
|
if (((fh = open("/dev/urandom", O_RDONLY)) >= 0) {
|
|
read(fh, buf, buflen);
|
|
close(fh);
|
|
} else {
|
|
p = buf;
|
|
while (p - buf < buflen)
|
|
*(p++) = rand() / ((((unsigned)RAND_MAX)+255) / 256);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static int countbits_l(char *buf, int bufsize) {
|
|
unsigned char b;
|
|
|
|
while ((--bufsize) && (!buf[bufsize]));
|
|
b = (unsigned char)buf[bufsize];
|
|
bufsize <<= 3;
|
|
while (b) {
|
|
b >>= 2; bufsize++;
|
|
}
|
|
return bufsize;
|
|
}
|
|
|
|
static void copyfill(void *outbuf, int outsize, const void *inbuf, int insize) {
|
|
if (outsize < insize) insize = outsize;
|
|
memcpy(outbuf, inbuf, insize);
|
|
memset((char *)outbuf + insize, 0, outsize - insize);
|
|
}
|
|
|
|
static uni_char c_public_key[] = {'P','u','b','l','i','c',' ','K','e','y',0};
|
|
|
|
static char keyprefix[] = {1, 0, 0, 0, 3, 0, 1, 0};
|
|
|
|
static int initkey(const char *key, char **keyptr, int *keylen) { /* 1=ok, 0=err */
|
|
if (!memcmp(key, keyprefix, 8)) {
|
|
if (keylen) *keylen = WVAL_LH(key, 8);
|
|
if (keyptr) (const char *)(*keyptr) = key + 10;
|
|
return 1;
|
|
} else
|
|
return 0;
|
|
}
|
|
|
|
static void clearkey(char *key) {
|
|
char *keyptr;
|
|
int keylen;
|
|
if (initkey(key, &keyptr, &keylen))
|
|
memset(key, 0, keylen + 10);
|
|
}
|
|
|
|
static int findchunk(const char *keyptr, int keylen, const char *chunk,
|
|
char **chunkptr) {
|
|
const char *p;
|
|
|
|
if ((p = keyptr)) {
|
|
while (p - keyptr < keylen) {
|
|
if ((p[0] != chunk[0]) || (p[1] != chunk[1]))
|
|
p += 4 + (unsigned char)p[2] + (unsigned char)p[3];
|
|
else {
|
|
if (chunkptr) (const char *)(*chunkptr) = p + 4;
|
|
return (unsigned char)p[2] + (unsigned char)p[3];
|
|
}
|
|
}
|
|
}
|
|
if (chunkptr) *chunkptr = NULL;
|
|
return 0;
|
|
}
|
|
|
|
static int checkkey(const char *key) { /* 0 - wrong key, != 0 - key ok */
|
|
char temp[8];
|
|
char *keyptr, *p;
|
|
int keylen;
|
|
|
|
if ((initkey(key, &keyptr, &keylen)) &&
|
|
(findchunk(keyptr, keylen, "MA", &p))) {
|
|
nwhash1init(temp, 8);
|
|
nwhash1(temp, 8, key + 10, WVAL_LH(key, 8) - 20);
|
|
return (!memcmp(p, temp, 8));
|
|
} else
|
|
return 0;
|
|
|
|
}
|
|
|
|
static long modexpkey(const char *s_key, char *buf, char *outbuf, int bufsize) {
|
|
char *s_keyptr;
|
|
int s_keylen, i, nbits, nblocksize;
|
|
int err = -1;
|
|
unitptr nmod, nexp, nin, nout;
|
|
char *p;
|
|
|
|
nmod = nexp = nin = nout = NULL;
|
|
|
|
if (!initkey(s_key, &s_keyptr, &s_keylen))
|
|
return NCPL_ET_REPLY_FORMAT;
|
|
i = findchunk(s_keyptr, s_keylen, "NN", &p);
|
|
if (!p)
|
|
return NCPL_ET_REPLY_FORMAT;
|
|
nbits = countbits_l(p, i);
|
|
nblocksize = ((nbits + 31) & (~31)) >> 3;
|
|
if (!(nmod = malloc(nblocksize)))
|
|
return ENOMEM;
|
|
copyfill(nmod, nblocksize, p, i);
|
|
i = findchunk(s_keyptr, s_keylen, "EN", &p);
|
|
err = NCPL_ET_REPLY_FORMAT;
|
|
if (!p) goto end;
|
|
err = ENOMEM;
|
|
if (!(nexp = malloc(nblocksize))) goto end;
|
|
copyfill(nexp, nblocksize, p, i);
|
|
if (!(nin = malloc(nblocksize))) goto end;
|
|
copyfill(nin, nblocksize, buf, bufsize);
|
|
if (!(nout = malloc(nblocksize))) goto end;
|
|
set_precision(bytes2units(nblocksize));
|
|
if (mp_modexp((unitptr) nout, (unitptr) nin, (unitptr) nexp,
|
|
(unitptr) nmod))
|
|
err = NCPL_ET_REPLY_FORMAT;
|
|
else {
|
|
copyfill(outbuf, bufsize, nout, nblocksize);
|
|
err = 0;
|
|
}
|
|
end:
|
|
if (nout) { mp_init0(nout); free(nout); }
|
|
if (nin) { mp_init0(nin); free(nin); }
|
|
if (nexp) free(nexp);
|
|
if (nmod) free(nmod);
|
|
return err;
|
|
}
|
|
|
|
long get_public_key(struct ncp_conn *conn, long obj_id, char **key) {
|
|
char *keybuf, *kptr;
|
|
long err;
|
|
int keylen, ofs, klen;
|
|
|
|
if ((err = nds_read(conn, obj_id, c_public_key, &keybuf, &keylen))) {
|
|
return err;
|
|
}
|
|
ofs = WVAL_LH(keybuf, 10) + 0x1a;
|
|
if ((ofs > keylen) || (!initkey(keybuf + ofs, &kptr, &klen)) ||
|
|
(klen + ofs > keylen) || (!checkkey(keybuf + ofs))) {
|
|
err = NCPL_ET_REPLY_FORMAT;
|
|
goto err_exit;
|
|
}
|
|
if (key) {
|
|
if (!(kptr = malloc(klen + 10))) {
|
|
err = ENOMEM;
|
|
goto err_exit;
|
|
}
|
|
memcpy(kptr, keybuf + ofs, klen + 10);
|
|
*key = kptr;
|
|
}
|
|
err = 0;
|
|
err_exit:
|
|
free(keybuf);
|
|
return err;
|
|
}
|
|
|
|
char buf2str1[8] = {1,0,0,0,9,0,2,0};
|
|
char buf2str2[16] = {65,0,0,0,1,0,0,0,1,0,9,0,53,0,28,0};
|
|
char buf2str3[8] = {1,0,0,0,1,0,6,0};
|
|
static long rsa_crypt(struct ncp_conn *conn, char *data, int datalen,
|
|
long serv_id, char **outp, char *pend) {
|
|
char rand[28];
|
|
char hashrand[8], temp[8];
|
|
unsigned short cryptbuf[128];
|
|
char buf2[56];
|
|
int i;
|
|
long err;
|
|
char *s_key;
|
|
char *p;
|
|
|
|
if ((*outp + datalen + 108) > pend)
|
|
return -1;
|
|
if ((err = get_public_key(conn, serv_id, &s_key)))
|
|
return err;
|
|
|
|
fillrandom(rand, 28);
|
|
nwhash1init(hashrand, 8);
|
|
for (i = 10; i; i--)
|
|
nwhash1(hashrand, 8, rand, 28);
|
|
|
|
memset(buf2 + 40, 0, 16);
|
|
buf2[0] = 11;
|
|
memcpy(buf2 + 1, rand, 28);
|
|
memset(buf2 + 29, 11, 11);
|
|
nwhash1(buf2 + 40, 5, buf2 + 1, 39);
|
|
nwhash1(buf2 + 45, 2, buf2, 45);
|
|
fillrandom(buf2 + 47, 5);
|
|
|
|
err = modexpkey(s_key, buf2, buf2, 56);
|
|
free(s_key);
|
|
if (err)
|
|
return err;
|
|
|
|
buf_put_dword_lh(outp, pend, datalen + 108);
|
|
buf_put_buf(outp, pend, buf2str1, sizeof(buf2str1));
|
|
buf_put_dword_lh(outp, pend, datalen + 96);
|
|
buf_put_buf(outp, pend, buf2str2, sizeof(buf2str2));
|
|
buf_put_buf(outp, pend, buf2, 56);
|
|
buf_put_dword_lh(outp, pend, datalen + 20);
|
|
buf_put_buf(outp, pend, buf2str3, sizeof(buf2str3));
|
|
buf_put_dword_lh(outp, pend, (datalen + 8) | (datalen << 16));
|
|
|
|
memset(temp, 3, 3);
|
|
nwhash1init(temp + 3, 5);
|
|
nwhash1(temp + 3, 5, data, datalen);
|
|
nwhash1(temp + 3, 5, temp, 3);
|
|
nwencryptblock(hashrand, data, datalen, *outp);
|
|
*outp += datalen;
|
|
for (i = 0, p = *outp - 8; i < 8; i++, p++)
|
|
temp[i] ^= *p;
|
|
nwcryptinit(cryptbuf, hashrand);
|
|
nwencrypt(cryptbuf, temp, *outp);
|
|
*outp += 8;
|
|
memzero(rand);
|
|
memzero(hashrand);
|
|
memzero(temp);
|
|
memzero(cryptbuf);
|
|
memzero(buf2);
|
|
return 0;
|
|
}
|
|
|
|
static char bufstr[16]={28, 0, 0, 0, 1, 0, 0, 0, 1, 0, 6, 0, 16, 0, 4, 0};
|
|
long nds_login(struct ncp_conn *conn, long user_id, const char *pwd,
|
|
long serv_id, char *logindata, char **u_priv_key) {
|
|
char *buf, *p, *pend;
|
|
char temp[16];
|
|
char hashshuf[8];
|
|
char loginid[4];
|
|
char crypt1strc[28];
|
|
char randno[4];
|
|
char randbuf[1024];
|
|
char *tempbuf;
|
|
int i, outlen;
|
|
int n1, n2;
|
|
u_int16_t n2a, n3;
|
|
long err;
|
|
int grace_period = 0;
|
|
|
|
if (u_priv_key) *u_priv_key = NULL;
|
|
if (!(buf = malloc(4096)))
|
|
return ENOMEM;
|
|
pend = (p = buf) + 2048;
|
|
buf_put_dword_lh(&p, pend, 0);
|
|
buf_put_dword_hl(&p, pend, user_id);
|
|
if ((err = ncp_send_nds_frag(conn, 57, buf, p - buf, buf + 2048, 2048,
|
|
&outlen))) {
|
|
free(buf);
|
|
return err;
|
|
}
|
|
pend = (p = buf + 2048) + outlen;
|
|
if ((buf_get_buf(&p, pend, temp, 4)) ||
|
|
(buf_get_buf(&p, pend, loginid, 4))) {
|
|
free(buf);
|
|
return NCPL_ET_REPLY_FORMAT;
|
|
}
|
|
free(buf);
|
|
if (strlen(pwd) > 127)
|
|
return NCPL_ET_PWD_TOO_LONG;
|
|
if (!(tempbuf = malloc(1064)))
|
|
return ENOMEM;
|
|
if (!(buf = malloc(4096))) {
|
|
free(tempbuf);
|
|
return ENOMEM;
|
|
}
|
|
strcpy(randbuf, pwd);
|
|
for (p = randbuf; *p; p++)
|
|
*p = toupper(*p);
|
|
#if 0
|
|
shuffle(temp, randbuf, temp);
|
|
#else
|
|
shuffle(temp, randbuf, strlen(randbuf), temp);
|
|
#endif
|
|
nwhash1init(hashshuf, 8);
|
|
for (i = 10; i; i--)
|
|
nwhash1(hashshuf, 8, temp, 16);
|
|
memcpy(temp, loginid, 4);
|
|
memset(temp + 4, 7, 7);
|
|
nwhash1init(temp + 11, 5);
|
|
nwhash1(temp + 11, 5, temp, 11);
|
|
memcpy(crypt1strc, bufstr + 4, 12);
|
|
nwencryptblock(hashshuf, temp, 16, crypt1strc + 12);
|
|
|
|
fillrandom(randno, 4);
|
|
fillrandom(randbuf, 1024);
|
|
pend = (p = tempbuf) + 1064;
|
|
buf_put_buf(&p, pend, randno, 4);
|
|
buf_put_dword_lh(&p, pend, 1024);
|
|
buf_put_buf(&p, pend, randbuf, 1024);
|
|
buf_put_buf(&p, pend, bufstr, sizeof(bufstr));
|
|
buf_put_buf(&p, pend, crypt1strc + 12, 16);
|
|
|
|
pend = (p = buf) + 2048;
|
|
buf_put_dword_lh(&p, pend, 2);
|
|
buf_put_dword_lh(&p, pend, 0);
|
|
buf_put_dword_hl(&p, pend, user_id);
|
|
|
|
rsa_crypt(conn, tempbuf, 1064, serv_id, &p, pend);
|
|
memset(tempbuf, 0, 1064);
|
|
free(tempbuf);
|
|
|
|
if ((err = ncp_send_nds_frag(conn, 58, buf, p - buf, buf + 2048, 2048,
|
|
&outlen))) {
|
|
if ((err != NCPL_ET_REQUEST_ERROR) ||
|
|
(conn->completion != NDS_GRACE_PERIOD))
|
|
goto err_exit;
|
|
grace_period = 1;
|
|
}
|
|
err = NCPL_ET_REPLY_FORMAT;
|
|
pend = (p = buf + 2048) + outlen;
|
|
if ((buf_get_buf(&p, pend, logindata, 8)) ||
|
|
(buf_get_dword_lh(&p, pend, &n1)) ||
|
|
(n1 > pend - p))
|
|
goto err_exit;
|
|
pend = p + n1;
|
|
if ((buf_get_dword_lh(&p, pend, &n1)) ||
|
|
(buf_get_dword_lh(&p, pend, &n2)) ||
|
|
(buf_get_word_lh(&p, pend, &n3)) ||
|
|
(n1 != 1) || (n2 != 0x060001) || (n3 > pend - p))
|
|
goto err_exit;
|
|
|
|
nwhash1init(temp, 8);
|
|
for (i = 10; i; i--)
|
|
nwhash1(temp, 8, crypt1strc, 28);
|
|
nwdecryptblock(temp, p, n3, p);
|
|
nwhash1init(temp, 5);
|
|
nwhash1(temp, 5, p, n3 - 5);
|
|
if (memcmp(temp, p + n3 - 5, 5))
|
|
goto err_exit;
|
|
pend = p + n3 - 12;
|
|
if ((buf_get_buf(&p, pend, loginid, 4)) ||
|
|
(buf_get_dword_lh(&p, pend, &n2)) ||
|
|
(memcmp(loginid, randno, 4)) || (n2 > pend - p))
|
|
goto err_exit;
|
|
pend = p + n2;
|
|
for (i = 0; i < n2; i++)
|
|
p[i] ^= randbuf[i];
|
|
if ((buf_get_dword_lh(&p, pend, &n1)) ||
|
|
(buf_get_dword_lh(&p, pend, &n2)) ||
|
|
(buf_get_word_lh(&p, pend, &n3)) ||
|
|
(n1 != 1) || (n2 != 0x060001) || (n3 > pend - p))
|
|
goto err_exit;
|
|
pend = p + n3;
|
|
nwdecryptblock(hashshuf, p, n3, p);
|
|
if ((buf_get_dword_lh(&p, pend, &n1)) ||
|
|
(buf_get_word_lh2(&p, pend, &n2a)) ||
|
|
(buf_get_word_lh2(&p, pend, &n3)) ||
|
|
(n1 != 1) || (n2a != 2) || (n3 > pend - p))
|
|
goto err_exit;
|
|
if (u_priv_key) {
|
|
if (!(tempbuf = malloc(n3 + 10))) {
|
|
err = ENOMEM;
|
|
goto err_exit;
|
|
}
|
|
memset(tempbuf, 0, 8);
|
|
tempbuf[0] = 1;
|
|
tempbuf[4] = 3;
|
|
tempbuf[6] = 1;
|
|
WSET_LH(tempbuf, 8, n3);
|
|
memcpy(tempbuf + 10, p, n3);
|
|
if (!checkkey(tempbuf)) {
|
|
free(tempbuf);
|
|
goto err_exit;
|
|
}
|
|
*u_priv_key = tempbuf;
|
|
}
|
|
err = 0;
|
|
if (grace_period) {
|
|
conn->completion = NDS_GRACE_PERIOD;
|
|
err = NCPL_ET_REQUEST_ERROR;
|
|
}
|
|
|
|
err_exit:
|
|
memzero(hashshuf);
|
|
memzero(randbuf);
|
|
memzero(crypt1strc);
|
|
memzero(randno);
|
|
memzero(temp);
|
|
if (buf) free(buf);
|
|
return err;
|
|
}
|
|
|
|
long nds_beginauth(struct ncp_conn *conn, long user_id, struct ncp_conn *readkey_conn,
|
|
long serv_id, char *authid) {
|
|
char *buf, *p, *pend, *n_temp, temp[8];
|
|
char *s_key;
|
|
char randno[4];
|
|
long err;
|
|
int outlen, n1, n2, n3, n4;
|
|
u_int16_t n3a;
|
|
|
|
if (!(buf = malloc(2048)))
|
|
return ENOMEM;
|
|
n_temp = NULL;
|
|
fillrandom(randno, 4);
|
|
pend = (p = buf) + 512;
|
|
buf_put_dword_lh(&p, pend, 0);
|
|
buf_put_dword_hl(&p, pend, user_id);
|
|
buf_put_buf(&p, pend, randno, 4);
|
|
if ((err = ncp_send_nds_frag(conn, 59, buf, p - buf, buf + 1024, 1024,
|
|
&outlen)))
|
|
goto err_exit;
|
|
|
|
err = NCPL_ET_REPLY_FORMAT;
|
|
pend = (p = buf + 1024) + outlen;
|
|
if ((buf_get_buf(&p, pend, authid, 4)) ||
|
|
(buf_get_dword_lh(&p, pend, &outlen)) ||
|
|
(outlen > pend - p))
|
|
goto err_exit;
|
|
pend = p + outlen;
|
|
if ((buf_get_dword_lh(&p, pend, &n1)) ||
|
|
(buf_get_dword_lh(&p, pend, &n2)) ||
|
|
(buf_get_dword_lh(&p, pend, &n3)) ||
|
|
(n1 != 1) || (n2 != 0x020009) || (n3 > pend - p))
|
|
goto err_exit;
|
|
pend = p + n3;
|
|
if ((buf_get_dword_lh(&p, pend, &n1)) ||
|
|
(buf_get_dword_lh(&p, pend, &n1)) ||
|
|
(buf_get_dword_lh(&p, pend, &n2)) ||
|
|
(buf_get_word_lh(&p, pend, &n3a)) ||
|
|
(n1 != 1) || (n2 != 0x0a0001) || (n3a > pend - p))
|
|
goto err_exit;
|
|
n1 = ((countbits_l(p, n3a) + 31) & (~31)) >> 3;
|
|
if (n1 < 52)
|
|
goto err_exit;
|
|
if (!(n_temp = malloc(n1))) {
|
|
err = ENOMEM;
|
|
goto err_exit;
|
|
}
|
|
copyfill(n_temp, n1, p, n3a);
|
|
p += (n3a + 3) & (~3);
|
|
|
|
if ((err = get_public_key(readkey_conn, serv_id, &s_key)))
|
|
goto err_exit;
|
|
err = modexpkey(s_key, n_temp, n_temp, n1);
|
|
free(s_key);
|
|
if (err)
|
|
goto err_exit;
|
|
err = NCPL_ET_REPLY_FORMAT;
|
|
nwhash1init(temp, 7);
|
|
nwhash1(temp + 5, 2, n_temp, 45);
|
|
nwhash1(temp, 5, n_temp + 1, 39);
|
|
if (memcmp(temp, n_temp + 40, 7))
|
|
goto err_exit;
|
|
nwhash1init(temp, 8);
|
|
for (n1 = 10; n1; n1--)
|
|
nwhash1(temp, 8, n_temp + 1, 28);
|
|
free(n_temp); n_temp = NULL;
|
|
if ((buf_get_dword_lh(&p, pend, &n1)) ||
|
|
(buf_get_dword_lh(&p, pend, &n2)) ||
|
|
(buf_get_dword_lh(&p, pend, &n3)) ||
|
|
(buf_get_dword_lh(&p, pend, &n4)) ||
|
|
(n1 != 28) || (n2 != 1) || (n3 != 0x060001) || (n4 != 0x040010) ||
|
|
(pend - p < 16))
|
|
goto err_exit;
|
|
nwdecryptblock(temp, p, 16, p);
|
|
nwhash1init(temp, 5);
|
|
nwhash1(temp, 5, p, 11);
|
|
if ((!memcmp(temp, p + 11, 5)) || (!memcmp(p, randno, 4)))
|
|
err = 0;
|
|
err_exit:
|
|
if (n_temp) free(n_temp);
|
|
if (buf) free(buf);
|
|
return err;
|
|
}
|
|
|
|
static char *allocfillchunk(const char *keyptr, int keylen, const char *chunk,
|
|
int destsize) {
|
|
char *p, *p2;
|
|
int i;
|
|
i = findchunk(keyptr, keylen, chunk, &p);
|
|
if (!p)
|
|
return NULL;
|
|
if (!(p2 = malloc(destsize)))
|
|
return NULL;
|
|
copyfill(p2, destsize, p, i);
|
|
return p2;
|
|
}
|
|
|
|
static long gen_auth_data(char **outp, char *outend,
|
|
const char *u_key, const char *u_priv_key,
|
|
const char *authid, char *loginstrc, int loginstrc_len) {
|
|
char *keyptr;
|
|
int keylen, i, j;
|
|
int nbits, nblocksize, nbytes;
|
|
unsigned char nmask;
|
|
unitptr n_mod, n_exp, n_pn, n_qn, n_dp, n_dq, n_cr, n_key, n_temp;
|
|
unitptr n_key_dp, n_key_dq;
|
|
unitptr up, up2;
|
|
char *p, *tempbuf;
|
|
char *randbuf = NULL;
|
|
char hashbuf[0x42];
|
|
long err;
|
|
|
|
n_temp = n_mod = n_exp = n_pn = n_qn = n_dp = n_dq = n_cr = n_key =
|
|
n_key_dp = n_key_dq = NULL;
|
|
if (!initkey(u_key, &keyptr, &keylen))
|
|
return NCPL_ET_REPLY_FORMAT;
|
|
i = findchunk(keyptr, keylen, "NN", &p);
|
|
if (!p)
|
|
return NCPL_ET_REPLY_FORMAT;
|
|
nbits = countbits_l(p, i);
|
|
nbytes = (nbits + 7) >> 3;
|
|
nmask = (unsigned char)(255 >> (8 - (nbits & 7)));
|
|
nblocksize = ((nbits + 31) & (~31)) >> 3;
|
|
|
|
set_precision(bytes2units(nblocksize));
|
|
|
|
n_mod = (unitptr)allocfillchunk(keyptr, keylen, "NN", nblocksize);
|
|
n_exp = (unitptr)allocfillchunk(keyptr, keylen, "EN", nblocksize);
|
|
if (!initkey(u_priv_key, &keyptr, &keylen)) {
|
|
err = NCPL_ET_REPLY_FORMAT;
|
|
goto err_exit;
|
|
}
|
|
n_pn = (unitptr)allocfillchunk(keyptr, keylen, "PN", nblocksize);
|
|
n_qn = (unitptr)allocfillchunk(keyptr, keylen, "QN", nblocksize);
|
|
n_dp = (unitptr)allocfillchunk(keyptr, keylen, "DP", nblocksize);
|
|
n_dq = (unitptr)allocfillchunk(keyptr, keylen, "DQ", nblocksize);
|
|
n_cr = (unitptr)allocfillchunk(keyptr, keylen, "CR", nblocksize);
|
|
n_key = malloc(nblocksize);
|
|
|
|
nwhash2init(hashbuf);
|
|
nwhash2block(hashbuf, loginstrc, loginstrc_len);
|
|
nwhash2end(hashbuf);
|
|
copyfill(n_key, nblocksize, hashbuf, 16);
|
|
|
|
if (!(tempbuf = malloc(loginstrc_len + 16))) {
|
|
err = ENOMEM;
|
|
goto err_exit;
|
|
}
|
|
memset(tempbuf, 0, 16);
|
|
tempbuf[4] = 0x3c;
|
|
memcpy(tempbuf + 8, authid, 4);
|
|
p = tempbuf + 12;
|
|
buf_put_dword_lh(&p, tempbuf + 16, loginstrc_len);
|
|
memcpy(p, loginstrc, loginstrc_len);
|
|
|
|
nwhash2init(hashbuf);
|
|
nwhash2block(hashbuf, tempbuf, loginstrc_len + 16);
|
|
free(tempbuf);
|
|
|
|
n_temp = malloc(nblocksize);
|
|
n_key_dp = malloc(nblocksize);
|
|
n_key_dq = malloc(nblocksize);
|
|
mp_mult(n_temp, n_pn, n_qn);
|
|
mp_modexp(n_key_dp, n_key, n_dp, n_pn);
|
|
mp_modexp(n_key_dq, n_key, n_dq, n_qn);
|
|
mp_move(n_temp, n_key_dp);
|
|
mp_add(n_temp, n_pn);
|
|
mp_sub(n_temp, n_key_dq);
|
|
stage_modulus(n_pn);
|
|
mp_modmult(n_temp, n_temp, n_cr);
|
|
mp_mult(n_key, n_temp, n_qn);
|
|
mp_add(n_key, n_key_dq);
|
|
|
|
randbuf = malloc(nblocksize * 3);
|
|
memset(randbuf, 0, nblocksize * 3);
|
|
|
|
buf_put_dword_lh(outp, outend, 12 + nblocksize * 6);
|
|
buf_put_dword_lh(outp, outend, 1);
|
|
buf_put_dword_lh(outp, outend, 0x100008);
|
|
buf_put_word_lh2(outp, outend, 3);
|
|
buf_put_word_lh2(outp, outend, nblocksize * 3);
|
|
memset(*outp, 0, nblocksize * 6);
|
|
|
|
up = (unitptr)randbuf; up2 = (unitptr)*outp;
|
|
for (i = 3; i; i--) {
|
|
fillrandom((char *)up, nbytes);
|
|
((char *)up)[nbytes - 1] &= nmask;
|
|
if (!(j = mp_compare(up, n_mod)))
|
|
mp_dec(up);
|
|
else if (j > 0) {
|
|
mp_sub(up, n_mod);
|
|
mp_neg(up);
|
|
mp_add(up, n_mod);
|
|
}
|
|
mp_modexp(up2, up, n_exp, n_mod);
|
|
((char *)up) += nblocksize;
|
|
((char *)up2) += nblocksize;
|
|
}
|
|
nwhash2block(hashbuf, *outp, nblocksize * 3);
|
|
nwhash2end(hashbuf);
|
|
|
|
up = (unitptr)randbuf;
|
|
for (i = 0; i < 3; i++) {
|
|
mp_init(n_temp, (unsigned char)hashbuf[i << 1] |
|
|
((unsigned char)hashbuf[(i << 1) + 1] << 8));
|
|
mp_modexp(up2, n_key, n_temp, n_mod);
|
|
stage_modulus(n_mod);
|
|
mp_modmult(up2, up2, up);
|
|
((char *)up) += nblocksize;
|
|
((char *)up2) += nblocksize;
|
|
}
|
|
*outp = (char *)up2;
|
|
err = 0;
|
|
err_exit:
|
|
memzero(hashbuf);
|
|
free(randbuf);
|
|
if (n_temp) { mp_init0(n_temp); free(n_temp); }
|
|
if (n_key_dp) { mp_init0(n_key_dp); free(n_key_dp); }
|
|
if (n_key_dq) { mp_init0(n_key_dq); free(n_key_dq); }
|
|
if (n_pn) { mp_init0(n_pn); free(n_pn); }
|
|
if (n_qn) { mp_init0(n_qn); free(n_qn); }
|
|
if (n_dp) { mp_init0(n_dp); free(n_dp); }
|
|
if (n_dq) { mp_init0(n_dq); free(n_dq); }
|
|
if (n_cr) { mp_init0(n_cr); free(n_cr); }
|
|
free(n_mod);
|
|
free(n_exp);
|
|
return err;
|
|
}
|
|
|
|
|
|
long nds_authenticate(struct ncp_conn *conn, long user_id, struct ncp_conn* readkey_conn,
|
|
long serv_id, const char *logindata, const char *u_priv_key) {
|
|
char authid[4];
|
|
long err;
|
|
int user_name_len;
|
|
uni_char *user_name = NULL;
|
|
char *loginstrc;
|
|
int loginstrc_len;
|
|
char *buf, *p, *pend;
|
|
char *u_key;
|
|
#ifdef SIGNATURES
|
|
char signkey[8];
|
|
#endif
|
|
|
|
if (!readkey_conn) readkey_conn = conn;
|
|
u_key = loginstrc = buf = NULL;
|
|
if ((err = nds_beginauth(conn, user_id, readkey_conn, serv_id, authid)))
|
|
return err;
|
|
if ((err = nds_readentryname(conn, user_id, &user_name, &user_name_len)))
|
|
return err;
|
|
loginstrc_len = user_name_len + 22;
|
|
if (!(loginstrc = malloc(loginstrc_len))) {
|
|
err = ENOMEM;
|
|
goto err_exit;
|
|
}
|
|
memset(loginstrc, 0, 22);
|
|
loginstrc[0] = 1;
|
|
loginstrc[4] = 6;
|
|
memcpy(loginstrc + 6, logindata, 8);
|
|
fillrandom(loginstrc + 14, 4);
|
|
WSET_LH(loginstrc, 20, user_name_len);
|
|
memcpy(loginstrc + 22, user_name, user_name_len);
|
|
free(user_name); user_name = NULL;
|
|
if ((err = get_public_key(conn, user_id, &u_key)))
|
|
goto err_exit;
|
|
if (!(buf = malloc(2048))) {
|
|
err = ENOMEM;
|
|
goto err_exit;
|
|
}
|
|
pend = (p = buf) + 2048;
|
|
buf_put_dword_lh(&p, pend, 0);
|
|
#ifdef SIGNATURES
|
|
if (conn->sign_wanted) {
|
|
fillrandom(signkey, 8);
|
|
rsa_crypt(readkey_conn, signkey, 8, serv_id, &p, pend);
|
|
} else
|
|
#endif
|
|
buf_put_dword_lh(&p, pend, 0);
|
|
buf_put_lbuf(&p, pend, loginstrc, loginstrc_len);
|
|
|
|
if ((err = gen_auth_data(&p, pend, u_key, u_priv_key,
|
|
authid, loginstrc, loginstrc_len)))
|
|
goto err_exit;
|
|
if ((err = ncp_send_nds_frag(conn, 60, buf, p - buf, NULL, 0, NULL)))
|
|
goto err_exit;
|
|
#ifdef SIGNATURES
|
|
if ((err = ncp_sign_start(conn, signkey)))
|
|
goto err_exit;
|
|
#endif
|
|
err = ncp_change_conn_state(conn, 1);
|
|
|
|
err_exit:
|
|
if (loginstrc) free(loginstrc);
|
|
if (buf) free(buf);
|
|
if (u_key) free(u_key);
|
|
if (user_name) free(user_name);
|
|
return err;
|
|
}
|
|
|
|
long nds_login_auth(struct ncp_conn *conn, const char *user,
|
|
const char *pwd) {
|
|
long err;
|
|
uni_char user_u[200];
|
|
char *u_priv_key = NULL;
|
|
char logindata[8];
|
|
uni_char *server_name = NULL;
|
|
__u32 serv_id, user_id;
|
|
struct sockaddr_ipx wserv_addr;
|
|
struct ncp_conn *login_conn, *wserv_conn = NULL, *readkey_conn = NULL;
|
|
int not_wserv; /* =1: current server doesn't have a writable replica */
|
|
int i;
|
|
struct timeval tv;
|
|
int grace_period = 0;
|
|
#ifdef ERR_MSG
|
|
char buf[200]; /* to print username */
|
|
#endif
|
|
gettimeofday(&tv, NULL);
|
|
srand(tv.tv_usec);
|
|
|
|
if (strlen(user) >= 200)
|
|
return NCPL_ET_NAMETOOLONG;
|
|
strcpy_cu(user_u, user);
|
|
i = sizeof(wserv_addr);
|
|
err = nds_resolve_name(conn, 0x64, user_u, &user_id, ¬_wserv,
|
|
(struct sockaddr *)&wserv_addr, &i);
|
|
if ((err == NCPL_ET_REQUEST_ERROR) && (conn->completion == -601) &&
|
|
(user_u[strlen_u(user_u)-1] != '.')) {
|
|
#ifdef ERR_MSG
|
|
strcpy_uc(buf, user_u);
|
|
printf("User %s not found in current context.\n"
|
|
"Trying server context...\n", buf);
|
|
#endif
|
|
if ((err = nds_get_server_name(conn, &server_name)) != 0)
|
|
goto err_exit;
|
|
i = 0;
|
|
while ((server_name[i]) && (server_name[i] != '.'))
|
|
i++;
|
|
memcpy(user_u + strlen_u(user_u), server_name + i,
|
|
(strlen_u(server_name) - i + 1) * 2);
|
|
free(server_name);
|
|
server_name = NULL;
|
|
i = sizeof(wserv_addr);
|
|
err = nds_resolve_name(conn, 0x64, user_u, &user_id, ¬_wserv,
|
|
(struct sockaddr *)&wserv_addr, &i);
|
|
}
|
|
if (err) {
|
|
#ifdef ERR_MSG
|
|
if (err == NCPL_ET_REQUEST_ERROR)
|
|
fprintf(stderr, "error %d finding user\n", conn->completion);
|
|
#endif
|
|
goto err_exit;
|
|
}
|
|
if (not_wserv) {
|
|
if (!(login_conn = wserv_conn = ncp_open_addr((struct sockaddr*)&wserv_addr, &err)))
|
|
goto err_exit;
|
|
} else
|
|
login_conn = conn;
|
|
if ((err = nds_get_server_name(login_conn, &server_name)) != 0)
|
|
goto err_exit2;
|
|
if ((err = nds_resolve_name(login_conn, 0x62, server_name, &serv_id,
|
|
NULL, NULL, NULL)) != 0)
|
|
goto err_exit2;
|
|
if ((err = nds_login(login_conn, user_id, pwd, serv_id, logindata,
|
|
&u_priv_key))) {
|
|
if ((err != NCPL_ET_REQUEST_ERROR) ||
|
|
(login_conn->completion != NDS_GRACE_PERIOD)) {
|
|
#ifdef ERR_MSG
|
|
if (err == NCPL_ET_REQUEST_ERROR)
|
|
fprintf(stderr, "error %d logging in\n", login_conn->completion);
|
|
#endif
|
|
err_exit2:;
|
|
conn->completion = login_conn->completion;
|
|
goto err_exit;
|
|
}
|
|
grace_period = 1;
|
|
}
|
|
if (not_wserv) {
|
|
struct sockaddr xaddr;
|
|
int remoteserver;
|
|
int i;
|
|
|
|
free(server_name);
|
|
if ((err = nds_get_server_name(conn, &server_name)) != 0)
|
|
goto err_exit;
|
|
i = sizeof(xaddr);
|
|
if ((err = nds_resolve_name(conn, 0x62, server_name, &serv_id,
|
|
&remoteserver, (struct sockaddr*)&xaddr, &i)) != 0)
|
|
goto err_exit;
|
|
if (remoteserver) {
|
|
if (!(readkey_conn = ncp_open_addr((struct sockaddr*)&xaddr, &err)))
|
|
goto err_exit;
|
|
}
|
|
if ((err = nds_resolve_name(conn, 0x51, user_u, &user_id,
|
|
NULL, NULL, NULL)) !=0)
|
|
goto err_exit;
|
|
}
|
|
if ((err = nds_authenticate(conn, user_id, readkey_conn, serv_id, logindata,
|
|
u_priv_key))) {
|
|
#ifdef ERR_MSG
|
|
if (err == NCPL_ET_REQUEST_ERROR)
|
|
fprintf(stderr, "error %d authenticating\n", conn->completion);
|
|
#endif
|
|
goto err_exit;
|
|
}
|
|
if (grace_period && (!err)) {
|
|
conn->completion = NDS_GRACE_PERIOD;
|
|
err = NCPL_ET_REQUEST_ERROR;
|
|
}
|
|
err_exit:
|
|
if (readkey_conn) ncp_close(readkey_conn);
|
|
if (wserv_conn) ncp_close(wserv_conn);
|
|
if (u_priv_key) { clearkey(u_priv_key); free(u_priv_key); }
|
|
free(server_name);
|
|
#ifdef RANDBUF
|
|
memset(global_randbuf, 0, RANDBUFSIZE);
|
|
g_rndp = global_randbuf + RANDBUFSIZE;
|
|
#endif
|
|
return err;
|
|
}
|
|
|
|
#ifdef NDS_PRIVATEKEY
|
|
long
|
|
nds_authenticate(struct ncp_conn* conn, uni_char* name, u_int8_t* code1, void* privateKey, size_t privateKeyLen) {
|
|
}
|
|
#endif /* NDS_PRIVATE_KEY */
|
|
|