Skip to content
This repository has been archived by the owner on May 2, 2024. It is now read-only.

Commit

Permalink
Merge pull request #55 from ubuntu/nss_module_in_c
Browse files Browse the repository at this point in the history
Nss module in c
  • Loading branch information
didrocks committed Aug 31, 2022
2 parents a60deb5 + 3656626 commit 79f51d5
Show file tree
Hide file tree
Showing 45 changed files with 447 additions and 1 deletion.
2 changes: 1 addition & 1 deletion .github/workflows/qa.yaml
Expand Up @@ -39,7 +39,7 @@ jobs:
go build -ldflags='-s -w' -buildmode=c-shared -o pam_aad.so ./pam
# Build NSS library
go build -ldflags='-s -w' -buildmode=c-shared -o libnss_aad.so.2 ./nss
go build -ldflags='-s -w' -buildmode=c-shared -o libnss_aad.so.2 ./nss/integration_tests
if: ${{ always() }}

tests:
Expand Down
20 changes: 20 additions & 0 deletions nss/Makefile
@@ -0,0 +1,20 @@
CC=gcc
CFLAGS=-g -Wall -Wextra $(shell pkg-config --cflags glib-2.0)
LDFLAGS=$(shell pkg-config --libs glib-2.0)

all: clean libnss_aad.so.2 copy

libnss_aad.so.2:
$(CC) -DSCRIPTPATH=\"/home/u/getent.sh\" passwd.c group.c shadow.c common.c $(CFLAGS) $(LDFLAGS) -fPIC -shared -Wl,-soname,libnss_aad.so.2 -o libnss_aad.so.2

clean:
rm -f libnss_aad.so.2

check:
make clean
codechecker check -b "make libnss_aad.so.2"

copy:
scp libnss_aad.so.2 u@192.168.122.144:~/
scp getent.sh u@192.168.122.144:~/

114 changes: 114 additions & 0 deletions nss/common.c
@@ -0,0 +1,114 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <nss.h>
#include <pwd.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <ctype.h>

#include <glib.h>
#include <glib/gprintf.h>

#ifndef SCRIPTPATH
#define SCRIPTPATH "/usr/libexec/aad-auth"
#endif

gint run_aad_auth(const char *db, const char *name, const uid_t uid, enum nss_status *nss_exit_status, int *errnop, GPtrArray *entries)
{
gchar *stdout = NULL;
gchar *stderr = NULL;
GError *error = NULL;
gchar *cmd;

if (name)
{
// Concatenate name with cmd
cmd = g_strconcat(SCRIPTPATH, " ", "getent", " ", db, " ", name, NULL);
}
else if (uid != 0)
{
gchar *uid_s = NULL;
uid_s = g_strdup_printf(" %u", uid);
cmd = g_strconcat(SCRIPTPATH, " ", "getent", " ", db, " ", uid_s, NULL);
g_free(uid_s);
}
else
{
cmd = g_strconcat(SCRIPTPATH, " ", "getent", " ", db, NULL);
}

gint exit_status;
if (!g_spawn_command_line_sync(cmd, &stdout, &stderr, &exit_status, &error) || exit_status != 0)
{
*errnop = ENOENT;
g_free(cmd);
return exit_status;
}
g_free(cmd);

gchar **lines = g_strsplit(stdout, "\n", -1);
for (gint i = 0; lines[i]; i++)
{
// first line is nss_exit_status:errno
if (i == 0)
{
gchar **statuses = g_strsplit(lines[i], ":", 2);
*nss_exit_status = atoi(statuses[0]);
*errnop = atoi(statuses[1]);
g_strfreev(statuses);
continue;
}

gchar *v = g_strdup(lines[i]);
g_ptr_array_add(entries, (gpointer)v);
}
g_strfreev(lines);

return 0;
}

enum nss_status fetch_info(const char *db, const char *name, const uid_t uid, GPtrArray *all_entries, guint *all_entries_index, gchar **entry, int *errnop)
{
gint nss_exit_status = NSS_STATUS_SUCCESS;

if (name != NULL || uid != 0)
{
GPtrArray *entries = g_ptr_array_new();
gint exit_status = run_aad_auth(db, name, uid, &nss_exit_status, errnop, entries);
if (exit_status != 0)
{
*errnop = ENOENT;
return NSS_STATUS_UNAVAIL;
}
*entry = g_strdup((gchar *)g_ptr_array_index(entries, 0));
g_ptr_array_free(entries, TRUE);
}
else if (all_entries->len == 0)
{
gint exit_status = run_aad_auth(db, name, uid, &nss_exit_status, errnop, all_entries);
if (exit_status != 0)
{
*errnop = ENOENT;
return NSS_STATUS_UNAVAIL;
}
*entry = g_strdup((gchar *)g_ptr_array_index(all_entries, *all_entries_index));
(*all_entries_index)++;
}
else if (*all_entries_index < all_entries->len)
{
*entry = g_strdup((gchar *)g_ptr_array_index(all_entries, *all_entries_index));
(*all_entries_index)++;
}
else
{
// iteration has ended, return our own status
(*all_entries_index) = 0;
*errnop = ENOENT;
return NSS_STATUS_UNAVAIL;
}

return nss_exit_status;
}
6 changes: 6 additions & 0 deletions nss/common.h
@@ -0,0 +1,6 @@
#include <nss.h>
#include <glib.h>

#define UNUSED(x) (void)(x)

enum nss_status fetch_info(const char *db, const char *name, const uid_t uid, GPtrArray *all_entries, guint *all_entries_index, gchar **entry, int *errnop);
103 changes: 103 additions & 0 deletions nss/group.c
@@ -0,0 +1,103 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <nss.h>
#include <grp.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <ctype.h>

