1 /***************************************************************************
2 passwd.c - Access the /etc/passwd file
5 copyright : (C) 2007 by Patrick Sabin
6 email : patricksabin@gmx.at
7 ***************************************************************************/
9 /***************************************************************************
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the BSD License (revised). *
14 ***************************************************************************/
18 int kdbOpen_passwd(KDB *handle)
25 const Key* mnt = kdbhGetMountpoint(handle);
26 KDBCap *cap = kdbhGetCapability (handle);
27 size_t mntsize = keyGetNameSize(mnt)+1;
34 data=malloc(sizeof(PasswdData));
35 kdbhSetBackendData(handle,data);
37 ks=kdbhGetConfig(handle);
43 t=s+KDB_KEY_MOUNTPOINTS_LEN;
46 while (!(*t=='/'||!*t))
50 fprintf(stderr, "Cannot happen\n");
55 t+=sizeof("/config/")-1;
58 data->mountpoint=malloc(mntsize);
59 snprintf(data->mountpoint,mntsize,"%s/",keyName(mnt));
62 data->path="/etc/passwd";
63 data->backend=BACKENDNAME;
64 for (;key;key=ksNext(ks)) {
65 if (strlen(keyName(key))<prefix_len) continue;
67 if (!strncmp(keyName(key)+prefix_len,"path",sizeof("path"))) {
68 data->path=keyValue(key);
72 data->mountpointlen=strlen(data->mountpoint);
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.
110 * Make sure to free all memory that your backend requested at runtime.
112 * After this call, libelektra.so will unload the backend library, so this is
113 * the point to shutdown any affairs with the storage.
115 * @return 0 on success, anything else otherwise.
119 int kdbClose_passwd(KDB *handle)
121 /* free all backend resources and shut it down */
123 data=kdbhGetBackendData(handle);
124 free(data->mountpoint);
127 return 0; /* success */
133 * Implementation for kdbGet() method.
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
144 ssize_t kdbGet_passwd(KDB *handle, KeySet *returned, const Key *parentKey)
146 int errnosave = errno;
148 /* get all keys below parentKey and count them with nr_keys */
157 data=kdbhGetBackendData(handle);
158 parent=keyName(parentKey);
159 parent_len=strlen(parent);
161 if (parent_len<data->mountpointlen-1 ||
162 strncmp(data->mountpoint,parent,data->mountpointlen-1))
164 // parentkey covers keys not handled by the backend
168 if (parent_len==data->mountpointlen-1 &&
169 !strncmp(data->mountpoint, parent,data->mountpointlen-1))
171 // return all username directories
176 f=fopen(data->path,"r");
179 /*errno=KDB_ERR_BACKEND;*/
183 while ((pwd=fgetpwent(f))) {
186 pw_name=pwd->pw_name;
187 pw_name_len=strlen(pw_name);
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));
199 } else if (parent_len>data->mountpointlen &&
200 !strncmp(data->mountpoint,parent,data->mountpointlen))
202 const char *username, *p;
203 p=username=parent+data->mountpointlen;
204 while (!(*p=='/'||*p==0)) p++;
210 usernamelen=p-username;
211 username=strndup(username,usernamelen);
213 /* get username directory */
214 f=fopen(data->path,"r");
220 while ((pwd=fgetpwent(f))) {
221 if (!strncmp(pwd->pw_name,username,usernamelen)) {
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));
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));
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));
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);
256 snprintf(id,id_size,"%d",(int)pwd->pw_uid);
257 ksAppendKey(returned, keyNew(name,KEY_VALUE,id,0));
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);
268 snprintf(id,id_size,"%d",(int)pwd->pw_gid);
269 ksAppendKey(returned, keyNew(name,KEY_VALUE,id,0));
278 kdbiFree ((void*)username);
280 /* entry not found */
281 /*errno=KDB_ERR_NOTFOUND;*/
286 /* parent key not a valid directory */
293 return nr_keys; /* success */
298 * Implementation for kdbSet() method.
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
309 ssize_t kdbSet_passwd(KDB *handle, KeySet *returned, const Key *parentKey)
311 int errnosave = errno;
318 parent=keyName(parentKey);
319 parent_len=strlen(parent);
321 data=kdbhGetBackendData(handle);
323 if (parent_len<data->mountpointlen-1 || strncmp(data->mountpoint,parent,data->mountpointlen-1)) {
324 // parentkey covers keys not handled by the backend
330 key=ksNext(returned);
331 for (;key;ksNext(returned)) {
332 const char *name=keyName(key);
333 int name_len=strlen(name);
335 if (name_len>data->mountpointlen-1 && !strncmp(data->mountpoint,name,name_len)) {
336 /* keyname is mounted name. This key is not writeable */
338 } else if (name_len>data->mountpointlen && !strncmp(data->mountpoint,name,data->mountpointlen)) {
344 /* set all keys below parentKey and count them with nr_keys */
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.
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.
359 * @return whatever kdbBackendExport() returns
360 * @see kdbBackendExport() for an example
361 * @see kdbOpenBackend()
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",
375 "Reads and writes /etc/passwd content",