67149aee893e600c2bc8c02f34259bae07497494
[platform/core/system/tlm.git] / src / common / tlm-utils.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 (Tizen Login Manager)
5  *
6  * Copyright (C) 2013 Intel Corporation.
7  *
8  * Contact: Amarnath Valluri <amarnath.valluri@linux.intel.com>
9  *          Jussi Laako <jussi.laako@linux.intel.com>
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2.1 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
24  * 02110-1301 USA
25  */
26
27 #include <sys/types.h>
28 #include <pwd.h>
29 #include <sys/stat.h>
30 #include <glib/gstdio.h>
31 #include <utmp.h>
32 #include <paths.h>
33 #include <ctype.h>
34 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <netdb.h>
37 #include <string.h>
38 #include <unistd.h>
39
40 #include "tlm-utils.h"
41 #include "tlm-log.h"
42
43 #define HOST_NAME_SIZE 256
44
45 void
46 g_clear_string (gchar **str)
47 {
48     if (str && *str) {
49         g_free (*str);
50         *str = NULL;
51     }
52 }
53
54 const gchar *
55 tlm_user_get_name (uid_t user_id)
56 {
57     struct passwd *pwent;
58
59     pwent = getpwuid (user_id);
60     if (!pwent)
61         return NULL;
62
63     return pwent->pw_name;
64 }
65
66 uid_t
67 tlm_user_get_uid (const gchar *username)
68 {
69     struct passwd *pwent;
70
71     pwent = getpwnam (username);
72     if (!pwent)
73         return -1;
74
75     return pwent->pw_uid;
76 }
77
78 gid_t
79 tlm_user_get_gid (const gchar *username)
80 {
81     struct passwd *pwent;
82
83     pwent = getpwnam (username);
84     if (!pwent)
85         return -1;
86
87     return pwent->pw_gid;
88 }
89
90 const gchar *
91 tlm_user_get_home_dir (const gchar *username)
92 {
93     struct passwd *pwent;
94
95     pwent = getpwnam (username);
96     if (!pwent)
97         return NULL;
98
99     return pwent->pw_dir;
100 }
101
102 const gchar *
103 tlm_user_get_shell (const gchar *username)
104 {
105     struct passwd *pwent;
106
107     pwent = getpwnam (username);
108     if (!pwent)
109         return NULL;
110
111     return pwent->pw_shell;
112 }
113
114 gboolean
115 tlm_utils_delete_dir (
116         const gchar *dir)
117 {
118     GDir* gdir = NULL;
119     struct stat sent;
120
121     if (!dir || !(gdir = g_dir_open(dir, 0, NULL))) {
122         return FALSE;
123     }
124
125     const gchar *fname = NULL;
126     gint retval = 0;
127     gchar *filepath = NULL;
128     while ((fname = g_dir_read_name (gdir)) != NULL) {
129         if (g_strcmp0 (fname, ".") == 0 ||
130             g_strcmp0 (fname, "..") == 0) {
131             continue;
132         }
133         retval = -1;
134         filepath = g_build_filename (dir, fname, NULL);
135         if (filepath) {
136             retval = lstat(filepath, &sent);
137             if (retval == 0) {
138                 /* recurse the directory */
139                 if (S_ISDIR (sent.st_mode)) {
140                     retval = (gint)!tlm_utils_delete_dir (filepath);
141                 } else {
142                     retval = g_remove (filepath);
143                 }
144             }
145             g_free (filepath);
146         }
147         if (retval != 0) {
148             g_dir_close (gdir);
149             return FALSE;
150         }
151     }
152     g_dir_close (gdir);
153
154     if (g_remove (dir) != 0) {
155         return FALSE;
156     }
157
158     return TRUE;
159 }
160
161 static gchar *
162 _get_tty_id (
163         const gchar *tty_name)
164 {
165     gchar *id = NULL;
166     const gchar *tmp = tty_name;
167
168     while (tmp) {
169         if (isdigit (*tmp)) {
170             id = g_strdup (tmp);
171             break;
172         }
173         tmp++;
174     }
175     return id;
176 }
177
178 static gchar *
179 _get_host_address (
180         const gchar *hostname)
181 {
182     gchar *hostaddress = NULL;
183     struct addrinfo hints, *info = NULL;
184
185     if (!hostname) return NULL;
186
187     memset (&hints, 0, sizeof (hints));
188     hints.ai_flags = AI_ADDRCONFIG;
189
190     if (getaddrinfo (hostname, NULL, &hints, &info) == 0) {
191         if (info) {
192             if (info->ai_family == AF_INET) {
193                 struct sockaddr_in *sa = (struct sockaddr_in *) info->ai_addr;
194                 hostaddress = g_malloc0 (sizeof(struct in_addr));
195                 memcpy (hostaddress, &(sa->sin_addr), sizeof (struct in_addr));
196             } else if (info->ai_family == AF_INET6) {
197                 struct sockaddr_in6 *sa = (struct sockaddr_in6 *) info->ai_addr;
198                 hostaddress = g_malloc0 (sizeof(struct in6_addr));
199                 memcpy (hostaddress, &(sa->sin6_addr),
200                         sizeof (struct in6_addr));
201             }
202             freeaddrinfo (info);
203         }
204     }
205     return hostaddress;
206 }
207
208 static gboolean
209 _is_tty_same (
210         const gchar *tty1_name,
211         const gchar *tty2_name)
212 {
213     gchar *tty1 = NULL, *tty2 = NULL;
214     gboolean res = FALSE;
215
216     if (tty1_name == tty2_name) return TRUE;
217     if (!tty1_name || !tty2_name) return FALSE;
218
219     if (*tty1_name == '/') tty1 = g_strdup (tty1_name);
220     else tty1 = g_strdup_printf ("/dev/%s", tty1_name);
221     if (*tty2_name == '/') tty2 = g_strdup (tty2_name);
222     else tty2 = g_strdup_printf ("/dev/%s", tty2_name);
223
224     res = (g_strcmp0 (tty1_name, tty2_name) == 0);
225
226     g_free (tty1);
227     g_free (tty2);
228     return res;
229 }
230
231 static gchar *
232 _get_host_name ()
233 {
234     gchar *name = g_malloc0 (HOST_NAME_SIZE);
235     if (gethostname (name, HOST_NAME_SIZE) != 0) {
236         g_free (name);
237         return NULL;
238     }
239     return name;
240 }
241
242 void
243 tlm_utils_log_utmp_entry (const gchar *username)
244 {
245     struct timeval tv;
246     pid_t pid;
247     struct utmp ut_ent;
248     struct utmp *ut_tmp = NULL;
249     gchar *hostname = NULL, *hostaddress = NULL;
250     const gchar *tty_name = NULL;
251     gchar *tty_no_dev_name = NULL, *tty_id = NULL;
252
253     DBG ("Log session entry to utmp/wtmp");
254
255     hostname = _get_host_name ();
256     hostaddress = _get_host_address (hostname);
257     tty_name = ttyname (0);
258     if (tty_name) {
259         tty_no_dev_name = g_strdup (strncmp(tty_name, "/dev/", 5) == 0 ?
260             tty_name + 5 : tty_name);
261     }
262     tty_id = _get_tty_id (tty_no_dev_name);
263     pid = getpid ();
264     utmpname (_PATH_UTMP);
265
266     setutent ();
267     while ((ut_tmp = getutent())) {
268         if ( (ut_tmp->ut_pid == pid) &&
269              (ut_tmp->ut_id[0] != '\0') &&
270              (ut_tmp->ut_type == LOGIN_PROCESS ||
271                      ut_tmp->ut_type == USER_PROCESS) &&
272              (_is_tty_same (ut_tmp->ut_line, tty_name))) {
273             break;
274         }
275     }
276
277     if (ut_tmp) memcpy (&ut_ent, ut_tmp, sizeof (ut_ent));
278     else        memset (&ut_ent, 0, sizeof (ut_ent));
279
280     ut_ent.ut_type = USER_PROCESS;
281     ut_ent.ut_pid = pid;
282     if (tty_id)
283         strncpy (ut_ent.ut_id, tty_id, sizeof (ut_ent.ut_id));
284     if (username)
285         strncpy (ut_ent.ut_user, username, sizeof (ut_ent.ut_user));
286     if (tty_no_dev_name)
287         strncpy (ut_ent.ut_line, tty_no_dev_name, sizeof (ut_ent.ut_line));
288     if (hostname)
289         strncpy (ut_ent.ut_host, hostname, sizeof (ut_ent.ut_host));
290     if (hostaddress)
291         memcpy (&ut_ent.ut_addr_v6, hostaddress, sizeof (ut_ent.ut_addr_v6));
292
293     ut_ent.ut_session = getsid (0);
294     gettimeofday (&tv, NULL);
295 #ifdef _HAVE_UT_TV
296     ut_ent.ut_tv.tv_sec = tv.tv_sec;
297     ut_ent.ut_tv.tv_usec = tv.tv_usec;
298 #else
299     ut_ent.ut_time = tv.tv_sec;
300 #endif
301
302     pututline (&ut_ent);
303     endutent ();
304
305     updwtmp (_PATH_WTMP, &ut_ent);
306
307     g_free (hostaddress);
308     g_free (hostname);
309     g_free (tty_no_dev_name);
310     g_free (tty_id);
311 }
312
313 static gchar **
314 _split_command_line_with_regex(const char *command, GRegex *regex) {
315   gchar **temp_strv = NULL;
316   gchar **temp_iter = NULL, **args_iter = NULL;
317   gchar **argv = NULL;
318
319   temp_strv = regex ? g_regex_split (regex, command, G_REGEX_MATCH_NOTEMPTY)
320                     : g_strsplit (command, " ", -1);
321   if (!temp_strv) {
322     WARN("Failed to split command: %s", command);
323     return NULL;
324   }
325
326   argv = g_new0 (gchar *, g_strv_length (temp_strv));
327   for (temp_iter = temp_strv, args_iter = argv;
328       *temp_iter != NULL;
329       temp_iter++) {
330     size_t item_len = 0;
331     gchar *item = g_strstrip (*temp_iter);
332
333     item_len = strlen (item);
334     if (item_len == 0) {
335       continue;
336     }
337     if ((item[0] == '\"' && item[item_len - 1] == '\"') ||
338         (item[0] == '\'' && item[item_len - 1] == '\'')) {
339       item[item_len - 1] = '\0';
340       memmove (item, item + 1, item_len - 1);
341     }
342     *args_iter = g_strcompress (item);
343     args_iter++;
344   }
345   g_strfreev (temp_strv);
346
347   return argv;
348 }
349
350 gchar **
351 tlm_utils_split_command_line(const gchar *command) {
352   const gchar *pattern = "('.*?'|\".*?\"|\\S+)";
353   GError *error = NULL;
354   GRegex *regex = NULL;
355   gchar **argv = NULL;
356  
357   if (!command) {
358     WARN("Cannot pase NULL arguments string");
359     return NULL;
360   }
361  
362   if (!(regex = g_regex_new(pattern, 0, G_REGEX_MATCH_NOTEMPTY, &error))) {
363     WARN("Failed to create regex: %s", error->message);
364     g_error_free(error);
365   }
366
367   argv = _split_command_line_with_regex (command, regex);
368
369   g_regex_unref (regex);
370
371   return argv;
372 }
373
374 GList *
375 tlm_utils_split_command_lines (const GList const *commands_list) {
376   const gchar *pattern = "('.*?'|\".*?\"|\\S+)";
377   GError *error = NULL;
378   GRegex *regex = NULL;
379   GList *argv_list = NULL;
380   const GList *tmp_list = NULL;
381
382   if (!commands_list) {
383     return NULL;
384   }
385
386   if (!(regex = g_regex_new(pattern, 0, G_REGEX_MATCH_NOTEMPTY, &error))) {
387     WARN("Failed to create regex: %s", error->message);
388     g_error_free(error);
389   }
390
391   for (tmp_list = commands_list; tmp_list; tmp_list = tmp_list->next) {
392     argv_list = g_list_append (argv_list, _split_command_line_with_regex (
393                     (const gchar *)tmp_list->data, regex));
394   }
395
396   g_regex_unref (regex);
397
398   return argv_list;
399 }