Project

General

Profile

Statistics
| Branch: | Tag: | Revision:

gdp / apps / gdp-name-add.c @ master

History | View | Annotate | Download (9.02 KB)

1
/* vim: set ai sw=4 sts=4 ts=4 : */
2

    
3
/*
4
**  GDP-NAME-ADD --- add a name to the external to internal name database.
5
**
6
**        ----- BEGIN LICENSE BLOCK -----
7
**        Applications for the Global Data Plane
8
**        From the Ubiquitous Swarm Lab, 490 Cory Hall, U.C. Berkeley.
9
**
10
**        Copyright (c) 2015-2019, Regents of the University of California.
11
**        All rights reserved.
12
**
13
**        Permission is hereby granted, without written agreement and without
14
**        license or royalty fees, to use, copy, modify, and distribute this
15
**        software and its documentation for any purpose, provided that the above
16
**        copyright notice and the following two paragraphs appear in all copies
17
**        of this software.
18
**
19
**        IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
20
**        SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST
21
**        PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
22
**        EVEN IF REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23
**
24
**        REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
25
**        LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26
**        FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION,
27
**        IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO
28
**        OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
29
**        OR MODIFICATIONS.
30
**        ----- END LICENSE BLOCK -----
31
*/
32

    
33
#include <ep/ep.h>
34
#include <ep/ep_app.h>
35
#include <ep/ep_dbg.h>
36
#include <gdp/gdp.h>
37
#include "../gdp/gdp_hongd.h"        // cheat
38

    
39
#include <mysql.h>
40

    
41
#include <string.h>
42
#include <sysexits.h>
43

    
44

    
45
static EP_DBG        Dbg = EP_DBG_INIT("gdp-name-add", "Update name database app");
46

    
47
#define MILLISECONDS                * INT64_C(1000000)
48

    
49
static MYSQL                *NameDb;                        // name mapping database
50

    
51
/*
52
**  This is essentially a copy of the standard startup routine but
53
**  with different database credentials.
54
*/
55

    
56
EP_STAT
57
name_init(struct hongdargs *ha)
58
{
59
        EP_STAT estat = EP_STAT_OK;
60
        bool i_own_passwd = false;
61

    
62
        // open a connection to the external => internal mapping database
63
        if (ha->dbhost == NULL)
64
                ha->dbhost = ep_adm_getstrparam("swarm.gdp.hongdb.host",
65
                                                                GDP_DEFAULT_HONGD_HOST);
66
        if (ha->dbhost == NULL)
67
        {
68
                ep_app_error("No database name available; set swarm.gdp.hongdb.host");
69
                estat = GDP_STAT_NAK_SVCUNAVAIL;
70
                goto fail0;
71
        }
72

    
73
        // read database password if we don't have one already
74
        if (ha->dbpasswd == NULL)
75
        {
76
                char prompt_buf[100];
77
                snprintf(prompt_buf, sizeof prompt_buf, "Password for %s: ", ha->dbuser);
78
                ha->dbpasswd = getpass(prompt_buf);
79
                i_own_passwd = true;
80
        }
81

    
82
        // attempt the actual connect and authentication
83
        _gdp_name_init(ha);
84

    
85
fail0:
86
        // make sure password isn't visible to intruders
87
        if (ha->dbpasswd != NULL && i_own_passwd)
88
                memset(ha->dbpasswd, 0, strlen(ha->dbpasswd));
89
        return estat;
90
}
91

    
92

    
93
int
94
do_insert(const char *hname, const gdp_name_t gname)
95
{
96
        int l = strlen(hname);
97
        char xescaped[2 * l + 1];
98
        char gescaped[2 * sizeof (gdp_name_t) + 1];
99
        char qbuf[1024];
100

    
101
        if (ep_dbg_test(Dbg, 9))
102
        {
103
                gdp_pname_t pname;
104

    
105
                ep_dbg_printf("adding %s -> %s\n",
106
                                hname, gdp_printable_name(gname, pname));
107
        }
108

    
109
        mysql_real_escape_string(NameDb, xescaped, hname, l);
110
        mysql_real_escape_string(NameDb, gescaped, (const char *) gname,
111
                                        sizeof (gdp_name_t));
112
        const char *q =
113
                        "INSERT INTO human_to_gdp (hname, gname)\n"
114
                        "        VALUES('%s', '%s')";
115
        snprintf(qbuf, sizeof qbuf, q, xescaped, gescaped);
116
        ep_dbg_cprintf(Dbg, 28, "    %s\n", qbuf);
117
        return mysql_query(NameDb, qbuf);
118
}
119

    
120

    
121
int
122
do_delete(const char *hname)
123
{
124
        int l = strlen(hname);
125
        char xescaped[2 * l + 1];
126
        char qbuf[1024];
127

    
128
        ep_dbg_cprintf(Dbg, 9, "deleting %s\n", hname);
129

    
130
        mysql_real_escape_string(NameDb, xescaped, hname, l);
131
        const char *q =
132
                        "DELETE FROM human_to_gdp WHERE hname = '%s'\n";
133
        snprintf(qbuf, sizeof qbuf, q, xescaped);
134
        ep_dbg_cprintf(Dbg, 28, "    %s\n", qbuf);
135
        return mysql_query(NameDb, qbuf);
136
}
137

    
138

    
139
void
140
usage(void)
141
{
142
        fprintf(stderr,
143
                        "Usage: %s [-d] [-D dbgspec] [-H db_host] [-p passwd] [-P pw_file]\n"
144
                        "        [-q] [-u db_user] human_name gdp_name\n"
145
                        "    -d  delete (instead of add)\n"
146
                        "    -D  set debugging flags\n"
147
                        "    -H  database host name (default: %s)\n"
148
                        "    -p  database password\n"
149
                        "    -P  name of file containing password\n"
150
                        "    -q  suppress output (exit status only)\n"
151
                        "    -u  database creation service user name (default: %s)\n"
152
                        "human_name is the human-oriented log name\n"
153
                        "gdp_name is the base-64 encoded 256-bit internal name\n",
154
                        ep_app_getprogname(),
155
                        ep_adm_getstrparam("swarm.gdp.hongdb.host",
156
                                                                GDP_DEFAULT_HONGD_HOST),
157
                        ep_adm_getstrparam("swarm.gdp.creation-service.user",
158
                                                                "gdp_creation_service"));
159
        exit(EX_USAGE);
160
}
161

    
162

    
163
int
164
main(int argc, char **argv)
165
{
166
        const char *hname;                                // external name, human-oriented text
167
        const char *pname;                                // internal name, base64-encoded
168
        gdp_name_t gname;                                // internal name, binary
169
        const char *db_passwd_file = NULL;        // file containing associated password
170
        bool quiet = false;
171
        bool delete = false;
172
        int opt;
173
        EP_STAT estat = EP_STAT_OK;
174
        int xstat = EX_OK;                                // exit status
175
        bool show_usage = false;
176
        const char *phase;
177
        struct hongdargs *ha = ep_mem_zalloc(sizeof *ha);
178

    
179
        // collect command-line arguments
180
        while ((opt = getopt(argc, argv, "dD:H:p:P:qu:")) > 0)
181
        {
182
                switch (opt)
183
                {
184
                 case 'd':
185
                        delete = true;
186
                        break;
187

    
188
                 case 'D':
189
                        ep_dbg_set(optarg);
190
                        break;
191

    
192
                 case 'H':
193
                        ha->dbhost = optarg;
194
                        break;
195

    
196
                 case 'p':
197
                        ha->dbpasswd = optarg;
198
                        break;
199

    
200
                 case 'P':
201
                        db_passwd_file = optarg;
202
                        break;
203

    
204
                 case 'q':
205
                        quiet = true;
206
                        break;
207

    
208
                 case 'u':
209
                        ha->dbuser = optarg;
210
                        break;
211

    
212
                 default:
213
                        show_usage = true;
214
                        break;
215
                }
216
        }
217
        argc -= optind;
218
        argv += optind;
219

    
220
        if (show_usage || argc-- != (delete ? 1 : 2))
221
                usage();
222

    
223
        hname = *argv++;
224
        if (!delete)
225
                pname = *argv++;
226

    
227
        // initialize the GDP library
228
        phase = "initialization";
229
        estat = gdp_init_phase_0(NULL, 0);
230
        if (!EP_STAT_ISOK(estat))
231
        {
232
                if (!quiet)
233
                        ep_app_error("GDP Library Initialization failed");
234
                goto fail0;
235
        }
236

    
237
        // figure out appropriate defaults
238
        if (delete)
239
        {
240
                if (ha->dbuser == NULL)
241
                        ha->dbuser = ep_adm_getstrparam("swarm.gdp.hongd.admin.user",
242
                                                                                "hongd_admin");
243
                if (db_passwd_file == NULL)
244
                        db_passwd_file = ep_adm_getstrparam("swarm.gdp.hongd.admin.passwd-file",
245
                                                                                "/etc/gdp/hongd_admin_pw.txt");
246
        }
247
        else
248
        {
249
                if (ha->dbuser == NULL)
250
                        ha->dbuser = ep_adm_getstrparam("swarm.gdp.creation-service.user",
251
                                                                                "gdp_creation_service");
252
                if (db_passwd_file == NULL)
253
                        db_passwd_file = ep_adm_getstrparam(
254
                                                                "swarm.gdp.creation-service.passwd-file",
255
                                                                "/etc/gdp/creation_service_pw.txt");
256
        }
257
        if (ha->dbpasswd == NULL && db_passwd_file != NULL)
258
        {
259
                FILE *pw_fp = fopen(db_passwd_file, "r");
260
                if (pw_fp != NULL)
261
                {
262
                        char pbuf[128];
263

    
264
                        if (fgets(pbuf, sizeof pbuf, pw_fp) != NULL && pbuf[0] != '\0')
265
                        {
266
                                char *p = strchr(pbuf, '\n');
267
                                if (p != NULL)
268
                                        *p = '\0';
269
                                ha->dbpasswd = strdup(pbuf);
270
                        }
271
                        fclose(pw_fp);
272
                }
273
                else if (!quiet)
274
                        ep_app_warn("Cannot read %s", db_passwd_file);
275
        }
276
        if (ha->dbpasswd == NULL && !quiet)
277
                ep_app_warn("No password for %s", ha->dbuser);
278

    
279
        NameDb = _gdp_hongd_conn_open(ha);
280

    
281
        if (!quiet)
282
                ep_app_info("Using HONGD server %s", ha->dbhost);
283

    
284
        // translate GDP name from base64 to binary
285
        if (!delete)
286
        {
287
                phase = "name translate";
288
                estat = gdp_internal_name(pname, gname);
289
                if (!EP_STAT_ISOK(estat))
290
                {
291
                        if (!quiet)
292
                        {
293
                                ep_app_message(estat, "cannot decode %s", pname);
294
                                fprintf(stderr, "\t(Should be base64-encoded log name)\n");
295
                        }
296
                        xstat = EX_DATAERR;
297
                        goto fail0;
298
                }
299
        }
300

    
301
        // figure out ultimate human name (perhaps using $GDP_NAME_ROOT)
302
        const char *root = getenv("GDP_NAME_ROOT");
303
        ep_dbg_cprintf(Dbg, 10, "GDP_NAME_ROOT=%s\n", root);
304
        if (root != NULL && root[0] != '\0' && strchr(hname, '.') == NULL)
305
        {
306
                int plen = strlen(root) + strlen(hname) + 2;
307
                char *p = ep_mem_malloc(plen);
308
                snprintf(p, plen, "%s.%s", root, hname);
309
                hname = p;
310
        }
311

    
312
        if (!quiet)
313
        {
314
                if (delete)
315
                        ep_app_info("deleting %s", hname);
316
                else
317
                        ep_app_info("adding %s => %s", hname, pname);
318
        }
319

    
320
        // open database connection
321
        phase = "database open";
322
        estat = name_init(ha);
323
        if (!EP_STAT_ISOK(estat))
324
        {
325
                if (!quiet)
326
                        ep_app_message(estat, "cannot initialize name database (%s)",
327
                                        mysql_error(NameDb));
328
                xstat = EX_UNAVAILABLE;
329
                goto fail0;
330
        }
331

    
332
        // now attempt the actual database update
333
        int istat;
334
        if (delete)
335
        {
336
                phase = "DELETE";
337
                istat = do_delete(hname);
338
                if (istat == 0)
339
                {
340
                        my_ulonglong nrows = mysql_affected_rows(NameDb);
341
                        if (nrows == 0)
342
                                xstat = EX_NOINPUT;
343
                        if (!quiet)
344
                        {
345
                                if (nrows == 0)
346
                                        ep_app_warn("no rows matched");
347
                                else
348
                                        ep_app_info("%lld rows deleted", nrows);
349
                        }
350
                }
351
        }
352
        else
353
        {
354
                phase = "INSERT";
355
                istat = do_insert(hname, gname);
356
        }
357

    
358
        // cleanup and exit
359
        if (istat != 0)
360
        {
361
                if (EP_STAT_ISOK(estat))
362
                        estat = GDP_STAT_MYSQL_ERROR;
363
                if (!quiet)
364
                        ep_app_error("%s failed: %s", phase, mysql_error(NameDb));
365
        }
366

    
367
fail0:
368
        if (NameDb != NULL)
369
                mysql_close(NameDb);
370
        NameDb = NULL;
371

    
372
        // OK status can have values; hide that from the user
373
        if (EP_STAT_ISOK(estat))
374
                estat = EP_STAT_OK;
375
        else if (xstat == EX_OK)
376
                xstat = EX_UNAVAILABLE;
377
        exit(xstat);
378
}