$OpenBSD: patch-src_daemon_c,v 1.27 2014/02/04 08:53:34 ajacoutot Exp $

OpenBSD does not have any function to parse a specified passwd(5) file.

Revert the following commit:
This reverts commit dfa1a6239b01c823ce0fec781c6c9541c988f56e.
The commit is wrong, since we're only interested in local users.
http://bugs.freedesktop.org/show_bug.cgi?id=41747
(XXX we need a way to only get local users)

From 980692e6b9cfe4a34e22f566e0981a8c549e4348 Mon Sep 17 00:00:00 2001
From: Matthias Clasen <mclasen@redhat.com>
Date: Fri, 01 Nov 2013 21:09:25 +0000
Subject: Avoid deleting the root user

--- src/daemon.c.orig	Tue Oct 15 22:25:19 2013
+++ src/daemon.c	Tue Feb  4 09:49:15 2014
@@ -36,6 +36,10 @@
 #include <utmpx.h>
 #endif
 
+#ifdef __OpenBSD__
+#include <grp.h> /* getgrnam */
+#endif
+
 #include <glib.h>
 #include <glib/gi18n.h>
 #include <glib-object.h>
@@ -48,7 +52,11 @@
 #include "util.h"
 
 #define PATH_PASSWD "/etc/passwd"
+#if defined (HAVE_SHADOW_H)
 #define PATH_SHADOW "/etc/shadow"
+#elif defined (__OpenBSD__)
+#define PATH_SHADOW "/etc/master.passwd"
+#endif
 #define PATH_GROUP "/etc/group"
 #define PATH_GDM_CUSTOM "/etc/gdm/custom.conf"
 #ifdef HAVE_UTMPX_H
@@ -307,6 +315,7 @@ entry_generator_fgetpwent (GHashTable *users,
                            gpointer   *state)
 {
         struct passwd *pwent;
+#ifdef HAVE_FGETPWENT
         FILE *fp;
 
         /* First iteration */
@@ -328,6 +337,11 @@ entry_generator_fgetpwent (GHashTable *users,
         /* Last iteration */
         fclose (fp);
         *state = NULL;
+#else
+        while ((pwent = getpwent ()) != NULL)
+                return pwent;
+        endpwent();
+#endif
         return NULL;
 }
 
@@ -1051,7 +1065,11 @@ daemon_create_user_authorized_cb (Daemon              
         CreateUserData *cd = data;
         User *user;
         GError *error;
+#ifndef __OpenBSD__
         const gchar *argv[9];
+#else
+        const gchar *argv[11];
+#endif
 
         if (getpwnam (cd->user_name) != NULL) {
                 throw_error (context, ERROR_USER_EXISTS, "A user with name '%s' already exists", cd->user_name);
@@ -1068,9 +1086,17 @@ daemon_create_user_authorized_cb (Daemon              
         if (cd->account_type == ACCOUNT_TYPE_ADMINISTRATOR) {
                 argv[4] = "-G";
                 argv[5] = ADMIN_GROUP;
+#ifdef __OpenBSD__
+                argv[6] = "-L";
+                argv[7] = "staff";
+                argv[8] = "--";
+                argv[9] = cd->user_name;
+                argv[10] = NULL;
+#else
                 argv[6] = "--";
                 argv[7] = cd->user_name;
                 argv[8] = NULL;
+#endif
         }
         else if (cd->account_type == ACCOUNT_TYPE_STANDARD) {
                 argv[4] = "--";
@@ -1232,7 +1258,7 @@ daemon_uncache_user (AccountsAccounts      *accounts,
 }
 
 typedef struct {
-        gint64 uid;
+        uid_t uid;
         gboolean remove_files;
 } DeleteUserData;
 
@@ -1257,6 +1283,34 @@ daemon_delete_user_authorized_cb (Daemon              
                 return;
         }
 
+/*
+ * Under OpenBSD there is no /etc/login.defs (for USERGROUPS_ENAB), so
+ * we need to explicitely remove the user's group if it contains no more
+ * members and matches the username.
+ */
+#ifdef __OpenBSD__
+        struct group *grp;
+        GError *grperror;
+        const gchar *grpargv[3];
+
+        grp = getgrnam (pwent->pw_name);
+
+        if ((grp != NULL) && (*grp->gr_name == *pwent->pw_name) && (*grp->gr_mem == NULL)) {
+                sys_log (context, "delete group '%d'", pwent->pw_gid);
+
+                grpargv[0] = "/usr/sbin/groupdel";
+                grpargv[1] = pwent->pw_name;
+                grpargv[2] = NULL;
+
+                grperror = NULL;
+                if (!spawn_with_login_uid (context, grpargv, &grperror)) {
+                    throw_error (context, ERROR_FAILED, "running '%s' failed: %s", grpargv[0], grperror->message);
+                    g_error_free (grperror);
+                    return;
+                }
+        }
+#endif
+
         sys_log (context, "delete user '%s' (%d)", pwent->pw_name, ud->uid);
 
         if (daemon->priv->autologin != NULL) {
@@ -1282,11 +1336,18 @@ daemon_delete_user_authorized_cb (Daemon              
 
         argv[0] = "/usr/sbin/userdel";
         if (ud->remove_files) {
+#ifdef __OpenBSD__
+                argv[1] = "-r";
+                argv[2] = "--";
+                argv[3] = pwent->pw_name;
+                argv[4] = NULL;
+#else
                 argv[1] = "-f";
                 argv[2] = "-r";
                 argv[3] = "--";
                 argv[4] = pwent->pw_name;
                 argv[5] = NULL;
+#endif
         }
         else {
                 argv[1] = "--";
@@ -1314,13 +1375,13 @@ daemon_delete_user (AccountsAccounts      *accounts,
         Daemon *daemon = (Daemon*)accounts;
         DeleteUserData *data;
 
-        if (uid == 0) {
+        if ((uid_t)uid == 0) {
                 throw_error (context, ERROR_FAILED, "Refuse to delete root user");
                 return TRUE;
         }
 
         data = g_new0 (DeleteUserData, 1);
-        data->uid = uid;
+        data->uid = (uid_t)uid;
         data->remove_files = remove_files;
 
         daemon_local_check_auth (daemon,
