- Put functions for generating SQL queries in pdb_sql.c
[Samba.git] / source / passdb / pdb_mysql.c
blobacc1eff8298f3c1eeed684cc9a566b801d19108c
1 /*
2 * MySQL password backend for samba
3 * Copyright (C) Jelmer Vernooij 2002-2004
4 *
5 * This program is free software; you can redistribute it and/or modify it under
6 * the terms of the GNU General Public License as published by the Free
7 * Software Foundation; either version 2 of the License, or (at your option)
8 * any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
15 * You should have received a copy of the GNU General Public License along with
16 * this program; if not, write to the Free Software Foundation, Inc., 675
17 * Mass Ave, Cambridge, MA 02139, USA.
20 #include "includes.h"
21 #include <mysql/mysql.h>
23 #define CONFIG_HOST_DEFAULT "localhost"
24 #define CONFIG_USER_DEFAULT "samba"
25 #define CONFIG_PASS_DEFAULT ""
26 #define CONFIG_PORT_DEFAULT "3306"
27 #define CONFIG_DB_DEFAULT "samba"
29 static int mysqlsam_debug_level = DBGC_ALL;
31 #undef DBGC_CLASS
32 #define DBGC_CLASS mysqlsam_debug_level
34 typedef struct pdb_mysql_data {
35 MYSQL *handle;
36 MYSQL_RES *pwent;
37 const char *location;
38 } pdb_mysql_data;
40 #define SET_DATA(data,methods) { \
41 if(!methods){ \
42 DEBUG(0, ("invalid methods!\n")); \
43 return NT_STATUS_INVALID_PARAMETER; \
44 } \
45 data = (struct pdb_mysql_data *)methods->private_data; \
46 if(!data || !(data->handle)){ \
47 DEBUG(0, ("invalid handle!\n")); \
48 return NT_STATUS_INVALID_HANDLE; \
49 } \
52 #define config_value( data, name, default_value ) \
53 lp_parm_const_string( GLOBAL_SECTION_SNUM, (data)->location, name, default_value )
55 static long xatol(const char *d)
57 if(!d) return 0;
58 return atol(d);
61 static NTSTATUS row_to_sam_account(MYSQL_RES * r, SAM_ACCOUNT * u)
63 MYSQL_ROW row;
64 pstring temp;
65 unsigned int num_fields;
66 DOM_SID sid;
68 num_fields = mysql_num_fields(r);
69 row = mysql_fetch_row(r);
70 if (!row)
71 return NT_STATUS_INVALID_PARAMETER;
73 pdb_set_logon_time(u, xatol(row[0]), PDB_SET);
74 pdb_set_logoff_time(u, xatol(row[1]), PDB_SET);
75 pdb_set_kickoff_time(u, xatol(row[2]), PDB_SET);
76 pdb_set_pass_last_set_time(u, xatol(row[3]), PDB_SET);
77 pdb_set_pass_can_change_time(u, xatol(row[4]), PDB_SET);
78 pdb_set_pass_must_change_time(u, xatol(row[5]), PDB_SET);
79 pdb_set_username(u, row[6], PDB_SET);
80 pdb_set_domain(u, row[7], PDB_SET);
81 pdb_set_nt_username(u, row[8], PDB_SET);
82 pdb_set_fullname(u, row[9], PDB_SET);
83 pdb_set_homedir(u, row[10], PDB_SET);
84 pdb_set_dir_drive(u, row[11], PDB_SET);
85 pdb_set_logon_script(u, row[12], PDB_SET);
86 pdb_set_profile_path(u, row[13], PDB_SET);
87 pdb_set_acct_desc(u, row[14], PDB_SET);
88 pdb_set_workstations(u, row[15], PDB_SET);
89 pdb_set_unknown_str(u, row[16], PDB_SET);
90 pdb_set_munged_dial(u, row[17], PDB_SET);
92 if(!row[18] || !string_to_sid(&sid, row[18])) {
93 DEBUG(0,("No user SID retrieved from database!\n"));
94 } else {
95 pdb_set_user_sid(u, &sid, PDB_SET);
98 if(row[19]) {
99 string_to_sid(&sid, row[19]);
100 pdb_set_group_sid(u, &sid, PDB_SET);
103 if (pdb_gethexpwd(row[20], temp))
104 pdb_set_lanman_passwd(u, temp, PDB_SET);
105 if (pdb_gethexpwd(row[21], temp))
106 pdb_set_nt_passwd(u, temp, PDB_SET);
108 /* Only use plaintext password storage when lanman and nt are
109 * NOT used */
110 if (!row[20] || !row[21])
111 pdb_set_plaintext_passwd(u, row[22]);
113 pdb_set_acct_ctrl(u, xatol(row[23]), PDB_SET);
114 pdb_set_unknown_3(u, xatol(row[24]), PDB_SET);
115 pdb_set_logon_divs(u, xatol(row[25]), PDB_SET);
116 pdb_set_hours_len(u, xatol(row[26]), PDB_SET);
117 pdb_set_bad_password_count(u, xatol(row[27]), PDB_SET);
118 pdb_set_logon_count(u, xatol(row[28]), PDB_SET);
119 pdb_set_unknown_6(u, xatol(row[29]), PDB_SET);
121 return NT_STATUS_OK;
124 static NTSTATUS mysqlsam_setsampwent(struct pdb_methods *methods, BOOL update)
126 struct pdb_mysql_data *data =
127 (struct pdb_mysql_data *) methods->private_data;
128 char *query;
129 int ret;
131 if (!data || !(data->handle)) {
132 DEBUG(0, ("invalid handle!\n"));
133 return NT_STATUS_INVALID_HANDLE;
136 query = sql_account_query_select(data->location, update, SQL_SEARCH_NONE, NULL);
138 ret = mysql_query(data->handle, query);
139 SAFE_FREE(query);
141 if (ret) {
142 DEBUG(0,
143 ("Error executing MySQL query %s\n", mysql_error(data->handle)));
144 return NT_STATUS_UNSUCCESSFUL;
147 data->pwent = mysql_store_result(data->handle);
149 if (data->pwent == NULL) {
150 DEBUG(0,
151 ("Error storing results: %s\n", mysql_error(data->handle)));
152 return NT_STATUS_UNSUCCESSFUL;
155 DEBUG(5,
156 ("mysqlsam_setsampwent succeeded(%llu results)!\n",
157 mysql_num_rows(data->pwent)));
159 return NT_STATUS_OK;
162 /***************************************************************
163 End enumeration of the passwd list.
164 ****************************************************************/
166 static void mysqlsam_endsampwent(struct pdb_methods *methods)
168 struct pdb_mysql_data *data =
169 (struct pdb_mysql_data *) methods->private_data;
171 if (data == NULL) {
172 DEBUG(0, ("invalid handle!\n"));
173 return;
176 if (data->pwent != NULL)
177 mysql_free_result(data->pwent);
179 data->pwent = NULL;
181 DEBUG(5, ("mysql_endsampwent called\n"));
184 /*****************************************************************
185 Get one SAM_ACCOUNT from the list (next in line)
186 *****************************************************************/
188 static NTSTATUS mysqlsam_getsampwent(struct pdb_methods *methods, SAM_ACCOUNT * user)
190 struct pdb_mysql_data *data;
192 SET_DATA(data, methods);
194 if (data->pwent == NULL) {
195 DEBUG(0, ("invalid pwent\n"));
196 return NT_STATUS_INVALID_PARAMETER;
199 return row_to_sam_account(data->pwent, user);
202 static NTSTATUS mysqlsam_select_by_field(struct pdb_methods * methods, SAM_ACCOUNT * user,
203 enum sql_search_field field, const char *sname)
205 char *esc_sname;
206 char *query;
207 NTSTATUS ret;
208 MYSQL_RES *res;
209 int mysql_ret;
210 struct pdb_mysql_data *data;
211 char *tmp_sname;
213 SET_DATA(data, methods);
215 esc_sname = malloc(strlen(sname) * 2 + 1);
216 if (!esc_sname) {
217 return NT_STATUS_NO_MEMORY;
220 tmp_sname = smb_xstrdup(sname);
222 /* Escape sname */
223 mysql_real_escape_string(data->handle, esc_sname, tmp_sname,
224 strlen(tmp_sname));
226 SAFE_FREE(tmp_sname);
228 if (user == NULL) {
229 DEBUG(0, ("pdb_getsampwnam: SAM_ACCOUNT is NULL.\n"));
230 SAFE_FREE(esc_sname);
231 return NT_STATUS_INVALID_PARAMETER;
234 query = sql_account_query_select(data->location, True, field, esc_sname);
236 SAFE_FREE(esc_sname);
238 DEBUG(5, ("Executing query %s\n", query));
240 mysql_ret = mysql_query(data->handle, query);
242 SAFE_FREE(query);
244 if (mysql_ret) {
245 DEBUG(0,
246 ("Error while executing MySQL query %s\n",
247 mysql_error(data->handle)));
248 return NT_STATUS_UNSUCCESSFUL;
251 res = mysql_store_result(data->handle);
252 if (res == NULL) {
253 DEBUG(0,
254 ("Error storing results: %s\n", mysql_error(data->handle)));
255 return NT_STATUS_UNSUCCESSFUL;
258 ret = row_to_sam_account(res, user);
259 mysql_free_result(res);
261 return ret;
264 /******************************************************************
265 Lookup a name in the SAM database
266 ******************************************************************/
268 static NTSTATUS mysqlsam_getsampwnam(struct pdb_methods *methods, SAM_ACCOUNT * user,
269 const char *sname)
271 struct pdb_mysql_data *data;
273 SET_DATA(data, methods);
275 if (!sname) {
276 DEBUG(0, ("invalid name specified"));
277 return NT_STATUS_INVALID_PARAMETER;
280 return mysqlsam_select_by_field(methods, user,
281 SQL_SEARCH_USER_NAME, sname);
285 /***************************************************************************
286 Search by sid
287 **************************************************************************/
289 static NTSTATUS mysqlsam_getsampwsid(struct pdb_methods *methods, SAM_ACCOUNT * user,
290 const DOM_SID * sid)
292 struct pdb_mysql_data *data;
293 fstring sid_str;
295 SET_DATA(data, methods);
297 sid_to_string(sid_str, sid);
299 return mysqlsam_select_by_field(methods, user, SQL_SEARCH_USER_SID, sid_str);
302 /***************************************************************************
303 Delete a SAM_ACCOUNT
304 ****************************************************************************/
306 static NTSTATUS mysqlsam_delete_sam_account(struct pdb_methods *methods,
307 SAM_ACCOUNT * sam_pass)
309 const char *sname = pdb_get_username(sam_pass);
310 char *esc;
311 char *query;
312 int ret;
313 struct pdb_mysql_data *data;
314 char *tmp_sname;
316 SET_DATA(data, methods);
318 if (!methods) {
319 DEBUG(0, ("invalid methods!\n"));
320 return NT_STATUS_INVALID_PARAMETER;
323 data = (struct pdb_mysql_data *) methods->private_data;
324 if (!data || !(data->handle)) {
325 DEBUG(0, ("invalid handle!\n"));
326 return NT_STATUS_INVALID_HANDLE;
329 if (!sname) {
330 DEBUG(0, ("invalid name specified\n"));
331 return NT_STATUS_INVALID_PARAMETER;
334 /* Escape sname */
335 esc = malloc(strlen(sname) * 2 + 1);
336 if (!esc) {
337 DEBUG(0, ("Can't allocate memory to store escaped name\n"));
338 return NT_STATUS_NO_MEMORY;
341 tmp_sname = smb_xstrdup(sname);
343 mysql_real_escape_string(data->handle, esc, tmp_sname,
344 strlen(tmp_sname));
346 SAFE_FREE(tmp_sname);
348 query = sql_account_query_delete(data->location, esc);
350 SAFE_FREE(esc);
352 ret = mysql_query(data->handle, query);
354 SAFE_FREE(query);
356 if (ret) {
357 DEBUG(0,
358 ("Error while executing query: %s\n",
359 mysql_error(data->handle)));
360 return NT_STATUS_UNSUCCESSFUL;
363 DEBUG(5, ("User '%s' deleted\n", sname));
364 return NT_STATUS_OK;
367 static NTSTATUS mysqlsam_replace_sam_account(struct pdb_methods *methods,
368 const SAM_ACCOUNT * newpwd, char isupdate)
370 struct pdb_mysql_data *data;
371 char *query;
373 if (!methods) {
374 DEBUG(0, ("invalid methods!\n"));
375 return NT_STATUS_INVALID_PARAMETER;
378 data = (struct pdb_mysql_data *) methods->private_data;
380 if (data == NULL || data->handle == NULL) {
381 DEBUG(0, ("invalid handle!\n"));
382 return NT_STATUS_INVALID_HANDLE;
385 query = sql_account_query_update(data->location, newpwd, isupdate);
387 /* Execute the query */
388 if (mysql_query(data->handle, query)) {
389 DEBUG(0,
390 ("Error executing %s, %s\n", query,
391 mysql_error(data->handle)));
392 return NT_STATUS_INVALID_PARAMETER;
394 SAFE_FREE(query);
396 return NT_STATUS_OK;
399 static NTSTATUS mysqlsam_add_sam_account(struct pdb_methods *methods, SAM_ACCOUNT * newpwd)
401 return mysqlsam_replace_sam_account(methods, newpwd, 0);
404 static NTSTATUS mysqlsam_update_sam_account(struct pdb_methods *methods,
405 SAM_ACCOUNT * newpwd)
407 return mysqlsam_replace_sam_account(methods, newpwd, 1);
410 static NTSTATUS mysqlsam_init(struct pdb_context * pdb_context, struct pdb_methods ** pdb_method,
411 const char *location)
413 NTSTATUS nt_status;
414 struct pdb_mysql_data *data;
416 mysqlsam_debug_level = debug_add_class("mysqlsam");
417 if (mysqlsam_debug_level == -1) {
418 mysqlsam_debug_level = DBGC_ALL;
419 DEBUG(0,
420 ("mysqlsam: Couldn't register custom debugging class!\n"));
424 if (!pdb_context) {
425 DEBUG(0, ("invalid pdb_methods specified\n"));
426 return NT_STATUS_UNSUCCESSFUL;
429 if (!NT_STATUS_IS_OK
430 (nt_status = make_pdb_methods(pdb_context->mem_ctx, pdb_method))) {
431 return nt_status;
434 (*pdb_method)->name = "mysqlsam";
436 (*pdb_method)->setsampwent = mysqlsam_setsampwent;
437 (*pdb_method)->endsampwent = mysqlsam_endsampwent;
438 (*pdb_method)->getsampwent = mysqlsam_getsampwent;
439 (*pdb_method)->getsampwnam = mysqlsam_getsampwnam;
440 (*pdb_method)->getsampwsid = mysqlsam_getsampwsid;
441 (*pdb_method)->add_sam_account = mysqlsam_add_sam_account;
442 (*pdb_method)->update_sam_account = mysqlsam_update_sam_account;
443 (*pdb_method)->delete_sam_account = mysqlsam_delete_sam_account;
445 data = talloc(pdb_context->mem_ctx, sizeof(struct pdb_mysql_data));
446 (*pdb_method)->private_data = data;
447 data->handle = NULL;
448 data->pwent = NULL;
450 if (!location) {
451 DEBUG(0, ("No identifier specified. Check the Samba HOWTO Collection for details\n"));
452 return NT_STATUS_INVALID_PARAMETER;
455 data->location = smb_xstrdup(location);
457 DEBUG(1,
458 ("Connecting to database server, host: %s, user: %s, password: %s, database: %s, port: %ld\n",
459 config_value(data, "mysql host", CONFIG_HOST_DEFAULT),
460 config_value(data, "mysql user", CONFIG_USER_DEFAULT),
461 config_value(data, "mysql password", CONFIG_PASS_DEFAULT),
462 config_value(data, "mysql database", CONFIG_DB_DEFAULT),
463 xatol(config_value(data, "mysql port", CONFIG_PORT_DEFAULT))));
465 /* Do the mysql initialization */
466 data->handle = mysql_init(NULL);
467 if (!data->handle) {
468 DEBUG(0, ("Failed to connect to server\n"));
469 return NT_STATUS_UNSUCCESSFUL;
472 if(!sql_account_config_valid(data->location)) {
473 return NT_STATUS_INVALID_PARAMETER;
476 /* Process correct entry in $HOME/.my.conf */
477 if (!mysql_real_connect(data->handle,
478 config_value(data, "mysql host", CONFIG_HOST_DEFAULT),
479 config_value(data, "mysql user", CONFIG_USER_DEFAULT),
480 config_value(data, "mysql password", CONFIG_PASS_DEFAULT),
481 config_value(data, "mysql database", CONFIG_DB_DEFAULT),
482 xatol(config_value (data, "mysql port", CONFIG_PORT_DEFAULT)),
483 NULL, 0)) {
484 DEBUG(0,
485 ("Failed to connect to mysql database: error: %s\n",
486 mysql_error(data->handle)));
487 return NT_STATUS_UNSUCCESSFUL;
490 DEBUG(5, ("Connected to mysql db\n"));
492 return NT_STATUS_OK;
495 NTSTATUS pdb_mysql_init(void)
497 return smb_register_passdb(PASSDB_INTERFACE_VERSION, "mysql", mysqlsam_init);