r560: Fix bugzilla 1279: cannot control individual print jobs using cups
[Samba/gebeck_regimport.git] / source3 / passdb / pdb_xml.c
blob64cb73ba5a4aa401a50c35228f36ad985c012743
2 /*
3 * XML password backend for samba
4 * Copyright (C) Jelmer Vernooij 2002
5 * Some parts based on the libxml gjobread example by Daniel Veillard
6 *
7 * This program is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
10 * any later version.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
17 * You should have received a copy of the GNU General Public License along with
18 * this program; if not, write to the Free Software Foundation, Inc., 675
19 * Mass Ave, Cambridge, MA 02139, USA.
22 /* FIXME:
23 * - Support stdin input by using '-'
24 * - Be faster. Don't rewrite the whole file when adding a user, but store it in the memory and save it when exiting. Requires changes to samba source.
25 * - Gives the ability to read/write to standard input/output
26 * - Do locking!
27 * - Better names!
31 #define XML_URL "http://samba.org/~jelmer/sambapdb.dtd"
33 #include "includes.h"
35 #include <libxml/xmlmemory.h>
36 #include <libxml/parser.h>
38 static int xmlsam_debug_level = DBGC_ALL;
40 #undef DBGC_CLASS
41 #define DBGC_CLASS xmlsam_debug_level
43 static char * iota(int a) {
44 static char tmp[10];
46 snprintf(tmp, 9, "%d", a);
47 return tmp;
50 static BOOL parsePass(xmlDocPtr doc, xmlNsPtr ns, xmlNodePtr cur, SAM_ACCOUNT * u)
52 pstring temp;
54 cur = cur->xmlChildrenNode;
55 while (cur != NULL) {
56 if (strcmp(cur->name, "crypt"))
57 DEBUG(0, ("Unknown element %s\n", cur->name));
58 else {
59 if (!strcmp(xmlGetProp(cur, "type"), "nt")
61 pdb_gethexpwd(xmlNodeListGetString
62 (doc, cur->xmlChildrenNode, 1), temp))
63 pdb_set_nt_passwd(u, temp, PDB_SET);
64 else if (!strcmp(xmlGetProp(cur, "type"), "lanman")
66 pdb_gethexpwd(xmlNodeListGetString
67 (doc, cur->xmlChildrenNode, 1), temp))
68 pdb_set_lanman_passwd(u, temp, PDB_SET);
69 else
70 DEBUG(0,
71 ("Unknown crypt type: %s\n",
72 xmlGetProp(cur, "type")));
74 cur = cur->next;
76 return True;
79 static BOOL parseUser(xmlDocPtr doc, xmlNsPtr ns, xmlNodePtr cur, SAM_ACCOUNT * u)
81 char *tmp;
82 DOM_SID sid;
84 tmp = xmlGetProp(cur, "sid");
85 if (tmp){
86 string_to_sid(&sid, tmp);
87 pdb_set_user_sid(u, &sid, PDB_SET);
89 pdb_set_username(u, xmlGetProp(cur, "name"), PDB_SET);
90 /* We don't care what the top level element name is */
91 cur = cur->xmlChildrenNode;
92 while (cur != NULL) {
93 if ((!strcmp(cur->name, "group")) && (cur->ns == ns)) {
94 tmp = xmlGetProp(cur, "sid");
95 if (tmp){
96 string_to_sid(&sid, tmp);
97 pdb_set_group_sid(u, &sid, PDB_SET);
101 else if ((!strcmp(cur->name, "domain")) && (cur->ns == ns))
102 pdb_set_domain(u,
103 xmlNodeListGetString(doc, cur->xmlChildrenNode,
104 1), PDB_SET);
106 else if (!strcmp(cur->name, "fullname") && cur->ns == ns)
107 pdb_set_fullname(u,
108 xmlNodeListGetString(doc,
109 cur->xmlChildrenNode,
110 1), PDB_SET);
112 else if (!strcmp(cur->name, "nt_username") && cur->ns == ns)
113 pdb_set_nt_username(u,
114 xmlNodeListGetString(doc,
115 cur->xmlChildrenNode,
116 1), PDB_SET);
118 else if (!strcmp(cur->name, "logon_script") && cur->ns == ns)
119 pdb_set_logon_script(u,
120 xmlNodeListGetString(doc,
121 cur->xmlChildrenNode,
122 1), PDB_SET);
124 else if (!strcmp(cur->name, "profile_path") && cur->ns == ns)
125 pdb_set_profile_path(u,
126 xmlNodeListGetString(doc,
127 cur->xmlChildrenNode,
128 1), PDB_SET);
130 else if (!strcmp(cur->name, "logon_time") && cur->ns == ns)
131 pdb_set_logon_time(u,
132 atol(xmlNodeListGetString
133 (doc, cur->xmlChildrenNode, 1)), PDB_SET);
135 else if (!strcmp(cur->name, "logoff_time") && cur->ns == ns)
136 pdb_set_logoff_time(u,
137 atol(xmlNodeListGetString
138 (doc, cur->xmlChildrenNode, 1)),
139 PDB_SET);
141 else if (!strcmp(cur->name, "kickoff_time") && cur->ns == ns)
142 pdb_set_kickoff_time(u,
143 atol(xmlNodeListGetString
144 (doc, cur->xmlChildrenNode, 1)),
145 PDB_SET);
147 else if (!strcmp(cur->name, "logon_divs") && cur->ns == ns)
148 pdb_set_logon_divs(u,
149 atol(xmlNodeListGetString
150 (doc, cur->xmlChildrenNode, 1)), PDB_SET);
152 else if (!strcmp(cur->name, "hours_len") && cur->ns == ns)
153 pdb_set_hours_len(u,
154 atol(xmlNodeListGetString
155 (doc, cur->xmlChildrenNode, 1)), PDB_SET);
157 else if (!strcmp(cur->name, "bad_password_count") && cur->ns == ns)
158 pdb_set_bad_password_count(u,
159 atol(xmlNodeListGetString
160 (doc, cur->xmlChildrenNode, 1)), PDB_SET);
162 else if (!strcmp(cur->name, "logon_count") && cur->ns == ns)
163 pdb_set_logon_count(u,
164 atol(xmlNodeListGetString
165 (doc, cur->xmlChildrenNode, 1)), PDB_SET);
167 else if (!strcmp(cur->name, "unknown_6") && cur->ns == ns)
168 pdb_set_unknown_6(u,
169 atol(xmlNodeListGetString
170 (doc, cur->xmlChildrenNode, 1)), PDB_SET);
172 else if (!strcmp(cur->name, "homedir") && cur->ns == ns)
173 pdb_set_homedir(u,
174 xmlNodeListGetString(doc, cur->xmlChildrenNode,
175 1), PDB_SET);
177 else if (!strcmp(cur->name, "unknown_str") && cur->ns == ns)
178 pdb_set_unknown_str(u,
179 xmlNodeListGetString(doc,
180 cur->xmlChildrenNode,
181 1), PDB_SET);
183 else if (!strcmp(cur->name, "dir_drive") && cur->ns == ns)
184 pdb_set_dir_drive(u,
185 xmlNodeListGetString(doc,
186 cur->xmlChildrenNode,
187 1), PDB_SET);
189 else if (!strcmp(cur->name, "munged_dial") && cur->ns == ns)
190 pdb_set_munged_dial(u,
191 xmlNodeListGetString(doc,
192 cur->xmlChildrenNode,
193 1), PDB_SET);
195 else if (!strcmp(cur->name, "acct_desc") && cur->ns == ns)
196 pdb_set_acct_desc(u,
197 xmlNodeListGetString(doc,
198 cur->xmlChildrenNode,
199 1), PDB_SET);
201 else if (!strcmp(cur->name, "acct_ctrl") && cur->ns == ns)
202 pdb_set_acct_ctrl(u,
203 atol(xmlNodeListGetString
204 (doc, cur->xmlChildrenNode, 1)), PDB_SET);
206 else if (!strcmp(cur->name, "workstations") && cur->ns == ns)
207 pdb_set_workstations(u,
208 xmlNodeListGetString(doc,
209 cur->xmlChildrenNode,
210 1), PDB_SET);
212 else if ((!strcmp(cur->name, "password")) && (cur->ns == ns)) {
213 tmp = xmlGetProp(cur, "last_set");
214 if (tmp)
215 pdb_set_pass_last_set_time(u, atol(tmp), PDB_SET);
216 tmp = xmlGetProp(cur, "must_change");
217 if (tmp)
218 pdb_set_pass_must_change_time(u, atol(tmp), PDB_SET);
219 tmp = xmlGetProp(cur, "can_change");
220 if (tmp)
221 pdb_set_pass_can_change_time(u, atol(tmp), PDB_SET);
222 parsePass(doc, ns, cur, u);
225 else
226 DEBUG(0, ("Unknown element %s\n", cur->name));
227 cur = cur->next;
230 return True;
233 typedef struct pdb_xml {
234 char *location;
235 char written;
236 xmlDocPtr doc;
237 xmlNodePtr users;
238 xmlNodePtr pwent;
239 xmlNsPtr ns;
240 } pdb_xml;
242 static xmlNodePtr parseSambaXMLFile(struct pdb_xml *data)
244 xmlNodePtr cur;
246 data->doc = xmlParseFile(data->location);
247 if (data->doc == NULL)
248 return NULL;
250 cur = xmlDocGetRootElement(data->doc);
251 if (!cur) {
252 DEBUG(0, ("empty document\n"));
253 xmlFreeDoc(data->doc);
254 return NULL;
256 data->ns = xmlSearchNsByHref(data->doc, cur, XML_URL);
257 if (!data->ns) {
258 DEBUG(0,
259 ("document of the wrong type, samba user namespace not found\n"));
260 xmlFreeDoc(data->doc);
261 return NULL;
263 if (strcmp(cur->name, "samba")) {
264 DEBUG(0, ("document of the wrong type, root node != samba"));
265 xmlFreeDoc(data->doc);
266 return NULL;
269 cur = cur->xmlChildrenNode;
270 while (cur && xmlIsBlankNode(cur)) {
271 cur = cur->next;
273 if (!cur)
274 return NULL;
275 if ((strcmp(cur->name, "users")) || (cur->ns != data->ns)) {
276 DEBUG(0, ("document of the wrong type, was '%s', users expected",
277 cur->name));
278 DEBUG(0, ("xmlDocDump follows\n"));
279 xmlDocDump(stderr, data->doc);
280 DEBUG(0, ("xmlDocDump finished\n"));
281 xmlFreeDoc(data->doc);
282 return NULL;
284 data->users = cur;
285 cur = cur->xmlChildrenNode;
286 return cur;
289 static NTSTATUS xmlsam_setsampwent(struct pdb_methods *methods, BOOL update)
291 pdb_xml *data;
293 if (!methods) {
294 DEBUG(0, ("Invalid methods\n"));
295 return NT_STATUS_INVALID_PARAMETER;
297 data = (pdb_xml *) methods->private_data;
298 if (!data) {
299 DEBUG(0, ("Invalid pdb_xml_data\n"));
300 return NT_STATUS_INVALID_PARAMETER;
302 data->pwent = parseSambaXMLFile(data);
303 if (!data->pwent)
304 return NT_STATUS_UNSUCCESSFUL;
306 return NT_STATUS_OK;
309 /***************************************************************
310 End enumeration of the passwd list.
311 ****************************************************************/
313 static void xmlsam_endsampwent(struct pdb_methods *methods)
315 pdb_xml *data;
317 if (!methods) {
318 DEBUG(0, ("Invalid methods\n"));
319 return;
322 data = (pdb_xml *) methods->private_data;
324 if (!data) {
325 DEBUG(0, ("Invalid pdb_xml_data\n"));
326 return;
329 xmlFreeDoc(data->doc);
330 data->doc = NULL;
331 data->pwent = NULL;
334 /*****************************************************************
335 Get one SAM_ACCOUNT from the list (next in line)
336 *****************************************************************/
338 static NTSTATUS xmlsam_getsampwent(struct pdb_methods *methods, SAM_ACCOUNT * user)
340 pdb_xml *data;
342 if (!methods) {
343 DEBUG(0, ("Invalid methods\n"));
344 return NT_STATUS_INVALID_PARAMETER;
346 data = (pdb_xml *) methods->private_data;
348 if (!data) {
349 DEBUG(0, ("Invalid pdb_xml_data\n"));
350 return NT_STATUS_INVALID_PARAMETER;
353 while (data->pwent) {
354 if ((!strcmp(data->pwent->name, "user")) &&
355 (data->pwent->ns == data->ns)) {
357 parseUser(data->doc, data->ns, data->pwent, user);
358 data->pwent = data->pwent->next;
359 return NT_STATUS_OK;
361 data->pwent = data->pwent->next;
363 return NT_STATUS_UNSUCCESSFUL;
366 /***************************************************************************
367 Adds an existing SAM_ACCOUNT
368 ****************************************************************************/
370 static NTSTATUS xmlsam_add_sam_account(struct pdb_methods *methods, SAM_ACCOUNT * u)
372 pstring temp;
373 fstring sid_str;
374 xmlNodePtr cur, user, pass, root;
375 pdb_xml *data;
377 DEBUG(10, ("xmlsam_add_sam_account called!\n"));
379 if (!methods) {
380 DEBUG(0, ("Invalid methods\n"));
381 return NT_STATUS_INVALID_PARAMETER;
384 data = (pdb_xml *) methods->private_data;
385 if (!data) {
386 DEBUG(0, ("Invalid pdb_xml_data\n"));
387 return NT_STATUS_INVALID_PARAMETER;
390 /* Create a new document if we can't open the current one */
391 if (!parseSambaXMLFile(data)) {
392 DEBUG(0, ("Can't load current XML file, creating a new one\n"));
393 data->doc = xmlNewDoc(XML_DEFAULT_VERSION);
394 root = xmlNewDocNode(data->doc, NULL, "samba", NULL);
395 cur = xmlDocSetRootElement(data->doc, root);
396 data->ns = xmlNewNs(root, XML_URL, "samba");
397 data->users = xmlNewChild(root, data->ns, "users", NULL);
400 user = xmlNewChild(data->users, data->ns, "user", NULL);
401 xmlNewProp(user, "sid",
402 sid_to_string(sid_str, pdb_get_user_sid(u)));
404 if (pdb_get_username(u) && strcmp(pdb_get_username(u), ""))
405 xmlNewProp(user, "name", pdb_get_username(u));
407 cur = xmlNewChild(user, data->ns, "group", NULL);
409 xmlNewProp(cur, "sid",
410 sid_to_string(sid_str, pdb_get_group_sid(u)));
412 if (pdb_get_init_flags(u, PDB_LOGONTIME) != PDB_DEFAULT)
413 xmlNewChild(user, data->ns, "logon_time",
414 iota(pdb_get_logon_time(u)));
416 if (pdb_get_init_flags(u, PDB_LOGOFFTIME) != PDB_DEFAULT)
417 xmlNewChild(user, data->ns, "logoff_time",
418 iota(pdb_get_logoff_time(u)));
420 if (pdb_get_init_flags(u, PDB_KICKOFFTIME) != PDB_DEFAULT)
421 xmlNewChild(user, data->ns, "kickoff_time",
422 iota(pdb_get_kickoff_time(u)));
424 if (pdb_get_domain(u) && strcmp(pdb_get_domain(u), ""))
425 xmlNewChild(user, data->ns, "domain", pdb_get_domain(u));
427 if (pdb_get_nt_username(u) && strcmp(pdb_get_nt_username(u), ""))
428 xmlNewChild(user, data->ns, "nt_username", pdb_get_nt_username(u));
430 if (pdb_get_fullname(u) && strcmp(pdb_get_fullname(u), ""))
431 xmlNewChild(user, data->ns, "fullname", pdb_get_fullname(u));
433 if (pdb_get_homedir(u) && strcmp(pdb_get_homedir(u), ""))
434 xmlNewChild(user, data->ns, "homedir", pdb_get_homedir(u));
436 if (pdb_get_dir_drive(u) && strcmp(pdb_get_dir_drive(u), ""))
437 xmlNewChild(user, data->ns, "dir_drive", pdb_get_dir_drive(u));
439 if (pdb_get_logon_script(u) && strcmp(pdb_get_logon_script(u), ""))
440 xmlNewChild(user, data->ns, "logon_script",
441 pdb_get_logon_script(u));
443 if (pdb_get_profile_path(u) && strcmp(pdb_get_profile_path(u), ""))
444 xmlNewChild(user, data->ns, "profile_path",
445 pdb_get_profile_path(u));
447 if (pdb_get_acct_desc(u) && strcmp(pdb_get_acct_desc(u), ""))
448 xmlNewChild(user, data->ns, "acct_desc", pdb_get_acct_desc(u));
450 if (pdb_get_workstations(u) && strcmp(pdb_get_workstations(u), ""))
451 xmlNewChild(user, data->ns, "workstations",
452 pdb_get_workstations(u));
454 if (pdb_get_unknown_str(u) && strcmp(pdb_get_unknown_str(u), ""))
455 xmlNewChild(user, data->ns, "unknown_str", pdb_get_unknown_str(u));
457 if (pdb_get_munged_dial(u) && strcmp(pdb_get_munged_dial(u), ""))
458 xmlNewChild(user, data->ns, "munged_dial", pdb_get_munged_dial(u));
461 /* Password stuff */
462 pass = xmlNewChild(user, data->ns, "password", NULL);
463 if (pdb_get_pass_last_set_time(u))
464 xmlNewProp(pass, "last_set", iota(pdb_get_pass_last_set_time(u)));
465 if (pdb_get_init_flags(u, PDB_CANCHANGETIME) != PDB_DEFAULT)
466 xmlNewProp(pass, "can_change",
467 iota(pdb_get_pass_can_change_time(u)));
469 if (pdb_get_init_flags(u, PDB_MUSTCHANGETIME) != PDB_DEFAULT)
470 xmlNewProp(pass, "must_change",
471 iota(pdb_get_pass_must_change_time(u)));
474 if (pdb_get_lanman_passwd(u)) {
475 pdb_sethexpwd(temp, pdb_get_lanman_passwd(u),
476 pdb_get_acct_ctrl(u));
477 cur = xmlNewChild(pass, data->ns, "crypt", temp);
478 xmlNewProp(cur, "type", "lanman");
481 if (pdb_get_nt_passwd(u)) {
482 pdb_sethexpwd(temp, pdb_get_nt_passwd(u), pdb_get_acct_ctrl(u));
483 cur = xmlNewChild(pass, data->ns, "crypt", temp);
484 xmlNewProp(cur, "type", "nt");
487 xmlNewChild(user, data->ns, "acct_ctrl", iota(pdb_get_acct_ctrl(u)));
489 if (pdb_get_logon_divs(u))
490 xmlNewChild(user, data->ns, "logon_divs",
491 iota(pdb_get_logon_divs(u)));
493 if (pdb_get_hours_len(u))
494 xmlNewChild(user, data->ns, "hours_len",
495 iota(pdb_get_hours_len(u)));
497 xmlNewChild(user, data->ns, "bad_password_count", iota(pdb_get_bad_password_count(u)));
498 xmlNewChild(user, data->ns, "logon_count", iota(pdb_get_logon_count(u)));
499 xmlNewChild(user, data->ns, "unknown_6", iota(pdb_get_unknown_6(u)));
500 xmlSaveFile(data->location, data->doc);
502 return NT_STATUS_OK;
505 static NTSTATUS xmlsam_init(PDB_CONTEXT * pdb_context, PDB_METHODS ** pdb_method,
506 const char *location)
508 NTSTATUS nt_status;
509 pdb_xml *data;
511 xmlsam_debug_level = debug_add_class("xmlsam");
512 if (xmlsam_debug_level == -1) {
513 xmlsam_debug_level = DBGC_ALL;
514 DEBUG(0, ("xmlsam: Couldn't register custom debugging class!\n"));
517 if (!pdb_context) {
518 DEBUG(0, ("invalid pdb_methods specified\n"));
519 return NT_STATUS_UNSUCCESSFUL;
522 if (!NT_STATUS_IS_OK
523 (nt_status = make_pdb_methods(pdb_context->mem_ctx, pdb_method))) {
524 return nt_status;
527 (*pdb_method)->name = "xmlsam";
529 (*pdb_method)->setsampwent = xmlsam_setsampwent;
530 (*pdb_method)->endsampwent = xmlsam_endsampwent;
531 (*pdb_method)->getsampwent = xmlsam_getsampwent;
532 (*pdb_method)->add_sam_account = xmlsam_add_sam_account;
533 (*pdb_method)->getsampwnam = NULL;
534 (*pdb_method)->getsampwsid = NULL;
535 (*pdb_method)->update_sam_account = NULL;
536 (*pdb_method)->delete_sam_account = NULL;
537 (*pdb_method)->getgrsid = NULL;
538 (*pdb_method)->getgrgid = NULL;
539 (*pdb_method)->getgrnam = NULL;
540 (*pdb_method)->add_group_mapping_entry = NULL;
541 (*pdb_method)->update_group_mapping_entry = NULL;
542 (*pdb_method)->delete_group_mapping_entry = NULL;
543 (*pdb_method)->enum_group_mapping = NULL;
545 data = talloc(pdb_context->mem_ctx, sizeof(pdb_xml));
546 data->location = talloc_strdup(pdb_context->mem_ctx, (location ? location : "passdb.xml"));
547 data->pwent = NULL;
548 data->written = 0;
549 (*pdb_method)->private_data = data;
551 LIBXML_TEST_VERSION xmlKeepBlanksDefault(0);
553 return NT_STATUS_OK;
556 NTSTATUS pdb_xml_init(void)
558 return smb_register_passdb(PASSDB_INTERFACE_VERSION, "xml", xmlsam_init);