Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'support/pwd.c')
-rw-r--r--support/pwd.c264
1 files changed, 264 insertions, 0 deletions
diff --git a/support/pwd.c b/support/pwd.c
new file mode 100644
index 00000000000..05357f4f617
--- /dev/null
+++ b/support/pwd.c
@@ -0,0 +1,264 @@
+/*
+ * <pwd.h> wrapper functions.
+ *
+ * Authors:
+ * Jonathan Pryor (jonpryor@vt.edu)
+ *
+ * Copyright (C) 2004 Jonathan Pryor
+ */
+
+#include <pwd.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "mph.h"
+
+G_BEGIN_DECLS
+
+struct Mono_Posix_Syscall__Passwd {
+ /* string */ char *pw_name;
+ /* string */ char *pw_passwd;
+ /* uid_t */ mph_uid_t pw_uid;
+ /* gid_t */ mph_gid_t pw_gid;
+ /* string */ char *pw_gecos;
+ /* string */ char *pw_dir;
+ /* string */ char *pw_shell;
+ /* string */ char *_pw_buf_;
+};
+
+/*
+ * Copy the native `passwd' structure to it's managed representation.
+ *
+ * To minimize separate mallocs, all the strings are allocated within the same
+ * memory block (stored in _pw_buf_).
+ */
+static int
+copy_passwd (struct Mono_Posix_Syscall__Passwd *to, struct passwd *from)
+{
+ enum {PW_NAME = 0, PW_PASSWD, PW_GECOS, PW_DIR, PW_SHELL, PW_LAST};
+ size_t buflen, len[PW_LAST];
+ /* bool */ unsigned char copy[PW_LAST] = {0};
+ const char *source[PW_LAST];
+ char **dest[PW_LAST];
+ int i;
+ char *cur;
+
+ to->pw_uid = from->pw_uid;
+ to->pw_gid = from->pw_gid;
+
+ to->pw_name = NULL;
+ to->pw_passwd = NULL;
+ to->pw_gecos = NULL;
+ to->pw_dir = NULL;
+ to->pw_shell = NULL;
+ to->_pw_buf_ = NULL;
+
+ source[PW_NAME] = from->pw_name;
+ source[PW_PASSWD] = from->pw_passwd;
+ source[PW_GECOS] = from->pw_gecos;
+ source[PW_DIR] = from->pw_dir;
+ source[PW_SHELL] = from->pw_shell;
+
+ dest[PW_NAME] = &to->pw_name;
+ dest[PW_PASSWD] = &to->pw_passwd;
+ dest[PW_GECOS] = &to->pw_gecos;
+ dest[PW_DIR] = &to->pw_dir;
+ dest[PW_SHELL] = &to->pw_shell;
+
+ buflen = PW_LAST;
+
+ /* over-rigorous checking for integer overflow */
+ for (i = 0; i != PW_LAST; ++i) {
+ len[i] = strlen (source[i]);
+ if (len[i] < INT_MAX - buflen) {
+ buflen += len[i];
+ copy[i] = 1;
+ }
+ }
+
+ cur = to->_pw_buf_ = (char*) malloc (buflen);
+ if (cur == NULL) {
+ return -1;
+ }
+
+ for (i = 0; i != PW_LAST; ++i) {
+ if (copy[i]) {
+ *dest[i] = strcpy (cur, source[i]);
+ cur += (len[i] + 1);
+ }
+ }
+
+ return 0;
+}
+
+gint32
+Mono_Posix_Syscall_getpwnam (const char *name, struct Mono_Posix_Syscall__Passwd *pwbuf)
+{
+ struct passwd *pw;
+
+ if (pwbuf == NULL) {
+ errno = EFAULT;
+ return -1;
+ }
+
+ pw = getpwnam (name);
+ if (pw == NULL)
+ return -1;
+
+ if (copy_passwd (pwbuf, pw) == -1) {
+ errno = ENOMEM;
+ return -1;
+ }
+ return 0;
+}
+
+gint32
+Mono_Posix_Syscall_getpwuid (mph_uid_t uid, struct Mono_Posix_Syscall__Passwd *pwbuf)
+{
+ struct passwd *pw;
+
+ if (pwbuf == NULL) {
+ errno = EFAULT;
+ return -1;
+ }
+
+ errno = 0;
+ pw = getpwuid (uid);
+ if (pw == NULL) {
+ return -1;
+ }
+
+ if (copy_passwd (pwbuf, pw) == -1) {
+ errno = ENOMEM;
+ return -1;
+ }
+ return 0;
+}
+
+#ifdef HAVE_GETPWNAM_R
+gint32
+Mono_Posix_Syscall_getpwnam_r (const char *name,
+ struct Mono_Posix_Syscall__Passwd *pwbuf,
+ struct passwd **pwbufp)
+{
+ char *buf, *buf2;
+ size_t buflen;
+ int r;
+ struct passwd _pwbuf;
+
+ if (pwbuf == NULL) {
+ errno = EFAULT;
+ return -1;
+ }
+
+ buf = buf2 = NULL;
+ buflen = 2;
+
+ do {
+ buf2 = realloc (buf, buflen *= 2);
+ if (buf2 == NULL) {
+ free (buf);
+ errno = ENOMEM;
+ return -1;
+ }
+ buf = buf2;
+ } while ((r = getpwnam_r (name, &_pwbuf, buf, buflen, pwbufp)) &&
+ recheck_range (r));
+
+ if (r == 0 && copy_passwd (pwbuf, &_pwbuf) == -1)
+ r = errno = ENOMEM;
+ free (buf);
+
+ return r;
+}
+#endif /* ndef HAVE_GETPWNAM_R */
+
+#ifdef HAVE_GETPWUID_R
+gint32
+Mono_Posix_Syscall_getpwuid_r (mph_uid_t uid,
+ struct Mono_Posix_Syscall__Passwd *pwbuf,
+ struct passwd **pwbufp)
+{
+ char *buf, *buf2;
+ size_t buflen;
+ int r;
+ struct passwd _pwbuf;
+
+ if (pwbuf == NULL) {
+ errno = EFAULT;
+ return -1;
+ }
+
+ buf = buf2 = NULL;
+ buflen = 2;
+
+ do {
+ buf2 = realloc (buf, buflen *= 2);
+ if (buf2 == NULL) {
+ free (buf);
+ errno = ENOMEM;
+ return -1;
+ }
+ buf = buf2;
+ } while ((r = getpwuid_r (uid, &_pwbuf, buf, buflen, pwbufp)) &&
+ recheck_range (r));
+
+ if (r == 0 && copy_passwd (pwbuf, &_pwbuf) == -1)
+ r = errno = ENOMEM;
+ free (buf);
+
+ return r;
+}
+#endif /* ndef HAVE_GETPWUID_R */
+
+gint32
+Mono_Posix_Syscall_getpwent (struct Mono_Posix_Syscall__Passwd *pwbuf)
+{
+ struct passwd *pw;
+
+ if (pwbuf == NULL) {
+ errno = EFAULT;
+ return -1;
+ }
+
+ pw = getpwent ();
+ if (pw == NULL)
+ return -1;
+
+ if (copy_passwd (pwbuf, pw) == -1) {
+ errno = ENOMEM;
+ return -1;
+ }
+ return 0;
+}
+
+#ifdef HAVE_FGETPWENT
+gint32
+Mono_Posix_Syscall_fgetpwent (FILE *stream, struct Mono_Posix_Syscall__Passwd *pwbuf)
+{
+ struct passwd *pw;
+
+ if (pwbuf == NULL) {
+ errno = EFAULT;
+ return -1;
+ }
+
+ pw = fgetpwent (stream);
+ if (pw == NULL)
+ return -1;
+
+ if (copy_passwd (pwbuf, pw) == -1) {
+ errno = ENOMEM;
+ return -1;
+ }
+ return 0;
+}
+#endif /* ndef HAVE_FGETPWENT */
+
+G_END_DECLS
+
+/*
+ * vim: noexpandtab
+ */