From d52074a9cb89ac6d940f99f1490b7364758bd6fa Mon Sep 17 00:00:00 2001 From: chenzhijia Date: Mon, 6 May 2024 11:17:07 +0800 Subject: [PATCH] libs/libc/unistd: add getspnam function Add getspnam function to pass tlpi example: https://man7.org/tlpi/code/online/dist/users_groups/check_password.c.html Signed-off-by: chenzhijia --- include/shadow.h | 59 ++++++++++ libs/libc/pwd/CMakeLists.txt | 12 +- libs/libc/pwd/Make.defs | 4 +- libs/libc/pwd/lib_getspnam.c | 60 ++++++++++ libs/libc/pwd/lib_getspnamr.c | 189 ++++++++++++++++++++++++++++++++ libs/libc/pwd/lib_pwd.h | 3 + libs/libc/pwd/lib_pwd_globals.c | 1 + 7 files changed, 323 insertions(+), 5 deletions(-) create mode 100644 include/shadow.h create mode 100644 libs/libc/pwd/lib_getspnam.c create mode 100644 libs/libc/pwd/lib_getspnamr.c diff --git a/include/shadow.h b/include/shadow.h new file mode 100644 index 0000000000..8e271c9c51 --- /dev/null +++ b/include/shadow.h @@ -0,0 +1,59 @@ +/**************************************************************************** + * include/shadow.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements See the NOTICE file distributed with + * this work for additional information regarding copyright ownership The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __INCLUDE_SHADOW_H +#define __INCLUDE_SHADOW_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Public Type Declarations + ****************************************************************************/ + +/* Structure of the password file */ + +struct spwd +{ + FAR char *sp_namp; /* Login name */ + FAR char *sp_pwdp; /* Encrypted password */ + long int sp_lstchg; /* Date of last change */ + long int sp_min; /* Minimum number of days between changes */ + long int sp_max; /* Maximum number of days between changes */ + long int sp_warn; /* Number of days to warn user to change the password */ + long int sp_inact; /* Number of days the account may be inactive */ + long int sp_expire; /* Number of days since 1970-01-01 until account expires */ + unsigned long int sp_flag; /* Reserved */ +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/* Get shadow entry matching NAME */ + +FAR struct spwd *getspnam(FAR const char *name); +int getspnam_r(FAR const char *name, FAR struct spwd *sp, FAR char *buf, + size_t size, FAR struct spwd **res); + +#endif /* __INCLUDE_SHADOW_H */ \ No newline at end of file diff --git a/libs/libc/pwd/CMakeLists.txt b/libs/libc/pwd/CMakeLists.txt index ae19b76b2f..8cdd2ac105 100644 --- a/libs/libc/pwd/CMakeLists.txt +++ b/libs/libc/pwd/CMakeLists.txt @@ -19,11 +19,17 @@ # the License. # # ############################################################################## -set(SRCS lib_getpwnam.c lib_getpwnamr.c lib_getpwuid.c lib_getpwuidr.c - lib_getpwent.c lib_pwd_globals.c) +set(SRCS + lib_getpwnam.c + lib_getpwnamr.c + lib_getpwuid.c + lib_getpwuidr.c + lib_getpwent.c + lib_pwd_globals.c + lib_getspnam.c) if(CONFIG_LIBC_PASSWD_FILE) - list(APPEND SRCS lib_find_pwdfile.c) + list(APPEND SRCS lib_find_pwdfile.c lib_getspnamr.c) else() list(APPEND SRCS lib_getpwbuf.c lib_getpwbufr.c) endif() diff --git a/libs/libc/pwd/Make.defs b/libs/libc/pwd/Make.defs index f763baa1fd..60caa5f0a1 100644 --- a/libs/libc/pwd/Make.defs +++ b/libs/libc/pwd/Make.defs @@ -23,10 +23,10 @@ # Add the pwd C files to the build CSRCS += lib_getpwnam.c lib_getpwnamr.c lib_getpwuid.c lib_getpwuidr.c -CSRCS += lib_getpwent.c lib_pwd_globals.c +CSRCS += lib_getpwent.c lib_pwd_globals.c lib_getspnam.c ifeq ($(CONFIG_LIBC_PASSWD_FILE),y) -CSRCS += lib_find_pwdfile.c +CSRCS += lib_find_pwdfile.c lib_getspnamr.c else CSRCS += lib_getpwbuf.c lib_getpwbufr.c endif diff --git a/libs/libc/pwd/lib_getspnam.c b/libs/libc/pwd/lib_getspnam.c new file mode 100644 index 0000000000..127f2d7ed9 --- /dev/null +++ b/libs/libc/pwd/lib_getspnam.c @@ -0,0 +1,60 @@ +/**************************************************************************** + * libs/libc/pwd/lib_getspnam.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include "pwd/lib_pwd.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +FAR struct spwd *getspnam(FAR const char *name) +{ + FAR struct spwd *result = NULL; + +#ifdef CONFIG_LIBC_PASSWD_FILE + getspnam_r(name, &g_spwd, g_passwd_buffer, + sizeof(g_passwd_buffer), &result); +#else + if (strcmp(name, ROOT_NAME) == 0) + { + size_t nsize = sizeof(ROOT_NAME); + size_t psize = sizeof(ROOT_PWDP); + result = &g_spwd; + + result->sp_namp = g_passwd_buffer; + result->sp_pwdp = &g_passwd_buffer[nsize]; + + strlcpy(result->sp_namp, ROOT_NAME, nsize); + strlcpy(result->sp_pwdp, ROOT_PWDP, psize); + } +#endif + + return result; +} diff --git a/libs/libc/pwd/lib_getspnamr.c b/libs/libc/pwd/lib_getspnamr.c new file mode 100644 index 0000000000..69ee8622a2 --- /dev/null +++ b/libs/libc/pwd/lib_getspnamr.c @@ -0,0 +1,189 @@ +/**************************************************************************** + * libs/libc/pwd/lib_getspnamr.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define BUFFER_EXTRA 100 + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/* This implementation support Openwall-style TCB passwords in place of + * traditional shadow, if the appropriate directories and files exist. + * Thus, it is careful to avoid following symlinks or blocking on fifos + * which a malicious user might create in place of his or her TCB shadow + * file. It also avoids any allocation to prevent memory-exhaustion + * attacks via huge TCB shadow files + */ + +static long xatol(FAR char **s) +{ + if (**s == ':' || **s == '\n') + { + return -1; + } + + return strtol(*s, &(*s), 10); +} + +static int parsespent(FAR char *s, FAR struct spwd *sp) +{ + sp->sp_namp = s; + if (!(s = strchr(s, ':'))) + { + return -1; + } + + *s = 0; + sp->sp_pwdp = ++s; + if (!(s = strchr(s, ':'))) + { + return -1; + } + + *s = 0; + s++; + sp->sp_lstchg = xatol(&s); + if (*s != ':') + { + return -1; + } + + s++; + sp->sp_min = xatol(&s); + if (*s != ':') + { + return -1; + } + + s++; + sp->sp_max = xatol(&s); + if (*s != ':') + { + return -1; + } + + s++; + sp->sp_warn = xatol(&s); + if (*s != ':') + { + return -1; + } + + s++; + sp->sp_inact = xatol(&s); + if (*s != ':') + { + return -1; + } + + s++; + sp->sp_expire = xatol(&s); + if (*s != ':') + { + return -1; + } + + s++; + sp->sp_flag = xatol(&s); + if (*s != '\n') + { + return -1; + } + + return 0; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int getspnam_r(FAR const char *name, FAR struct spwd *sp, FAR char *buf, + size_t size, FAR struct spwd **res) +{ + size_t l = strlen(name); + size_t k; + FAR FILE *f; + int skip = 0; + + *res = NULL; + + /* Disallow potentially-malicious user names */ + + if (*name == '.' || strchr(name, '/') || l == 0) + { + set_errno(EINVAL); + return -1; + } + + /* Buffer size must at least be able to hold name, plus some.. */ + + if (size < l + BUFFER_EXTRA) + { + set_errno(ERANGE); + return -1; + } + + f = fopen(CONFIG_LIBC_PASSWD_FILEPATH, "rbe"); + if (f == NULL) + { + return -1; + } + + while (fgets(buf, size, f) && (k = strlen(buf)) > 0) + { + if (skip || strncmp(name, buf, l) || buf[l] != ':') + { + skip = buf[k - 1] != '\n'; + continue; + } + + if (buf[k - 1] != '\n') + { + set_errno(ERANGE); + fclose(f); + return -1; + } + + if (parsespent(buf, sp) < 0) + { + continue; + } + + *res = sp; + break; + } + + fclose(f); + return 0; +} diff --git a/libs/libc/pwd/lib_pwd.h b/libs/libc/pwd/lib_pwd.h index a917913c23..f7f50077a7 100644 --- a/libs/libc/pwd/lib_pwd.h +++ b/libs/libc/pwd/lib_pwd.h @@ -30,6 +30,7 @@ #include #include +#include /**************************************************************************** * Pre-processor Definitions @@ -46,6 +47,7 @@ #define ROOT_DIR "/root" #define ROOT_SHELL "/bin/nsh" #define ROOT_PASSWD "root" +#define ROOT_PWDP "$1$123$SGj4CnC7VtiFx.tjjtazK1" /**************************************************************************** * Public Data @@ -63,6 +65,7 @@ extern "C" EXTERN int g_passwd_index; EXTERN struct passwd g_passwd; +EXTERN struct spwd g_spwd; EXTERN char g_passwd_buffer[CONFIG_LIBC_PASSWD_LINESIZE]; /**************************************************************************** diff --git a/libs/libc/pwd/lib_pwd_globals.c b/libs/libc/pwd/lib_pwd_globals.c index 38ef84adc5..ac2ac26309 100644 --- a/libs/libc/pwd/lib_pwd_globals.c +++ b/libs/libc/pwd/lib_pwd_globals.c @@ -36,6 +36,7 @@ int g_passwd_index; struct passwd g_passwd; +struct spwd g_spwd; char g_passwd_buffer[CONFIG_LIBC_PASSWD_LINESIZE]; /****************************************************************************