Viewing: lgss.h
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
/*
* Copyright (c) 2022, Whamcloud.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
*/
#ifndef _LGSS_H
#define _LGSS_H
#ifndef __KERNEL__
# define __USE_ISOC99 1
# include <stdio.h> /* snprintf() */
# include <stdlib.h> /* abs() */
# include <inttypes.h> /* PRIu64 */
# include <ctype.h> /* isascii() */
# include <errno.h>
# define __USE_GNU 1
# define __USE_XOPEN2K8 1
#else
#include <linux/ctype.h>
#define PRIu64 "llu"
#define PRIx64 "llx"
#endif /* !__KERNEL__ */
#include <linux/types.h>
#include <linux/string.h>
#include <linux/unistd.h>
/*
* sparse kernel source annotations
*/
#ifndef __user
#define __user
#endif
struct lgssd_ioctl_param {
/* in */
__u32 version;
__u32 secid;
char __user *uuid;
__u32 lustre_svc;
__kernel_uid_t uid;
__kernel_gid_t gid;
__u64 send_token_size;
char __user *send_token;
__u64 reply_buf_size;
/* out */
char __user *reply_buf;
__s64 __user *status;
};
#define GSS_SOCKET_PATH "/tmp/svcgssd.socket"
/*
* Old RSI_DOWNCALL_MAGIC was:
* #define RSI_DOWNCALL_MAGIC 0x6d6dd62a
*
* This is an uapi and to catch cases like kernel modules
* being updated separately from user tools new
* RSI_DOWNCALL_MAGIC(0x6d6dd63a) was introduced
*/
#define RSI_DOWNCALL_MAGIC 0x6d6dd63a
#define RSI_DOWNCALL_PATH "sptlrpc/gss/rsi_info"
#define RSI_CACHE_NAME "rsicache"
struct rsi_downcall_data {
__u32 sid_magic;
__s32 sid_err; /* negative errno */
__u32 sid_unused;
__u32 sid_maj_stat;
__u32 sid_min_stat;
__u32 sid_len;
__s64 sid_offset;
__u64 sid_hash;
/* sid_val contains in_handle, in_token,
* out_handle, out_token
*/
char sid_val[];
};
#define RSC_DOWNCALL_MAGIC 0x6d6dd62b
#define RSC_DOWNCALL_PATH "sptlrpc/gss/rsc_info"
#define RSC_CACHE_NAME "rsccache"
/* rsc_downcall_data flags */
enum scd_flag_bits {
RSC_DATA_FLAG_REMOTE = 0x0001,
RSC_DATA_FLAG_ROOT = 0x0002,
RSC_DATA_FLAG_MDS = 0x0004,
RSC_DATA_FLAG_OSS = 0x0008,
};
struct rsc_downcall_data {
__u32 scd_magic;
__s32 scd_err; /* negative errno */
__u32 scd_flags;
__u32 scd_mapped_uid;
__u32 scd_uid;
__u32 scd_gid;
char scd_mechname[8];
/* nodemap name, LUSTRE_NODEMAP_NAME_LENGTH = 16 */
char scd_nmname[24];
__s64 scd_offset;
__u32 scd_len;
__u32 scd_padding;
/* scd_val contains handle and context token */
char scd_val[];
};
/*
* gss_string_write() - write some string
*
* If string is empty, write single digit 0.
* Pad with a trailing space.
*/
static inline void gss_string_write(char **dst, int *dstlen, const char *src)
{
char *cp = *dst;
int ret;
if (*dstlen < 0)
return;
if (!strlen(src))
ret = snprintf(cp, *dstlen, "0");
else
ret = snprintf(cp, *dstlen, "%s", src);
if (ret >= *dstlen) {
cp += *dstlen;
*dstlen = -1;
} else {
cp[ret] = ' ';
cp += ret + 1;
*dstlen -= ret + 1;
}
*dst = cp;
}
/*
* gss_u64_write() - write some u64
*/
static inline void gss_u64_write_string(char **dst, int *dstlen, uint64_t n)
{
char *cp = *dst;
int ret;
if (*dstlen < 0)
return;
ret = snprintf(cp, *dstlen, "%"PRIu64, n);
if (ret >= *dstlen) {
cp += *dstlen;
*dstlen = -1;
} else {
cp[ret] = ' ';
cp += ret + 1;
*dstlen -= ret + 1;
}
*dst = cp;
}
/*
* gss_u64_write_hex() - write some u64 in hex
*/
static inline void gss_u64_write_hex_string(char **dst, int *dstlen, uint64_t n)
{
char *cp = *dst;
int ret;
if (*dstlen < 0)
return;
ret = snprintf(cp, *dstlen, "0x%"PRIx64, n);
if (ret >= *dstlen) {
cp += *dstlen;
*dstlen = -1;
} else {
cp[ret] = ' ';
cp += ret + 1;
*dstlen -= ret + 1;
}
*dst = cp;
}
/*
* gss_buffer_write() - write some buffer
*/
static inline void gss_buffer_write(char **dst, int *dstlen,
const __u8 *src, int srclen)
{
char *cp = *dst;
int len = *dstlen;
__u32 *p;
if (len < 0)
return;
if (len < sizeof(__u32)) {
len = -1;
goto out;
}
/* write size of data */
p = (__u32 *)cp;
*p = srclen;
cp += sizeof(__u32);
len -= sizeof(__u32);
if (!srclen)
goto out;
/* write data itself */
while (srclen && len) {
*cp++ = *src++;
len--;
srclen--;
}
if (!len && srclen)
len = -1;
out:
*dst = cp;
*dstlen = len;
}
/*
* gss_u32_write() - write some u32
*/
static inline void gss_u32_write(char **dst, int *dstlen, __u32 val)
{
char *cp = *dst;
int len = *dstlen;
__u32 *p;
if (len < 0)
return;
if (len < sizeof(__u32)) {
len = -1;
goto out;
}
p = (__u32 *)cp;
*p = val;
cp += sizeof(__u32);
len -= sizeof(__u32);
out:
*dst = cp;
*dstlen = len;
}
static const char base64url_table[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
#define BASE64URL_CHARS(nbytes) ((((nbytes) * 4) + 3 - 1) / 3)
/*
* gss_base64url_encode() - base64url-encode some binary data
*
* Encode data using base64url encoding, i.e. the "Base 64 Encoding with URL
* and Filename Safe Alphabet" specified by RFC 4648. '='-padding isn't used,
* as it's unneeded and not required by the RFC.
* Pad with a trailing space.
*
* \param dst (in/out) pointer to the destination buffer pointer. Memory space
* must be allocated by the caller. On success, the pointer is positioned after
* the trailing space.
* \param dstlen (in/out) buffer size at @dst; updated to remaining length on
* success
* \param src the binary data to encode
* \param srclen the length of @src in bytes
*
* \retval 0 on success
* \retval -EINVAL if @dstlen is negative on entry
* \retval -ENOBUFS if @dstlen is too small
*/
static inline int gss_base64url_encode(char **dst, int *dstlen,
const __u8 *src, int srclen)
{
char *cp = *dst;
int len = *dstlen;
__u32 ac = 0;
int bits = 0;
int rc = 0;
int i;
if (len < 0)
return -EINVAL;
if (len == 0)
return 0;
if (!srclen) {
gss_string_write(dst, dstlen, "");
return 0;
}
for (i = 0; i < srclen; i++) {
ac = (ac << 8) | src[i];
bits += 8;
do {
bits -= 6;
*cp++ = base64url_table[(ac >> bits) & 0x3f];
len--;
} while (bits >= 6 && len > 0);
if (!len)
break;
}
if (i < srclen) {
len = -1;
goto out;
}
if (bits) {
*cp++ = base64url_table[(ac << (6 - bits)) & 0x3f];
len--;
}
if (!len) {
len = -1;
goto out;
}
*cp++ = ' ';
len--;
out:
*dst = cp;
*dstlen = len;
if (len == -1)
rc = -ENOBUFS;
return rc;
}
/*
* gss_base64url_decode() - base64url-decode a string
*
* Decode a string using base64url encoding, i.e. the "Base 64 Encoding with
* URL and Filename Safe Alphabet" specified by RFC 4648. '='-padding isn't
* accepted, nor are non-encoding characters such as whitespace.
* String end is marked with a trailing space or '\n' or '\0'.
*/
static inline int gss_base64url_decode(char **src, char *dst, int destsize)
{
int bits = 0, len = 0;
char *cp = *src, *p;
char *bp = dst;
__u32 ac = 0;
while (*cp == ' ')
cp++;
/* the single digit 0 is inserted if field is empty */
if (*cp == '0' &&
(*(cp + 1) == ' ' || *(cp + 1) == '\n' || *(cp + 1) == '\0')) {
cp++;
goto fini;
}
while (isascii(*cp)) {
if (*cp == ' ' || *cp == '\n' || *cp == '\0')
break;
p = strchr(base64url_table, *cp);
if (len > destsize || p == NULL || *cp == '\0') {
len = -1;
goto out;
}
cp++;
ac = (ac << 6) | (p - base64url_table);
bits += 6;
if (bits >= 8) {
bits -= 8;
*bp++ = (__u8)(ac >> bits);
len++;
}
}
if (!isascii(*cp) || (ac & ((1 << bits) - 1))) {
len = -1;
goto out;
}
fini:
*src = cp;
out:
return len;
}
/*
* gss_string_read() - read some string
*
* An empty string is represented with the single digit 0.
* String end is marked with a trailing space or '\n' or '\0'.
*/
static inline int gss_string_read(char **src, char *dst, int destsize,
int allowzero)
{
char *cp = *src;
char *bp = dst;
int len = 0;
while (*cp == ' ')
cp++;
/* the single digit 0 is inserted if field is empty */
if (!allowzero && *cp == '0' &&
(*(cp + 1) == ' ' || *(cp + 1) == '\n')) {
cp++;
goto out;
}
while (isascii(*cp)) {
if (*cp == ' ' || *cp == '\n')
break;
if (len >= destsize || *cp == '\0') {
len = -1;
goto out;
}
*(bp++) = *(cp++);
len++;
}
if (!isascii(*cp)) {
len = -1;
goto out;
}
*src = cp;
out:
return len;
}
#ifndef __KERNEL__
/*
* gss_u64_read() - read some u64
*/
static inline int gss_u64_read_string(char **src, __u64 *n)
{
char buf[24];
char *ep;
int ret;
ret = gss_string_read(src, buf, sizeof(buf), 1);
if (ret < 0)
return ret;
buf[ret] = '\0';
*n = strtoull(buf, &ep, 0);
if (*ep)
return -1;
return 0;
}
#endif
/*
* gss_buffer_read() - read some buffer
*/
static inline int gss_buffer_read(char **src, char *dst, int destsize)
{
char *cp = *src;
char *bp = dst;
__u32 *p;
int len, size;
/* read data size */
p = (__u32 *)cp;
len = *p;
cp += sizeof(__u32);
if (len > destsize) {
len = -1;
goto out;
}
if (!len)
goto fini;
/* read data itself */
size = len;
while (size && destsize) {
*(bp++) = *(cp++);
destsize--;
size--;
}
if (!destsize && size)
len = -1;
fini:
*src = cp;
out:
return len;
}
/*
* gss_buffer_get() - get reference to gss buffer
*/
static inline int gss_buffer_get(char **src, __u32 *len, __u8 **data)
{
char *cp = *src;
__u32 *p;
/* read data size */
p = (__u32 *)cp;
*len = *p;
cp += sizeof(__u32);
/* point to data buf */
if (!*len)
*data = NULL;
else
*data = (__u8 *)cp;
/* move forward */
cp += *len;
*src = cp;
return *len;
}
/*
* gss_u32_read() - read some u32
*/
static inline int gss_u32_read(char **src, __u32 *val)
{
char *cp = *src;
__u32 *p;
p = (__u32 *)cp;
*val = *p;
cp += sizeof(__u32);
*src = cp;
return 0;
}
#endif /* _LGSS_H */