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