be4c6b26b741bd6d8510ba5382def13ebb495399
[platform/core/system/tlm.git] / src / plugins / default / tlm-account-plugin-default.c
1 /* vi: set et sw=4 ts=4 cino=t0,(0: */
2 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 /*
4  * This file is part of tlm (Tiny Login Manager)
5  *
6  * Copyright (C) 2013 Intel Corporation.
7  *
8  * Contact: Amarnath Valluri <amarnath.valluri@linux.intel.com>
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
23  * 02110-1301 USA
24  */
25
26 #include <pwd.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <unistd.h>
30 #include <errno.h>
31 #include <string.h>
32 #include <glib.h>
33 #include <sys/stat.h>
34 #include <sys/wait.h>
35 #include "tzplatform_config.h"
36
37 #include "tlm-account-plugin-default.h"
38 #include "tlm-log.h"
39
40 /**
41  * SECTION:tlm-account-plugin-default
42  * @short_description: an default plugin for user account operation
43  *
44  * #TlmAccountPluginDefault provides a default implementation of user account
45  * operations:
46  * - setting up guest account is performed by running 'useradd'
47  * - cleaning up guest account is performed by running 'rm -rf' on the account's
48  * home directory
49  * - check the account validity is done using getpwnam().
50  *
51  * It is recommended to use a GUM plugin instead: see #TlmAccountPluginGumd.
52  *
53  */
54
55 /**
56  * TlmAccountPluginDefault:
57  *
58  * Opaque data structure
59  */
60 /**
61  * TlmAccountPluginDefaultClass:
62  * @parent_class: a reference to a parent class
63  *
64  * The class structure for the #TlmAccountPluginDefault objects,
65  */
66
67 enum {
68     PROP_0,
69     PROP_CONFIG
70 };
71
72 struct _TlmAccountPluginDefault
73 {
74     GObject parent;
75     GHashTable *config;
76 };
77
78
79 static gboolean
80 _setup_guest_account (TlmAccountPlugin *plugin, const gchar *user_name)
81 {
82     int res = -1;
83     pid_t pid;
84
85     g_return_val_if_fail (plugin, FALSE);
86     g_return_val_if_fail (TLM_IS_ACCOUNT_PLUGIN_DEFAULT(plugin), FALSE);
87     g_return_val_if_fail (user_name && user_name[0], FALSE);
88
89     pid = fork();
90     if (0 == pid) {    //child process
91         gchar **args = NULL;
92         const gchar *path = tzplatform_getenv(TZ_SYS_SBIN);
93
94         args = g_new0 (gchar *, 3);
95         if (NULL == args)
96             return FALSE;
97
98         args[0] = g_strdup_printf("%s/useradd", path);
99         args[1] = g_strdup(user_name);
100         args[2] = NULL;
101
102         execv(args[0], args);
103         //fail execv
104         g_strfreev(args);
105         exit(EXIT_FAILURE);
106     }
107     else if (-1 != pid) {  // parent process
108         pid_t ret;
109         int status;
110         while ((ret = waitpid(pid, &status, WNOHANG))== 0) {
111             sleep(1);
112         }
113         if ((ret == pid) && (WIFEXITED(status)))
114             res = WEXITSTATUS(status);
115         else
116             res = 0;
117     }
118
119     return ((res != -1) && (res != EXIT_FAILURE));
120 }
121
122 gboolean delete_sub_files(const gchar* dir)
123 {
124     DIR *dirp;
125     struct dirent *result;
126     struct stat file_stat;
127     gchar *file = NULL;
128     gboolean ret = FALSE;
129     int max_path = 0;
130
131     max_path = pathconf("/", _PC_PATH_MAX);
132     if (0 >= max_path)  max_path=1025;
133
134     if ((dirp = opendir(dir)) == NULL)
135         return FALSE;
136
137     file = g_malloc(max_path);
138     if (file == NULL) {
139         closedir(dirp);
140         return FALSE;
141     }
142
143     errno = 0;
144     while ((result = readdir(dirp)) != NULL)
145     {
146         if ((0 == strcmp(".", result->d_name)) || (0 == strcmp("..", result->d_name)))
147             continue;
148
149         snprintf(file, max_path, "%s/%s", dir, result->d_name);
150         lstat(file, &file_stat);
151         if (S_ISDIR(file_stat.st_mode)) {
152             if (!delete_sub_files(file)) {
153                 break;
154             } else {
155                 if(0 != rmdir(file)) {
156                     DBG("Could not delete directory '%s', error : %s", file, strerror(errno));
157                     break;
158                 }
159             }
160         } else {
161             if (0 != unlink(file)) {
162                 DBG("Could not delete file '%s', error : %s", file, strerror(errno));
163                 break;
164             }
165         }
166     }
167     if (errno == 0)
168         ret = TRUE;
169
170     g_free(file);
171     closedir(dirp);
172     return ret;
173 }
174
175 static gboolean
176 _cleanup_guest_user (TlmAccountPlugin *plugin,
177                      const gchar *user_name,
178                      gboolean delete)
179 {
180     struct passwd *pwd_entry = NULL;
181     struct passwd buf_pwd;
182     gboolean res;
183     gchar *buf = NULL, *tmp = NULL;
184     gsize size;
185     glong pw_size_max = sysconf(_SC_GETPW_R_SIZE_MAX);
186     if (pw_size_max <= sizeof(struct passwd))
187         size = 1024;
188     else
189         size = pw_size_max;
190
191     (void) delete;
192
193     g_return_val_if_fail (plugin, FALSE);
194     g_return_val_if_fail (TLM_IS_ACCOUNT_PLUGIN_DEFAULT(plugin), FALSE);
195     g_return_val_if_fail (user_name && user_name[0], FALSE);
196
197     /* clear error */
198     errno = 0;
199
200     for (; NULL != (tmp = realloc(buf, size)); size*=2)
201     {
202         buf = tmp;
203
204         if (ERANGE == getpwnam_r(user_name, &buf_pwd, buf, size, &pwd_entry))
205             continue;
206         break;
207     }
208
209     if (!pwd_entry) {
210         DBG("Could not get info for user '%s', error : %s", 
211             user_name, strerror(errno));
212
213         if (buf)
214             free(buf);
215
216         return FALSE;
217     }
218
219     if (!pwd_entry->pw_dir) {
220         DBG("No home folder entry found for user '%s'", user_name);
221
222         if (buf)
223             free(buf);
224
225         return FALSE;
226     }
227
228     res = delete_sub_files(pwd_entry->pw_dir);
229
230     if (buf)
231         free(buf);
232
233     return res;
234 }
235
236 static gboolean
237 _is_valid_user (TlmAccountPlugin *plugin, const gchar *user_name)
238 {
239     struct passwd *pwd_entry = NULL;
240     struct passwd pwd_buf;
241     gchar *buf = NULL, *tmp = NULL;
242     gsize size;
243     glong pw_size_max = sysconf(_SC_GETPW_R_SIZE_MAX);
244     if (pw_size_max <= sizeof(struct passwd))
245         size = 1024;
246     else
247         size = pw_size_max;
248
249     g_return_val_if_fail (plugin, FALSE);
250     g_return_val_if_fail (TLM_IS_ACCOUNT_PLUGIN_DEFAULT(plugin), FALSE);
251     g_return_val_if_fail (user_name && user_name[0], FALSE);
252
253     /* clear error */
254     errno = 0;
255
256     for (; NULL != (tmp = realloc(buf, size)); size*=2)
257     {
258         buf = tmp;
259
260         if (ERANGE == getpwnam_r(user_name, &pwd_buf, buf, size, &pwd_entry))
261             continue;
262         break;
263     }
264
265     if (!pwd_entry) {
266         gchar strerr_buf[MAX_STRERROR_LEN] = {0,};
267         strerror_r(errno, strerr_buf, MAX_STRERROR_LEN);
268         DBG("Could not get info for user '%s', error : %s",
269             user_name, strerr_buf);
270         if (buf)
271             free(buf);
272         return FALSE;
273     }
274
275     if (buf)
276         free(buf);
277
278     return TRUE;
279 }
280
281 static void
282 _plugin_interface_init (TlmAccountPluginInterface *iface)
283 {
284     iface->setup_guest_user_account = _setup_guest_account;
285     iface->cleanup_guest_user = _cleanup_guest_user;
286     iface->is_valid_user = _is_valid_user;
287 }
288
289 G_DEFINE_TYPE_WITH_CODE (TlmAccountPluginDefault, tlm_account_plugin_default,
290                          G_TYPE_OBJECT,
291                          G_IMPLEMENT_INTERFACE (TLM_TYPE_ACCOUNT_PLUGIN,
292                                                 _plugin_interface_init));
293
294
295 static void
296 _plugin_finalize (GObject *self)
297 {
298     TlmAccountPluginDefault *plugin = TLM_ACCOUNT_PLUGIN_DEFAULT(self);
299
300     if (plugin->config) g_hash_table_unref (plugin->config);
301
302     G_OBJECT_CLASS (tlm_account_plugin_default_parent_class)->finalize(self);
303 }
304
305 static void
306 _plugin_set_property (GObject      *object,
307                       guint         prop_id,
308                       const GValue *value,
309                       GParamSpec   *pspec)
310 {
311     TlmAccountPluginDefault *self = TLM_ACCOUNT_PLUGIN_DEFAULT (object);
312
313     switch (prop_id) {
314         case PROP_CONFIG: {
315             gpointer p = g_value_get_boxed (value);
316             if (p)
317                 self->config = g_hash_table_ref ((GHashTable *)p);
318             break;
319         }
320         default:
321             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
322             break;
323     }
324 }
325
326 static void
327 _plugin_get_property (GObject *object,
328                       guint    prop_id,
329                       GValue  *value,
330                       GParamSpec *pspec)
331 {
332     TlmAccountPluginDefault *self = TLM_ACCOUNT_PLUGIN_DEFAULT (object);
333
334     switch (prop_id) {
335         case PROP_CONFIG:
336             g_value_set_boxed (value, self->config);
337             break;
338         default:
339             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
340             break;
341     }
342 }
343
344 static void
345 tlm_account_plugin_default_class_init (TlmAccountPluginDefaultClass *kls)
346 {
347     GObjectClass *g_class = G_OBJECT_CLASS (kls);
348
349     g_class->set_property = _plugin_set_property;
350     g_class->get_property = _plugin_get_property;
351     g_class->finalize = _plugin_finalize;
352
353     g_object_class_override_property (g_class, PROP_CONFIG, "config");
354 }
355
356 static void
357 tlm_account_plugin_default_init (TlmAccountPluginDefault *self)
358 {
359     tlm_log_init(G_LOG_DOMAIN);
360 }
361