summaryrefslogtreecommitdiff
path: root/nslcd/db_shadow.c
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@sbcglobal.net>2014-10-04 16:13:03 -0400
committerLuke Shumaker <lukeshu@sbcglobal.net>2014-10-04 16:13:03 -0400
commitc9618dfe442305531ee6cab9660333f4a697e094 (patch)
tree63da3cf1c107fdebd82987519b858f0d98c12d23 /nslcd/db_shadow.c
parentbe4588009b7106859e1beae6038aaea8d7f85825 (diff)
foo
Diffstat (limited to 'nslcd/db_shadow.c')
-rw-r--r--nslcd/db_shadow.c243
1 files changed, 243 insertions, 0 deletions
diff --git a/nslcd/db_shadow.c b/nslcd/db_shadow.c
new file mode 100644
index 0000000..7e24ea4
--- /dev/null
+++ b/nslcd/db_shadow.c
@@ -0,0 +1,243 @@
+/*
+ shadow.c - shadow entry lookup routines
+ Parts of this file were part of the nss_ldap library (as ldap-spwd.c)
+ which has been forked into the nss-pam-ldapd library.
+
+ Copyright (C) 1997-2005 Luke Howard
+ Copyright (C) 2006 West Consulting
+ Copyright (C) 2006-2014 Arthur de Jong
+
+ This library 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 library 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 library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA
+*/
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "common.h"
+#include "log.h"
+#include "myldap.h"
+#include "cfg.h"
+#include "attmap.h"
+
+static long to_date(const char *dn, const char *date, const char *attr)
+{
+ char buffer[32];
+ long value;
+ char *tmp;
+ size_t l;
+ /* do some special handling for date values on AD */
+ if (strcasecmp(attr, "pwdLastSet") == 0)
+ {
+ /* we expect an AD 64-bit datetime value;
+ we should do date=date/864000000000-134774
+ but that causes problems on 32-bit platforms,
+ first we devide by 1000000000 by stripping the
+ last 9 digits from the string and going from there */
+ l = strlen(date) - 9;
+ if (l > (sizeof(buffer) - 1))
+ return -1; /* error */
+ strncpy(buffer, date, l);
+ buffer[l] = '\0';
+ errno = 0;
+ value = strtol(buffer, &tmp, 10);
+ if ((*date == '\0') || (*tmp != '\0'))
+ {
+ log_log(LOG_WARNING, "%s: %s: non-numeric", dn, attr);
+ return -1;
+ }
+ else if (errno != 0)
+ {
+ log_log(LOG_WARNING, "%s: %s: out of range", dn, attr);
+ return -1;
+ }
+ return value / 864 - 134774;
+ /* note that AD does not have expiry dates but a lastchangeddate
+ and some value that needs to be added */
+ }
+ errno = 0;
+ value = strtol(date, &tmp, 10);
+ if ((*date == '\0') || (*tmp != '\0'))
+ {
+ log_log(LOG_WARNING, "%s: %s: non-numeric", dn, attr);
+ return -1;
+ }
+ else if (errno != 0)
+ {
+ log_log(LOG_WARNING, "%s: %s: out of range", dn, attr);
+ return -1;
+ }
+ return value;
+}
+
+#ifndef UF_DONT_EXPIRE_PASSWD
+#define UF_DONT_EXPIRE_PASSWD 0x10000
+#endif
+
+#define GET_OPTIONAL_LONG(var, att, fallback) \
+ tmpvalue = attmap_get_value(entry, attmap_shadow_##att, \
+ buffer, sizeof(buffer)); \
+ if (tmpvalue == NULL) \
+ tmpvalue = ""; \
+ errno = 0; \
+ var = strtol(tmpvalue, &tmp, 10); \
+ if ((*(tmpvalue) == '\0') || (*tmp != '\0')) \
+ { \
+ log_log(LOG_WARNING, "%s: %s: non-numeric", \
+ myldap_get_dn(entry), attmap_shadow_##att); \
+ var = fallback; \
+ } \
+ else if (errno != 0) \
+ { \
+ log_log(LOG_WARNING, "%s: %s: out of range", \
+ myldap_get_dn(entry), attmap_shadow_##att); \
+ var = fallback; \
+ }
+
+void get_shadow_properties(MYLDAP_ENTRY *entry, long *lastchangedate,
+ long *mindays, long *maxdays, long *warndays,
+ long *inactdays, long *expiredate,
+ unsigned long *flag)
+{
+ char buffer[64];
+ const char *tmpvalue;
+ char *tmp;
+ /* get lastchange date */
+ tmpvalue = attmap_get_value(entry, attmap_shadow_shadowLastChange,
+ buffer, sizeof(buffer));
+ if (tmpvalue == NULL)
+ tmpvalue = "";
+ *lastchangedate = to_date(myldap_get_dn(entry), tmpvalue, attmap_shadow_shadowLastChange);
+ /* get other shadow properties */
+ GET_OPTIONAL_LONG(*mindays, shadowMin, -1);
+ GET_OPTIONAL_LONG(*maxdays, shadowMax, -1);
+ GET_OPTIONAL_LONG(*warndays, shadowWarning, -1);
+ GET_OPTIONAL_LONG(*inactdays, shadowInactive, -1);
+ GET_OPTIONAL_LONG(*expiredate, shadowExpire, -1);
+ GET_OPTIONAL_LONG(*flag, shadowFlag, 0);
+ /* if we're using AD handle the flag specially */
+ if (strcasecmp(attmap_shadow_shadowLastChange, "pwdLastSet") == 0)
+ {
+ if (*flag & UF_DONT_EXPIRE_PASSWD)
+ *maxdays = -1;
+ *flag = 0;
+ }
+}
+
+static int write_shadow(TFILE *fp, MYLDAP_ENTRY *entry, const char *requser,
+ uid_t calleruid)
+{
+ int32_t tmpint32;
+ const char **usernames;
+ const char *passwd;
+ long lastchangedate;
+ long mindays;
+ long maxdays;
+ long warndays;
+ long inactdays;
+ long expiredate;
+ unsigned long flag;
+ int i;
+ char passbuffer[BUFLEN_PASSWORDHASH];
+ /* get username */
+ usernames = myldap_get_values(entry, attmap_shadow_uid);
+ if ((usernames == NULL) || (usernames[0] == NULL))
+ {
+ log_log(LOG_WARNING, "%s: %s: missing",
+ myldap_get_dn(entry), attmap_shadow_uid);
+ return 0;
+ }
+ /* get password */
+ passwd = get_userpassword(entry, attmap_shadow_userPassword,
+ passbuffer, sizeof(passbuffer));
+ if ((passwd == NULL) || (calleruid != 0))
+ passwd = default_shadow_userPassword;
+ /* get expiry properties */
+ get_shadow_properties(entry, &lastchangedate, &mindays, &maxdays, &warndays,
+ &inactdays, &expiredate, &flag);
+ /* write the entries */
+ for (i = 0; usernames[i] != NULL; i++)
+ if ((requser == NULL) || (STR_CMP(requser, usernames[i]) == 0))
+ {
+ WRITE_INT32(fp, NSLCD_RESULT_BEGIN);
+ WRITE_STRING(fp, usernames[i]);
+ WRITE_STRING(fp, passwd);
+ WRITE_INT32(fp, lastchangedate);
+ WRITE_INT32(fp, mindays);
+ WRITE_INT32(fp, maxdays);
+ WRITE_INT32(fp, warndays);
+ WRITE_INT32(fp, inactdays);
+ WRITE_INT32(fp, expiredate);
+ WRITE_INT32(fp, flag);
+ }
+ return 0;
+}
+
+MYLDAP_ENTRY *shadow_uid2entry(MYLDAP_SESSION *session, const char *username,
+ int *rcp)
+{
+ MYLDAP_SEARCH *search = NULL;
+ MYLDAP_ENTRY *entry = NULL;
+ const char *base;
+ char filter[BUFLEN_FILTER];
+ int i;
+ /* if it isn't a valid username, just bail out now */
+ if (!isvalidname(username))
+ {
+ if (rcp != NULL)
+ *rcp = LDAP_INVALID_SYNTAX;
+ return NULL;
+ }
+ /* we have to look up the entry */
+ mkfilter_shadow_byname(username, filter, sizeof(filter));
+ for (i = 0; (i < NSS_LDAP_CONFIG_MAX_BASES) && ((base = shadow_bases[i]) != NULL); i++)
+ {
+ search = myldap_search(session, base, shadow_scope, filter, shadow_attrs, rcp);
+ if (search == NULL)
+ {
+ if ((rcp != NULL) && (*rcp == LDAP_SUCCESS))
+ *rcp = LDAP_NO_SUCH_OBJECT;
+ return NULL;
+ }
+ entry = myldap_get_entry(search, rcp);
+ if (entry != NULL)
+ return entry;
+ }
+ if ((rcp != NULL) && (*rcp == LDAP_SUCCESS))
+ *rcp = LDAP_NO_SUCH_OBJECT;
+ return NULL;
+}
+
+NSLCD_HANDLE_UID(
+ shadow, byname, NSLCD_ACTION_SHADOW_BYNAME,
+ char name[BUFLEN_NAME];
+ char filter[BUFLEN_FILTER];
+ READ_STRING(fp, name);
+ log_setrequest("shadow=\"%s\"", name);,
+ mkfilter_shadow_byname(name, filter, sizeof(filter)),
+ write_shadow(fp, entry, name, calleruid)
+)
+
+NSLCD_HANDLE_UID(
+ shadow, all, NSLCD_ACTION_SHADOW_ALL,
+ const char *filter;
+ log_setrequest("shadow(all)");,
+ (filter = shadow_filter, 0),
+ write_shadow(fp, entry, NULL, calleruid)
+)