Git init
[pkgs/e/elektra.git] / src / backends / passwd / passwd.c
1 /***************************************************************************
2             passwd.c  -  Access the /etc/passwd file
3                              -------------------
4     begin                : Nov 15 2007
5     copyright            : (C) 2007 by Patrick Sabin
6     email                : patricksabin@gmx.at
7  ***************************************************************************/
8
9 /***************************************************************************
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the BSD License (revised).                      *
13  *                                                                         *
14  ***************************************************************************/
15
16 #include <passwd.h>
17
18 int kdbOpen_passwd(KDB *handle)
19 {
20         KeySet *ks;
21         Key *key;
22         const char *s, *t;
23         int prefix_len;
24         PasswdData *data;
25         const Key* mnt = kdbhGetMountpoint(handle);
26         KDBCap *cap = kdbhGetCapability (handle);
27         size_t mntsize = keyGetNameSize(mnt)+1;
28
29         if (mnt==0)
30         {
31                 return -1;
32         }
33
34         data=malloc(sizeof(PasswdData));
35         kdbhSetBackendData(handle,data);
36         data->mountpoint=0;
37         ks=kdbhGetConfig(handle);
38
39         ksRewind(ks);
40         key=ksNext(ks);
41
42         s=keyName(key);
43         t=s+KDB_KEY_MOUNTPOINTS_LEN;
44
45         /* skip entry name */
46         while (!(*t=='/'||!*t))
47                 t++;
48         
49         if (!*t) {
50                 fprintf(stderr, "Cannot happen\n");
51                 exit(1);
52         }
53
54         
55         t+=sizeof("/config/")-1;
56         prefix_len=t-s;
57
58         data->mountpoint=malloc(mntsize);
59         snprintf(data->mountpoint,mntsize,"%s/",keyName(mnt));
60
61
62         data->path="/etc/passwd";
63         data->backend=BACKENDNAME;
64         for (;key;key=ksNext(ks)) {
65                 if (strlen(keyName(key))<prefix_len) continue;
66
67                 if (!strncmp(keyName(key)+prefix_len,"path",sizeof("path"))) {
68                         data->path=keyValue(key);
69                 }
70         }
71
72         data->mountpointlen=strlen(data->mountpoint);
73
74         cap->onlyRemoveAll=1;
75         cap->onlyAddKeys=1;
76         cap->onlyFullSet=1;
77
78         cap->onlySystem=1;
79         cap->onlyUser=1;
80
81         cap->noOwner=1;
82         cap->noValue=1;
83         cap->noComment=1;
84         cap->noUID=1;
85         cap->noGID=1;
86         cap->noMode=1;
87         cap->noDir=1;
88         cap->noATime=1;
89         cap->noMTime=1;
90         cap->noCTime=1;
91         cap->noRemove=1;
92         cap->noStat=1;
93         cap->noMount=1;
94         cap->noBinary=1;
95         cap->noString=1;
96         cap->noTypes=1;
97         cap->noError=1;
98
99         return 0;
100 }
101
102
103
104
105 /**
106  * Finalize the backend.
107  * Called prior to unloading the backend dynamic module. Should ensure that no
108  * functions or static/global variables from the module will ever be accessed again.
109  *
110  * Make sure to free all memory that your backend requested at runtime.
111  *
112  * After this call, libelektra.so will unload the backend library, so this is
113  * the point to shutdown any affairs with the storage.
114  *
115  * @return 0 on success, anything else otherwise.
116  * @see kdbClose()
117  * @ingroup backend
118  */
119 int kdbClose_passwd(KDB *handle)
120 {
121         /* free all backend resources and shut it down */
122         PasswdData *data;
123         data=kdbhGetBackendData(handle);
124         free(data->mountpoint);
125         free(data);
126
127         return 0; /* success */
128 }
129
130
131
132 /**
133  * Implementation for kdbGet() method.
134  *
135  * @see kdbGet() for caller.
136  * @param handle contains internal information of @link kdbOpen() opened @endlink key database
137  * @param returned contains a keyset with relevant keys
138  * @param parentKey contains the information where to get the keys
139  * @return the number of keys got
140  * @return 0 on success with no changed key
141  * @return -1 on failure, the current key in returned shows the position and/or errno is set
142  * @ingroup backend
143  */
144 ssize_t kdbGet_passwd(KDB *handle, KeySet *returned, const Key *parentKey)
145 {
146         int errnosave = errno;
147         ssize_t nr_keys = 0;
148         /* get all keys below parentKey and count them with nr_keys */
149         PasswdData *data;
150         const char *parent;
151         int parent_len;
152         /*KeySet *ks;
153         Key *key;
154         char *s,*t;
155         int prefix_len;
156         */
157         data=kdbhGetBackendData(handle);
158         parent=keyName(parentKey);
159         parent_len=strlen(parent);
160
161         if (parent_len<data->mountpointlen-1 ||
162                         strncmp(data->mountpoint,parent,data->mountpointlen-1))
163         {
164                 // parentkey covers keys not handled by the backend
165                 return -1;
166         }
167
168         if (parent_len==data->mountpointlen-1 &&
169                         !strncmp(data->mountpoint, parent,data->mountpointlen-1))
170         {
171                 // return all username directories
172                 char *name;
173                 FILE *f;
174                 struct passwd *pwd;
175
176                 f=fopen(data->path,"r");
177
178                 if (f==NULL) {
179                         /*errno=KDB_ERR_BACKEND;*/
180                         errno = errnosave;
181                         return -1;
182                 }
183                 while ((pwd=fgetpwent(f))) {
184                         char *pw_name;
185                         int pw_name_len;
186                         pw_name=pwd->pw_name;
187                         pw_name_len=strlen(pw_name);
188
189                         name=malloc(data->mountpointlen+pw_name_len+1);
190                         strncpy(name,data->mountpoint,data->mountpointlen+1);
191                         strncat(name,pw_name,pw_name_len);
192                         ksAppendKey(returned, keyNew(name,KEY_VALUE,"",0));
193                         nr_keys++;
194                         free (name);
195                 }
196
197                 fclose(f);
198
199         } else if (parent_len>data->mountpointlen &&
200                         !strncmp(data->mountpoint,parent,data->mountpointlen))
201         {
202                 const char *username, *p;
203                 p=username=parent+data->mountpointlen;
204                 while (!(*p=='/'||*p==0)) p++;
205                 if (*p==0) {
206                         FILE *f;
207                         struct passwd *pwd;
208                         int usernamelen;
209
210                         usernamelen=p-username;
211                         username=strndup(username,usernamelen);
212
213                         /* get username directory */
214                         f=fopen(data->path,"r");
215                         if (!f)
216                         {
217                                 errno = errnosave;
218                                 return -1;
219                         }
220                         while ((pwd=fgetpwent(f))) {
221                                 if (!strncmp(pwd->pw_name,username,usernamelen)) {
222                                         char *name;
223                                         char *id;
224                                         size_t id_size;
225
226                                         name=malloc(data->mountpointlen+usernamelen+sizeof("/gecos"));
227                                         strncpy(name,data->mountpoint,data->mountpointlen+1);
228                                         strncat(name,username,usernamelen);
229                                         strncat(name,"/gecos",sizeof("/gecos")-1);
230                                         ksAppendKey(returned, keyNew(name,KEY_VALUE,pwd->pw_gecos,0));
231                                         nr_keys++;
232                                         free (name);
233
234                                         name=malloc(data->mountpointlen+usernamelen+sizeof("/home"));
235                                         strncpy(name,data->mountpoint,data->mountpointlen+1);
236                                         strncat(name,username,usernamelen);
237                                         strncat(name,"/home",sizeof("/home")-1);
238                                         ksAppendKey(returned, keyNew(name,KEY_VALUE,pwd->pw_dir,0));
239                                         nr_keys++;
240                                         free (name);
241
242                                         name=malloc(data->mountpointlen+usernamelen+sizeof("/shell"));
243                                         strncpy(name,data->mountpoint,data->mountpointlen+1);
244                                         strncat(name,username,usernamelen);
245                                         strncat(name,"/shell",sizeof("/shell")-1);
246                                         ksAppendKey(returned, keyNew(name,KEY_VALUE,pwd->pw_shell,0));
247                                         nr_keys++;
248                                         free (name);
249
250                                         name=malloc(data->mountpointlen+usernamelen+sizeof("/uid"));
251                                         strncpy(name,data->mountpoint,data->mountpointlen+1);
252                                         strncat(name,username,usernamelen);
253                                         strncat(name,"/uid",sizeof("/uid")-1);
254                                         id_size=snprintf(NULL,0,"%d",(int)pwd->pw_uid);
255                                         id=malloc(id_size);
256                                         snprintf(id,id_size,"%d",(int)pwd->pw_uid);
257                                         ksAppendKey(returned, keyNew(name,KEY_VALUE,id,0));
258                                         nr_keys++;
259                                         free (name);
260                                         free (id);
261
262                                         name=malloc(data->mountpointlen+usernamelen+sizeof("/gid"));
263                                         strncpy(name,data->mountpoint,data->mountpointlen+1);
264                                         strncat(name,username,usernamelen);
265                                         strncat(name,"/gid",sizeof("/gid")-1);
266                                         id_size=snprintf(NULL,0,"%d",(int)pwd->pw_gid);
267                                         id=malloc(id_size);
268                                         snprintf(id,id_size,"%d",(int)pwd->pw_gid);
269                                         ksAppendKey(returned, keyNew(name,KEY_VALUE,id,0));
270                                         nr_keys++;
271                                         free (name);
272                                         free (id);
273
274                                         break;
275                                 }
276                         }
277                         fclose (f);
278                         kdbiFree ((void*)username);
279                         if (!pwd) {
280                                 /* entry not found */
281                                 /*errno=KDB_ERR_NOTFOUND;*/
282                                 errno = errnosave;
283                                 return -1;
284                         }
285                 } else {
286                         /* parent key not a valid directory */
287                         errno = errnosave;
288                         return -1;
289                 }
290         }
291
292         errno = errnosave;
293         return nr_keys; /* success */
294 }
295
296
297 /**
298  * Implementation for kdbSet() method.
299  *
300  * @see kdbSet() for caller.
301  * @param handle contains internal information of @link kdbOpen() opened @endlink key database
302  * @param returned contains a keyset with relevant keys
303  * @param parentKey contains the information where to set the keys
304  * @return the number of keys set
305  * @return 0 on success with no changed key in database
306  * @return -1 on failure, the current key in returned shows the position and/or errno is set
307  * @ingroup backend
308  */
309 ssize_t kdbSet_passwd(KDB *handle, KeySet *returned, const Key *parentKey)
310 {
311         int errnosave = errno;
312         ssize_t nr_keys = 0;
313         Key *key;
314         PasswdData *data;
315         const char *parent;
316         int parent_len;
317
318         parent=keyName(parentKey);
319         parent_len=strlen(parent);
320
321         data=kdbhGetBackendData(handle);
322
323         if (parent_len<data->mountpointlen-1 || strncmp(data->mountpoint,parent,data->mountpointlen-1)) {
324                 // parentkey covers keys not handled by the backend
325                 errno = errnosave;
326                 return -1;
327         }
328
329         ksRewind(returned);
330         key=ksNext(returned);
331         for (;key;ksNext(returned)) {
332                 const char *name=keyName(key);
333                 int name_len=strlen(name);
334
335                 if (name_len>data->mountpointlen-1 && !strncmp(data->mountpoint,name,name_len)) {
336                         /* keyname is mounted name. This key is not writeable */
337
338                 } else if (name_len>data->mountpointlen && !strncmp(data->mountpoint,name,data->mountpointlen)) {
339
340                 } else {
341
342                 }
343         }
344         /* set all keys below parentKey and count them with nr_keys */
345         errno = errnosave;
346         return nr_keys;
347 }
348
349 /**
350  * All KDB methods implemented by the backend can have random names, except
351  * kdbBackendFactory(). This is the single symbol that will be looked up
352  * when loading the backend, and the first method of the backend
353  * implementation that will be called.
354  * 
355  * Its purpose is to "publish" the exported methods for libelektra.so. The
356  * implementation inside the provided skeleton is usually enough: simply
357  * call kdbBackendExport() with all methods that must be exported.
358  * 
359  * @return whatever kdbBackendExport() returns
360  * @see kdbBackendExport() for an example
361  * @see kdbOpenBackend()
362  * @ingroup backend
363  */
364 KDBEXPORT(passwd)
365 {
366         return kdbBackendExport(BACKENDNAME,
367                 KDB_BE_OPEN,    &kdbOpen_passwd,
368                 KDB_BE_CLOSE,   &kdbClose_passwd,
369                 KDB_BE_GET,     &kdbGet_passwd,
370                 KDB_BE_SET,     &kdbSet_passwd,
371                 KDB_BE_VERSION, BACKENDVERSION,
372                 KDB_BE_AUTHOR,  "Patrick Sabin <patricksabin@gmx.at>",
373                 KDB_BE_LICENCE, "BSD",
374                 KDB_BE_DESCRIPTION,
375                         "Reads and writes /etc/passwd content",
376                 KDB_BE_END);
377 }