cobbler-enlist-0.3/0000775000175000017500000000000011662722632014151 5ustar davedave00000000000000cobbler-enlist-0.3/cobbler-enlist.h0000664000175000017500000002122511662722332017225 0ustar davedave00000000000000/* cobbler-enlist - Cobbler enlistment tool Copyright (C) 2011 Canonical Ltd. Authors: Dave Walker (Daviey) Carlos de-Avillez Adam Gandelman This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 3 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Usage: ./cobbler-enlist --serverurl=http://cobbler.server/cobbler_api \ --username=cobbler --password=cobbler --name=test \ --profile=ubuntu-server-x86_64 optionally, '--netif=' can also be passed, restricting registration to this I/F. If no --netif, then all I/Fs will be registered. */ #define NAME "Cobbler Enlistment Tool" #define VERSION "1.0" #define OPT_URL 0 #define OPT_USRNAME 1 #define OPT_PASWD 2 #define OPT_NAME 3 #define OPT_PROFILE 4 #define OPT_NETIF 5 #define OPT_HELP 6 #define NO_MACADDR "00:00:00:00:00:00" static int debug = 0; struct cobbler_client { xmlrpc_env env; xmlrpc_client *client; xmlrpc_value *resultP; const char *token; const char *system; const char *serverUrl; const char *username; const char *password; const char *name; const char *profile; const char *netif; const char *mgmt_class; const char *macaddr; struct netif *netifs; }; struct netif { const char *interface; const char *macaddr; struct netif *next; }; void get_netifs(struct cobbler_client *enlister); int init_client(struct cobbler_client *enlister) { enlister->client = NULL; enlister->token = NULL; enlister->system = NULL; enlister->serverUrl = NULL; enlister->username = NULL; enlister->password = NULL; enlister->name = NULL; enlister->profile = NULL; enlister->netif = NULL; enlister->mgmt_class = NULL; enlister->macaddr = NULL; enlister->netifs = NULL; return 0; } void display_config(struct cobbler_client *enlister) { printf("[DEBUG] Enlisting system using the following config:\n"); printf("\tserverUrl: %s\n", enlister->serverUrl); printf("\tusername: %s\n", enlister->username); printf("\tpassword: %s\n", enlister->password); printf("\tname: %s\n", enlister->name); printf("\tprofile: %s\n", enlister->profile); if (enlister->netifs) { get_netifs(enlister); } if (enlister->mgmt_class) printf("\tmgmt class: %s\n", enlister->mgmt_class); } void get_netifs(struct cobbler_client *enlister) { struct netif *current = enlister->netifs; if (current == NULL) { printf("Interface list is empty\n"); return; } int i = 0; while (current != NULL) { printf("\tinterface %d: %s - %s\n", i, current->interface, current->macaddr); i++; current = current->next; } } void die(char *msg) { fprintf(stderr, "[ERROR] %s\n", msg); exit(1); } /* append a new interface to the netifs list. macaddr remains empty until populated by get_macaddresses() */ int append_netif(struct cobbler_client *enlister, char *netif) { if (debug) printf("[DEBUG] Appending interface %s to enlister's netif list\n", netif); struct netif *new_netif, *current; new_netif = (struct netif *) malloc(sizeof(struct netif)); if (new_netif == NULL) die("malloc() - append_netif()"); memset(new_netif, 0, sizeof(struct netif)); new_netif->interface = netif; new_netif->macaddr = NULL; new_netif->next = NULL; if (enlister->netifs == NULL) { enlister->netifs = new_netif; return 0; } int i; current = enlister->netifs; while (current->next != NULL) { current = current->next; i++; } current->next = new_netif; return 0; } /* delete an interface from the netifs list */ int remove_netif(struct cobbler_client *enlister, const char *interface) { if (debug) printf("[DEBUG] Removing from interface list: %s\n", interface); struct netif *current = enlister->netifs; int i = 0; if (strcasecmp(current->interface, interface) == 0) { enlister->netifs = current->next; return 0; } i++; while (current->next) { if (strcasecmp(current->next->interface, interface) == 0) { current->next = current->next->next; return 0; } current = current->next; i++; } printf("ERROR: NEtif: %s doesn't exist in enlister->netifs\n", interface); return 1; } // Overide ether_ntoa_r because stock decides the convention of leading zeros is silly. char * ether_ntoa_r (const struct ether_addr *addr, char *buf) { snprintf (buf, 18, "%02x:%02x:%02x:%02x:%02x:%02x", addr->ether_addr_octet[0], addr->ether_addr_octet[1], addr->ether_addr_octet[2], addr->ether_addr_octet[3], addr->ether_addr_octet[4], addr->ether_addr_octet[5]); return buf; } int interface_exists(const char *interface) { if (debug) printf("[DEBUG] Checking for interface: %s\n", interface); struct if_nameindex *curif, *ifs = if_nameindex(); for (curif = ifs; curif && curif->if_name; curif++) { if (strcasecmp(interface, curif->if_name) == 0) return 0; } return 1; } /* inspect each enlister->netifs. Make sure the interface exists on the system Remove it from the list if it doesn't. If we've cleaned the entire list because none of them exist, return 1. Can/should be extended to do more verification? */ int verify_netifs(struct cobbler_client *enlister) { struct netif *current = enlister->netifs; while (current) { if (interface_exists(current->interface) != 0) { printf("[WARNING] Interface %s doesn't exist, removing.\n", current->interface); remove_netif(enlister, current->interface); } current = current->next; } if (enlister->netifs == NULL) return 1; return 0; } /* utility function to test whether the netifs list contains at least one mac address */ int contains_one_macaddr(struct cobbler_client *enlister) { struct netif *current = enlister->netifs; while (current) { if ((current->macaddr != NULL) && (strcasecmp(current->macaddr, NO_MACADDR) != 0)) { return 0; } } return 1; } char *get_interface_macaddr(const char *interface) { if (debug) printf("[DEBUG] Getting mac addr for interface %s\n", interface); char mac_str[255]; char *macaddr; int ioctl_data = 0; struct ifreq ifr; ioctl_data = socket(PF_INET, SOCK_STREAM, 0); memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, interface, sizeof(interface)); ioctl(ioctl_data, SIOCGIFHWADDR, &ifr); ether_ntoa_r((const struct ether_addr *) &(ifr.ifr_hwaddr.sa_data), mac_str); macaddr = malloc(sizeof(mac_str)); if (macaddr == NULL) die("malloc() - get_interface_macaddr()"); strncpy(macaddr, mac_str, sizeof(mac_str)); return macaddr; } /* iterate through enlister->netifs, populating macaddr for each. if we can't determine a valid mac addr, remove from list and continue returns non-zero if the resulting enlister->netifs does not contain at least one mac addr. */ int get_mac_addresses(struct cobbler_client *enlister) { if (debug) printf("[DEBUG] get_mac_address()\n"); const char *addr; struct netif *current = enlister->netifs; while (current != NULL) { addr = get_interface_macaddr(current->interface); if (strcasecmp(addr, NO_MACADDR) == 0) { printf("[WARNING] Could not determine mac addr for %s, skipping.\n", current->interface); remove_netif(enlister, current->interface); } else { current->macaddr = addr; }; current = current->next; } return contains_one_macaddr(enlister); } void help(char *progname) { printf("Usage: %s --help -- provides this help\n" , progname); printf(" : %s \n", progname); printf("Parameters: -s, --serverurl -- resolvable Cobbler server API URL\n"); printf(" -u, --username -- valid Cobbler user\n"); printf(" -p, --password -- password for above user\n"); printf(" -n, --name -- Cobbler name\n"); printf(" -P, --profile -- Cobbler profile\n"); printf(" -i, --netif -- single network I/F to be registered\n"); printf(" -m, --manclass -- Cobbler management class\n"); printf("\n --netif is optional; if not specified, all network I/Fs will be registered\n"); printf(" all other parameters are required\n"); } cobbler-enlist-0.3/cobbler-enlist.c0000664000175000017500000001213211662722332017215 0ustar davedave00000000000000/* cobbler-enlist - Cobbler enlistment tool Copyright (C) 2011 Canonical Ltd. Authors: Dave Walker (Daviey) Carlos de-Avillez Adam Gandelman This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 3 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Usage: ./cobbler-enlist --serverurl=http://cobbler.server/cobbler_api \ --username=cobbler --password=cobbler --name=test \ --profile=ubuntu-server-x86_64 optionally, '--netif=' can also be passed, restricting registration to this I/F. If no --netif, then all I/Fs will be registered. */ #include #include #include #include #include #include #include #include #include #include #include "cobbler-enlist.h" #include "cobbler-xmlrpc.h" int main (int const argc, char **argv) { int rc; struct cobbler_client *enlister; enlister = (struct cobbler_client *) malloc(sizeof(struct cobbler_client)); if (enlister == NULL) die("malloc() failed for enlister- main()"); memset(enlister, 0, sizeof(struct cobbler_client)); init_client(enlister); int c; int option_index = 0; const char* const short_options = "hds:u:p:n:P:i:m:"; static struct option long_options[] = { {"serverurl", 1, 0, 's'}, {"username", 1, 0, 'u'}, {"password", 1, 0, 'p'}, {"name", 1, 0, 'n'}, {"profile", 1, 0, 'P'}, {"netif", 1, 0, 'i'}, {"manclass", 1, 0, 'm'}, {"help", 0, 0, 'h'}, {0, 0, 0, 0} }; if (getenv("COBBLER_ENLIST_DEBUG")) debug = 1; while (1) { c = getopt_long (argc, argv, short_options, long_options, &option_index); if (c == -1) break; if (c == '?') { help(argv[0]); exit(1); } switch (c) { case '?': help(argv[0]); exit(1); case 's': enlister->serverUrl = optarg; break; case 'u': enlister->username = optarg; break; case 'p': enlister->password = optarg; break; case 'n': enlister->name = optarg; break; case 'P': enlister->profile = optarg; break; case 'i': append_netif(enlister, optarg); break; case 'm': enlister->mgmt_class = optarg; break; case 'h': help(argv[0]); exit(0); break; default: break; } } if (optind < argc) { printf ("[%s]non-option ARGV-elements: ", argv[0]); while (optind < argc) { printf ("%s ", argv[optind++]); } printf ("\n"); } /* check if all required parameters have been passed */ if ((enlister->serverUrl == NULL) || (enlister->username == NULL) || (enlister->password == NULL) || (enlister->name == NULL) || (enlister->profile == NULL)) { help(argv[0]); die("Not all required parameters were passed"); } /* if no interfaces were specified on command line, add all interfaces on the system */ if (!enlister->netifs) { if (debug) printf("[DEBUG] Populating netifs list with all interfaces on system.\n"); struct if_nameindex *ifs = if_nameindex(); while (ifs && ifs->if_name) { if (strcasecmp(ifs->if_name, "lo") != 0) append_netif(enlister, ifs->if_name); ifs++; } } /* ensure list isn't empty and all interfaces exist */ if (verify_netifs(enlister) != 0) die("Could not verify any of specified interfaces"); /* get mac addresses for interfaces contained in enlister->netifs */ if (get_mac_addresses(enlister) != 0) die("Could not determine mac address for any interface on system."); if (debug) display_config(enlister); /* Initialize our error-handling environment. */ if ((rc = init_xmlrpc_env(enlister)) != 0) goto out; /* Initialize the client */ if ((rc = init_xmlrpc_client(enlister)) != 0) goto out; /* Login to cobbler */ if ((rc = cobbler_login(enlister)) != 0) goto out; /* Register new system with everything contained in the enlister */ if ((rc = cobbler_register_system(enlister)) != 0) goto out; /* Save the system */ if ((rc = cobbler_save_system(enlister)) != 0) goto out; if (debug) printf("[DEBUG] Enlistment complete\n"); out: if (debug) printf("[DEBUG] Exit: %d\n", rc); xmlrpc_env_clean(&enlister->env); return rc; } cobbler-enlist-0.3/Makefile0000664000175000017500000000034311662722332015606 0ustar davedave00000000000000LIBS = -lxmlrpc -lxmlrpc_util -lxmlrpc_client all: cobbler-enlist cobbler-enlist: $(CC) -o cobbler-enlist cobbler-enlist.c $(LIBS) -Wall #install: # install cobbler-enlist $(DESTDIR)/usr/bin/ clean: rm -f cobbler-enlist cobbler-enlist-0.3/man/0000775000175000017500000000000011662722632014724 5ustar davedave00000000000000cobbler-enlist-0.3/man/cobbler-enlist.10000664000175000017500000000226411662722332017713 0ustar davedave00000000000000.TH USAGE: "1" "cobbler-enlist" .SH NAME cobbler-enlist -- Cobbler Enlistment tool, for enlisting with a cobbler server over a network .SH SYNOPSIS .B cobbler-enlist --serverurl=http://cobbler.server/cobbler_api --username=cobbler --password=cobbler --name=test --profile=ubuntu-server-x86_64 .SH DESCRIPTION .IP : cobbler\-enlist .PP Parameters: .TP \fB\-s\fR, \fB\-\-serverurl\fR \fB\-\-\fR resolvable Cobbler server API URL .TP \fB\-u\fR, \fB\-\-username\fR \fB\-\-\fR valid Cobbler user .TP \fB\-p\fR, \fB\-\-password\fR \fB\-\-\fR password for above user .TP \fB\-n\fR, \fB\-\-name\fR \fB\-\-\fR Cobbler name .TP \fB\-P\fR, \fB\-\-profile\fR \fB\-\-\fR Cobbler profile .TP \fB\-i\fR, \fB\-\-netif\fR \fB\-\-\fR single network I/F to be registered .TP \fB\-m\fR, \fB\-\-manclass\fR \fB\-\-\fR Cobbler management class .HP \fB\-\-netif\fR is optional; if not specified, all network I/Fs will be registered .IP all other parameters are required .SH "WARNING" Currently all traffic sent is done so via plain HTTP. SSL is currently not supported. This includes the cobbler server credentials. It is strongly recommended that this tool is only used in a trusted network segment. cobbler-enlist-0.3/cobbler-xmlrpc.h0000664000175000017500000002262611662722332017242 0ustar davedave00000000000000/* cobbler-enlist - Cobbler enlistment tool Copyright (C) 2011 Canonical Ltd. Authors: Dave Walker (Daviey) Carlos de-Avillez Adam Gandelman This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 3 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ static int fault_occurred (xmlrpc_env * const envP) { if (!envP->fault_occurred) return 0; fprintf (stderr, "ERROR: %s (%d)\n", envP->fault_string, envP->fault_code); return 1; } int init_xmlrpc_env(struct cobbler_client *enlister) { if (debug) { printf("[DEBUG] Initializing xmlrpc enviornment.\n"); } xmlrpc_env_init(&enlister->env); if(fault_occurred(&enlister->env) != 0) return 1; xmlrpc_client_setup_global_const(&enlister->env); return fault_occurred(&enlister->env); } int init_xmlrpc_client(struct cobbler_client *enlister) { if (debug) printf("[DEBUG] Initializing xmlrpc client.\n"); /* xmlrpc_client_init2(&enlister->env, XMLRPC_CLIENT_NO_FLAGS, NAME, VERSION, NULL, 0); if (!fault_occured(&enlister->env)) return 1;*/ xmlrpc_client_create(&enlister->env, XMLRPC_CLIENT_NO_FLAGS, NAME, VERSION, 0, 0, &enlister->client); return fault_occurred(&enlister->env); } int make_xmlrpc_call(struct cobbler_client *enlister, char *method, xmlrpc_value *arguments) { if (debug) printf("[DEBUG] Making xmlrpc call for method: %s\n", method); xmlrpc_server_info *serverinfo; serverinfo = xmlrpc_server_info_new(&enlister->env, enlister->serverUrl); xmlrpc_client_call2(&enlister->env, enlister->client, serverinfo, method, arguments, &enlister->resultP); /* TODO: This causes error, find out why. xmlrpc_server_info_free(serverinfo); */ return fault_occurred(&enlister->env); } int cobbler_login(struct cobbler_client *enlister) { if (debug) printf("[DEBUG] cobbler_login()\n"); int rc = 0; xmlrpc_value *argument_array; xmlrpc_value *username; xmlrpc_value *password; argument_array = xmlrpc_array_new(&enlister->env); username = xmlrpc_string_new(&enlister->env, enlister->username); password = xmlrpc_string_new(&enlister->env, enlister->password); xmlrpc_array_append_item(&enlister->env, argument_array, username); xmlrpc_array_append_item(&enlister->env, argument_array, password); xmlrpc_DECREF(username); xmlrpc_DECREF(password); rc = make_xmlrpc_call(enlister, "login", argument_array); if (rc != 0) goto out; xmlrpc_read_string(&enlister->env, enlister->resultP, &enlister->token); if ((rc = fault_occurred(&enlister->env)) != 0) goto out; if (debug) printf("[DEBUG] The token is %s\n", enlister->token); out: xmlrpc_DECREF(argument_array); if (debug) printf("[DEBUG] Login complete. rc=%d\n", rc); return rc; } int cobbler_register_system(struct cobbler_client *enlister) { if (debug) printf("[DEBUG] cobbler_register_system()\n"); int rc = 0; /* at this point, everything we need should be containedin the enlister */ xmlrpc_value *token = xmlrpc_string_new(&enlister->env, enlister->token); xmlrpc_value *name = xmlrpc_string_new(&enlister->env, enlister->name); xmlrpc_value *profile = xmlrpc_string_new(&enlister->env, enlister->profile); // xmlrpc_value *macaddr = xmlrpc_string_new(&enlister->env, enlister->macaddr); /* used for forming modify_interface request */ xmlrpc_value *macaddr_struct = xmlrpc_struct_new(&enlister->env); char macaddr_form_item[100]; xmlrpc_value *argument_array; /* register a new server-side system object */ argument_array = xmlrpc_array_new(&enlister->env); xmlrpc_array_append_item(&enlister->env, argument_array, token); if ((rc = make_xmlrpc_call(enlister, "new_system", argument_array)) != 0) goto out; xmlrpc_read_string(&enlister->env, enlister->resultP, &enlister->system); xmlrpc_value *system = xmlrpc_string_new(&enlister->env, enlister->system); if (debug) printf("[DEBUG] Registered new system: rc: %d system: %s\n", rc, enlister->system); /* modify the new system, set its name */ argument_array = xmlrpc_array_new(&enlister->env); xmlrpc_array_append_item(&enlister->env, argument_array, system); xmlrpc_array_append_item(&enlister->env, argument_array, xmlrpc_string_new(&enlister->env, "name")); xmlrpc_array_append_item(&enlister->env, argument_array, name); xmlrpc_array_append_item(&enlister->env, argument_array, token); if ((rc = make_xmlrpc_call(enlister, "modify_system", argument_array)) != 0) goto out; if (debug) printf("[DEBUG] Modified system name: %d\n", rc); /* also set its hostname to match its system name */ argument_array = xmlrpc_array_new(&enlister->env); xmlrpc_array_append_item(&enlister->env, argument_array, system); xmlrpc_array_append_item(&enlister->env, argument_array, xmlrpc_string_new(&enlister->env, "hostname")); xmlrpc_array_append_item(&enlister->env, argument_array, name); xmlrpc_array_append_item(&enlister->env, argument_array, token); if ((rc = make_xmlrpc_call(enlister, "modify_system", argument_array)) != 0) goto out; if (debug) printf("[DEBUG] Modified system hostname: %d\n", rc); /* assign a profile */ argument_array = xmlrpc_array_new(&enlister->env); xmlrpc_array_append_item(&enlister->env, argument_array, system); xmlrpc_array_append_item(&enlister->env, argument_array, xmlrpc_string_new(&enlister->env, "profile")); xmlrpc_array_append_item(&enlister->env, argument_array, profile); xmlrpc_array_append_item(&enlister->env, argument_array, token); if ((rc = make_xmlrpc_call(enlister, "modify_system", argument_array)) != 0) goto out; if (debug) printf("[DEBUG] Modified system profile: %d\n", rc); /* set its mac addresses */ struct netif *current_netif = enlister->netifs; while (current_netif != NULL) { if (debug) { printf("[DEBUG] Registering interface and macaddr: %s %s\n", current_netif->interface, current_netif->macaddr); } xmlrpc_value *macaddr = xmlrpc_string_new(&enlister->env, current_netif->macaddr); sprintf(macaddr_form_item, "macaddress-%s", current_netif->interface); xmlrpc_struct_set_value(&enlister->env, macaddr_struct, macaddr_form_item, macaddr); argument_array = xmlrpc_array_new(&enlister->env); xmlrpc_array_append_item(&enlister->env, argument_array, system); xmlrpc_array_append_item(&enlister->env, argument_array, xmlrpc_string_new(&enlister->env, "modify_interface")); xmlrpc_array_append_item(&enlister->env, argument_array, macaddr_struct); xmlrpc_array_append_item(&enlister->env, argument_array, token); if ((rc = make_xmlrpc_call(enlister, "modify_system", argument_array)) != 0) { xmlrpc_DECREF(macaddr); xmlrpc_DECREF(macaddr_struct); goto out; } if (debug) printf("[DEBUG] Modified interface: %d\n", rc); current_netif = current_netif->next; } /* assign a mgmt class */ if (enlister->mgmt_class) { xmlrpc_value *mgmt_class = xmlrpc_string_new(&enlister->env, enlister->mgmt_class); argument_array = xmlrpc_array_new(&enlister->env); xmlrpc_array_append_item(&enlister->env, argument_array, system); xmlrpc_array_append_item(&enlister->env, argument_array, xmlrpc_string_new(&enlister->env, "mgmt_classes")); xmlrpc_array_append_item(&enlister->env, argument_array, mgmt_class); xmlrpc_array_append_item(&enlister->env, argument_array, token); if ((rc = make_xmlrpc_call(enlister, "modify_system", argument_array)) != 0) xmlrpc_DECREF(mgmt_class); goto out; if (debug) printf("[DEBUG] Modified mgmt class: %d\n", rc); xmlrpc_DECREF(mgmt_class); } out: xmlrpc_DECREF(token); xmlrpc_DECREF(name); xmlrpc_DECREF(profile); xmlrpc_DECREF(system); xmlrpc_DECREF(argument_array); return rc; } int cobbler_save_system(struct cobbler_client *enlister) { if (debug) printf("[DEBUG] cobbler_save_system()\n"); int rc = 0; xmlrpc_value *argument_array; argument_array = xmlrpc_array_new(&enlister->env); xmlrpc_value *token = xmlrpc_string_new(&enlister->env, enlister->token); xmlrpc_value *system = xmlrpc_string_new(&enlister->env, enlister->system); xmlrpc_array_append_item(&enlister->env, argument_array, system); xmlrpc_array_append_item(&enlister->env, argument_array, token); if ((rc = make_xmlrpc_call(enlister, "save_system", argument_array)) != 0) goto out; printf("[DEBUG] System saved.\n"); out: xmlrpc_DECREF(token); xmlrpc_DECREF(system); xmlrpc_DECREF(argument_array); return rc; }