diff options
Diffstat (limited to 'winsup/cygwin/passwd.cc')
-rw-r--r-- | winsup/cygwin/passwd.cc | 809 |
1 files changed, 0 insertions, 809 deletions
diff --git a/winsup/cygwin/passwd.cc b/winsup/cygwin/passwd.cc deleted file mode 100644 index b8ed09466..000000000 --- a/winsup/cygwin/passwd.cc +++ /dev/null @@ -1,809 +0,0 @@ -/* passwd.cc: getpwnam () and friends - - Copyright 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, - 2009, 2010, 2011, 2012, 2013, 2014 Red Hat, Inc. - -This file is part of Cygwin. - -This software is a copyrighted work licensed under the terms of the -Cygwin license. Please consult the file "CYGWIN_LICENSE" for -details. */ - -#include "winsup.h" -#include <lm.h> -#include <stdlib.h> -#include <stdio.h> -#include "cygerrno.h" -#include "security.h" -#include "path.h" -#include "fhandler.h" -#include "dtable.h" -#include "pinfo.h" -#include "cygheap.h" -#include "shared_info.h" -#include "miscfuncs.h" -#include "ldap.h" -#include "tls_pbuf.h" - -/* Parse /etc/passwd line into passwd structure. */ -bool -pwdgrp::parse_passwd () -{ - pg_pwd &res = passwd ()[curr_lines]; - res.p.pw_name = next_str (':'); - res.p.pw_passwd = next_str (':'); - if (!next_num (res.p.pw_uid)) - return false; - if (!next_num (res.p.pw_gid)) - return false; - res.p.pw_comment = NULL; - res.p.pw_gecos = next_str (':'); - res.p.pw_dir = next_str (':'); - res.p.pw_shell = next_str (':'); - res.sid.getfrompw (&res.p); - /* lptr points to the \0 after pw_shell. Increment by one to get the correct - required buffer len in getpw_cp. */ - res.len = lptr - res.p.pw_name + 1; - return true; -} - -void -pwdgrp::init_pwd () -{ - pwdgrp_buf_elem_size = sizeof (pg_pwd); - parse = &pwdgrp::parse_passwd; -} - -struct passwd * -pwdgrp::find_user (cygpsid &sid) -{ - for (ULONG i = 0; i < curr_lines; i++) - if (sid == passwd ()[i].sid) - return &passwd ()[i].p; - return NULL; -} - -struct passwd * -pwdgrp::find_user (const char *name) -{ - for (ULONG i = 0; i < curr_lines; i++) - /* on Windows NT user names are case-insensitive */ - if (strcasematch (name, passwd ()[i].p.pw_name)) - return &passwd ()[i].p; - return NULL; -} - -struct passwd * -pwdgrp::find_user (uid_t uid) -{ - for (ULONG i = 0; i < curr_lines; i++) - if (uid == passwd ()[i].p.pw_uid) - return &passwd ()[i].p; - return NULL; -} - -struct passwd * -internal_getpwsid (cygpsid &sid, cyg_ldap *pldap) -{ - struct passwd *ret; - - cygheap->pg.nss_init (); - /* Check caches first. */ - if (cygheap->pg.nss_cygserver_caching () - && (ret = cygheap->pg.pwd_cache.cygserver.find_user (sid))) - return ret; - if (cygheap->pg.nss_pwd_files () - && (ret = cygheap->pg.pwd_cache.file.find_user (sid))) - return ret; - if (cygheap->pg.nss_pwd_db () - && (ret = cygheap->pg.pwd_cache.win.find_user (sid))) - return ret; - /* Ask sources afterwards. */ - if (cygheap->pg.nss_cygserver_caching () - && (ret = cygheap->pg.pwd_cache.cygserver.add_user_from_cygserver (sid))) - return ret; - if (cygheap->pg.nss_pwd_files ()) - { - cygheap->pg.pwd_cache.file.check_file (); - if ((ret = cygheap->pg.pwd_cache.file.add_user_from_file (sid))) - return ret; - } - if (cygheap->pg.nss_pwd_db ()) - return cygheap->pg.pwd_cache.win.add_user_from_windows (sid, pldap); - return NULL; -} - -/* This function gets only called from mkpasswd via cygwin_internal. */ -struct passwd * -internal_getpwsid_from_db (cygpsid &sid) -{ - cygheap->pg.nss_init (); - return cygheap->pg.pwd_cache.win.add_user_from_windows (sid); -} - -struct passwd * -internal_getpwnam (const char *name, cyg_ldap *pldap) -{ - struct passwd *ret; - - cygheap->pg.nss_init (); - /* Check caches first. */ - if (cygheap->pg.nss_cygserver_caching () - && (ret = cygheap->pg.pwd_cache.cygserver.find_user (name))) - return ret; - if (cygheap->pg.nss_pwd_files () - && (ret = cygheap->pg.pwd_cache.file.find_user (name))) - return ret; - if (cygheap->pg.nss_pwd_db () - && (ret = cygheap->pg.pwd_cache.win.find_user (name))) - return ret; - /* Ask sources afterwards. */ - if (cygheap->pg.nss_cygserver_caching () - && (ret = cygheap->pg.pwd_cache.cygserver.add_user_from_cygserver (name))) - return ret; - if (cygheap->pg.nss_pwd_files ()) - { - cygheap->pg.pwd_cache.file.check_file (); - if ((ret = cygheap->pg.pwd_cache.file.add_user_from_file (name))) - return ret; - } - if (cygheap->pg.nss_pwd_db ()) - return cygheap->pg.pwd_cache.win.add_user_from_windows (name, pldap); - return NULL; -} - -struct passwd * -internal_getpwuid (uid_t uid, cyg_ldap *pldap) -{ - struct passwd *ret; - - cygheap->pg.nss_init (); - /* Check caches first. */ - if (cygheap->pg.nss_cygserver_caching () - && (ret = cygheap->pg.pwd_cache.cygserver.find_user (uid))) - return ret; - if (cygheap->pg.nss_pwd_files () - && (ret = cygheap->pg.pwd_cache.file.find_user (uid))) - return ret; - if (cygheap->pg.nss_pwd_db () - && (ret = cygheap->pg.pwd_cache.win.find_user (uid))) - return ret; - /* Ask sources afterwards. */ - if (cygheap->pg.nss_cygserver_caching () - && (ret = cygheap->pg.pwd_cache.cygserver.add_user_from_cygserver (uid))) - return ret; - if (cygheap->pg.nss_pwd_files ()) - { - cygheap->pg.pwd_cache.file.check_file (); - if ((ret = cygheap->pg.pwd_cache.file.add_user_from_file (uid))) - return ret; - } - if (cygheap->pg.nss_pwd_db () || uid == ILLEGAL_UID) - return cygheap->pg.pwd_cache.win.add_user_from_windows (uid, pldap); - return NULL; -} - -/* getpwuid/getpwnam are not reentrant. */ -static struct { - struct passwd p; - char *buf; - size_t bufsiz; -} app_pw; - -static struct passwd * -getpw_cp (struct passwd *temppw) -{ - if (!temppw) - return NULL; - pg_pwd *pw = (pg_pwd *) temppw; - if (app_pw.bufsiz < pw->len) - { - char *newbuf = (char *) realloc (app_pw.buf, pw->len); - if (!newbuf) - { - set_errno (ENOMEM); - return NULL; - } - app_pw.buf = newbuf; - app_pw.bufsiz = pw->len; - } - memcpy (app_pw.buf, pw->p.pw_name, pw->len); - memcpy (&app_pw.p, &pw->p, sizeof pw->p); - ptrdiff_t diff = app_pw.buf - pw->p.pw_name; - app_pw.p.pw_name += diff; - app_pw.p.pw_passwd += diff; - app_pw.p.pw_gecos += diff; - app_pw.p.pw_dir += diff; - app_pw.p.pw_shell += diff; - return &app_pw.p; -} - -extern "C" struct passwd * -getpwuid32 (uid_t uid) -{ - struct passwd *temppw = internal_getpwuid (uid); - pthread_testcancel (); - return getpw_cp (temppw); -} - -#ifdef __x86_64__ -EXPORT_ALIAS (getpwuid32, getpwuid) -#else -extern "C" struct passwd * -getpwuid (__uid16_t uid) -{ - return getpwuid32 (uid16touid32 (uid)); -} -#endif - -extern "C" int -getpwuid_r32 (uid_t uid, struct passwd *pwd, char *buffer, size_t bufsize, struct passwd **result) -{ - *result = NULL; - - if (!pwd || !buffer) - return ERANGE; - - struct passwd *temppw = internal_getpwuid (uid); - pthread_testcancel (); - if (!temppw) - return 0; - - /* check needed buffer size. */ - size_t needsize = strlen (temppw->pw_name) + strlen (temppw->pw_passwd) - + strlen (temppw->pw_gecos) + strlen (temppw->pw_dir) - + strlen (temppw->pw_shell) + 5; - if (needsize > bufsize) - return ERANGE; - - /* make a copy of temppw */ - *result = pwd; - pwd->pw_uid = temppw->pw_uid; - pwd->pw_gid = temppw->pw_gid; - buffer = stpcpy (pwd->pw_name = buffer, temppw->pw_name); - buffer = stpcpy (pwd->pw_passwd = buffer + 1, temppw->pw_passwd); - buffer = stpcpy (pwd->pw_gecos = buffer + 1, temppw->pw_gecos); - buffer = stpcpy (pwd->pw_dir = buffer + 1, temppw->pw_dir); - stpcpy (pwd->pw_shell = buffer + 1, temppw->pw_shell); - pwd->pw_comment = NULL; - return 0; -} - -#ifdef __x86_64__ -EXPORT_ALIAS (getpwuid_r32, getpwuid_r) -#else -extern "C" int -getpwuid_r (__uid16_t uid, struct passwd *pwd, char *buffer, size_t bufsize, struct passwd **result) -{ - return getpwuid_r32 (uid16touid32 (uid), pwd, buffer, bufsize, result); -} -#endif - -extern "C" struct passwd * -getpwnam (const char *name) -{ - struct passwd *temppw = internal_getpwnam (name); - pthread_testcancel (); - return getpw_cp (temppw); -} - - -/* the max size buffer we can expect to - * use is returned via sysconf with _SC_GETPW_R_SIZE_MAX. - * This may need updating! - Rob Collins April 2001. - */ -extern "C" int -getpwnam_r (const char *nam, struct passwd *pwd, char *buffer, size_t bufsize, struct passwd **result) -{ - *result = NULL; - - if (!pwd || !buffer || !nam) - return ERANGE; - - struct passwd *temppw = internal_getpwnam (nam); - pthread_testcancel (); - - if (!temppw) - return 0; - - /* check needed buffer size. */ - size_t needsize = strlen (temppw->pw_name) + strlen (temppw->pw_passwd) - + strlen (temppw->pw_gecos) + strlen (temppw->pw_dir) - + strlen (temppw->pw_shell) + 5; - if (needsize > bufsize) - return ERANGE; - - /* make a copy of temppw */ - *result = pwd; - pwd->pw_uid = temppw->pw_uid; - pwd->pw_gid = temppw->pw_gid; - buffer = stpcpy (pwd->pw_name = buffer, temppw->pw_name); - buffer = stpcpy (pwd->pw_passwd = buffer + 1, temppw->pw_passwd); - buffer = stpcpy (pwd->pw_gecos = buffer + 1, temppw->pw_gecos); - buffer = stpcpy (pwd->pw_dir = buffer + 1, temppw->pw_dir); - stpcpy (pwd->pw_shell = buffer + 1, temppw->pw_shell); - pwd->pw_comment = NULL; - return 0; -} - -/* getpwent functions are not reentrant. */ -static pw_ent pwent; - -void -pg_ent::clear_cache () -{ - if (pg.curr_lines) - { - if (state > from_file) - cfree (group ? grp.g.gr_name : pwd.p.pw_name); - pg.curr_lines = 0; - } -} - -void -pg_ent::setent (bool _group, int _enums, PCWSTR _enum_tdoms) -{ - cygheap->dom.init (); - endent (_group); - if (!_enums && !_enum_tdoms) - { - /* This is the default, when called from the usual setpwent/setgrent - functions. */ - enums = cygheap->pg.nss_db_enums (); - enum_tdoms = cygheap->pg.nss_db_enum_tdoms (); - if (_group) - { - from_files = cygheap->pg.nss_grp_files (); - from_db = cygheap->pg.nss_grp_db (); - } - else - { - from_files = cygheap->pg.nss_pwd_files (); - from_db = cygheap->pg.nss_pwd_db (); - } - } - else - { - /* This case is when called from mkpasswd/mkgroup via cygwin_internal. */ - enums = _enums; - enum_tdoms = _enum_tdoms; - from_files = false; - from_db = true; - } - state = from_cache; -} - -void * -pg_ent::getent (void) -{ - void *entry; - - switch (state) - { - case rewound: - state = from_cache; - /*FALLTHRU*/ - case from_cache: - if (nss_db_enum_caches () - && (entry = enumerate_caches ())) - return entry; - state = from_file; - /*FALLTHRU*/ - case from_file: - if (from_files - && nss_db_enum_files () - && (entry = enumerate_file ())) - return entry; - state = from_builtin; - /*FALLTHRU*/ - case from_builtin: - if (from_db - && nss_db_enum_builtin () - && (entry = enumerate_builtin ())) - return entry; - state = from_local; - /*FALLTHRU*/ - case from_local: - if (from_db - && nss_db_enum_local () - && (!cygheap->dom.member_machine () - || !nss_db_enum_primary ()) - && (entry = enumerate_local ())) - return entry; - state = from_sam; - /*FALLTHRU*/ - case from_sam: - if (from_db - && nss_db_enum_local () - /* Domain controller? If so, sam and ad are one and the same - and "local ad" would list all domain accounts twice without - this test. */ - && (cygheap->dom.account_flat_name ()[0] != L'@' - || !nss_db_enum_primary ()) - && (entry = enumerate_sam ())) - return entry; - state = from_ad; - /*FALLTHRU*/ - case from_ad: - if (cygheap->dom.member_machine () - && from_db - && (entry = enumerate_ad ())) - return entry; - state = finished; - /*FALLTHRU*/ - case finished: - break; - } - return NULL; -} - -void -pg_ent::endent (bool _group) -{ - if (buf) - { - if (state == from_file) - free (buf); - else if (state == from_local || state == from_sam) - NetApiBufferFree (buf); - buf = NULL; - } - if (!pg.curr_lines) - { - if ((group = _group)) - { - pg.init_grp (); - pg.pwdgrp_buf = (void *) &grp; - } - else - { - pg.init_pwd (); - pg.pwdgrp_buf = (void *) &pwd; - } - pg.max_lines = 1; - } - else - clear_cache (); - cldap.close (); - rl.close (); - cnt = max = resume = 0; - enums = 0; - enum_tdoms = NULL; - state = rewound; -} - -void * -pg_ent::enumerate_file () -{ - void *entry; - - if (!cnt) - { - pwdgrp &prf = group ? cygheap->pg.grp_cache.file - : cygheap->pg.pwd_cache.file; - if (prf.check_file ()) - { - if (!buf) - buf = (char *) malloc (NT_MAX_PATH); - if (buf - && !rl.init (prf.file_attr (), buf, NT_MAX_PATH)) - { - free (buf); - buf = NULL; - } - } - } - ++cnt; - if ((entry = pg.add_account_post_fetch (rl.gets (), false))) - return entry; - rl.close (); - free (buf); - buf = NULL; - cnt = max = resume = 0; - return NULL; -} - -void * -pg_ent::enumerate_builtin () -{ - static cygpsid *pwd_builtins[] = { - &well_known_system_sid, - &well_known_local_service_sid, - &well_known_network_service_sid, - &well_known_admins_sid, - &trusted_installer_sid, - NULL - }; - static cygpsid *grp_builtins[] = { - &well_known_system_sid, - &trusted_installer_sid, - NULL - }; - - cygpsid **builtins = group ? grp_builtins : pwd_builtins; - if (!builtins[cnt]) - { - cnt = max = resume = 0; - return NULL; - } - cygsid sid (*builtins[cnt++]); - fetch_user_arg_t arg; - arg.type = SID_arg; - arg.sid = &sid; - char *line = pg.fetch_account_from_windows (arg); - return pg.add_account_post_fetch (line, false); -} - -void * -pg_ent::enumerate_sam () -{ - while (true) - { - if (!cnt) - { - DWORD total; - NET_API_STATUS ret; - - if (buf) - { - NetApiBufferFree (buf); - buf = NULL; - } - if (resume == ULONG_MAX) - ret = ERROR_NO_MORE_ITEMS; - else if (group) - ret = NetGroupEnum (NULL, 2, (PBYTE *) &buf, MAX_PREFERRED_LENGTH, - &max, &total, &resume); - else - ret = NetUserEnum (NULL, 20, FILTER_NORMAL_ACCOUNT, (PBYTE *) &buf, - MAX_PREFERRED_LENGTH, &max, &total, - (PDWORD) &resume); - if (ret == NERR_Success) - resume = ULONG_MAX; - else if (ret != ERROR_MORE_DATA) - { - cnt = max = resume = 0; - return NULL; - } - } - while (cnt < max) - { - cygsid sid (cygheap->dom.account_sid ()); - sid_sub_auth (sid, sid_sub_auth_count (sid)) = - group ? ((PGROUP_INFO_2) buf)[cnt].grpi2_group_id - : ((PUSER_INFO_20) buf)[cnt].usri20_user_id; - ++cnt; - ++sid_sub_auth_count (sid); - fetch_user_arg_t arg; - arg.type = SID_arg; - arg.sid = &sid; - char *line = pg.fetch_account_from_windows (arg); - if (line) - return pg.add_account_post_fetch (line, false); - } - cnt = 0; - } -} - -void * -pg_ent::enumerate_ad () -{ - while (true) - { - if (!cnt) - { - PDS_DOMAIN_TRUSTSW td; - - if (!resume) - { - ++resume; - if (!nss_db_enum_primary () - || cldap.enumerate_ad_accounts (NULL, group) != NO_ERROR) - continue; - } - else if ((td = cygheap->dom.trusted_domain (resume - 1))) - { - ++resume; - /* Ignore primary domain in list of trusted domains only if all - trusted domains are enumerated anyway. This handles an - annoying backward compatibility problem in mkpasswd/mkgroup. - Without this test, `mkpasswd -d PRIMARY_DOMAIN' wouldn't - work as expected. */ - if (((enums & ENUM_TDOMS_ALL) && td->Flags & DS_DOMAIN_PRIMARY) - || !td->DomainSid - || (!nss_db_enum_tdom (td->NetbiosDomainName) - && !nss_db_enum_tdom (td->DnsDomainName)) - || cldap.enumerate_ad_accounts (td->DnsDomainName, group) - != NO_ERROR) - continue; - } - else - { - cldap.close (); - return NULL; - } - } - ++cnt; - cygsid sid; - int ret = cldap.next_account (sid); - if (ret == NO_ERROR) - { - fetch_user_arg_t arg; - arg.type = SID_arg; - arg.sid = &sid; - char *line = pg.fetch_account_from_windows (arg, &cldap); - if (line) - return pg.add_account_post_fetch (line, false); - ret = EIO; - } - if (ret != ENMFILE) - { - cldap.close (); - set_errno (ret); - return NULL; - } - cnt = 0; - } -} - -void * -pw_ent::enumerate_caches () -{ - switch (max) - { - case 0: - if (cygheap->pg.nss_cygserver_caching ()) - { - pwdgrp &prc = cygheap->pg.pwd_cache.cygserver; - if (cnt < prc.cached_users ()) - return &prc.passwd ()[cnt++].p; - } - cnt = 0; - max = 1; - /*FALLTHRU*/ - case 1: - if (from_files) - { - pwdgrp &prf = cygheap->pg.pwd_cache.file; - prf.check_file (); - if (cnt < prf.cached_users ()) - return &prf.passwd ()[cnt++].p; - } - cnt = 0; - max = 2; - /*FALLTHRU*/ - default: - if (from_db) - { - pwdgrp &prw = cygheap->pg.pwd_cache.win; - if (cnt < prw.cached_users ()) - return &prw.passwd ()[cnt++].p; - } - break; - } - cnt = max = 0; - return NULL; -} - -void * -pw_ent::enumerate_local () -{ - return NULL; -} - -struct passwd * -pw_ent::getpwent (void) -{ - if (state == rewound) - setent (false); - else - clear_cache (); - return (struct passwd *) getent (); -} - -extern "C" void -setpwent () -{ - pwent.setpwent (); -} - -extern "C" struct passwd * -getpwent (void) -{ - return pwent.getpwent (); -} - -extern "C" void -endpwent (void) -{ - pwent.endpwent (); -} - -/* *_filtered functions are called from mkpasswd */ -void * -setpwent_filtered (int enums, PCWSTR enum_tdoms) -{ - pw_ent *pw = new pw_ent; - if (pw) - pw->setpwent (enums, enum_tdoms); - return (void *) pw; -} - -void * -getpwent_filtered (void *pw) -{ - return (void *) ((pw_ent *) pw)->getpwent (); -} - -void -endpwent_filtered (void *pw) -{ - ((pw_ent *) pw)->endpwent (); -} - -#ifndef __x86_64__ -extern "C" struct passwd * -getpwduid (__uid16_t) -{ - return NULL; -} -#endif - -extern "C" int -setpassent (int) -{ - return 0; -} - -static void -_getpass_close_fd (void *arg) -{ - if (arg) - fclose ((FILE *) arg); -} - -extern "C" char * -getpass (const char * prompt) -{ - char *pass = _my_tls.locals.pass; - struct termios ti, newti; - bool tc_set = false; - - /* Try to use controlling tty in the first place. Use stdin and stderr - only as fallback. */ - FILE *in = stdin, *err = stderr; - FILE *tty = fopen ("/dev/tty", "w+b"); - pthread_cleanup_push (_getpass_close_fd, tty); - if (tty) - { - /* Set close-on-exec for obvious reasons. */ - fcntl (fileno (tty), F_SETFD, fcntl (fileno (tty), F_GETFD) | FD_CLOEXEC); - in = err = tty; - } - - /* Make sure to notice if stdin is closed. */ - if (fileno (in) >= 0) - { - flockfile (in); - /* Change tty attributes if possible. */ - if (!tcgetattr (fileno (in), &ti)) - { - newti = ti; - newti.c_lflag &= ~(ECHO | ISIG); /* No echo, no signal handling. */ - if (!tcsetattr (fileno (in), TCSANOW, &newti)) - tc_set = true; - } - fputs (prompt, err); - fflush (err); - fgets (pass, _PASSWORD_LEN, in); - fprintf (err, "\n"); - if (tc_set) - tcsetattr (fileno (in), TCSANOW, &ti); - funlockfile (in); - char *crlf = strpbrk (pass, "\r\n"); - if (crlf) - *crlf = '\0'; - } - pthread_cleanup_pop (1); - return pass; -} |