#include <glib.h>
#include <glib/gprintf.h>

#include "common.h"

GPtrArray *all_grp_entries = NULL;
guint all_grp_entries_index = 0;

enum nss_status grp_search(const char *name, const gid_t gid, struct group *gr, int *errnop, char *buffer, size_t buflen)
{
UNUSED(buffer);
UNUSED(buflen);

if (all_grp_entries == NULL)
{
all_grp_entries = g_ptr_array_new();
}

gchar *entry = calloc(1000, sizeof(gchar));
gint exit_status = fetch_info("group", name, gid, all_grp_entries, &all_grp_entries_index, &entry, errnop);

// return the exit status if no success
if (exit_status != NSS_STATUS_SUCCESS)
{
g_free(entry);
return exit_status;
}

gchar **tokens = g_strsplit(entry, ":", 4);
g_free(entry);

gr->gr_name = g_strdup(tokens[0]);
gr->gr_passwd = g_strdup(tokens[1]);
gr->gr_gid = strtol(tokens[2], NULL, 10);
gr->gr_mem = g_strsplit(tokens[3], ",", -1);

g_strfreev(tokens);

return exit_status;
}

enum nss_status _nss_aad_getgrgid_r(gid_t gid, struct group *result, char *buf, size_t buflen, int *errnop)
{
*errnop = 0;
if (result)
return grp_search(NULL, gid, result, errnop, buf, buflen);
else
return NSS_STATUS_UNAVAIL;
}

enum nss_status _nss_aad_getgrnam_r(const char *name, struct group *result, char *buf, size_t buflen, int *errnop)
{
*errnop = 0;
if (result)
return grp_search(name, 0, result, errnop, buf, buflen);
else
return NSS_STATUS_UNAVAIL;
}

enum nss_status _nss_aad_setgrent(void)
{
if (all_grp_entries != NULL)
{
g_ptr_array_free(all_grp_entries, TRUE);
all_grp_entries = NULL;
}

all_grp_entries_index = 0;
return NSS_STATUS_SUCCESS;
}

enum nss_status _nss_aad_endgrent(void)
{
if (all_grp_entries != NULL)
{
g_ptr_array_free(all_grp_entries, TRUE);
all_grp_entries = NULL;
}

all_grp_entries_index = 0;
return NSS_STATUS_SUCCESS;
}

enum nss_status _nss_aad_getgrent_r(struct group *result, char *buf, size_t buflen, int *errnop)
{
*errnop = -1;

if (result)
return grp_search(NULL, 0, result, errnop, buf, buflen);

return NSS_STATUS_UNAVAIL;
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
105 changes: 105 additions & 0 deletions nss/passwd.c
@@ -0,0 +1,105 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <nss.h>
#include <pwd.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <ctype.h>

#include <glib.h>
#include <glib/gprintf.h>

#include "common.h"

GPtrArray *all_pwd_entries = NULL;
guint all_pwd_entries_index = 0;

enum nss_status pwd_search(const char *name, const uid_t uid, struct passwd *pw, int *errnop, char *buffer, size_t buflen)
{
UNUSED(buffer);
UNUSED(buflen);

if (all_pwd_entries == NULL)
{
all_pwd_entries = g_ptr_array_new();
}

gchar *entry = calloc(1000, sizeof(gchar));
gint exit_status = fetch_info("passwd", name, uid, all_pwd_entries, &all_pwd_entries_index, &entry, errnop);

// return the exit status if no success
if (exit_status != NSS_STATUS_SUCCESS)
{
g_free(entry);
return exit_status;
}

gchar **tokens = g_strsplit(entry, ":", 7);
g_free(entry);

pw->pw_name = g_strdup(tokens[0]);
pw->pw_passwd = g_strdup(tokens[1]);
pw->pw_uid = strtol(tokens[2], NULL, 10);
pw->pw_gid = strtol(tokens[3], NULL, 10);
pw->pw_gecos = g_strdup(tokens[4]);
pw->pw_dir = g_strdup(tokens[5]);
pw->pw_shell = g_strdup(tokens[6]);
g_strfreev(tokens);

return exit_status;
}

enum nss_status _nss_aad_getpwuid_r(uid_t uid, struct passwd *result, char *buf, size_t buflen, int *errnop)
{
*errnop = 0;
if (result)
return pwd_search(NULL, uid, result, errnop, buf, buflen);
else
return NSS_STATUS_UNAVAIL;
}

enum nss_status _nss_aad_getpwnam_r(const char *name, struct passwd *result, char *buf, size_t buflen, int *errnop)
{
*errnop = 0;
if (result)
return pwd_search(name, 0, result, errnop, buf, buflen);
else
return NSS_STATUS_UNAVAIL;
}

enum nss_status _nss_aad_setpwent(void)
{
if (all_pwd_entries != NULL)
{
g_ptr_array_free(all_pwd_entries, TRUE);
all_pwd_entries = NULL;
}

all_pwd_entries_index = 0;
return NSS_STATUS_SUCCESS;
}

enum nss_status _nss_aad_endpwent(void)
{
if (all_pwd_entries != NULL)
{
g_ptr_array_free(all_pwd_entries, TRUE);
all_pwd_entries = NULL;
}

all_pwd_entries_index = 0;
return NSS_STATUS_SUCCESS;
}

enum nss_status _nss_aad_getpwent_r(struct passwd *result, char *buf, size_t buflen, int *errnop)
{
*errnop = -1;

if (result)
return pwd_search(NULL, 0, result, errnop, buf, buflen);

return NSS_STATUS_UNAVAIL;
}

0 comments on commit 79f51d5

Please sign in to comment.