summaryrefslogtreecommitdiffstats
path: root/sss_client/passwd.c
diff options
context:
space:
mode:
Diffstat (limited to 'sss_client/passwd.c')
-rw-r--r--sss_client/passwd.c346
1 files changed, 346 insertions, 0 deletions
diff --git a/sss_client/passwd.c b/sss_client/passwd.c
new file mode 100644
index 000000000..d02e067f1
--- /dev/null
+++ b/sss_client/passwd.c
@@ -0,0 +1,346 @@
+/*
+ * System Security Services Daemon. NSS client interface
+ *
+ * Copyright (C) Simo Sorce 2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* PASSWD database NSS interface */
+
+#include <nss.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include "sss_cli.h"
+
+static struct sss_nss_getpwent_data {
+ size_t len;
+ size_t ptr;
+ uint8_t *data;
+} sss_nss_getpwent_data;
+
+static void sss_nss_getpwent_data_clean(void) {
+
+ if (sss_nss_getpwent_data.data != NULL) {
+ free(sss_nss_getpwent_data.data);
+ sss_nss_getpwent_data.data = NULL;
+ }
+ sss_nss_getpwent_data.len = 0;
+ sss_nss_getpwent_data.ptr = 0;
+}
+
+/* GETPWNAM Request:
+ *
+ * 0-X: string with name
+ *
+ * GERTPWUID Request:
+ *
+ * 0-7: 64bit number with uid
+ *
+ * Replies:
+ *
+ * 0-3: 32bit unsigned number of results
+ * 4-7: 32bit unsigned (reserved/padding)
+ * For each result:
+ * 0-7: 64bit number uid
+ * 8-15: 64bit number gid
+ * 16-X: sequence of 5, 0 terminated, strings (name, passwd, gecos, dir, shell)
+ */
+
+struct sss_nss_pw_rep {
+ struct passwd *result;
+ char *buffer;
+ size_t buflen;
+};
+
+static int sss_nss_getpw_readrep(struct sss_nss_pw_rep *pr,
+ uint8_t *buf, size_t *len)
+{
+ size_t i, slen;
+ char *sbuf;
+ int err;
+
+ if (*len < 21) { /* not enough space for data, bad packet */
+ return EBADMSG;
+ }
+
+ pr->result->pw_uid = ((int64_t *)buf)[0];
+ pr->result->pw_gid = ((int64_t *)buf)[1];
+
+ sbuf = (char *)&buf[16];
+ if (*len < pr->buflen) {
+ slen = *len;
+ err = EBADMSG;
+ } else {
+ slen = pr->buflen;
+ err = ENOMEM;
+ }
+
+ pr->result->pw_name = &(pr->buffer[0]);
+ i = 0;
+ while (i < slen) {
+ pr->buffer[i] = sbuf[i];
+ if (pr->buffer[i] == '\0') break;
+ i++;
+ }
+ if (i == slen) { /* premature end of buf */
+ return err;
+ }
+
+ i++;
+ pr->result->pw_passwd = &(pr->buffer[i]);
+ while (i < slen) {
+ pr->buffer[i] = sbuf[i];
+ if (pr->buffer[i] == '\0') break;
+ i++;
+ }
+ if (i == slen) { /* premature end of buf */
+ return err;
+ }
+
+ i++;
+ pr->result->pw_gecos = &(pr->buffer[i]);
+ while (i < slen) {
+ pr->buffer[i] = sbuf[i];
+ if (pr->buffer[i] == '\0') break;
+ i++;
+ }
+ if (i == slen) { /* premature end of buf */
+ return err;
+ }
+
+ i++;
+ pr->result->pw_dir = &(pr->buffer[i]);
+ while (i < slen) {
+ pr->buffer[i] = sbuf[i];
+ if (pr->buffer[i] == '\0') break;
+ i++;
+ }
+ if (i == slen) { /* premature end of buf */
+ return err;
+ }
+
+ i++;
+ pr->result->pw_shell = &(pr->buffer[i]);
+ while (i < slen) {
+ pr->buffer[i] = sbuf[i];
+ if (pr->buffer[i] == '\0') break;
+ i++;
+ }
+ if (pr->buffer[i] != '\0') { /* premature end of buf */
+ return err;
+ }
+
+ *len = *len -16 -i -1;
+
+ return 0;
+}
+
+enum nss_status _nss_sss_getpwnam_r(const char *name, struct passwd *result,
+ char *buffer, size_t buflen, int *errnop)
+{
+ struct sss_cli_req_data rd;
+ struct sss_nss_pw_rep pwrep;
+ uint8_t *repbuf;
+ size_t replen, len;
+ enum nss_status nret;
+ int ret;
+
+ rd.len = strlen(name) + 1;
+ rd.data = name;
+
+ nret = sss_nss_make_request(SSS_NSS_GETPWNAM, &rd,
+ &repbuf, &replen, errnop);
+ if (nret != NSS_STATUS_SUCCESS) {
+ return nret;
+ }
+
+ pwrep.result = result;
+ pwrep.buffer = buffer;
+ pwrep.buflen = buflen;
+
+ /* no results if not found */
+ if (((uint32_t *)repbuf)[0] == 0) {
+ free(repbuf);
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ /* only 1 result is accepted for this function */
+ if (((uint32_t *)repbuf)[0] != 1) {
+ *errnop = EBADMSG;
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ len = replen - 8;
+ ret = sss_nss_getpw_readrep(&pwrep, repbuf+8, &len);
+ free(repbuf);
+ if (ret) {
+ *errnop = ret;
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status _nss_sss_getpwuid_r(uid_t uid, struct passwd *result,
+ char *buffer, size_t buflen, int *errnop)
+{
+ struct sss_cli_req_data rd;
+ struct sss_nss_pw_rep pwrep;
+ uint8_t *repbuf;
+ size_t replen, len;
+ enum nss_status nret;
+ int64_t user_uid;
+ int ret;
+
+ user_uid = uid;
+ rd.len = sizeof(int64_t);
+ rd.data = &user_uid;
+
+ nret = sss_nss_make_request(SSS_NSS_GETPWUID, &rd,
+ &repbuf, &replen, errnop);
+ if (nret != NSS_STATUS_SUCCESS) {
+ return nret;
+ }
+
+ pwrep.result = result;
+ pwrep.buffer = buffer;
+ pwrep.buflen = buflen;
+
+ /* no results if not found */
+ if (((uint32_t *)repbuf)[0] == 0) {
+ free(repbuf);
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ /* only 1 result is accepted for this function */
+ if (((uint32_t *)repbuf)[0] != 1) {
+ *errnop = EBADMSG;
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ len = replen - 8;
+ ret = sss_nss_getpw_readrep(&pwrep, repbuf+8, &len);
+ free(repbuf);
+ if (ret) {
+ *errnop = ret;
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status _nss_sss_setpwent(void)
+{
+ enum nss_status nret;
+ int errnop;
+
+ /* make sure we do not have leftovers, and release memory */
+ sss_nss_getpwent_data_clean();
+
+ nret = sss_nss_make_request(SSS_NSS_SETPWENT,
+ NULL, NULL, NULL, &errnop);
+ if (nret != NSS_STATUS_SUCCESS) {
+ errno = errnop;
+ return nret;
+ }
+
+ return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status _nss_sss_getpwent_r(struct passwd *result,
+ char *buffer, size_t buflen,
+ int *errnop)
+{
+ struct sss_cli_req_data rd;
+ struct sss_nss_pw_rep pwrep;
+ uint8_t *repbuf;
+ size_t replen;
+ enum nss_status nret;
+ uint32_t num_entries;
+ int ret;
+
+ /* if there are leftovers return the next one */
+ if (sss_nss_getpwent_data.data != NULL &&
+ sss_nss_getpwent_data.ptr < sss_nss_getpwent_data.len) {
+
+ repbuf = sss_nss_getpwent_data.data + sss_nss_getpwent_data.ptr;
+ replen = sss_nss_getpwent_data.len - sss_nss_getpwent_data.ptr;
+
+ pwrep.result = result;
+ pwrep.buffer = buffer;
+ pwrep.buflen = buflen;
+
+ ret = sss_nss_getpw_readrep(&pwrep, repbuf, &replen);
+ if (ret) {
+ *errnop = ret;
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ /* advance buffer pointer */
+ sss_nss_getpwent_data.ptr = sss_nss_getpwent_data.len - replen;
+
+ return NSS_STATUS_SUCCESS;
+ }
+
+ /* release memory if any */
+ sss_nss_getpwent_data_clean();
+
+ /* retrieve no more than SSS_NSS_MAX_ENTRIES at a time */
+ num_entries = SSS_NSS_MAX_ENTRIES;
+ rd.len = sizeof(uint32_t);
+ rd.data = &num_entries;
+
+ nret = sss_nss_make_request(SSS_NSS_GETPWENT, &rd,
+ &repbuf, &replen, errnop);
+ if (nret != NSS_STATUS_SUCCESS) {
+ return nret;
+ }
+
+ /* no results if not found */
+ if ((((uint32_t *)repbuf)[0] == 0) || (replen - 8 == 0)) {
+ free(repbuf);
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ sss_nss_getpwent_data.data = repbuf;
+ sss_nss_getpwent_data.len = replen;
+ sss_nss_getpwent_data.ptr = 8; /* skip metadata fields */
+
+ /* call again ourselves, this will return the first result */
+ return _nss_sss_getpwent_r(result, buffer, buflen, errnop);
+}
+
+enum nss_status _nss_sss_endpwent(void)
+{
+ enum nss_status nret;
+ int errnop;
+
+ /* make sure we do not have leftovers, and release memory */
+ sss_nss_getpwent_data_clean();
+
+ nret = sss_nss_make_request(SSS_NSS_ENDPWENT,
+ NULL, NULL, NULL, &errnop);
+ if (nret != NSS_STATUS_SUCCESS) {
+ errno = errnop;
+ return nret;
+ }
+
+ return NSS_STATUS_SUCCESS;
+}