📄 user.c
字号:
/* Copyright (C) 2002, 2003, 2004, 2005 Thorsten Kukuk Author: Thorsten Kukuk <kukuk@thkukuk.de> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */#ifdef HAVE_CONFIG_H#include <config.h>#endif#define _GNU_SOURCE#include <nss.h>#include <dlfcn.h>#include <errno.h>#include <unistd.h>#include <sys/stat.h>#include <rpcsvc/yp_prot.h>#include <rpcsvc/ypclnt.h>#ifdef USE_LDAP#ifdef HAVE_LDAP_H#include <ldap.h>#endif#include "libldap.h"#endif#include "nsw.h"#include "i18n.h"#include "public.h"#include "yppasswd.h"#include "read-files.h"char *files_etc_dir = "/etc";const char *nsw2str (service_t service){ switch (service) { case S_LOCAL: return "files"; break; case S_YP: return "NIS"; break; case S_NISPLUS: return "NIS+"; break;#ifdef USE_LDAP case S_LDAP: return "LDAP"; break;#endif default: return "unknown"; break; }}char *getnismaster (void){ char *master, *domainname; int port, err; yp_get_default_domain (&domainname); if ((err = yp_master (domainname, "passwd.byname", &master)) != 0) { fprintf (stderr, _("Can't find the NIS master server: %s\n"), yperr_string (err)); return NULL; } port = getrpcport (master, YPPASSWDPROG, YPPASSWDPROC_UPDATE, IPPROTO_UDP); if (port == 0) { fprintf (stderr, _("rpc.yppasswdd not running on NIS master %s.\n"), master); return NULL; } if (port >= IPPORT_RESERVED) { fprintf (stderr, _("rpc.yppasswdd running on illegal port on NIS master %s.\n"), master); return NULL; } return master;}voidfree_user_t (user_t *data){ if (data == NULL) return; if (data->pwdbuffer) free (data->pwdbuffer); if (data->spwbuffer) free (data->spwbuffer); if (data->newpassword) free (data->newpassword); if (data->new_name) free (data->new_name); if (data->new_shell) free (data->new_shell); if (data->new_gecos) free (data->new_gecos); if (data->new_home) free (data->new_home); if (data->oldclearpwd) free (data->oldclearpwd); if (data->binddn) free (data->binddn); free (data);}user_t *do_getpwnam (const char *user, const char *use_service){ enum nss_status (*nss_getpwnam_r)(const char *name, struct passwd *pwd, char *buffer, size_t buflen, int *errnop); enum nss_status (*nss_getspnam_r)(const char *name, struct spwd *sp, char *buffer, size_t buflen, int *errnop); enum nss_status status; void *nss_handle = NULL; user_t *data; struct nsw *nswp; int i; data = calloc (1, sizeof (user_t)); if (data == NULL) return NULL; data->service = S_NONE; /* UNIX passwords area */ if (use_service) { nswp = calloc (1, sizeof (struct nsw)); if (nswp == NULL) return data; nswp->name = strdup ("passwd"); nswp->orderc = 1; nswp->orders = calloc (2, sizeof (char *)); nswp->orders[0] = strdup (use_service); nswp->orders[1] = NULL; } else nswp = _getnswbyname ("passwd"); if (nswp == NULL) return data; for (i = 0; i < nswp->orderc; ++i) { const char *cmpptr = nswp->orders[i]; again: if (nswp->orders[i][0] == '[') continue; if (strcasecmp ("files", cmpptr) == 0 || strcasecmp ("compat", cmpptr) == 0) { nss_getpwnam_r = files_getpwnam_r; /* Get password file entry... */ do { errno = 0; data->pwdbuflen += 1024; data->pwdbuffer = realloc (data->pwdbuffer, data->pwdbuflen); status = (*nss_getpwnam_r)(user, &data->pw, data->pwdbuffer, data->pwdbuflen, &errno); } while (status == NSS_STATUS_TRYAGAIN && errno == ERANGE); if (status != NSS_STATUS_SUCCESS) { free (data->pwdbuffer); data->pwdbuffer = NULL; data->pwdbuflen = 0; if (strcasecmp ("compat", cmpptr) == 0) { struct nsw *nswp2 = _getnswbyname ("passwd_compat"); if (nswp2 == NULL) cmpptr = "nis"; else { char *cp = alloca (strlen (nswp2->orders[0]) + 1); strcpy (cp, nswp2->orders[0]); cmpptr = cp; nsw_free (nswp2); } goto again; } } else { data->service = S_LOCAL; break; } } else if (strcasecmp ("nis", cmpptr) == 0 || strcasecmp ("yp", cmpptr) == 0) { nss_handle = dlopen ("libnss_nis.so.2", RTLD_NOW); if (!nss_handle) continue; nss_getpwnam_r = dlsym (nss_handle, "_nss_nis_getpwnam_r"); if (dlerror () != NULL) { dlclose (nss_handle); continue; } /* Get NIS passwd entry... */ do { errno = 0; data->pwdbuflen += 1024; data->pwdbuffer = realloc (data->pwdbuffer, data->pwdbuflen); status = (*nss_getpwnam_r)(user, &data->pw, data->pwdbuffer, data->pwdbuflen, &errno); } while (status == NSS_STATUS_TRYAGAIN && errno == ERANGE); if (status != NSS_STATUS_SUCCESS) { dlclose (nss_handle); free (data->pwdbuffer); data->pwdbuffer = NULL; data->pwdbuflen = 0; } else { data->service = S_YP; break; } } else if (strcasecmp ("nisplus", cmpptr) == 0 || strcasecmp ("nis+", cmpptr) == 0) { nss_handle = dlopen ("libnss_nisplus.so.2", RTLD_NOW); if (!nss_handle) continue; nss_getpwnam_r = dlsym (nss_handle, "_nss_nisplus_getpwnam_r"); if (dlerror () != NULL) { dlclose (nss_handle); continue; } /* Get password NIS+ entry... */ do { errno = 0; data->pwdbuflen += 1024; data->pwdbuffer = realloc (data->pwdbuffer, data->pwdbuflen); status = (*nss_getpwnam_r)(user, &data->pw, data->pwdbuffer, data->pwdbuflen, &errno); } while (status == NSS_STATUS_TRYAGAIN && errno == ERANGE); if (status != NSS_STATUS_SUCCESS) { dlclose (nss_handle); free (data->pwdbuffer); data->pwdbuffer = NULL; data->pwdbuflen = 0; } else { data->service = S_NISPLUS; break; } }#ifdef USE_LDAP else if (strcasecmp ("ldap", cmpptr) == 0) { nss_handle = dlopen ("libnss_ldap.so.2", RTLD_NOW); if (!nss_handle) continue; nss_getpwnam_r = dlsym (nss_handle, "_nss_ldap_getpwnam_r"); if (dlerror () != NULL) { dlclose (nss_handle); continue; } /* Get LDAP passwd entry... */ do { errno = 0; data->pwdbuflen += 1024; data->pwdbuffer = realloc (data->pwdbuffer, data->pwdbuflen); status = (*nss_getpwnam_r)(user, &data->pw, data->pwdbuffer, data->pwdbuflen, &errno); } while (status == NSS_STATUS_TRYAGAIN && errno == ERANGE); if (status != NSS_STATUS_SUCCESS) { dlclose (nss_handle); free (data->pwdbuffer); data->pwdbuffer = NULL; data->pwdbuflen = 0; } else { data->service = S_LDAP; break; } }#endif } nsw_free (nswp); if (data->service == S_NONE) return data; nss_getspnam_r = NULL; status = NSS_STATUS_NOTFOUND; if (data->service == S_LOCAL) { nss_getspnam_r = files_getspnam_r; } else if (data->service == S_YP) { nss_getspnam_r = dlsym (nss_handle, "_nss_nis_getspnam_r"); if (dlerror () != NULL) { data->service = S_NONE; free (data->pwdbuffer); data->pwdbuffer = NULL; data->pwdbuflen = 0; dlclose (nss_handle); return data; } } else if (data->service == S_NISPLUS) { nss_getspnam_r = dlsym (nss_handle, "_nss_nisplus_getspnam_r"); if (dlerror () != NULL) { data->service = S_NONE; free (data->pwdbuffer); data->pwdbuffer = NULL; data->pwdbuflen = 0; dlclose (nss_handle); return data; } }#ifdef USE_LDAP else if (data->service == S_LDAP) { nss_getspnam_r = dlsym (nss_handle, "_nss_ldap_getspnam_r"); if (dlerror () != NULL) { data->service = S_NONE; free (data->pwdbuffer); data->pwdbuffer = NULL; data->pwdbuflen = 0; dlclose (nss_handle); return data; } }#endif if (nss_getspnam_r) { do { errno = 0; data->spwbuflen += 1024; data->spwbuffer = realloc (data->spwbuffer, data->spwbuflen); status = (*nss_getspnam_r)(user, &data->sp, data->spwbuffer, data->spwbuflen, &errno); } while (status == NSS_STATUS_TRYAGAIN && errno == ERANGE); } if (data->service != S_LOCAL && data->service != S_NONE) dlclose (nss_handle); if (status == NSS_STATUS_SUCCESS) { data->use_shadow = TRUE; data->spn = data->sp; data->sp_changed = FALSE; } else memset (&(data->sp), 0, sizeof (struct spwd)); return data;}intwrite_user_data (user_t *data, int is_locked){ int retval = 0; if (data->service == S_LOCAL) { if (!is_locked && lock_database() != 0) { fputs (_("Cannot lock password file: already locked.\n"), stderr); retval = -1; } else if ((data->newpassword && !data->use_shadow) || data->new_shell || data->new_gecos || data->new_home || data->have_new_uid || data->have_new_gid || data->new_name || data->todo == DO_CREATE || data->todo == DO_DELETE) { /* Only run through /etc/passwd if we really have something to change. */ const char *file_tmp = "/passwd.tmpXXXXXX"; char *passwd_tmp = alloca (strlen (files_etc_dir) + strlen (file_tmp) + 1); char *passwd_orig = alloca (strlen (files_etc_dir) + 8); char *passwd_old = alloca (strlen (files_etc_dir) + 12); struct stat passwd_stat; struct passwd *pw; /* passwd struct obtained from fgetpwent() */ FILE *oldpf, *newpf; int gotit, newpf_fd; char *cp; cp = stpcpy (passwd_tmp, files_etc_dir); strcpy (cp, file_tmp); cp = stpcpy (passwd_orig, files_etc_dir); strcpy (cp, "/passwd"); cp = stpcpy (passwd_old, passwd_orig); strcpy (cp, ".old"); if ((oldpf = fopen (passwd_orig, "r")) == NULL) { fprintf (stderr, _("Can't open `%s': %m\n"), passwd_orig); retval = -1; goto error_passwd; } if (fstat (fileno (oldpf), &passwd_stat) < 0) { fprintf (stderr, _("Can't stat `%s': %m\n"), passwd_orig); fclose (oldpf); retval = -1; goto error_passwd; }#ifdef WITH_SELINUX security_context_t prev_context; if (set_default_context (passwd_orig, &prev_context) < 0) { fclose (oldpf); retval = -1; goto error_passwd; }#endif /* Open a temp passwd file */ newpf_fd = mkstemp (passwd_tmp);#ifdef WITH_SELINUX if (restore_default_context (prev_context) < 0) { if (newpf_fd >= 0) close (newpf_fd); fclose (oldpf); retval = -1; goto error_passwd; }#endif if (newpf_fd == -1) { fprintf (stderr, _("Can't create `%s': %m\n"), passwd_orig); fclose (oldpf); retval = -1; goto error_passwd; } if (fchmod (newpf_fd, passwd_stat.st_mode) < 0) { fprintf (stderr, _("Cannot change permissions for `%s': %s\n"), passwd_tmp, strerror (errno)); fclose (oldpf); close (newpf_fd); unlink (passwd_tmp); retval = -1; goto error_passwd; } if (fchown (newpf_fd, passwd_stat.st_uid, passwd_stat.st_gid) < 0) { fprintf (stderr, _("Cannot change owner/group for `%s': %s\n"), passwd_tmp, strerror (errno)); fclose (oldpf); close (newpf_fd); unlink (passwd_tmp); retval = -1; goto error_passwd; } if (copy_xattr (passwd_orig, passwd_tmp) != 0) { fclose (oldpf); close (newpf_fd); unlink (passwd_tmp); retval = -1; goto error_passwd; } newpf = fdopen (newpf_fd, "w+"); if (newpf == NULL) { fprintf (stderr, _("Can't open `%s': %m\n"), passwd_tmp); fclose (oldpf); close (newpf_fd); unlink (passwd_tmp); retval = -1; goto error_passwd; } gotit = 0; /* Loop over all passwd entries */ while ((pw = fgetpwent (oldpf)) != NULL) { if (data->todo == DO_CREATE) { /* insert the new user before we find a user with a higher UID or before we find a +/- character. */ if (!gotit && (/* data->pw.pw_uid < pw->pw_uid || XXX not yet? */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -