- Update to latest from NSA
- Add getseuserbyname
This commit is contained in:
parent
e8346fc44d
commit
bebb529bd5
@ -1,229 +1,242 @@
|
|||||||
diff --exclude-from=exclude -N -u -r nsalibselinux/include/selinux/selinux.h libselinux-1.26/include/selinux/selinux.h
|
diff --exclude-from=exclude -N -u -r nsalibselinux/include/selinux/selinux.h libselinux-1.27.1/include/selinux/selinux.h
|
||||||
--- nsalibselinux/include/selinux/selinux.h 2005-09-01 11:17:40.000000000 -0400
|
--- nsalibselinux/include/selinux/selinux.h 2005-09-01 11:17:40.000000000 -0400
|
||||||
+++ libselinux-1.26/include/selinux/selinux.h 2005-09-16 14:16:26.000000000 -0400
|
+++ libselinux-1.27.1/include/selinux/selinux.h 2005-09-28 14:37:04.000000000 -0400
|
||||||
@@ -304,6 +304,12 @@
|
@@ -354,6 +354,25 @@
|
||||||
extern int selinux_getenforcemode(int *enforce);
|
extern int selinux_raw_to_trans_context(security_context_t raw,
|
||||||
|
security_context_t *transp);
|
||||||
|
|
||||||
/*
|
|
||||||
+ selinux_getpolicytype reads the /etc/selinux/config file and determines
|
|
||||||
+ whether the policy tyep for this machine, type must be freed.
|
|
||||||
+ */
|
|
||||||
+extern void selinux_getpolicytype(char **type);
|
|
||||||
+
|
+
|
||||||
+/*
|
+/* the following functions are used to retrieve the SELinux user and their
|
||||||
selinux_policy_root reads the /etc/selinux/config file and returns
|
+ security level via the Linux usernames selinux */
|
||||||
the directory path under which the compiled policy file and context
|
+
|
||||||
configuration files exist.
|
+#define SEUSERFILE "/etc/selinux/seusers.conf"
|
||||||
diff --exclude-from=exclude -N -u -r nsalibselinux/src/get_context_list.c libselinux-1.26/src/get_context_list.c
|
+
|
||||||
--- nsalibselinux/src/get_context_list.c 2005-08-11 22:41:15.000000000 -0400
|
+/* Define data structures */
|
||||||
+++ libselinux-1.26/src/get_context_list.c 2005-09-16 16:22:03.000000000 -0400
|
+typedef struct seuser {
|
||||||
@@ -288,6 +288,40 @@
|
+ char* username;
|
||||||
return strcmp(c1->con, c2->con);
|
+ char* seusername;
|
||||||
|
+ char* level;
|
||||||
|
+} seuser_t;
|
||||||
|
+
|
||||||
|
+/* read /etc/selinux/seusers.conf file an return selinux user info */
|
||||||
|
+
|
||||||
|
+extern void freeseuser(seuser_t *seuser);
|
||||||
|
+
|
||||||
|
+extern int getseuserbyname(const char *name, seuser_t **r_seuser);
|
||||||
|
+
|
||||||
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
+int get_ordered_context_list_with_level (const char *user,
|
diff --exclude-from=exclude -N -u -r nsalibselinux/include/selinux/seuser.h libselinux-1.27.1/include/selinux/seuser.h
|
||||||
+ const char *level,
|
--- nsalibselinux/include/selinux/seuser.h 1969-12-31 19:00:00.000000000 -0500
|
||||||
+ security_context_t fromcon,
|
+++ libselinux-1.27.1/include/selinux/seuser.h 2005-09-28 14:32:11.000000000 -0400
|
||||||
+ security_context_t **list)
|
@@ -0,0 +1,32 @@
|
||||||
|
+#ifndef _SEUSER_H_
|
||||||
|
+#define _SEUSER_H_
|
||||||
|
+
|
||||||
|
+#include <sys/types.h>
|
||||||
|
+#include <stdarg.h>
|
||||||
|
+
|
||||||
|
+#ifdef __cplusplus
|
||||||
|
+extern "C"
|
||||||
+{
|
+{
|
||||||
+ int rc;
|
+#endif
|
||||||
+ int freefrom = 0;
|
|
||||||
+ context_t con;
|
|
||||||
+
|
+
|
||||||
+ if (!level)
|
+#define SEUSERFILE "/etc/selinux/seusers.conf"
|
||||||
+ return get_ordered_context_list (user, fromcon, list);
|
|
||||||
+
|
+
|
||||||
+ if (!fromcon) {
|
+/* Define data structures */
|
||||||
+ rc = getcon(&fromcon);
|
+typedef struct seuser {
|
||||||
+ if (rc < 0)
|
+ char* username;
|
||||||
+ return rc;
|
+ char* seusername;
|
||||||
+ freefrom = 1;
|
+ char* sensitivity;
|
||||||
+ }
|
+ char* categories;
|
||||||
|
+} seuser_t;
|
||||||
+
|
+
|
||||||
+ con=context_new(fromcon);
|
+/* read /etc/selinux/seusers.conf file an return selinux user info */
|
||||||
+ if (con) {
|
|
||||||
+ context_range_set(con, level);
|
|
||||||
+ rc = get_ordered_context_list (user, context_str(con), list);
|
|
||||||
+ context_free(con);
|
|
||||||
+ }
|
|
||||||
+ else
|
|
||||||
+ rc=-1;
|
|
||||||
+
|
+
|
||||||
+ if (freefrom)
|
+extern void free_seuser(seuser_t *seuser);
|
||||||
+ freecon(fromcon);
|
|
||||||
+
|
+
|
||||||
+ return rc;
|
+extern int getseuserbyname(const char *name, seuser_t **r_seuser);
|
||||||
|
+
|
||||||
|
+#ifdef __cplusplus
|
||||||
+}
|
+}
|
||||||
|
+#endif
|
||||||
+
|
+
|
||||||
int get_ordered_context_list (const char *user,
|
+#endif
|
||||||
security_context_t fromcon,
|
diff --exclude-from=exclude -N -u -r nsalibselinux/man/Makefile libselinux-1.27.1/man/Makefile
|
||||||
security_context_t **list)
|
--- nsalibselinux/man/Makefile 2004-10-20 16:31:36.000000000 -0400
|
||||||
diff --exclude-from=exclude -N -u -r nsalibselinux/src/matchpathcon.c libselinux-1.26/src/matchpathcon.c
|
+++ libselinux-1.27.1/man/Makefile 2005-09-28 14:32:16.000000000 -0400
|
||||||
--- nsalibselinux/src/matchpathcon.c 2005-08-24 09:07:11.000000000 -0400
|
@@ -8,3 +8,6 @@
|
||||||
+++ libselinux-1.26/src/matchpathcon.c 2005-09-16 15:54:01.000000000 -0400
|
install -m 644 man3/*.3 $(MAN3DIR)
|
||||||
@@ -12,6 +12,7 @@
|
install -m 644 man8/*.8 $(MAN8DIR)
|
||||||
#include <regex.h>
|
|
||||||
#include <stdarg.h>
|
+clean:
|
||||||
#include "policy.h"
|
+ -rm -f *~ \#*
|
||||||
|
+ -rm -f man8/*~ man8/\#*
|
||||||
|
diff --exclude-from=exclude -N -u -r nsalibselinux/src/seusers.c libselinux-1.27.1/src/seusers.c
|
||||||
|
--- nsalibselinux/src/seusers.c 1969-12-31 19:00:00.000000000 -0500
|
||||||
|
+++ libselinux-1.27.1/src/seusers.c 2005-09-28 14:48:28.000000000 -0400
|
||||||
|
@@ -0,0 +1,132 @@
|
||||||
|
+#include <unistd.h>
|
||||||
|
+#include <fcntl.h>
|
||||||
|
+#include <stdlib.h>
|
||||||
|
+#include <string.h>
|
||||||
|
+#include <stdio.h>
|
||||||
|
+#include <ctype.h>
|
||||||
|
+#include <selinux/selinux.h>
|
||||||
+#include <selinux/context.h>
|
+#include <selinux/context.h>
|
||||||
|
+#include "selinux_internal.h"
|
||||||
static void
|
|
||||||
#ifdef __GNUC__
|
|
||||||
@@ -25,6 +26,19 @@
|
|
||||||
va_end(ap);
|
|
||||||
}
|
|
||||||
|
|
||||||
+#define STRIP_LEVEL(CON) \
|
|
||||||
+ if (! mls_enabled) { \
|
|
||||||
+ security_context_t newcon; \
|
|
||||||
+ context_t con=context_new(CON); \
|
|
||||||
+ if (con) { \
|
|
||||||
+ context_range_set(con,NULL); \
|
|
||||||
+ newcon=strdup(context_str(con));\
|
|
||||||
+ context_free(con); \
|
|
||||||
+ freecon(CON); \
|
|
||||||
+ CON=newcon; \
|
|
||||||
+ } \
|
|
||||||
+ }
|
|
||||||
+
|
+
|
||||||
static void (*myprintf)(const char *fmt, ...) = &default_printf;
|
+void freeseuser(seuser_t *seuser) {
|
||||||
|
+ if (!seuser) return;
|
||||||
void set_matchpathcon_printf(void (*f)(const char *fmt, ...))
|
+ if (seuser->username)
|
||||||
@@ -415,7 +429,7 @@
|
+ free(seuser->username);
|
||||||
}
|
+ if (seuser->seusername)
|
||||||
return;
|
+ free(seuser->seusername);
|
||||||
}
|
+ if (seuser->level)
|
||||||
-static int process_line( const char *path, char *line_buf, int pass, unsigned lineno) {
|
+ free(seuser->level);
|
||||||
+static int process_line( const char *path, char *line_buf, int pass, unsigned lineno, int mls_enabled) {
|
+ free(seuser);
|
||||||
int items, len, regerr;
|
+ return;
|
||||||
char *buf_p;
|
+}
|
||||||
char *regex, *type, *context;
|
+
|
||||||
@@ -438,6 +452,7 @@
|
+/* Process line from SEUSERSFILE.
|
||||||
} else if (items == 2) {
|
+ Remove white space and set name do data before the "=" and sename to data
|
||||||
/* The type field is optional. */
|
+ after it */
|
||||||
free(context);
|
+static int process_seusers(const char *buffer, seuser_t **r_user) {
|
||||||
+ STRIP_LEVEL(type)
|
+ seuser_t *user=NULL;
|
||||||
context = type;
|
+ char *ptr;
|
||||||
type = 0;
|
+ int rc=-1;
|
||||||
}
|
+ char *tok;
|
||||||
@@ -510,7 +525,7 @@
|
+ char *newbuf=strdup(buffer);
|
||||||
}
|
+ if (!newbuf) return -1;
|
||||||
|
+
|
||||||
skip_type:
|
+ user=calloc(1, sizeof(seuser_t));
|
||||||
-
|
+ if (!user) return -1;
|
||||||
+ STRIP_LEVEL(context)
|
+
|
||||||
spec_arr[nspec].context = context;
|
+ tok=strtok_r(newbuf,":",&ptr);
|
||||||
|
+ if (!tok) goto err;
|
||||||
if (strcmp(context, "<<none>>")) {
|
+ if ( tok[0]=='#' ) goto err;
|
||||||
@@ -557,6 +572,7 @@
|
+ user->username=strdup(tok);
|
||||||
unsigned int lineno, pass, i, j, maxnspec;
|
+ if (!user->username) {
|
||||||
spec_t *spec_copy=NULL;
|
+ freeseuser(user);
|
||||||
int status=-1;
|
+ rc=-1;
|
||||||
+ int mls_enabled=is_selinux_mls_enabled();
|
+ goto err;
|
||||||
|
+ }
|
||||||
/* Open the specification file. */
|
+
|
||||||
if (!path)
|
+ tok=strtok_r(NULL,":",&ptr);
|
||||||
@@ -590,20 +606,20 @@
|
+ if (!tok) goto err;
|
||||||
lineno = 0;
|
+ while (isspace(*tok)) tok++;
|
||||||
nspec = 0;
|
+ if(strlen(tok))
|
||||||
while (getline(&line_buf, &line_len, fp) > 0 && nspec < maxnspec) {
|
+ user->seusername=strdup(tok);
|
||||||
- if (process_line(path, line_buf, pass, ++lineno) != 0)
|
+ if (!user->seusername) {
|
||||||
+ if (process_line(path, line_buf, pass, ++lineno, mls_enabled) != 0)
|
+ freeseuser(user);
|
||||||
goto finish;
|
+ rc=-1;
|
||||||
}
|
+ goto err;
|
||||||
lineno = 0;
|
+ }
|
||||||
if (homedirfp)
|
+
|
||||||
while (getline(&line_buf, &line_len, homedirfp) > 0 && nspec < maxnspec) {
|
+ tok=strtok_r(NULL,":",&ptr);
|
||||||
- if (process_line(homedir_path, line_buf, pass, ++lineno) != 0)
|
+ if (!tok) goto err;
|
||||||
+ if (process_line(homedir_path, line_buf, pass, ++lineno, mls_enabled) != 0)
|
+ while (isspace(*tok)) tok++;
|
||||||
goto finish;
|
+ if(strlen(tok))
|
||||||
}
|
+ user->level=strdup(tok);
|
||||||
|
+ if (!user->level) {
|
||||||
lineno = 0;
|
+ freeseuser(user);
|
||||||
if (localfp)
|
+ rc=-1;
|
||||||
while (getline(&line_buf, &line_len, localfp) > 0 && nspec < maxnspec) {
|
+ goto err;
|
||||||
- if (process_line(local_path, line_buf, pass, ++lineno) != 0)
|
+ }
|
||||||
+ if (process_line(local_path, line_buf, pass, ++lineno, mls_enabled) != 0)
|
+
|
||||||
goto finish;
|
+ tok=strtok_r(NULL,":",&ptr);
|
||||||
}
|
+ if (tok) {
|
||||||
|
+ int len;
|
||||||
diff --exclude-from=exclude -N -u -r nsalibselinux/src/selinux_config.c libselinux-1.26/src/selinux_config.c
|
+ while (isspace(*tok)) tok++;
|
||||||
--- nsalibselinux/src/selinux_config.c 2005-03-17 14:56:21.000000000 -0500
|
+ len=strlen(tok);
|
||||||
+++ libselinux-1.26/src/selinux_config.c 2005-09-16 14:16:26.000000000 -0400
|
+ if(len) {
|
||||||
@@ -85,6 +85,29 @@
|
+ char *ptr=realloc(user->level, strlen(user->level) + len + 2);
|
||||||
|
+ if (ptr==NULL) {
|
||||||
static int use_compat_file_path;
|
+ freeseuser(user);
|
||||||
|
+ rc=-1;
|
||||||
+void selinux_getpolicytype(char **rtype) {
|
+ goto err;
|
||||||
+ char *type=SELINUXDEFAULT;
|
+ }
|
||||||
+ char buf[4097];
|
+ user->level=ptr;
|
||||||
+ int i=0;
|
+ strcat(user->level,":");
|
||||||
+ int len=sizeof(SELINUXTYPETAG)-1;
|
+ strcat(user->level,tok);
|
||||||
+ FILE *cfg = fopen(SELINUXCONFIG,"r");
|
+ }
|
||||||
+ if (cfg) {
|
+ }
|
||||||
+ while (fgets_unlocked(buf, 4096, cfg)) {
|
+
|
||||||
+ if (strncmp(buf,SELINUXTYPETAG,len)==0) {
|
+ *r_user=user;
|
||||||
+ type=buf+len;
|
+ rc=0;
|
||||||
+ break;
|
+err:
|
||||||
+ }
|
+ free(newbuf);
|
||||||
+ }
|
+ return rc;
|
||||||
+ fclose(cfg);
|
+}
|
||||||
+ }
|
+
|
||||||
+ i=strlen(type)-1;
|
+int getseuserbyname(const char *name, seuser_t **r_seuser) {
|
||||||
+ while ((i>=0) &&
|
+ FILE *cfg=NULL;
|
||||||
+ (isspace(type[i]) || iscntrl(type[i]))) {
|
+ size_t size=0;
|
||||||
+ type[i]=0;
|
+ char *buffer=NULL;
|
||||||
+ i--;
|
+
|
||||||
+ }
|
+ static seuser_t *seuser=NULL;
|
||||||
+ *rtype=strdup(type);
|
+ static seuser_t *defaultseuser=NULL;
|
||||||
|
+
|
||||||
|
+ cfg = fopen(SEUSERFILE,"r");
|
||||||
|
+ if (!cfg) return -1;
|
||||||
|
+
|
||||||
|
+ while (getline(&buffer, &size, cfg) > 0) {
|
||||||
|
+ if(process_seusers(buffer, &seuser) == 0) {
|
||||||
|
+ if (strcasecmp(seuser->username, name)==0)
|
||||||
|
+ break;
|
||||||
|
+
|
||||||
|
+ if (strcasecmp(seuser->username,"default")==0) {
|
||||||
|
+ if (defaultseuser) freeseuser(defaultseuser);
|
||||||
|
+ defaultseuser=seuser;
|
||||||
|
+ }
|
||||||
|
+ else
|
||||||
|
+ freeseuser(seuser);
|
||||||
|
+ seuser=NULL;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ if (buffer) free(buffer);
|
||||||
|
+ fclose(cfg);
|
||||||
|
+ if (seuser) {
|
||||||
|
+ freeseuser(defaultseuser);
|
||||||
|
+ *r_seuser=seuser;
|
||||||
|
+ return 0;
|
||||||
|
+ }
|
||||||
|
+ if (defaultseuser) {
|
||||||
|
+ *r_seuser=defaultseuser;
|
||||||
|
+ return 0;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return -1;
|
||||||
|
+}
|
||||||
|
diff --exclude-from=exclude -N -u -r nsalibselinux/utils/getseuser.c libselinux-1.27.1/utils/getseuser.c
|
||||||
|
--- nsalibselinux/utils/getseuser.c 1969-12-31 19:00:00.000000000 -0500
|
||||||
|
+++ libselinux-1.27.1/utils/getseuser.c 2005-09-28 14:49:21.000000000 -0400
|
||||||
|
@@ -0,0 +1,27 @@
|
||||||
|
+#include <unistd.h>
|
||||||
|
+#include <stdlib.h>
|
||||||
|
+#include <stdio.h>
|
||||||
|
+#include <getopt.h>
|
||||||
|
+#include <errno.h>
|
||||||
|
+#include <string.h>
|
||||||
|
+#include <selinux/selinux.h>
|
||||||
|
+
|
||||||
|
+void usage(const char *progname)
|
||||||
|
+{
|
||||||
|
+ fprintf(stderr, "usage: %s\n", progname);
|
||||||
|
+ exit(1);
|
||||||
|
+}
|
||||||
|
+int main(int argc, char **argv) {
|
||||||
|
+ seuser_t *seuser;
|
||||||
|
+ if ( argc != 2 ) usage(argv[0]);
|
||||||
|
+ if (getseuserbyname(argv[1], &seuser) == 0 ) {
|
||||||
|
+ printf("%s\n", seuser->username);
|
||||||
|
+ printf("%s\n", seuser->seusername);
|
||||||
|
+ printf("%s", seuser->level);
|
||||||
|
+ freeseuser(seuser);
|
||||||
|
+ return 0;
|
||||||
|
+ } else {
|
||||||
|
+ printf("%s not found\n", argv[1]);
|
||||||
|
+ return -1;
|
||||||
|
+ }
|
||||||
+}
|
+}
|
||||||
int selinux_getenforcemode(int *enforce) {
|
|
||||||
int ret=-1;
|
|
||||||
FILE *cfg = fopen(SELINUXCONFIG,"r");
|
|
||||||
@@ -122,38 +145,24 @@
|
|
||||||
|
|
||||||
static void init_selinux_policyroot(void)
|
|
||||||
{
|
|
||||||
- char *type=SELINUXDEFAULT;
|
|
||||||
- int i=0, len=sizeof(SELINUXTYPETAG)-1, len2;
|
|
||||||
- char buf[4097];
|
|
||||||
- FILE *cfg;
|
|
||||||
+ char *type=NULL;
|
|
||||||
+ int i=0, len, len2;
|
|
||||||
if (selinux_policyroot) return;
|
|
||||||
if (access(SELINUXDIR, F_OK) != 0) {
|
|
||||||
selinux_policyroot = SECURITYDIR;
|
|
||||||
use_compat_file_path = 1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
- cfg = fopen(SELINUXCONFIG,"r");
|
|
||||||
- if (cfg) {
|
|
||||||
- while (fgets_unlocked(buf, 4096, cfg)) {
|
|
||||||
- if (strncmp(buf,SELINUXTYPETAG,len)==0) {
|
|
||||||
- type=buf+len;
|
|
||||||
- break;
|
|
||||||
- }
|
|
||||||
- }
|
|
||||||
- fclose(cfg);
|
|
||||||
- }
|
|
||||||
- i=strlen(type)-1;
|
|
||||||
- while ((i>=0) &&
|
|
||||||
- (isspace(type[i]) || iscntrl(type[i]))) {
|
|
||||||
- type[i]=0;
|
|
||||||
- i--;
|
|
||||||
- }
|
|
||||||
+ selinux_getpolicytype(&type);
|
|
||||||
+ if (!type) return;
|
|
||||||
len=sizeof(SELINUXDIR) + strlen(type);
|
|
||||||
selinux_policyroot=malloc(len);
|
|
||||||
- if (!selinux_policyroot)
|
|
||||||
+ if (!selinux_policyroot) {
|
|
||||||
+ free(type);
|
|
||||||
return;
|
|
||||||
+ }
|
|
||||||
snprintf(selinux_policyroot,len, "%s%s", SELINUXDIR, type);
|
|
||||||
-
|
|
||||||
+ free(type);
|
|
||||||
for (i = 0; i < NEL; i++) {
|
|
||||||
len2 = len + strlen(file_path_suffixes_data.str
|
|
||||||
+ file_path_suffixes_idx[i])+1;
|
|
||||||
|
@ -1,16 +1,17 @@
|
|||||||
Summary: SELinux library and simple utilities
|
Summary: SELinux library and simple utilities
|
||||||
Name: libselinux
|
Name: libselinux
|
||||||
Version: 1.27.1
|
Version: 1.27.1
|
||||||
Release: 1
|
Release: 2
|
||||||
License: Public domain (uncopyrighted)
|
License: Public domain (uncopyrighted)
|
||||||
Group: System Environment/Libraries
|
Group: System Environment/Libraries
|
||||||
Source: http://www.nsa.gov/selinux/archives/%{name}-%{version}.tgz
|
Source: http://www.nsa.gov/selinux/archives/%{name}-%{version}.tgz
|
||||||
|
Patch: libselinux-rhat.patch
|
||||||
Prereq: libsetrans
|
Prereq: libsetrans
|
||||||
|
|
||||||
BuildRoot: %{_tmppath}/%{name}-%{version}-buildroot
|
BuildRoot: %{_tmppath}/%{name}-%{version}-buildroot
|
||||||
|
|
||||||
%description
|
%description
|
||||||
Security-enhanced Linux is a patch of the Linux® kernel and a number
|
Security-enhanced Linux is a feature of the Linux® kernel and a number
|
||||||
of utilities with enhanced security functionality designed to add
|
of utilities with enhanced security functionality designed to add
|
||||||
mandatory access controls to Linux. The Security-enhanced Linux
|
mandatory access controls to Linux. The Security-enhanced Linux
|
||||||
kernel contains new architectural components originally developed to
|
kernel contains new architectural components originally developed to
|
||||||
@ -35,6 +36,7 @@ needed for developing SELinux applications.
|
|||||||
|
|
||||||
%prep
|
%prep
|
||||||
%setup -q
|
%setup -q
|
||||||
|
%patch -p1 -b .rhat
|
||||||
|
|
||||||
%build
|
%build
|
||||||
make CFLAGS="-g %{optflags}"
|
make CFLAGS="-g %{optflags}"
|
||||||
@ -84,6 +86,10 @@ rm -rf ${RPM_BUILD_ROOT}
|
|||||||
%{_mandir}/man8/*
|
%{_mandir}/man8/*
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Wed Sep 28 2005 Dan Walsh <dwalsh@redhat.com> 1.27.1-2
|
||||||
|
- Update to latest from NSA
|
||||||
|
- Add getseuserbyname
|
||||||
|
|
||||||
* Fri Sep 12 2005 Dan Walsh <dwalsh@redhat.com> 1.26-6
|
* Fri Sep 12 2005 Dan Walsh <dwalsh@redhat.com> 1.26-6
|
||||||
- Fix patch call
|
- Fix patch call
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user