Adding pdb_xml and pdb_mysql passdb modules.
[kai/samba.git] / examples / pdb / mysql / pdb_mysql.c
1
2 /*
3  * MySQL password backend for samba
4  * Copyright (C) Jelmer Vernooij 2002
5  * 
6  * This program is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU General Public License as published by the Free
8  * Software Foundation; either version 2 of the License, or (at your option)
9  * any later version.
10  * 
11  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
14  * more details.
15  * 
16  * You should have received a copy of the GNU General Public License along with
17  * this program; if not, write to the Free Software Foundation, Inc., 675
18  * Mass Ave, Cambridge, MA 02139, USA.
19  */
20
21 #include "includes.h"
22 #include <mysql/mysql.h>
23
24 #define CONFIG_TABLE_DEFAULT                            "user"
25 #define CONFIG_LOGON_TIME_DEFAULT                       "logon_time"
26 #define CONFIG_LOGOFF_TIME_DEFAULT                      "logoff_time"
27 #define CONFIG_KICKOFF_TIME_DEFAULT                     "kickoff_time"
28 #define CONFIG_PASS_LAST_SET_TIME_DEFAULT       "pass_last_set_time"
29 #define CONFIG_PASS_CAN_CHANGE_TIME_DEFAULT     "pass_can_change_time"
30 #define CONFIG_PASS_MUST_CHANGE_TIME_DEFAULT "pass_must_change_time"
31 #define CONFIG_USERNAME_DEFAULT                         "username"
32 #define CONFIG_DOMAIN_DEFAULT                           "domain"
33 #define CONFIG_NT_USERNAME_DEFAULT              "nt_username"
34 #define CONFIG_FULLNAME_DEFAULT                         "nt_fullname"
35 #define CONFIG_HOME_DIR_DEFAULT                         "home_dir"
36 #define CONFIG_DIR_DRIVE_DEFAULT                        "dir_drive"
37 #define CONFIG_LOGON_SCRIPT_DEFAULT                     "logon_script"
38 #define CONFIG_PROFILE_PATH_DEFAULT                     "profile_path"
39 #define CONFIG_ACCT_DESC_DEFAULT                        "acct_desc"
40 #define CONFIG_WORKSTATIONS_DEFAULT                     "workstations"
41 #define CONFIG_UNKNOWN_STR_DEFAULT                      "unknown_str"
42 #define CONFIG_MUNGED_DIAL_DEFAULT                      "munged_dial"
43 #define CONFIG_UID_DEFAULT                                      "uid"
44 #define CONFIG_GID_DEFAULT                                      "gid"
45 #define CONFIG_USER_SID_DEFAULT                         "user_sid"
46 #define CONFIG_GROUP_SID_DEFAULT                        "group_sid"
47 #define CONFIG_LM_PW_DEFAULT                            "lm_pw"
48 #define CONFIG_NT_PW_DEFAULT                            "nt_pw"
49 #define CONFIG_PLAIN_PW_DEFAULT                         "NULL"
50 #define CONFIG_ACCT_CTRL_DEFAULT                        "acct_ctrl"
51 #define CONFIG_UNKNOWN_3_DEFAULT                        "unknown_3"
52 #define CONFIG_LOGON_DIVS_DEFAULT                       "logon_divs"
53 #define CONFIG_HOURS_LEN_DEFAULT                        "hours_len"
54 #define CONFIG_UNKNOWN_5_DEFAULT                        "unknown_5"
55 #define CONFIG_UNKNOWN_6_DEFAULT                        "unknown_6"
56 #define CONFIG_HOST_DEFAULT                                     "localhost"
57 #define CONFIG_USER_DEFAULT                                     "samba"
58 #define CONFIG_PASS_DEFAULT                                     ""
59 #define CONFIG_PORT_DEFAULT                                     "3306"
60 #define CONFIG_DB_DEFAULT                                       "samba"
61
62 static int mysqlsam_debug_level = DBGC_ALL;
63
64 #undef DBGC_CLASS
65 #define DBGC_CLASS mysqlsam_debug_level
66
67 PDB_MODULE_VERSIONING_MAGIC
68
69 typedef struct pdb_mysql_data {
70         MYSQL *handle;
71         MYSQL_RES *pwent;
72         char *location;
73 } pdb_mysql_data;
74
75 /* Used to construct insert and update queries */
76
77 typedef struct pdb_mysql_query {
78         char update;
79         TALLOC_CTX *mem_ctx;
80         char *part1;
81         char *part2;
82 } pdb_mysql_query;
83
84 #define SET_DATA(data,methods) { \
85         if(!methods){ \
86                 DEBUG(0, ("invalid methods!\n")); \
87                         return False; \
88         } \
89         data = (struct pdb_mysql_data *)methods->private_data; \
90                 if(!data || !(data->handle)){ \
91                         DEBUG(0, ("invalid handle!\n")); \
92                                 return False; \
93                 } \
94 }
95 void
96 pdb_mysql_int_field(struct pdb_methods *m,
97                                         struct pdb_mysql_query *q, char *name, int value)
98 {
99         if (!name || strchr(name, '\''))
100                 return;                 /* This field shouldn't be set by us */
101
102         if (q->update) {
103                 q->part1 =
104                         talloc_asprintf_append(q->mem_ctx, q->part1,
105                                                                    "%s = %d,", name, value);
106         } else {
107                 q->part1 =
108                         talloc_asprintf_append(q->mem_ctx, q->part1, "%s,", name);
109                 q->part2 =
110                         talloc_asprintf_append(q->mem_ctx, q->part2, "%d,", value);
111         }
112 }
113
114 static BOOL
115 pdb_mysql_string_field(struct pdb_methods *methods,
116                                            struct pdb_mysql_query *q,
117                                            char *name, const char *value)
118 {
119         char *esc_value;
120         struct pdb_mysql_data *data;
121
122         SET_DATA(data, methods);
123
124         if (!name || !value || !strcmp(value, "") || strchr(name, '\''))
125                 return False;   /* This field shouldn't be set by module */
126
127         esc_value = malloc(strlen(value) * 2 + 1);
128         mysql_real_escape_string(data->handle, esc_value, (char *) value,
129                                                          strlen(value));
130
131         if (q->update) {
132                 q->part1 =
133                         talloc_asprintf_append(q->mem_ctx, q->part1,
134                                                                    "%s = '%s',", name, esc_value);
135         } else {
136                 q->part1 =
137                         talloc_asprintf_append(q->mem_ctx, q->part1, "%s,", name);
138                 q->part2 =
139                         talloc_asprintf_append(q->mem_ctx, q->part2, "'%s',",
140                                                                    esc_value);
141         }
142
143         SAFE_FREE(esc_value);
144
145         return True;
146 }
147
148 static char *
149 config_value(pdb_mysql_data * data, char *name, char *default_value)
150 {
151         if (lp_parm_string(NULL, data->location, name))
152                 return lp_parm_string(NULL, data->location, name);
153
154         return default_value;
155 }
156
157 static char *
158 config_value_write(pdb_mysql_data * data, char *name, char *default_value)
159 {
160         char *v = config_value(data, name, NULL);
161         char *write;
162
163         if (!v)
164                 return default_value;
165
166         write = strchr(v, ':');
167
168         /* Default to the same field as read field */
169         if (!write)
170                 return v;
171
172         write++;
173
174         /* If the field is 0 chars long, we shouldn't write to it */
175         if (!strlen(write) || !strcmp(write, "NULL"))
176                 return NULL;
177
178         /* Otherwise, use the additionally specified */
179         return write;
180 }
181
182 static const char *
183 config_value_read(pdb_mysql_data * data, char *name, char *default_value)
184 {
185         char *v = config_value(data, name, NULL);
186         char *write;
187
188         if (!v)
189                 return default_value;
190
191         write = strchr(v, ':');
192
193         /* If no write is specified, there are no problems */
194         if (!write) {
195                 if (strlen(v) == 0)
196                         return "NULL";
197                 return v;
198         }
199
200         /* Otherwise, we have to cut the ':write_part' */
201         *write = '\0';
202         if (strlen(v) == 0)
203                 return "NULL";
204
205         return v;
206 }
207
208 /* Wrapper for atol that returns 0 if 'a' points to NULL */
209 static long
210 xatol(char *a)
211 {
212         long ret = 0;
213
214         if (a != NULL)
215                 ret = atol(a);
216
217         return ret;
218 }
219
220 static BOOL
221 row_to_sam_account(MYSQL_RES * r, SAM_ACCOUNT * u)
222 {
223         MYSQL_ROW row;
224         pstring temp;
225         unsigned int num_fields;
226         unsigned long *lengths;
227         DOM_SID sid;
228
229         num_fields = mysql_num_fields(r);
230         row = mysql_fetch_row(r);
231         if (!row)
232                 return False;
233
234         pdb_set_logon_time(u, xatol(row[0]), FALSE);
235         pdb_set_logoff_time(u, xatol(row[1]), FALSE);
236         pdb_set_kickoff_time(u, xatol(row[2]), FALSE);
237         pdb_set_pass_last_set_time(u, xatol(row[3]));
238         pdb_set_pass_can_change_time(u, xatol(row[4]), FALSE);
239         pdb_set_pass_must_change_time(u, xatol(row[5]), FALSE);
240         pdb_set_username(u, row[6]);
241         pdb_set_domain(u, row[7]);
242         pdb_set_nt_username(u, row[8]);
243         pdb_set_fullname(u, row[9]);
244         pdb_set_homedir(u, row[10], True);
245         pdb_set_dir_drive(u, row[11], True);
246         pdb_set_logon_script(u, row[12], True);
247         pdb_set_profile_path(u, row[13], True);
248         pdb_set_acct_desc(u, row[14]);
249         pdb_set_workstations(u, row[15]);
250         pdb_set_unknown_str(u, row[16]);
251         pdb_set_munged_dial(u, row[17]);
252
253         if (row[18])
254                 pdb_set_uid(u, xatol(row[18]));
255         if (row[19])
256                 pdb_set_gid(u, xatol(row[19]));
257
258         string_to_sid(&sid, row[20]);
259         pdb_set_user_sid(u, &sid);
260         string_to_sid(&sid, row[21]);
261         pdb_set_group_sid(u, &sid);
262
263         if (pdb_gethexpwd(row[22], temp))
264                 pdb_set_lanman_passwd(u, temp);
265         if (pdb_gethexpwd(row[23], temp))
266                 pdb_set_nt_passwd(u, temp);
267
268         /* Only use plaintext password storage when lanman and nt are
269          * NOT used */
270         if (!row[22] || !row[23])
271                 pdb_set_plaintext_passwd(u, row[24]);
272
273         pdb_set_acct_ctrl(u, xatol(row[25]));
274         pdb_set_unknown_3(u, xatol(row[26]));
275         pdb_set_logon_divs(u, xatol(row[27]));
276         pdb_set_hours_len(u, xatol(row[28]));
277         pdb_set_unknown_5(u, xatol(row[29]));
278         pdb_set_unknown_6(u, xatol(row[30]));
279
280         return True;
281 }
282
283 static BOOL
284 mysqlsam_setsampwent(struct pdb_methods *methods, BOOL update)
285 {
286         struct pdb_mysql_data *data =
287                 (struct pdb_mysql_data *) methods->private_data;
288         char *query;
289         int ret;
290
291         if (!data || !(data->handle)) {
292                 DEBUG(0, ("invalid handle!\n"));
293                 return False;
294         }
295
296         asprintf(&query,
297                          "SELECT %s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s FROM %s",
298                          config_value_read(data, "logon time column",
299                                                            CONFIG_LOGON_TIME_DEFAULT),
300                          config_value_read(data, "logoff time column",
301                                                            CONFIG_LOGOFF_TIME_DEFAULT),
302                          config_value_read(data, "kickoff time column",
303                                                            CONFIG_KICKOFF_TIME_DEFAULT),
304                          config_value_read(data, "pass last set time column",
305                                                            CONFIG_PASS_LAST_SET_TIME_DEFAULT),
306                          config_value_read(data, "pass can change time column",
307                                                            CONFIG_PASS_CAN_CHANGE_TIME_DEFAULT),
308                          config_value_read(data, "pass must change time column",
309                                                            CONFIG_PASS_MUST_CHANGE_TIME_DEFAULT),
310                          config_value_read(data, "username column",
311                                                            CONFIG_USERNAME_DEFAULT),
312                          config_value_read(data, "domain column",
313                                                            CONFIG_DOMAIN_DEFAULT),
314                          config_value_read(data, "nt username column",
315                                                            CONFIG_NT_USERNAME_DEFAULT),
316                          config_value_read(data, "fullname column",
317                                                            CONFIG_FULLNAME_DEFAULT),
318                          config_value_read(data, "home dir column",
319                                                            CONFIG_HOME_DIR_DEFAULT),
320                          config_value_read(data, "dir drive column",
321                                                            CONFIG_DIR_DRIVE_DEFAULT),
322                          config_value_read(data, "logon script column",
323                                                            CONFIG_LOGON_SCRIPT_DEFAULT),
324                          config_value_read(data, "profile path column",
325                                                            CONFIG_PROFILE_PATH_DEFAULT),
326                          config_value_read(data, "acct desc column",
327                                                            CONFIG_ACCT_DESC_DEFAULT),
328                          config_value_read(data, "workstations column",
329                                                            CONFIG_WORKSTATIONS_DEFAULT),
330                          config_value_read(data, "unknown string column",
331                                                            CONFIG_UNKNOWN_STR_DEFAULT),
332                          config_value_read(data, "munged dial column",
333                                                            CONFIG_MUNGED_DIAL_DEFAULT),
334                          config_value_read(data, "uid column", CONFIG_UID_DEFAULT),
335                          config_value_read(data, "gid column", CONFIG_GID_DEFAULT),
336                          config_value_read(data, "user sid column",
337                                                            CONFIG_USER_SID_DEFAULT),
338                          config_value_read(data, "group sid column",
339                                                            CONFIG_GROUP_SID_DEFAULT),
340                          config_value_read(data, "lanman pass column",
341                                                            CONFIG_LM_PW_DEFAULT),
342                          config_value_read(data, "nt pass column",
343                                                            CONFIG_NT_PW_DEFAULT),
344                          config_value_read(data, "plain pass column",
345                                                            CONFIG_PLAIN_PW_DEFAULT),
346                          config_value_read(data, "acct ctrl column",
347                                                            CONFIG_ACCT_CTRL_DEFAULT),
348                          config_value_read(data, "unknown 3 column",
349                                                            CONFIG_UNKNOWN_3_DEFAULT),
350                          config_value_read(data, "logon divs column",
351                                                            CONFIG_LOGON_DIVS_DEFAULT),
352                          config_value_read(data, "hours len column",
353                                                            CONFIG_HOURS_LEN_DEFAULT),
354                          config_value_read(data, "unknown 5 column",
355                                                            CONFIG_UNKNOWN_5_DEFAULT),
356                          config_value_read(data, "unknown 6 column",
357                                                            CONFIG_UNKNOWN_6_DEFAULT),
358                          config_value(data, "table", CONFIG_TABLE_DEFAULT)
359                                  );
360         
361         ret = mysql_query(data->handle, query);
362         SAFE_FREE(query);
363
364         if (ret) {
365                 DEBUG(0,
366                            ("Error executing query: %s\n", mysql_error(data->handle)));
367                 return False;
368         }
369
370         data->pwent = mysql_store_result(data->handle);
371
372         if (data->pwent == NULL) {
373                 DEBUG(0,
374                         ("Error storing results: %s\n", mysql_error(data->handle)));
375                 return False;
376         }
377         
378         DEBUG(5,
379                 ("mysqlsam_setsampwent succeeded(%d results)!\n",
380                                 mysql_num_fields(data->pwent)));
381         
382         return True;
383 }
384
385 /***************************************************************
386   End enumeration of the passwd list.
387  ****************************************************************/
388
389 static void
390 mysqlsam_endsampwent(struct pdb_methods *methods)
391 {
392         struct pdb_mysql_data *data =
393                 (struct pdb_mysql_data *) methods->private_data;
394
395         if (data == NULL) {
396                 DEBUG(0, ("invalid handle!\n"));
397                 return;
398         }
399
400         if (data->pwent != NULL)
401                 mysql_free_result(data->pwent);
402
403         data->pwent = NULL;
404
405         DEBUG(5, ("mysql_endsampwent called\n"));
406 }
407
408 /*****************************************************************
409   Get one SAM_ACCOUNT from the list (next in line)
410  *****************************************************************/
411
412 static BOOL
413 mysqlsam_getsampwent(struct pdb_methods *methods, SAM_ACCOUNT * user)
414 {
415         struct pdb_mysql_data *data;
416
417         SET_DATA(data, methods);
418
419         if (data->pwent == NULL) {
420                 DEBUG(0, ("invalid pwent\n"));
421                 return False;
422         }
423
424         return row_to_sam_account(data->pwent, user);
425 }
426
427 BOOL
428 mysqlsam_select_by_field(struct pdb_methods * methods, SAM_ACCOUNT * user,
429                                                  const char *field, const char *sname)
430 {
431         char *esc_sname;
432         char *query;
433         int ret;
434         MYSQL_RES *res;
435         struct pdb_mysql_data *data;
436
437         SET_DATA(data, methods);
438
439         esc_sname = malloc(strlen(sname) * 2 + 1);
440         if (!esc_sname) {
441                 DEBUG(0, ("Not enough memory available!\n"));
442                 return False;
443         }
444
445         DEBUG(5,
446                   ("mysqlsam_select_by_field: getting data where %s = %s(nonescaped)\n",
447                    field, sname));
448
449         /* Escape sname */
450         mysql_real_escape_string(data->handle, esc_sname, (char *) sname,
451                                                          strlen(sname));
452
453         if (user == NULL) {
454                 DEBUG(0, ("pdb_getsampwnam: SAM_ACCOUNT is NULL.\n"));
455                 SAFE_FREE(esc_sname);
456                 return False;
457         }
458
459         asprintf(&query,
460                          "SELECT %s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s FROM %s WHERE %s = '%s'",
461                          config_value_read(data, "logon time column",
462                                                            CONFIG_LOGON_TIME_DEFAULT),
463                          config_value_read(data, "logoff time column",
464                                                            CONFIG_LOGOFF_TIME_DEFAULT),
465                          config_value_read(data, "kickoff time column",
466                                                            CONFIG_KICKOFF_TIME_DEFAULT),
467                          config_value_read(data, "pass last set time column",
468                                                            CONFIG_PASS_LAST_SET_TIME_DEFAULT),
469                          config_value_read(data, "pass can change time column",
470                                                            CONFIG_PASS_CAN_CHANGE_TIME_DEFAULT),
471                          config_value_read(data, "pass must change time column",
472                                                            CONFIG_PASS_MUST_CHANGE_TIME_DEFAULT),
473                          config_value_read(data, "username column",
474                                                            CONFIG_USERNAME_DEFAULT),
475                          config_value_read(data, "domain column",
476                                                            CONFIG_DOMAIN_DEFAULT),
477                          config_value_read(data, "nt username column",
478                                                            CONFIG_NT_USERNAME_DEFAULT),
479                          config_value_read(data, "fullname column",
480                                                            CONFIG_FULLNAME_DEFAULT),
481                          config_value_read(data, "home dir column",
482                                                            CONFIG_HOME_DIR_DEFAULT),
483                          config_value_read(data, "dir drive column",
484                                                            CONFIG_DIR_DRIVE_DEFAULT),
485                          config_value_read(data, "logon script column",
486                                                            CONFIG_LOGON_SCRIPT_DEFAULT),
487                          config_value_read(data, "profile path column",
488                                                            CONFIG_PROFILE_PATH_DEFAULT),
489                          config_value_read(data, "acct desc column",
490                                                            CONFIG_ACCT_DESC_DEFAULT),
491                          config_value_read(data, "workstations column",
492                                                            CONFIG_WORKSTATIONS_DEFAULT),
493                          config_value_read(data, "unknown string column",
494                                                            CONFIG_UNKNOWN_STR_DEFAULT),
495                          config_value_read(data, "munged dial column",
496                                                            CONFIG_MUNGED_DIAL_DEFAULT),
497                          config_value_read(data, "uid column", CONFIG_UID_DEFAULT),
498                          config_value_read(data, "gid column", CONFIG_GID_DEFAULT),
499                          config_value_read(data, "user sid column",
500                                                            CONFIG_USER_SID_DEFAULT),
501                          config_value_read(data, "group sid column",
502                                                            CONFIG_GROUP_SID_DEFAULT),
503                          config_value_read(data, "lanman pass column",
504                                                            CONFIG_LM_PW_DEFAULT),
505                          config_value_read(data, "nt pass column",
506                                                            CONFIG_NT_PW_DEFAULT),
507                          config_value_read(data, "plain pass column",
508                                                            CONFIG_PLAIN_PW_DEFAULT),
509                          config_value_read(data, "acct ctrl column",
510                                                            CONFIG_ACCT_CTRL_DEFAULT),
511                          config_value_read(data, "unknown 3 column",
512                                                            CONFIG_UNKNOWN_3_DEFAULT),
513                          config_value_read(data, "logon divs column",
514                                                            CONFIG_LOGON_DIVS_DEFAULT),
515                          config_value_read(data, "hours len column",
516                                                            CONFIG_HOURS_LEN_DEFAULT),
517                          config_value_read(data, "unknown 5 column",
518                                                            CONFIG_UNKNOWN_5_DEFAULT),
519                          config_value_read(data, "unknown 6 column",
520                                                            CONFIG_UNKNOWN_6_DEFAULT),
521                          config_value(data, "table", CONFIG_TABLE_DEFAULT), field,
522                          esc_sname);
523         
524         SAFE_FREE(esc_sname);
525         
526         ret = mysql_query(data->handle, query);
527         
528         SAFE_FREE(query);
529         
530         if (ret) {
531                 DEBUG(0,
532                         ("Error while executing MySQL query: %s\n",
533                                 mysql_error(data->handle)));
534                 return False;
535         }
536         
537         res = mysql_store_result(data->handle);
538         if (res == NULL) {
539                 DEBUG(0,
540                         ("Error storing results: %s\n", mysql_error(data->handle)));
541                 return False;
542         }
543         
544         ret = row_to_sam_account(res, user);
545         mysql_free_result(res);
546
547         return ret;
548 }
549
550 /******************************************************************
551   Lookup a name in the SAM database
552  ******************************************************************/
553
554 static BOOL
555 mysqlsam_getsampwnam(struct pdb_methods *methods, SAM_ACCOUNT * user,
556                                          const char *sname)
557 {
558         struct pdb_mysql_data *data;
559
560         SET_DATA(data, methods);
561
562         if (!sname) {
563                 DEBUG(0, ("invalid name specified"));
564                 return False;
565         }
566         return mysqlsam_select_by_field(methods, user,
567                         config_value_read(data, "username column",
568                                 CONFIG_USERNAME_DEFAULT), sname);
569 }
570
571
572 /***************************************************************************
573   Search by sid
574  **************************************************************************/
575
576 static BOOL
577 mysqlsam_getsampwsid(struct pdb_methods *methods, SAM_ACCOUNT * user,
578                                          const DOM_SID * sid)
579 {
580         BOOL ret = False;
581         struct pdb_mysql_data *data;
582         fstring sid_str;
583
584         SET_DATA(data, methods);
585
586         sid_to_string(sid_str, sid);
587
588         ret =
589                 mysqlsam_select_by_field(methods, user,
590                         config_value_read(data, "user sid column",
591                                 CONFIG_USER_SID_DEFAULT), sid_str);
592
593         return ret;
594 }
595
596 /***************************************************************************
597   Delete a SAM_ACCOUNT
598  ****************************************************************************/
599
600 static BOOL
601 mysqlsam_delete_sam_account(struct pdb_methods *methods,
602                                                         SAM_ACCOUNT * sam_pass)
603 {
604         const char *sname = pdb_get_username(sam_pass);
605         char *esc;
606         char *query;
607         int ret;
608         struct pdb_mysql_data *data;
609
610         SET_DATA(data, methods);
611
612         if (!methods) {
613                 DEBUG(0, ("invalid methods!\n"));
614                 return False;
615         }
616
617         data = (struct pdb_mysql_data *) methods->private_data;
618         if (!data || !(data->handle)) {
619                 DEBUG(0, ("invalid handle!\n"));
620                 return False;
621         }
622
623         if (!sname) {
624                 DEBUG(0, ("invalid name specified\n"));
625                 return False;
626         }
627
628         /* Escape sname */
629         esc = malloc(strlen(sname) * 2 + 1);
630         if (!esc) {
631                 DEBUG(0, ("Can't allocate memory to store escaped name\n"));
632                 return False;
633         }
634         mysql_real_escape_string(data->handle, esc, (char *) sname,
635                                                          strlen(sname));
636
637         asprintf(&query, "DELETE FROM %s WHERE %s = '%s'",
638                          config_value(data, "table", CONFIG_TABLE_DEFAULT),
639                          config_value_read(data, "username column",
640                                                            CONFIG_USERNAME_DEFAULT), esc);
641
642         SAFE_FREE(esc);
643
644         ret = mysql_query(data->handle, query);
645
646         SAFE_FREE(query);
647
648         if (ret) {
649                 DEBUG(0,
650                           ("Error while executing query: %s\n",
651                            mysql_error(data->handle)));
652                 return False;
653         }
654
655         DEBUG(5, ("User '%s' deleted\n", sname));
656         return True;
657 }
658
659 static BOOL
660 mysqlsam_replace_sam_account(struct pdb_methods *methods,
661                                                          const SAM_ACCOUNT * newpwd, char isupdate)
662 {
663         pstring temp;
664         uint32 store = pdb_get_init_flag(newpwd);
665         struct pdb_mysql_data *data;
666         pdb_mysql_query query;
667         fstring sid_str;
668
669         if (!methods) {
670                 DEBUG(0, ("invalid methods!\n"));
671                 return False;
672         }
673
674         data = (struct pdb_mysql_data *) methods->private_data;
675         if (data == NULL || data->handle == NULL) {
676                 DEBUG(0, ("invalid handle!\n"));
677                 return False;
678         }
679         query.update = isupdate;
680
681         /* I know this is somewhat overkill but only the talloc 
682          * functions have asprint_append and the 'normal' asprintf 
683          * is a GNU extension */
684         query.mem_ctx = talloc_init();
685         query.part2 = talloc_asprintf(query.mem_ctx, "%s", "");
686         if (query.update) {
687                 query.part1 =
688                         talloc_asprintf(query.mem_ctx, "UPDATE %s SET ",
689                                                         config_value(data, "table",
690                                                                                  CONFIG_TABLE_DEFAULT));
691         } else {
692                 query.part1 =
693                         talloc_asprintf(query.mem_ctx, "INSERT INTO %s (",
694                                                         config_value(data, "table",
695                                                                                  CONFIG_TABLE_DEFAULT));
696         }
697
698         pdb_mysql_int_field(methods, &query,
699                                                 config_value_write(data, "acct ctrl column",
700                                                                                    CONFIG_ACCT_CTRL_DEFAULT),
701                                                 pdb_get_acct_ctrl(newpwd));
702
703         if (store & FLAG_SAM_LOGONTIME) {
704                 pdb_mysql_int_field(methods, &query,
705                                                         config_value_write(data,
706                                                                                            "logon time column",
707                                                                                            CONFIG_LOGON_TIME_DEFAULT),
708                                                         pdb_get_logon_time(newpwd));
709         }
710
711         if (store & FLAG_SAM_LOGOFFTIME) {
712                 pdb_mysql_int_field(methods, &query,
713                                                         config_value_write(data,
714                                                                                            "logoff time column",
715                                                                                            CONFIG_LOGOFF_TIME_DEFAULT),
716                                                         pdb_get_logoff_time(newpwd));
717         }
718
719         if (store & FLAG_SAM_KICKOFFTIME) {
720                 pdb_mysql_int_field(methods, &query,
721                                                         config_value_write(data,
722                                                                                            "kickoff time column",
723                                                                                            CONFIG_KICKOFF_TIME_DEFAULT),
724                                                         pdb_get_kickoff_time(newpwd));
725         }
726
727         if (store & FLAG_SAM_CANCHANGETIME) {
728                 pdb_mysql_int_field(methods, &query,
729                                                         config_value_write(data,
730                                                                                            "pass can change time column",
731                                                                                            CONFIG_PASS_CAN_CHANGE_TIME_DEFAULT),
732                                                         pdb_get_pass_can_change_time(newpwd));
733         }
734
735         if (store & FLAG_SAM_MUSTCHANGETIME) {
736                 pdb_mysql_int_field(methods, &query,
737                                                         config_value_write(data,
738                                                                                            "pass must change time column",
739                                                                                            CONFIG_PASS_MUST_CHANGE_TIME_DEFAULT),
740                                                         pdb_get_pass_must_change_time(newpwd));
741         }
742
743         if (pdb_get_pass_last_set_time(newpwd)) {
744                 pdb_mysql_int_field(methods, &query,
745                                                         config_value_write(data,
746                                                                                            "pass must change time column",
747                                                                                            CONFIG_PASS_LAST_SET_TIME_DEFAULT),
748                                                         pdb_get_pass_last_set_time(newpwd));
749         }
750
751         if (pdb_get_hours_len(newpwd)) {
752                 pdb_mysql_int_field(methods, &query,
753                                                         config_value_write(data,
754                                                                                            "hours len column",
755                                                                                            CONFIG_HOURS_LEN_DEFAULT),
756                                                         pdb_get_hours_len(newpwd));
757         }
758
759         if (pdb_get_logon_divs(newpwd)) {
760                 pdb_mysql_int_field(methods, &query,
761                                                         config_value_write(data,
762                                                                                            "logon divs column",
763                                                                                            CONFIG_LOGON_DIVS_DEFAULT),
764                                                         pdb_get_logon_divs(newpwd));
765         }
766
767         if (store & FLAG_SAM_UID) {
768                 pdb_mysql_int_field(methods, &query,
769                                                         config_value_write(data, "uid column",
770                                                                                            CONFIG_UID_DEFAULT),
771                                                         pdb_get_uid(newpwd));
772         }
773
774         if (store & FLAG_SAM_GID) {
775                 pdb_mysql_int_field(methods, &query,
776                                                         config_value_write(data, "gid column",
777                                                                                            CONFIG_GID_DEFAULT),
778                                                         pdb_get_gid(newpwd));
779         }
780
781         pdb_mysql_string_field(methods, &query,
782                                                    config_value_write(data, "user sid column",
783                                                                                           CONFIG_USER_SID_DEFAULT),
784                                                    sid_to_string(sid_str, (DOM_SID *)
785                                                                                  pdb_get_user_sid(newpwd)));
786
787         pdb_mysql_string_field(methods, &query,
788                                                    config_value_write(data, "group sid column",
789                                                                                           CONFIG_GROUP_SID_DEFAULT),
790                                                    sid_to_string(sid_str, (DOM_SID *)
791                                                                                  pdb_get_group_sid(newpwd)));
792
793         pdb_mysql_string_field(methods, &query,
794                                                    config_value_write(data, "username column",
795                                                                                           CONFIG_USERNAME_DEFAULT),
796                                                    pdb_get_username(newpwd));
797
798         pdb_mysql_string_field(methods, &query,
799                                                    config_value_write(data, "domain column",
800                                                                                           CONFIG_DOMAIN_DEFAULT),
801                                                    pdb_get_domain(newpwd));
802
803         pdb_mysql_string_field(methods, &query,
804                                                    config_value_write(data,
805                                                                                           "nt username column",
806                                                                                           CONFIG_NT_USERNAME_DEFAULT),
807                                                    pdb_get_nt_username(newpwd));
808
809         pdb_mysql_string_field(methods, &query,
810                                                    config_value_write(data, "fullname column",
811                                                                                           CONFIG_FULLNAME_DEFAULT),
812                                                    pdb_get_fullname(newpwd));
813
814         pdb_mysql_string_field(methods, &query,
815                                                    config_value_write(data,
816                                                                                           "logon script column",
817                                                                                           CONFIG_LOGON_SCRIPT_DEFAULT),
818                                                    pdb_get_logon_script(newpwd));
819
820         pdb_mysql_string_field(methods, &query,
821                                                    config_value_write(data,
822                                                                                           "profile path column",
823                                                                                           CONFIG_PROFILE_PATH_DEFAULT),
824                                                    pdb_get_profile_path(newpwd));
825
826         pdb_mysql_string_field(methods, &query,
827                                                    config_value_write(data, "dir drive column",
828                                                                                           CONFIG_DIR_DRIVE_DEFAULT),
829                                                    pdb_get_dir_drive(newpwd));
830
831         pdb_mysql_string_field(methods, &query,
832                                                    config_value_write(data, "home dir column",
833                                                                                           CONFIG_HOME_DIR_DEFAULT),
834                                                    pdb_get_homedir(newpwd));
835
836         pdb_mysql_string_field(methods, &query,
837                                                    config_value_write(data,
838                                                                                           "workstations column",
839                                                                                           CONFIG_WORKSTATIONS_DEFAULT),
840                                                    pdb_get_workstations(newpwd));
841
842         pdb_mysql_string_field(methods, &query,
843                                                    config_value_write(data,
844                                                                                           "unknown string column",
845                                                                                           CONFIG_UNKNOWN_STR_DEFAULT),
846                                                    pdb_get_workstations(newpwd));
847
848         pdb_sethexpwd(temp, pdb_get_lanman_passwd(newpwd),
849                                   pdb_get_acct_ctrl(newpwd));
850         pdb_mysql_string_field(methods, &query,
851                                                    config_value_write(data,
852                                                                                           "lanman pass column",
853                                                                                           CONFIG_LM_PW_DEFAULT), temp);
854
855         pdb_sethexpwd(temp, pdb_get_nt_passwd(newpwd),
856                                   pdb_get_acct_ctrl(newpwd));
857         pdb_mysql_string_field(methods, &query,
858                                                    config_value_write(data, "nt pass column",
859                                                                                           CONFIG_NT_PW_DEFAULT), temp);
860
861         if (query.update) {
862                 query.part1[strlen(query.part1) - 1] = '\0';
863                 query.part1 =
864                         talloc_asprintf_append(query.mem_ctx, query.part1,
865                                                                    " WHERE %s = '%s'",
866                                                                    config_value_read(data,
867                                                                                                          "user sid column",
868                                                                                                          CONFIG_USER_SID_DEFAULT),
869                                                                    sid_to_string(sid_str, (DOM_SID *)
870                                                                                                  pdb_get_user_sid
871                                                                                                  (newpwd)));
872         } else {
873                 query.part2[strlen(query.part2) - 1] = ')';
874                 query.part1[strlen(query.part1) - 1] = ')';
875                 query.part1 =
876                         talloc_asprintf_append(query.mem_ctx, query.part1,
877                                                                    " VALUES (%s", query.part2);
878         }
879
880         DEBUG(0, ("%s\n", query.part1));
881         /* Execute the query */
882         if (mysql_query(data->handle, query.part1)) {
883                 DEBUG(0,
884                           ("Error executing %s, %s\n", query.part1,
885                            mysql_error(data->handle)));
886                 return False;
887         }
888         talloc_destroy(query.mem_ctx);
889         return True;
890 }
891
892 static BOOL
893 mysqlsam_add_sam_account(struct pdb_methods *methods, SAM_ACCOUNT * newpwd)
894 {
895         return mysqlsam_replace_sam_account(methods, newpwd, 0);
896 }
897
898 static BOOL
899 mysqlsam_update_sam_account(struct pdb_methods *methods,
900                                                         SAM_ACCOUNT * newpwd)
901 {
902         return mysqlsam_replace_sam_account(methods, newpwd, 1);
903 }
904
905 NTSTATUS
906 pdb_init(PDB_CONTEXT * pdb_context, PDB_METHODS ** pdb_method,
907                  char *location)
908 {
909         NTSTATUS nt_status;
910         struct pdb_mysql_data *data;
911
912         mysqlsam_debug_level = debug_add_class("mysqlsam");
913         if (mysqlsam_debug_level == -1) {
914                 mysqlsam_debug_level = DBGC_ALL;
915                 DEBUG(0,
916                           ("mysqlsam: Couldn't register custom debugging class!\n"));
917         }
918
919         if (!pdb_context) {
920                 DEBUG(0, ("invalid pdb_methods specified\n"));
921                 return NT_STATUS_UNSUCCESSFUL;
922         }
923
924         if (!NT_STATUS_IS_OK
925                 (nt_status = make_pdb_methods(pdb_context->mem_ctx, pdb_method))) {
926                 return nt_status;
927         }
928
929         (*pdb_method)->name = "mysqlsam";
930
931         (*pdb_method)->setsampwent = mysqlsam_setsampwent;
932         (*pdb_method)->endsampwent = mysqlsam_endsampwent;
933         (*pdb_method)->getsampwent = mysqlsam_getsampwent;
934         (*pdb_method)->getsampwnam = mysqlsam_getsampwnam;
935         (*pdb_method)->getsampwsid = mysqlsam_getsampwsid;
936         (*pdb_method)->add_sam_account = mysqlsam_add_sam_account;
937         (*pdb_method)->update_sam_account = mysqlsam_update_sam_account;
938         (*pdb_method)->delete_sam_account = mysqlsam_delete_sam_account;
939
940         data = talloc(pdb_context->mem_ctx, sizeof(struct pdb_mysql_data));
941         (*pdb_method)->private_data = data;
942         data->handle = NULL;
943         data->pwent = NULL;
944
945         if (!location) {
946                 DEBUG(0, ("No identifier specified. See README for details\n"));
947                 return NT_STATUS_INVALID_PARAMETER;
948         }
949
950         data->location = smb_xstrdup(location);
951
952         DEBUG(1,
953                   ("Connecting to database server, host: %s, user: %s, password: %s, database: %s, port: %d\n",
954                    config_value(data, "mysql host", CONFIG_HOST_DEFAULT),
955                    config_value(data, "mysql user", CONFIG_USER_DEFAULT),
956                    config_value(data, "mysql password", CONFIG_PASS_DEFAULT),
957                    config_value(data, "mysql database", CONFIG_DB_DEFAULT),
958                    xatol(config_value(data, "mysql port", CONFIG_PORT_DEFAULT))));
959
960         /* Do the mysql initialization */
961         data->handle = mysql_init(NULL);
962         if (!data->handle) {
963                 DEBUG(0, ("Failed to connect to server\n"));
964                 return NT_STATUS_UNSUCCESSFUL;
965         }
966         /* Process correct entry in $HOME/.my.conf */
967         if (!mysql_real_connect(data->handle,
968                         config_value(data, "mysql host", CONFIG_HOST_DEFAULT),
969                         config_value(data, "mysql user", CONFIG_USER_DEFAULT),
970                         config_value(data, "mysql password", CONFIG_PASS_DEFAULT),
971                         config_value(data, "mysql database", CONFIG_DB_DEFAULT),
972                         xatol(config_value (data, "mysql port", CONFIG_PORT_DEFAULT)), 
973                         NULL, 0)) {
974                 DEBUG(0,
975                           ("Failed to connect to mysql database: error: %s\n",
976                            mysql_error(data->handle)));
977                 return NT_STATUS_UNSUCCESSFUL;
978         }
979         
980         DEBUG(5, ("Connected to mysql db\n"));
981
982         return NT_STATUS_OK;
983 }