utils/net_ads.c

説明を見る。
00001 /* 
00002    Samba Unix/Linux SMB client library 
00003    net ads commands
00004    Copyright (C) 2001 Andrew Tridgell (tridge@samba.org)
00005    Copyright (C) 2001 Remus Koos (remuskoos@yahoo.com)
00006    Copyright (C) 2002 Jim McDonough (jmcd@us.ibm.com)
00007    Copyright (C) 2006 Gerald (Jerry) Carter (jerry@samba.org)
00008 
00009    This program is free software; you can redistribute it and/or modify
00010    it under the terms of the GNU General Public License as published by
00011    the Free Software Foundation; either version 2 of the License, or
00012    (at your option) any later version.
00013    
00014    This program is distributed in the hope that it will be useful,
00015    but WITHOUT ANY WARRANTY; without even the implied warranty of
00016    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017    GNU General Public License for more details.
00018    
00019    You should have received a copy of the GNU General Public License
00020    along with this program; if not, write to the Free Software
00021    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
00022 */
00023 
00024 #include "includes.h"
00025 #include "utils/net.h"
00026 
00027 #ifdef HAVE_ADS
00028 
00029 int net_ads_usage(int argc, const char **argv)
00030 {
00031         d_printf("join [createupn[=principal]] [createcomputer=<org_unit>]\n");
00032         d_printf("    Join the local machine to a ADS realm\n");
00033         d_printf("leave\n");
00034         d_printf("    Remove the local machine from a ADS realm\n");
00035         d_printf("testjoin\n");
00036         d_printf("    Validates the machine account in the domain\n");
00037         d_printf("user\n");
00038         d_printf("    List, add, or delete users in the realm\n");
00039         d_printf("group\n");
00040         d_printf("    List, add, or delete groups in the realm\n");
00041         d_printf("info\n");
00042         d_printf("    Displays details regarding a specific AD server\n");
00043         d_printf("status\n");
00044         d_printf("    Display details regarding the machine's account in AD\n");
00045         d_printf("lookup\n");
00046         d_printf("    Performs CLDAP query of AD domain controllers\n");
00047         d_printf("password <username@realm> <password> -Uadmin_username@realm%%admin_pass\n");
00048         d_printf("    Change a user's password using an admin account\n");
00049         d_printf("    (note: use realm in UPPERCASE, prompts if password is obmitted)\n");
00050         d_printf("changetrustpw\n");
00051         d_printf("    Change the trust account password of this machine in the AD tree\n");
00052         d_printf("printer [info | publish | remove] <printername> <servername>\n");
00053         d_printf("    Lookup, add, or remove directory entry for a printer\n");
00054         d_printf("{search,dn,sid}\n");
00055         d_printf("    Issue LDAP search queries using a general filter, by DN, or by SID\n");
00056         d_printf("keytab\n");
00057         d_printf("    Manage a local keytab file based on the machine account in AD\n");
00058         d_printf("dns\n");
00059         d_printf("    Issue a dynamic DNS update request the server's hostname\n");
00060         d_printf("    (using the machine credentials)\n");
00061         
00062         return -1;
00063 }
00064 
00065 /* when we do not have sufficient input parameters to contact a remote domain
00066  * we always fall back to our own realm - Guenther*/
00067 
00068 static const char *assume_own_realm(void)
00069 {
00070         if (!opt_host && strequal(lp_workgroup(), opt_target_workgroup)) {
00071                 return lp_realm();
00072         }
00073 
00074         return NULL;
00075 }
00076 
00077 /*
00078   do a cldap netlogon query
00079 */
00080 static int net_ads_cldap_netlogon(ADS_STRUCT *ads)
00081 {
00082         struct cldap_netlogon_reply reply;
00083 
00084         if ( !ads_cldap_netlogon( inet_ntoa(ads->ldap_ip), ads->server.realm, &reply ) ) {
00085                 d_fprintf(stderr, "CLDAP query failed!\n");
00086                 return -1;
00087         }
00088 
00089         d_printf("Information for Domain Controller: %s\n\n", 
00090                 inet_ntoa(ads->ldap_ip));
00091 
00092         d_printf("Response Type: ");
00093         switch (reply.type) {
00094         case SAMLOGON_AD_UNK_R:
00095                 d_printf("SAMLOGON\n");
00096                 break;
00097         case SAMLOGON_AD_R:
00098                 d_printf("SAMLOGON_USER\n");
00099                 break;
00100         default:
00101                 d_printf("0x%x\n", reply.type);
00102                 break;
00103         }
00104         d_printf("GUID: %s\n", 
00105                  smb_uuid_string_static(smb_uuid_unpack_static(reply.guid))); 
00106         d_printf("Flags:\n"
00107                  "\tIs a PDC:                                   %s\n"
00108                  "\tIs a GC of the forest:                      %s\n"
00109                  "\tIs an LDAP server:                          %s\n"
00110                  "\tSupports DS:                                %s\n"
00111                  "\tIs running a KDC:                           %s\n"
00112                  "\tIs running time services:                   %s\n"
00113                  "\tIs the closest DC:                          %s\n"
00114                  "\tIs writable:                                %s\n"
00115                  "\tHas a hardware clock:                       %s\n"
00116                  "\tIs a non-domain NC serviced by LDAP server: %s\n",
00117                  (reply.flags & ADS_PDC) ? "yes" : "no",
00118                  (reply.flags & ADS_GC) ? "yes" : "no",
00119                  (reply.flags & ADS_LDAP) ? "yes" : "no",
00120                  (reply.flags & ADS_DS) ? "yes" : "no",
00121                  (reply.flags & ADS_KDC) ? "yes" : "no",
00122                  (reply.flags & ADS_TIMESERV) ? "yes" : "no",
00123                  (reply.flags & ADS_CLOSEST) ? "yes" : "no",
00124                  (reply.flags & ADS_WRITABLE) ? "yes" : "no",
00125                  (reply.flags & ADS_GOOD_TIMESERV) ? "yes" : "no",
00126                  (reply.flags & ADS_NDNC) ? "yes" : "no");
00127 
00128         printf("Forest:\t\t\t%s\n", reply.forest);
00129         printf("Domain:\t\t\t%s\n", reply.domain);
00130         printf("Domain Controller:\t%s\n", reply.hostname);
00131 
00132         printf("Pre-Win2k Domain:\t%s\n", reply.netbios_domain);
00133         printf("Pre-Win2k Hostname:\t%s\n", reply.netbios_hostname);
00134 
00135         if (*reply.unk) printf("Unk:\t\t\t%s\n", reply.unk);
00136         if (*reply.user_name) printf("User name:\t%s\n", reply.user_name);
00137 
00138         printf("Server Site Name :\t\t%s\n", reply.server_site_name);
00139         printf("Client Site Name :\t\t%s\n", reply.client_site_name);
00140 
00141         d_printf("NT Version: %d\n", reply.version);
00142         d_printf("LMNT Token: %.2x\n", reply.lmnt_token);
00143         d_printf("LM20 Token: %.2x\n", reply.lm20_token);
00144 
00145         return 0;
00146 }
00147 
00148 
00149 /*
00150   this implements the CLDAP based netlogon lookup requests
00151   for finding the domain controller of a ADS domain
00152 */
00153 static int net_ads_lookup(int argc, const char **argv)
00154 {
00155         ADS_STRUCT *ads;
00156 
00157         if (!ADS_ERR_OK(ads_startup_nobind(False, &ads))) {
00158                 d_fprintf(stderr, "Didn't find the cldap server!\n");
00159                 return -1;
00160         }
00161 
00162         if (!ads->config.realm) {
00163                 ads->config.realm = CONST_DISCARD(char *, opt_target_workgroup);
00164                 ads->ldap_port = 389;
00165         }
00166 
00167         return net_ads_cldap_netlogon(ads);
00168 }
00169 
00170 
00171 
00172 static int net_ads_info(int argc, const char **argv)
00173 {
00174         ADS_STRUCT *ads;
00175 
00176         if (!ADS_ERR_OK(ads_startup_nobind(False, &ads))) {
00177                 d_fprintf(stderr, "Didn't find the ldap server!\n");
00178                 return -1;
00179         }
00180 
00181         if (!ads || !ads->config.realm) {
00182                 d_fprintf(stderr, "Didn't find the ldap server!\n");
00183                 return -1;
00184         }
00185 
00186         /* Try to set the server's current time since we didn't do a full
00187            TCP LDAP session initially */
00188 
00189         if ( !ADS_ERR_OK(ads_current_time( ads )) ) {
00190                 d_fprintf( stderr, "Failed to get server's current time!\n");
00191         }
00192 
00193         d_printf("LDAP server: %s\n", inet_ntoa(ads->ldap_ip));
00194         d_printf("LDAP server name: %s\n", ads->config.ldap_server_name);
00195         d_printf("Realm: %s\n", ads->config.realm);
00196         d_printf("Bind Path: %s\n", ads->config.bind_path);
00197         d_printf("LDAP port: %d\n", ads->ldap_port);
00198         d_printf("Server time: %s\n", http_timestring(ads->config.current_time));
00199 
00200         d_printf("KDC server: %s\n", ads->auth.kdc_server );
00201         d_printf("Server time offset: %d\n", ads->auth.time_offset );
00202 
00203         return 0;
00204 }
00205 
00206 static void use_in_memory_ccache(void) {
00207         /* Use in-memory credentials cache so we do not interfere with
00208          * existing credentials */
00209         setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
00210 }
00211 
00212 static ADS_STATUS ads_startup_int(BOOL only_own_domain, uint32 auth_flags, ADS_STRUCT **ads_ret)
00213 {
00214         ADS_STRUCT *ads = NULL;
00215         ADS_STATUS status;
00216         BOOL need_password = False;
00217         BOOL second_time = False;
00218         char *cp;
00219         const char *realm = NULL;
00220         BOOL tried_closest_dc = False;
00221 
00222         /* lp_realm() should be handled by a command line param, 
00223            However, the join requires that realm be set in smb.conf
00224            and compares our realm with the remote server's so this is
00225            ok until someone needs more flexibility */
00226 
00227         *ads_ret = NULL;
00228 
00229 retry_connect:
00230         if (only_own_domain) {
00231                 realm = lp_realm();
00232         } else {
00233                 realm = assume_own_realm();
00234         }
00235 
00236         ads = ads_init(realm, opt_target_workgroup, opt_host);
00237 
00238         if (!opt_user_name) {
00239                 opt_user_name = "administrator";
00240         }
00241 
00242         if (opt_user_specified) {
00243                 need_password = True;
00244         }
00245 
00246 retry:
00247         if (!opt_password && need_password && !opt_machine_pass) {
00248                 char *prompt = NULL;
00249                 asprintf(&prompt,"%s's password: ", opt_user_name);
00250                 if (!prompt) {
00251                         ads_destroy(&ads);
00252                         return ADS_ERROR(LDAP_NO_MEMORY);
00253                 }
00254                 opt_password = getpass(prompt);
00255                 free(prompt);
00256         }
00257 
00258         if (opt_password) {
00259                 use_in_memory_ccache();
00260                 SAFE_FREE(ads->auth.password);
00261                 ads->auth.password = smb_xstrdup(opt_password);
00262         }
00263 
00264         ads->auth.flags |= auth_flags;
00265         SAFE_FREE(ads->auth.user_name);
00266         ads->auth.user_name = smb_xstrdup(opt_user_name);
00267 
00268        /*
00269         * If the username is of the form "name@realm", 
00270         * extract the realm and convert to upper case.
00271         * This is only used to establish the connection.
00272         */
00273        if ((cp = strchr_m(ads->auth.user_name, '@'))!=0) {
00274                 *cp++ = '\0';
00275                 SAFE_FREE(ads->auth.realm);
00276                 ads->auth.realm = smb_xstrdup(cp);
00277                 strupper_m(ads->auth.realm);
00278        }
00279 
00280         status = ads_connect(ads);
00281 
00282         if (!ADS_ERR_OK(status)) {
00283 
00284                 if (NT_STATUS_EQUAL(ads_ntstatus(status), 
00285                                     NT_STATUS_NO_LOGON_SERVERS)) {
00286                         DEBUG(0,("ads_connect: %s\n", ads_errstr(status)));
00287                         ads_destroy(&ads);
00288                         return status;
00289                 }
00290         
00291                 if (!need_password && !second_time && !(auth_flags & ADS_AUTH_NO_BIND)) {
00292                         need_password = True;
00293                         second_time = True;
00294                         goto retry;
00295                 } else {
00296                         ads_destroy(&ads);
00297                         return status;
00298                 }
00299         }
00300 
00301         /* when contacting our own domain, make sure we use the closest DC.
00302          * This is done by reconnecting to ADS because only the first call to
00303          * ads_connect will give us our own sitename */
00304 
00305         if ((only_own_domain || !opt_host) && !tried_closest_dc) {
00306 
00307                 tried_closest_dc = True; /* avoid loop */
00308 
00309                 if (!ads->config.tried_closest_dc) {
00310 
00311                         namecache_delete(ads->server.realm, 0x1C);
00312                         namecache_delete(ads->server.workgroup, 0x1C);
00313 
00314                         ads_destroy(&ads);
00315                         ads = NULL;
00316 
00317                         goto retry_connect;
00318                 }
00319         }
00320 
00321         *ads_ret = ads;
00322         return status;
00323 }
00324 
00325 ADS_STATUS ads_startup(BOOL only_own_domain, ADS_STRUCT **ads)
00326 {
00327         return ads_startup_int(only_own_domain, 0, ads);
00328 }
00329 
00330 ADS_STATUS ads_startup_nobind(BOOL only_own_domain, ADS_STRUCT **ads)
00331 {
00332         return ads_startup_int(only_own_domain, ADS_AUTH_NO_BIND, ads);
00333 }
00334 
00335 /*
00336   Check to see if connection can be made via ads.
00337   ads_startup() stores the password in opt_password if it needs to so
00338   that rpc or rap can use it without re-prompting.
00339 */
00340 static int net_ads_check_int(const char *realm, const char *workgroup, const char *host)
00341 {
00342         ADS_STRUCT *ads;
00343         ADS_STATUS status;
00344 
00345         if ( (ads = ads_init( realm, workgroup, host )) == NULL ) {
00346                 return -1;
00347         }
00348 
00349         ads->auth.flags |= ADS_AUTH_NO_BIND;
00350 
00351         status = ads_connect(ads);
00352         if ( !ADS_ERR_OK(status) ) {
00353                 return -1;
00354         }
00355 
00356         ads_destroy(&ads);
00357         return 0;
00358 }
00359 
00360 int net_ads_check_our_domain(void)
00361 {
00362         return net_ads_check_int(lp_realm(), lp_workgroup(), NULL);
00363 }
00364 
00365 int net_ads_check(void)
00366 {
00367         return net_ads_check_int(NULL, opt_workgroup, opt_host);
00368 }
00369 /* 
00370    determine the netbios workgroup name for a domain
00371  */
00372 static int net_ads_workgroup(int argc, const char **argv)
00373 {
00374         ADS_STRUCT *ads;
00375         struct cldap_netlogon_reply reply;
00376 
00377         if (!ADS_ERR_OK(ads_startup_nobind(False, &ads))) {
00378                 d_fprintf(stderr, "Didn't find the cldap server!\n");
00379                 return -1;
00380         }
00381         
00382         if (!ads->config.realm) {
00383                 ads->config.realm = CONST_DISCARD(char *, opt_target_workgroup);
00384                 ads->ldap_port = 389;
00385         }
00386         
00387         if ( !ads_cldap_netlogon( inet_ntoa(ads->ldap_ip), ads->server.realm, &reply ) ) {
00388                 d_fprintf(stderr, "CLDAP query failed!\n");
00389                 return -1;
00390         }
00391 
00392         d_printf("Workgroup: %s\n", reply.netbios_domain);
00393 
00394         ads_destroy(&ads);
00395         
00396         return 0;
00397 }
00398 
00399 
00400 
00401 static BOOL usergrp_display(char *field, void **values, void *data_area)
00402 {
00403         char **disp_fields = (char **) data_area;
00404 
00405         if (!field) { /* must be end of record */
00406                 if (disp_fields[0]) {
00407                         if (!strchr_m(disp_fields[0], '$')) {
00408                                 if (disp_fields[1])
00409                                         d_printf("%-21.21s %s\n", 
00410                                                disp_fields[0], disp_fields[1]);
00411                                 else
00412                                         d_printf("%s\n", disp_fields[0]);
00413                         }
00414                 }
00415                 SAFE_FREE(disp_fields[0]);
00416                 SAFE_FREE(disp_fields[1]);
00417                 return True;
00418         }
00419         if (!values) /* must be new field, indicate string field */
00420                 return True;
00421         if (StrCaseCmp(field, "sAMAccountName") == 0) {
00422                 disp_fields[0] = SMB_STRDUP((char *) values[0]);
00423         }
00424         if (StrCaseCmp(field, "description") == 0)
00425                 disp_fields[1] = SMB_STRDUP((char *) values[0]);
00426         return True;
00427 }
00428 
00429 static int net_ads_user_usage(int argc, const char **argv)
00430 {
00431         return net_help_user(argc, argv);
00432 } 
00433 
00434 static int ads_user_add(int argc, const char **argv)
00435 {
00436         ADS_STRUCT *ads;
00437         ADS_STATUS status;
00438         char *upn, *userdn;
00439         LDAPMessage *res=NULL;
00440         int rc = -1;
00441         char *ou_str = NULL;
00442 
00443         if (argc < 1) return net_ads_user_usage(argc, argv);
00444         
00445         if (!ADS_ERR_OK(ads_startup(False, &ads))) {
00446                 return -1;
00447         }
00448 
00449         status = ads_find_user_acct(ads, &res, argv[0]);
00450 
00451         if (!ADS_ERR_OK(status)) {
00452                 d_fprintf(stderr, "ads_user_add: %s\n", ads_errstr(status));
00453                 goto done;
00454         }
00455         
00456         if (ads_count_replies(ads, res)) {
00457                 d_fprintf(stderr, "ads_user_add: User %s already exists\n", argv[0]);
00458                 goto done;
00459         }
00460 
00461         if (opt_container) {
00462                 ou_str = SMB_STRDUP(opt_container);
00463         } else {
00464                 ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
00465         }
00466 
00467         status = ads_add_user_acct(ads, argv[0], ou_str, opt_comment);
00468 
00469         if (!ADS_ERR_OK(status)) {
00470                 d_fprintf(stderr, "Could not add user %s: %s\n", argv[0],
00471                          ads_errstr(status));
00472                 goto done;
00473         }
00474 
00475         /* if no password is to be set, we're done */
00476         if (argc == 1) { 
00477                 d_printf("User %s added\n", argv[0]);
00478                 rc = 0;
00479                 goto done;
00480         }
00481 
00482         /* try setting the password */
00483         asprintf(&upn, "%s@%s", argv[0], ads->config.realm);
00484         status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1], 
00485                                        ads->auth.time_offset);
00486         safe_free(upn);
00487         if (ADS_ERR_OK(status)) {
00488                 d_printf("User %s added\n", argv[0]);
00489                 rc = 0;
00490                 goto done;
00491         }
00492 
00493         /* password didn't set, delete account */
00494         d_fprintf(stderr, "Could not add user %s.  Error setting password %s\n",
00495                  argv[0], ads_errstr(status));
00496         ads_msgfree(ads, res);
00497         status=ads_find_user_acct(ads, &res, argv[0]);
00498         if (ADS_ERR_OK(status)) {
00499                 userdn = ads_get_dn(ads, res);
00500                 ads_del_dn(ads, userdn);
00501                 ads_memfree(ads, userdn);
00502         }
00503 
00504  done:
00505         if (res)
00506                 ads_msgfree(ads, res);
00507         ads_destroy(&ads);
00508         SAFE_FREE(ou_str);
00509         return rc;
00510 }
00511 
00512 static int ads_user_info(int argc, const char **argv)
00513 {
00514         ADS_STRUCT *ads;
00515         ADS_STATUS rc;
00516         LDAPMessage *res;
00517         const char *attrs[] = {"memberOf", NULL};
00518         char *searchstring=NULL;
00519         char **grouplist;
00520         char *escaped_user;
00521 
00522         if (argc < 1) {
00523                 return net_ads_user_usage(argc, argv);
00524         }
00525 
00526         escaped_user = escape_ldap_string_alloc(argv[0]);
00527 
00528         if (!escaped_user) {
00529                 d_fprintf(stderr, "ads_user_info: failed to escape user %s\n", argv[0]);
00530                 return -1;
00531         }
00532 
00533         if (!ADS_ERR_OK(ads_startup(False, &ads))) {
00534                 SAFE_FREE(escaped_user);
00535                 return -1;
00536         }
00537 
00538         asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user);
00539         rc = ads_search(ads, &res, searchstring, attrs);
00540         safe_free(searchstring);
00541 
00542         if (!ADS_ERR_OK(rc)) {
00543                 d_fprintf(stderr, "ads_search: %s\n", ads_errstr(rc));
00544                 ads_destroy(&ads);
00545                 SAFE_FREE(escaped_user);
00546                 return -1;
00547         }
00548         
00549         grouplist = ldap_get_values((LDAP *)ads->ld,
00550                                     (LDAPMessage *)res, "memberOf");
00551 
00552         if (grouplist) {
00553                 int i;
00554                 char **groupname;
00555                 for (i=0;grouplist[i];i++) {
00556                         groupname = ldap_explode_dn(grouplist[i], 1);
00557                         d_printf("%s\n", groupname[0]);
00558                         ldap_value_free(groupname);
00559                 }
00560                 ldap_value_free(grouplist);
00561         }
00562         
00563         ads_msgfree(ads, res);
00564         ads_destroy(&ads);
00565         SAFE_FREE(escaped_user);
00566         return 0;
00567 }
00568 
00569 static int ads_user_delete(int argc, const char **argv)
00570 {
00571         ADS_STRUCT *ads;
00572         ADS_STATUS rc;
00573         LDAPMessage *res = NULL;
00574         char *userdn;
00575 
00576         if (argc < 1) {
00577                 return net_ads_user_usage(argc, argv);
00578         }
00579         
00580         if (!ADS_ERR_OK(ads_startup(False, &ads))) {
00581                 return -1;
00582         }
00583 
00584         rc = ads_find_user_acct(ads, &res, argv[0]);
00585         if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
00586                 d_printf("User %s does not exist.\n", argv[0]);
00587                 ads_msgfree(ads, res);
00588                 ads_destroy(&ads);
00589                 return -1;
00590         }
00591         userdn = ads_get_dn(ads, res);
00592         ads_msgfree(ads, res);
00593         rc = ads_del_dn(ads, userdn);
00594         ads_memfree(ads, userdn);
00595         if (ADS_ERR_OK(rc)) {
00596                 d_printf("User %s deleted\n", argv[0]);
00597                 ads_destroy(&ads);
00598                 return 0;
00599         }
00600         d_fprintf(stderr, "Error deleting user %s: %s\n", argv[0], 
00601                  ads_errstr(rc));
00602         ads_destroy(&ads);
00603         return -1;
00604 }
00605 
00606 int net_ads_user(int argc, const char **argv)
00607 {
00608         struct functable func[] = {
00609                 {"ADD", ads_user_add},
00610                 {"INFO", ads_user_info},
00611                 {"DELETE", ads_user_delete},
00612                 {NULL, NULL}
00613         };
00614         ADS_STRUCT *ads;
00615         ADS_STATUS rc;
00616         const char *shortattrs[] = {"sAMAccountName", NULL};
00617         const char *longattrs[] = {"sAMAccountName", "description", NULL};
00618         char *disp_fields[2] = {NULL, NULL};
00619         
00620         if (argc == 0) {
00621                 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
00622                         return -1;
00623                 }
00624 
00625                 if (opt_long_list_entries)
00626                         d_printf("\nUser name             Comment"\
00627                                  "\n-----------------------------\n");
00628 
00629                 rc = ads_do_search_all_fn(ads, ads->config.bind_path, 
00630                                           LDAP_SCOPE_SUBTREE,
00631                                           "(objectCategory=user)", 
00632                                           opt_long_list_entries ? longattrs :
00633                                           shortattrs, usergrp_display, 
00634                                           disp_fields);
00635                 ads_destroy(&ads);
00636                 return ADS_ERR_OK(rc) ? 0 : -1;
00637         }
00638 
00639         return net_run_function(argc, argv, func, net_ads_user_usage);
00640 }
00641 
00642 static int net_ads_group_usage(int argc, const char **argv)
00643 {
00644         return net_help_group(argc, argv);
00645 } 
00646 
00647 static int ads_group_add(int argc, const char **argv)
00648 {
00649         ADS_STRUCT *ads;
00650         ADS_STATUS status;
00651         LDAPMessage *res=NULL;
00652         int rc = -1;
00653         char *ou_str = NULL;
00654 
00655         if (argc < 1) {
00656                 return net_ads_group_usage(argc, argv);
00657         }
00658         
00659         if (!ADS_ERR_OK(ads_startup(False, &ads))) {
00660                 return -1;
00661         }
00662 
00663         status = ads_find_user_acct(ads, &res, argv[0]);
00664 
00665         if (!ADS_ERR_OK(status)) {
00666                 d_fprintf(stderr, "ads_group_add: %s\n", ads_errstr(status));
00667                 goto done;
00668         }
00669         
00670         if (ads_count_replies(ads, res)) {
00671                 d_fprintf(stderr, "ads_group_add: Group %s already exists\n", argv[0]);
00672                 goto done;
00673         }
00674 
00675         if (opt_container) {
00676                 ou_str = SMB_STRDUP(opt_container);
00677         } else {
00678                 ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
00679         }
00680 
00681         status = ads_add_group_acct(ads, argv[0], ou_str, opt_comment);
00682 
00683         if (ADS_ERR_OK(status)) {
00684                 d_printf("Group %s added\n", argv[0]);
00685                 rc = 0;
00686         } else {
00687                 d_fprintf(stderr, "Could not add group %s: %s\n", argv[0],
00688                          ads_errstr(status));
00689         }
00690 
00691  done:
00692         if (res)
00693                 ads_msgfree(ads, res);
00694         ads_destroy(&ads);
00695         SAFE_FREE(ou_str);
00696         return rc;
00697 }
00698 
00699 static int ads_group_delete(int argc, const char **argv)
00700 {
00701         ADS_STRUCT *ads;
00702         ADS_STATUS rc;
00703         LDAPMessage *res = NULL;
00704         char *groupdn;
00705 
00706         if (argc < 1) {
00707                 return net_ads_group_usage(argc, argv);
00708         }
00709         
00710         if (!ADS_ERR_OK(ads_startup(False, &ads))) {
00711                 return -1;
00712         }
00713 
00714         rc = ads_find_user_acct(ads, &res, argv[0]);
00715         if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
00716                 d_printf("Group %s does not exist.\n", argv[0]);
00717                 ads_msgfree(ads, res);
00718                 ads_destroy(&ads);
00719                 return -1;
00720         }
00721         groupdn = ads_get_dn(ads, res);
00722         ads_msgfree(ads, res);
00723         rc = ads_del_dn(ads, groupdn);
00724         ads_memfree(ads, groupdn);
00725         if (ADS_ERR_OK(rc)) {
00726                 d_printf("Group %s deleted\n", argv[0]);
00727                 ads_destroy(&ads);
00728                 return 0;
00729         }
00730         d_fprintf(stderr, "Error deleting group %s: %s\n", argv[0], 
00731                  ads_errstr(rc));
00732         ads_destroy(&ads);
00733         return -1;
00734 }
00735 
00736 int net_ads_group(int argc, const char **argv)
00737 {
00738         struct functable func[] = {
00739                 {"ADD", ads_group_add},
00740                 {"DELETE", ads_group_delete},
00741                 {NULL, NULL}
00742         };
00743         ADS_STRUCT *ads;
00744         ADS_STATUS rc;
00745         const char *shortattrs[] = {"sAMAccountName", NULL};
00746         const char *longattrs[] = {"sAMAccountName", "description", NULL};
00747         char *disp_fields[2] = {NULL, NULL};
00748 
00749         if (argc == 0) {
00750                 if (!ADS_ERR_OK(ads_startup(False, &ads))) {
00751                         return -1;
00752                 }
00753 
00754                 if (opt_long_list_entries)
00755                         d_printf("\nGroup name            Comment"\
00756                                  "\n-----------------------------\n");
00757                 rc = ads_do_search_all_fn(ads, ads->config.bind_path, 
00758                                           LDAP_SCOPE_SUBTREE, 
00759                                           "(objectCategory=group)", 
00760                                           opt_long_list_entries ? longattrs : 
00761                                           shortattrs, usergrp_display, 
00762                                           disp_fields);
00763 
00764                 ads_destroy(&ads);
00765                 return ADS_ERR_OK(rc) ? 0 : -1;
00766         }
00767         return net_run_function(argc, argv, func, net_ads_group_usage);
00768 }
00769 
00770 static int net_ads_status(int argc, const char **argv)
00771 {
00772         ADS_STRUCT *ads;
00773         ADS_STATUS rc;
00774         LDAPMessage *res;
00775 
00776         if (!ADS_ERR_OK(ads_startup(True, &ads))) {
00777                 return -1;
00778         }
00779 
00780         rc = ads_find_machine_acct(ads, &res, global_myname());
00781         if (!ADS_ERR_OK(rc)) {
00782                 d_fprintf(stderr, "ads_find_machine_acct: %s\n", ads_errstr(rc));
00783                 ads_destroy(&ads);
00784                 return -1;
00785         }
00786 
00787         if (ads_count_replies(ads, res) == 0) {
00788                 d_fprintf(stderr, "No machine account for '%s' found\n", global_myname());
00789                 ads_destroy(&ads);
00790                 return -1;
00791         }
00792 
00793         ads_dump(ads, res);
00794         ads_destroy(&ads);
00795         return 0;
00796 }
00797 
00798 /*******************************************************************
00799  Leave an AD domain.  Windows XP disables the machine account.
00800  We'll try the same.  The old code would do an LDAP delete.
00801  That only worked using the machine creds because added the machine
00802  with full control to the computer object's ACL.
00803 *******************************************************************/
00804 
00805 static int net_ads_leave(int argc, const char **argv)
00806 {
00807         ADS_STRUCT *ads = NULL;
00808         ADS_STATUS adsret;
00809         NTSTATUS status;
00810         int ret = -1;
00811         struct cli_state *cli = NULL;
00812         TALLOC_CTX *ctx;
00813         DOM_SID *dom_sid = NULL;
00814         char *short_domain_name = NULL;      
00815 
00816         if (!secrets_init()) {
00817                 DEBUG(1,("Failed to initialise secrets database\n"));
00818                 return -1;
00819         }
00820 
00821         if (!(ctx = talloc_init("net_ads_leave"))) {
00822                 d_fprintf(stderr, "Could not initialise talloc context.\n");
00823                 return -1;
00824         }
00825 
00826         /* The finds a DC and takes care of getting the 
00827            user creds if necessary */
00828 
00829         if (!ADS_ERR_OK(ads_startup(True, &ads))) {
00830                 return -1;
00831         }
00832 
00833         /* make RPC calls here */
00834 
00835         if ( !NT_STATUS_IS_OK(connect_to_ipc_krb5(&cli, &ads->ldap_ip, 
00836                 ads->config.ldap_server_name)) )
00837         {
00838                 goto done;
00839         }
00840         
00841         if ( !NT_STATUS_IS_OK(netdom_get_domain_sid( ctx, cli, &short_domain_name, &dom_sid )) ) {
00842                 goto done;
00843         }
00844 
00845         saf_delete( short_domain_name );
00846 
00847         status = netdom_leave_domain(ctx, cli, dom_sid);
00848 
00849         /* Try and delete it via LDAP - the old way we used to. */
00850 
00851         adsret = ads_leave_realm(ads, global_myname());
00852         if (ADS_ERR_OK(adsret)) {
00853                 d_printf("Deleted account for '%s' in realm '%s'\n",
00854                         global_myname(), ads->config.realm);
00855                 ret = 0;
00856         } else {
00857                 /* We couldn't delete it - see if the disable succeeded. */
00858                 if (NT_STATUS_IS_OK(status)) {
00859                         d_printf("Disabled account for '%s' in realm '%s'\n",
00860                                 global_myname(), ads->config.realm);
00861                         ret = 0;
00862                 } else {
00863                         d_fprintf(stderr, "Failed to disable machine account for '%s' in realm '%s'\n",
00864                                 global_myname(), ads->config.realm);
00865                 }
00866         }
00867 
00868 done:
00869 
00870         if ( cli ) 
00871                 cli_shutdown(cli);
00872 
00873         ads_destroy(&ads);
00874         TALLOC_FREE( ctx );
00875 
00876         return ret;
00877 }
00878 
00879 static NTSTATUS net_ads_join_ok(void)
00880 {
00881         ADS_STRUCT *ads = NULL;
00882         ADS_STATUS status;
00883 
00884         if (!secrets_init()) {
00885                 DEBUG(1,("Failed to initialise secrets database\n"));
00886                 return NT_STATUS_ACCESS_DENIED;
00887         }
00888 
00889         net_use_krb_machine_account();
00890 
00891         status = ads_startup(True, &ads);
00892         if (!ADS_ERR_OK(status)) {
00893                 return ads_ntstatus(status);
00894         }
00895 
00896         ads_destroy(&ads);
00897         return NT_STATUS_OK;
00898 }
00899 
00900 /*
00901   check that an existing join is OK
00902  */
00903 int net_ads_testjoin(int argc, const char **argv)
00904 {
00905         NTSTATUS status;
00906         use_in_memory_ccache();
00907 
00908         /* Display success or failure */
00909         status = net_ads_join_ok();
00910         if (!NT_STATUS_IS_OK(status)) {
00911                 fprintf(stderr,"Join to domain is not valid: %s\n", 
00912                         get_friendly_nt_error_msg(status));
00913                 return -1;
00914         }
00915 
00916         printf("Join is OK\n");
00917         return 0;
00918 }
00919 
00920 /*******************************************************************
00921   Simple configu checks before beginning the join
00922  ********************************************************************/
00923 
00924 static NTSTATUS check_ads_config( void )
00925 {
00926         if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
00927                 d_printf("Host is not configured as a member server.\n");
00928                 return NT_STATUS_INVALID_DOMAIN_ROLE;
00929         }
00930 
00931         if (strlen(global_myname()) > 15) {
00932                 d_printf("Our netbios name can be at most 15 chars long, "
00933                          "\"%s\" is %u chars long\n", global_myname(),
00934                          (unsigned int)strlen(global_myname()));
00935                 return NT_STATUS_NAME_TOO_LONG;
00936         }
00937 
00938         if ( lp_security() == SEC_ADS && !*lp_realm()) {
00939                 d_fprintf(stderr, "realm must be set in in %s for ADS "
00940                         "join to succeed.\n", dyn_CONFIGFILE);
00941                 return NT_STATUS_INVALID_PARAMETER;
00942         }
00943 
00944         if (!secrets_init()) {
00945                 DEBUG(1,("Failed to initialise secrets database\n"));
00946                 /* This is a good bet for failure of secrets_init ... */
00947                 return NT_STATUS_ACCESS_DENIED;
00948         }
00949         
00950         return NT_STATUS_OK;
00951 }
00952 
00953 /*******************************************************************
00954  Do the domain join
00955  ********************************************************************/
00956 
00957 static NTSTATUS net_join_domain(TALLOC_CTX *ctx, const char *servername, 
00958                                 struct in_addr *ip, char **domain, 
00959                                 DOM_SID **dom_sid, 
00960                                 const char *password)
00961 {
00962         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
00963         struct cli_state *cli = NULL;
00964 
00965         ret = connect_to_ipc_krb5(&cli, ip, servername);
00966         if ( !NT_STATUS_IS_OK(ret) ) {
00967                 goto done;
00968         }
00969         
00970         ret = netdom_get_domain_sid( ctx, cli, domain, dom_sid );
00971         if ( !NT_STATUS_IS_OK(ret) ) {
00972                 goto done;
00973         }
00974 
00975         /* cli->server_domain is not filled in when using krb5 
00976            session setups */
00977 
00978         saf_store( *domain, cli->desthost );
00979 
00980         ret = netdom_join_domain( ctx, cli, *dom_sid, password, ND_TYPE_AD );
00981 
00982 done:
00983         if ( cli ) 
00984                 cli_shutdown(cli);
00985 
00986         return ret;
00987 }
00988 
00989 /*******************************************************************
00990  Set a machines dNSHostName and servicePrincipalName attributes
00991  ********************************************************************/
00992 
00993 static ADS_STATUS net_set_machine_spn(TALLOC_CTX *ctx, ADS_STRUCT *ads_s )
00994 {
00995         ADS_STATUS status = ADS_ERROR(LDAP_SERVER_DOWN);
00996         char *new_dn;
00997         ADS_MODLIST mods;
00998         const char *servicePrincipalName[3] = {NULL, NULL, NULL};
00999         char *psp;
01000         fstring my_fqdn;
01001         LDAPMessage *res = NULL;
01002         char *dn_string = NULL;
01003         const char *machine_name = global_myname();
01004         int count;
01005         
01006         if ( !machine_name ) {
01007                 return ADS_ERROR(LDAP_NO_MEMORY);
01008         }
01009         
01010         /* Find our DN */
01011         
01012         status = ads_find_machine_acct(ads_s, &res, machine_name);
01013         if (!ADS_ERR_OK(status)) 
01014                 return status;
01015                 
01016         if ( (count = ads_count_replies(ads_s, res)) != 1 ) {
01017                 DEBUG(1,("net_set_machine_spn: %d entries returned!\n", count));
01018                 return ADS_ERROR(LDAP_NO_MEMORY);       
01019         }
01020         
01021         if ( (dn_string = ads_get_dn(ads_s, res)) == NULL ) {
01022                 DEBUG(1, ("ads_add_machine_acct: ads_get_dn returned NULL (malloc failure?)\n"));
01023                 goto done;
01024         }
01025         
01026         new_dn = talloc_strdup(ctx, dn_string);
01027         ads_memfree(ads_s, dn_string);
01028         if (!new_dn) {
01029                 return ADS_ERROR(LDAP_NO_MEMORY);
01030         }
01031 
01032         /* Windows only creates HOST/shortname & HOST/fqdn. */
01033            
01034         if ( !(psp = talloc_asprintf(ctx, "HOST/%s", machine_name)) ) 
01035                 goto done;
01036         strupper_m(psp);
01037         servicePrincipalName[0] = psp;
01038 
01039         name_to_fqdn(my_fqdn, machine_name);
01040         strlower_m(my_fqdn);
01041         if ( !(psp = talloc_asprintf(ctx, "HOST/%s", my_fqdn)) ) 
01042                 goto done;
01043         servicePrincipalName[1] = psp;
01044         
01045         if (!(mods = ads_init_mods(ctx))) {
01046                 goto done;
01047         }
01048         
01049         /* fields of primary importance */
01050         
01051         ads_mod_str(ctx, &mods, "dNSHostName", my_fqdn);
01052         ads_mod_strlist(ctx, &mods, "servicePrincipalName", servicePrincipalName);
01053 
01054         status = ads_gen_mod(ads_s, new_dn, mods);
01055 
01056 done:
01057         ads_msgfree(ads_s, res);
01058         
01059         return status;
01060 }
01061 
01062 /*******************************************************************
01063  Set a machines dNSHostName and servicePrincipalName attributes
01064  ********************************************************************/
01065 
01066 static ADS_STATUS net_set_machine_upn(TALLOC_CTX *ctx, ADS_STRUCT *ads_s, const char *upn )
01067 {
01068         ADS_STATUS status = ADS_ERROR(LDAP_SERVER_DOWN);
01069         char *new_dn;
01070         ADS_MODLIST mods;
01071         LDAPMessage *res = NULL;
01072         char *dn_string = NULL;
01073         const char *machine_name = global_myname();
01074         int count;
01075         
01076         if ( !machine_name ) {
01077                 return ADS_ERROR(LDAP_NO_MEMORY);
01078         }
01079         
01080         /* Find our DN */
01081         
01082         status = ads_find_machine_acct(ads_s, &res, machine_name);
01083         if (!ADS_ERR_OK(status)) 
01084                 return status;
01085                 
01086         if ( (count = ads_count_replies(ads_s, res)) != 1 ) {
01087                 DEBUG(1,("net_set_machine_spn: %d entries returned!\n", count));
01088                 return ADS_ERROR(LDAP_NO_MEMORY);       
01089         }
01090         
01091         if ( (dn_string = ads_get_dn(ads_s, res)) == NULL ) {
01092                 DEBUG(1, ("ads_add_machine_acct: ads_get_dn returned NULL (malloc failure?)\n"));
01093                 goto done;
01094         }
01095         
01096         new_dn = talloc_strdup(ctx, dn_string);
01097         ads_memfree(ads_s, dn_string);
01098         if (!new_dn) {
01099                 return ADS_ERROR(LDAP_NO_MEMORY);
01100         }
01101         
01102         /* now do the mods */
01103         
01104         if (!(mods = ads_init_mods(ctx))) {
01105                 goto done;
01106         }
01107         
01108         /* fields of primary importance */
01109         
01110         ads_mod_str(ctx, &mods, "userPrincipalName", upn);
01111 
01112         status = ads_gen_mod(ads_s, new_dn, mods);
01113 
01114 done:
01115         ads_msgfree(ads_s, res);
01116         
01117         return status;
01118 }
01119 
01120 /*******************************************************************
01121  Set a machines dNSHostName and servicePrincipalName attributes
01122  ********************************************************************/
01123 
01124 static ADS_STATUS net_set_os_attributes(TALLOC_CTX *ctx, ADS_STRUCT *ads_s, 
01125                                         const char *os_name, const char *os_version )
01126 {
01127         ADS_STATUS status = ADS_ERROR(LDAP_SERVER_DOWN);
01128         char *new_dn;
01129         ADS_MODLIST mods;
01130         LDAPMessage *res = NULL;
01131         char *dn_string = NULL;
01132         const char *machine_name = global_myname();
01133         int count;
01134         char *os_sp = NULL;
01135         
01136         if ( !os_name || !os_version ) {
01137                 return ADS_ERROR(LDAP_NO_MEMORY);
01138         }
01139         
01140         /* Find our DN */
01141         
01142         status = ads_find_machine_acct(ads_s, &res, machine_name);
01143         if (!ADS_ERR_OK(status)) 
01144                 return status;
01145                 
01146         if ( (count = ads_count_replies(ads_s, res)) != 1 ) {
01147                 DEBUG(1,("net_set_machine_spn: %d entries returned!\n", count));
01148                 return ADS_ERROR(LDAP_NO_MEMORY);       
01149         }
01150         
01151         if ( (dn_string = ads_get_dn(ads_s, res)) == NULL ) {
01152                 DEBUG(1, ("ads_add_machine_acct: ads_get_dn returned NULL (malloc failure?)\n"));
01153                 goto done;
01154         }
01155         
01156         new_dn = talloc_strdup(ctx, dn_string);
01157         ads_memfree(ads_s, dn_string);
01158         if (!new_dn) {
01159                 return ADS_ERROR(LDAP_NO_MEMORY);
01160         }
01161         
01162         /* now do the mods */
01163         
01164         if (!(mods = ads_init_mods(ctx))) {
01165                 goto done;
01166         }
01167 
01168         os_sp = talloc_asprintf( ctx, "Samba %s", SAMBA_VERSION_STRING );
01169         
01170         /* fields of primary importance */
01171         
01172         ads_mod_str(ctx, &mods, "operatingSystem", os_name);
01173         ads_mod_str(ctx, &mods, "operatingSystemVersion", os_version);
01174         if ( os_sp )
01175                 ads_mod_str(ctx, &mods, "operatingSystemServicePack", os_sp);
01176 
01177         status = ads_gen_mod(ads_s, new_dn, mods);
01178 
01179 done:
01180         ads_msgfree(ads_s, res);
01181         TALLOC_FREE( os_sp );   
01182         
01183         return status;
01184 }
01185 
01186 /*******************************************************************
01187   join a domain using ADS (LDAP mods)
01188  ********************************************************************/
01189 
01190 static ADS_STATUS net_precreate_machine_acct( ADS_STRUCT *ads, const char *ou )
01191 {
01192         ADS_STATUS rc = ADS_ERROR(LDAP_SERVER_DOWN);
01193         char *dn, *ou_str;
01194         LDAPMessage *res = NULL;
01195 
01196         ou_str = ads_ou_string(ads, ou);
01197         if ((asprintf(&dn, "%s,%s", ou_str, ads->config.bind_path)) == -1) {
01198                 SAFE_FREE(ou_str);
01199                 return ADS_ERROR(LDAP_NO_MEMORY);
01200         }
01201 
01202         rc = ads_search_dn(ads, &res, dn, NULL);
01203         ads_msgfree(ads, res);
01204 
01205         if (ADS_ERR_OK(rc)) {
01206                 /* Attempt to create the machine account and bail if this fails.
01207                    Assume that the admin wants exactly what they requested */
01208 
01209                 rc = ads_create_machine_acct( ads, global_myname(), dn );
01210                 if ( rc.error_type == ENUM_ADS_ERROR_LDAP && rc.err.rc == LDAP_ALREADY_EXISTS ) {
01211                         rc = ADS_SUCCESS;
01212                 }
01213         }
01214 
01215         SAFE_FREE( ou_str );
01216         SAFE_FREE( dn );
01217 
01218         return rc;
01219 }
01220 
01221 /************************************************************************
01222  ************************************************************************/
01223 
01224 static BOOL net_derive_salting_principal( TALLOC_CTX *ctx, ADS_STRUCT *ads )
01225 {
01226         uint32 domain_func;
01227         ADS_STATUS status;
01228         fstring salt;
01229         char *std_salt;
01230         LDAPMessage *res = NULL;
01231         const char *machine_name = global_myname();
01232 
01233         status = ads_domain_func_level( ads, &domain_func );
01234         if ( !ADS_ERR_OK(status) ) {
01235                 DEBUG(2,("Failed to determine domain functional level!\n"));
01236                 return False;
01237         }
01238 
01239         /* go ahead and setup the default salt */
01240 
01241         if ( (std_salt = kerberos_standard_des_salt()) == NULL ) {
01242                 d_fprintf(stderr, "net_derive_salting_principal: failed to obtain stanard DES salt\n");
01243                 return False;
01244         }
01245 
01246         fstrcpy( salt, std_salt );
01247         SAFE_FREE( std_salt );
01248         
01249         /* if it's a Windows functional domain, we have to look for the UPN */
01250            
01251         if ( domain_func == DS_DOMAIN_FUNCTION_2000 ) { 
01252                 char *upn;
01253                 int count;
01254                 
01255                 status = ads_find_machine_acct(ads, &res, machine_name);
01256                 if (!ADS_ERR_OK(status)) {
01257                         return False;
01258                 }
01259                 
01260                 if ( (count = ads_count_replies(ads, res)) != 1 ) {
01261                         DEBUG(1,("net_set_machine_spn: %d entries returned!\n", count));
01262                         return False;
01263                 }
01264                 
01265                 upn = ads_pull_string(ads, ctx, res, "userPrincipalName");
01266                 if ( upn ) {
01267                         fstrcpy( salt, upn );
01268                 }
01269                 
01270                 ads_msgfree(ads, res);
01271         }
01272 
01273         return kerberos_secrets_store_des_salt( salt );
01274 }
01275 
01276 /*******************************************************************
01277  Send a DNS update request
01278 *******************************************************************/
01279 
01280 #if defined(WITH_DNS_UPDATES)
01281 #include "dns.h"
01282 DNS_ERROR DoDNSUpdate(char *pszServerName,
01283                       const char *pszDomainName,
01284                       const char *pszHostName,
01285                       const struct in_addr *iplist, int num_addrs );
01286 
01287 
01288 static NTSTATUS net_update_dns_internal(TALLOC_CTX *ctx, ADS_STRUCT *ads,
01289                                         const char *machine_name,
01290                                         const struct in_addr *addrs,
01291                                         int num_addrs)
01292 {
01293         struct dns_rr_ns *nameservers = NULL;
01294         int ns_count = 0;
01295         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
01296         DNS_ERROR dns_err;
01297         fstring dns_server;
01298         const char *dnsdomain = NULL;   
01299         char *root_domain = NULL;       
01300 
01301         if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
01302                 d_printf("No DNS domain configured for %s. "
01303                          "Unable to perform DNS Update.\n", machine_name);
01304                 status = NT_STATUS_INVALID_PARAMETER;
01305                 goto done;
01306         }
01307         dnsdomain++;
01308 
01309         status = ads_dns_lookup_ns( ctx, dnsdomain, &nameservers, &ns_count );
01310         if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
01311                 /* Child domains often do not have NS records.  Look
01312                    for the NS record for the forest root domain 
01313                    (rootDomainNamingContext in therootDSE) */
01314 
01315                 const char *rootname_attrs[] =  { "rootDomainNamingContext", NULL };
01316                 LDAPMessage *msg = NULL;
01317                 char *root_dn;
01318                 ADS_STATUS ads_status;
01319                 
01320                 if ( !ads->ld ) {
01321                         ads_status = ads_connect( ads );
01322                         if ( !ADS_ERR_OK(ads_status) ) {
01323                                 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
01324                                 goto done;                              
01325                         }                       
01326                 }
01327                 
01328                 ads_status = ads_do_search(ads, "", LDAP_SCOPE_BASE, 
01329                                        "(objectclass=*)", rootname_attrs, &msg);
01330                 if (!ADS_ERR_OK(ads_status)) {
01331                         goto done;
01332                 }
01333 
01334                 root_dn = ads_pull_string(ads, ctx, msg,  "rootDomainNamingContext");
01335                 if ( !root_dn ) {
01336                         ads_msgfree( ads, msg );                        
01337                         goto done;
01338                 }
01339 
01340                 root_domain = ads_build_domain( root_dn );
01341 
01342                 /* cleanup */
01343                 ads_msgfree( ads, msg );
01344 
01345                 /* try again for NS servers */
01346 
01347                 status = ads_dns_lookup_ns( ctx, root_domain, &nameservers, &ns_count );
01348                 
01349                 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {                     
01350                 DEBUG(3,("net_ads_join: Failed to find name server for the %s "
01351                          "realm\n", ads->config.realm));
01352                 goto done;
01353         }
01354 
01355                 dnsdomain = root_domain;                
01356                 
01357         }
01358 
01359         /* Now perform the dns update - we'll try non-secure and if we fail,
01360            we'll follow it up with a secure update */
01361 
01362         fstrcpy( dns_server, nameservers[0].hostname );
01363 
01364         dns_err = DoDNSUpdate(dns_server, dnsdomain, machine_name, addrs, num_addrs);
01365         if (!ERR_DNS_IS_OK(dns_err)) {
01366                 status = NT_STATUS_UNSUCCESSFUL;
01367         }
01368 
01369 done:
01370 
01371         SAFE_FREE( root_domain );
01372         
01373         return status;
01374 }
01375 
01376 static NTSTATUS net_update_dns(TALLOC_CTX *mem_ctx, ADS_STRUCT *ads)
01377 {
01378         int num_addrs;
01379         struct in_addr *iplist = NULL;
01380         fstring machine_name;
01381         NTSTATUS status;
01382 
01383         name_to_fqdn( machine_name, global_myname() );
01384         strlower_m( machine_name );
01385 
01386         /* Get our ip address (not the 127.0.0.x address but a real ip
01387          * address) */
01388 
01389         num_addrs = get_my_ip_address( &iplist );
01390         if ( num_addrs <= 0 ) {
01391                 DEBUG(4,("net_ads_join: Failed to find my non-loopback IP "
01392                          "addresses!\n"));
01393                 return NT_STATUS_INVALID_PARAMETER;
01394         }
01395 
01396         status = net_update_dns_internal(mem_ctx, ads, machine_name,
01397                                          iplist, num_addrs);
01398         SAFE_FREE( iplist );
01399         return status;
01400 }
01401 #endif
01402 
01403 
01404 /*******************************************************************
01405  utility function to parse an integer parameter from 
01406  "parameter = value"
01407 **********************************************************/
01408 static char* get_string_param( const char* param )
01409 {
01410         char *p;
01411         
01412         if ( (p = strchr( param, '=' )) == NULL )
01413                 return NULL;
01414                 
01415         return (p+1);
01416 }
01417 
01418 /*******************************************************************
01419  ********************************************************************/
01420  
01421 static int net_ads_join_usage(int argc, const char **argv)
01422 {
01423         d_printf("net ads join [options]\n");
01424         d_printf("Valid options:\n");
01425         d_printf("   createupn[=UPN]    Set the userPrincipalName attribute during the join.\n");
01426         d_printf("                      The deault UPN is in the form host/netbiosname@REALM.\n");
01427         d_printf("   createcomputer=OU  Precreate the computer account in a specific OU.\n");
01428         d_printf("                      The OU string read from top to bottom without RDNs and delimited by a '/'.\n");
01429         d_printf("                      E.g. \"createcomputer=Computers/Servers/Unix\"\n");
01430         d_printf("                      NB: A backslash '\\' is used as escape at multiple levels and may\n");
01431         d_printf("                          need to be doubled or even quadrupled.  It is not used as a separator");
01432 
01433         return -1;
01434 }
01435 
01436 /*******************************************************************
01437  ********************************************************************/
01438  
01439 int net_ads_join(int argc, const char **argv)
01440 {
01441         ADS_STRUCT *ads = NULL;
01442         ADS_STATUS status;
01443         NTSTATUS nt_status;
01444         char *machine_account = NULL;
01445         char *short_domain_name = NULL;
01446         char *tmp_password, *password;
01447         TALLOC_CTX *ctx = NULL;
01448         DOM_SID *domain_sid = NULL;
01449         BOOL createupn = False;
01450         const char *machineupn = NULL;
01451         const char *create_in_ou = NULL;
01452         int i;
01453         fstring dc_name;
01454         struct in_addr dcip;
01455         const char *os_name = NULL;
01456         const char *os_version = NULL;
01457         
01458         nt_status = check_ads_config();
01459         if (!NT_STATUS_IS_OK(nt_status)) {
01460                 d_fprintf(stderr, "Invalid configuration.  Exiting....\n");
01461                 goto fail;
01462         }
01463 
01464         /* find a DC to initialize the server affinity cache */
01465 
01466         get_dc_name( lp_workgroup(), lp_realm(), dc_name, &dcip );
01467 
01468         status = ads_startup(True, &ads);
01469         if (!ADS_ERR_OK(status)) {
01470                 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
01471                 nt_status = ads_ntstatus(status);
01472                 goto fail;
01473         }
01474 
01475         if (strcmp(ads->config.realm, lp_realm()) != 0) {
01476                 d_fprintf(stderr, "realm of remote server (%s) and realm in %s "
01477                         "(%s) DO NOT match.  Aborting join\n", ads->config.realm, 
01478                         dyn_CONFIGFILE, lp_realm());
01479                 nt_status = NT_STATUS_INVALID_PARAMETER;
01480                 goto fail;
01481         }
01482 
01483         if (!(ctx = talloc_init("net_ads_join"))) {
01484                 d_fprintf(stderr, "Could not initialise talloc context.\n");
01485                 nt_status = NT_STATUS_NO_MEMORY;
01486                 goto fail;
01487         }
01488 
01489         /* process additional command line args */
01490         
01491         for ( i=0; i<argc; i++ ) {
01492                 if ( !StrnCaseCmp(argv[i], "createupn", strlen("createupn")) ) {
01493                         createupn = True;
01494                         machineupn = get_string_param(argv[i]);
01495                 }
01496                 else if ( !StrnCaseCmp(argv[i], "createcomputer", strlen("createcomputer")) ) {
01497                         if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
01498                                 d_fprintf(stderr, "Please supply a valid OU path.\n");
01499                                 nt_status = NT_STATUS_INVALID_PARAMETER;
01500                                 goto fail;
01501                         }               
01502                 }
01503                 else if ( !StrnCaseCmp(argv[i], "osName", strlen("osName")) ) {
01504                         if ( (os_name = get_string_param(argv[i])) == NULL ) {
01505                                 d_fprintf(stderr, "Please supply a operating system name.\n");
01506                                 nt_status = NT_STATUS_INVALID_PARAMETER;
01507                                 goto fail;
01508                         }               
01509                 }
01510                 else if ( !StrnCaseCmp(argv[i], "osVer", strlen("osVer")) ) {
01511                         if ( (os_version = get_string_param(argv[i])) == NULL ) {
01512                                 d_fprintf(stderr, "Please supply a valid operating system version.\n");
01513                                 nt_status = NT_STATUS_INVALID_PARAMETER;
01514                                 goto fail;
01515                         }               
01516                 }
01517                 else {
01518                         d_fprintf(stderr, "Bad option: %s\n", argv[i]);
01519                         nt_status = NT_STATUS_INVALID_PARAMETER;
01520                         goto fail;
01521                 }
01522         }
01523 
01524         /* If we were given an OU, try to create the machine in 
01525            the OU account first and then do the normal RPC join */
01526 
01527         if  ( create_in_ou ) {
01528                 status = net_precreate_machine_acct( ads, create_in_ou );
01529                 if ( !ADS_ERR_OK(status) ) {
01530                         d_fprintf( stderr, "Failed to pre-create the machine object "
01531                                 "in OU %s.\n", argv[0]);
01532                         DEBUG(1, ("error calling net_precreate_machine_acct: %s\n", 
01533                                   ads_errstr(status)));
01534                         nt_status = ads_ntstatus(status);
01535                         goto fail;
01536                 }
01537         }
01538 
01539         /* Do the domain join here */
01540 
01541         tmp_password = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
01542         password = talloc_strdup(ctx, tmp_password);
01543         
01544         nt_status = net_join_domain(ctx, ads->config.ldap_server_name, 
01545                                     &ads->ldap_ip, &short_domain_name, &domain_sid, password);
01546         if ( !NT_STATUS_IS_OK(nt_status) ) {
01547                 DEBUG(1, ("call of net_join_domain failed: %s\n", 
01548                           get_friendly_nt_error_msg(nt_status)));
01549                 goto fail;
01550         }
01551 
01552         /* Check the short name of the domain */
01553         
01554         if ( !strequal(lp_workgroup(), short_domain_name) ) {
01555                 d_printf("The workgroup in %s does not match the short\n", dyn_CONFIGFILE);
01556                 d_printf("domain name obtained from the server.\n");
01557                 d_printf("Using the name [%s] from the server.\n", short_domain_name);
01558                 d_printf("You should set \"workgroup = %s\" in %s.\n", 
01559                          short_domain_name, dyn_CONFIGFILE);
01560         }
01561         
01562         d_printf("Using short domain name -- %s\n", short_domain_name);
01563 
01564         /*  HACK ALERT!  Store the sid and password under both the lp_workgroup() 
01565             value from smb.conf and the string returned from the server.  The former is
01566             neede to bootstrap winbindd's first connection to the DC to get the real 
01567             short domain name   --jerry */
01568            
01569         if ( (netdom_store_machine_account( lp_workgroup(), domain_sid, password ) == -1)
01570                 || (netdom_store_machine_account( short_domain_name, domain_sid, password ) == -1) )
01571         {
01572                 /* issue an internal error here for now.
01573                  * everything else would mean changing tdb routines. */
01574                 nt_status = NT_STATUS_INTERNAL_ERROR;
01575                 goto fail;
01576         }
01577 
01578         /* Verify that everything is ok */
01579 
01580         if ( net_rpc_join_ok(short_domain_name, ads->config.ldap_server_name, &ads->ldap_ip) != 0 ) {
01581                 d_fprintf(stderr, "Failed to verify membership in domain!\n");
01582                 goto fail;
01583         }       
01584 
01585         /* create the dNSHostName & servicePrincipalName values */
01586         
01587         status = net_set_machine_spn( ctx, ads );
01588         if ( !ADS_ERR_OK(status) )  {
01589 
01590                 d_fprintf(stderr, "Failed to set servicePrincipalNames. Please ensure that\n");
01591                 d_fprintf(stderr, "the DNS domain of this server matches the AD domain,\n");
01592                 d_fprintf(stderr, "Or rejoin with using Domain Admin credentials.\n");
01593                 
01594                 /* Disable the machine account in AD.  Better to fail than to leave 
01595                    a confused admin.  */
01596                 
01597                 if ( net_ads_leave( 0, NULL ) != 0 ) {
01598                         d_fprintf( stderr, "Failed to disable machine account in AD.  Please do so manually.\n");
01599                 }
01600                 
01601                 /* clear out the machine password */
01602                 
01603                 netdom_store_machine_account( lp_workgroup(), domain_sid, "" ); 
01604                 netdom_store_machine_account( short_domain_name, domain_sid, "" );
01605                 
01606                 nt_status = ads_ntstatus(status);
01607                 goto fail;
01608         }
01609 
01610         if ( !net_derive_salting_principal( ctx, ads ) ) {
01611                 DEBUG(1,("Failed to determine salting principal\n"));
01612                 goto fail;
01613         }
01614 
01615         if ( createupn ) {
01616                 pstring upn;
01617                 
01618                 /* default to using the short UPN name */
01619                 if ( !machineupn ) {
01620                         snprintf( upn, sizeof(upn), "host/%s@%s", global_myname(), 
01621                                 ads->config.realm );
01622                         machineupn = upn;
01623                 }
01624                 
01625                 status = net_set_machine_upn( ctx, ads, machineupn );
01626                 if ( !ADS_ERR_OK(status) )  {
01627                         d_fprintf(stderr, "Failed to set userPrincipalName.  Are you a Domain Admin?\n");
01628                 }
01629         }
01630 
01631         /* Try to set the operatingSystem attributes if asked */
01632 
01633         if ( os_name && os_version ) {
01634                 status = net_set_os_attributes( ctx, ads, os_name, os_version );
01635                 if ( !ADS_ERR_OK(status) )  {
01636                         d_fprintf(stderr, "Failed to set operatingSystem attributes.  "
01637                                   "Are you a Domain Admin?\n");
01638                 }
01639         }
01640 
01641         /* Now build the keytab, using the same ADS connection */
01642 
01643         if (lp_use_kerberos_keytab() && ads_keytab_create_default(ads)) {
01644                 DEBUG(1,("Error creating host keytab!\n"));
01645         }
01646 
01647 #if defined(WITH_DNS_UPDATES)
01648         /* We enter this block with user creds */
01649         ads_kdestroy( NULL );   
01650         ads_destroy(&ads);
01651         ads = NULL;
01652         
01653         if ( (ads = ads_init( lp_realm(), NULL, NULL )) != NULL ) {
01654                 /* kinit with the machine password */
01655 
01656                 use_in_memory_ccache();
01657                 asprintf( &ads->auth.user_name, "%s$", global_myname() );
01658                 ads->auth.password = secrets_fetch_machine_password(
01659                         lp_workgroup(), NULL, NULL );
01660                 ads->auth.realm = SMB_STRDUP( lp_realm() );
01661                 ads_kinit_password( ads );
01662         }
01663         
01664         if ( !ads || !NT_STATUS_IS_OK(net_update_dns( ctx, ads )) ) {
01665                 d_fprintf( stderr, "DNS update failed!\n" );
01666         }
01667         
01668         /* exit from this block using machine creds */
01669 #endif
01670 
01671         d_printf("Joined '%s' to realm '%s'\n", global_myname(), ads->server.realm);
01672 
01673         SAFE_FREE(machine_account);
01674         TALLOC_FREE( ctx );
01675         ads_destroy(&ads);
01676         
01677         return 0;
01678 
01679 fail:
01680         /* issue an overall failure message at the end. */
01681         d_printf("Failed to join domain: %s\n", get_friendly_nt_error_msg(nt_status));
01682 
01683         SAFE_FREE(machine_account);
01684         TALLOC_FREE( ctx );
01685         ads_destroy(&ads);
01686 
01687         return -1;
01688 
01689 }
01690 
01691 /*******************************************************************
01692  ********************************************************************/
01693  
01694 static int net_ads_dns_usage(int argc, const char **argv)
01695 {
01696 #if defined(WITH_DNS_UPDATES)
01697         d_printf("net ads dns <command>\n");
01698         d_printf("Valid commands:\n");
01699         d_printf("   register         Issue a dynamic DNS update request for our hostname\n");
01700 
01701         return 0;
01702 #else
01703         d_fprintf(stderr, "DNS update support not enabled at compile time!\n");
01704         return -1;
01705 #endif
01706 }
01707 
01708 /*******************************************************************
01709  ********************************************************************/
01710  
01711 static int net_ads_dns_register(int argc, const char **argv)
01712 {
01713 #if defined(WITH_DNS_UPDATES)
01714         ADS_STRUCT *ads;
01715         ADS_STATUS status;
01716         TALLOC_CTX *ctx;
01717         
01718 #ifdef DEVELOPER
01719         talloc_enable_leak_report();
01720 #endif
01721         
01722         if (argc > 0) {
01723                 d_fprintf(stderr, "net ads dns register\n");
01724                 return -1;
01725         }
01726 
01727         if (!(ctx = talloc_init("net_ads_dns"))) {
01728                 d_fprintf(stderr, "Could not initialise talloc context\n");
01729                 return -1;
01730         }
01731 
01732         status = ads_startup(True, &ads);
01733         if ( !ADS_ERR_OK(status) ) {
01734                 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
01735                 TALLOC_FREE(ctx);
01736                 return -1;
01737         }
01738 
01739         if ( !NT_STATUS_IS_OK(net_update_dns(ctx, ads)) ) {             
01740                 d_fprintf( stderr, "DNS update failed!\n" );
01741                 ads_destroy( &ads );
01742                 TALLOC_FREE( ctx );
01743                 return -1;
01744         }
01745         
01746         d_fprintf( stderr, "Successfully registered hostname with DNS\n" );
01747 
01748         ads_destroy(&ads);
01749         TALLOC_FREE( ctx );
01750         
01751         return 0;
01752 #else
01753         d_fprintf(stderr, "DNS update support not enabled at compile time!\n");
01754         return -1;
01755 #endif
01756 }
01757 
01758 #if defined(WITH_DNS_UPDATES)
01759 DNS_ERROR do_gethostbyname(const char *server, const char *host);
01760 #endif
01761 
01762 static int net_ads_dns_gethostbyname(int argc, const char **argv)
01763 {
01764 #if defined(WITH_DNS_UPDATES)
01765         DNS_ERROR err;
01766         
01767 #ifdef DEVELOPER
01768         talloc_enable_leak_report();
01769 #endif
01770 
01771         if (argc != 2) {
01772                 d_fprintf(stderr, "net ads dns gethostbyname <server> "
01773                           "<name>\n");
01774                 return -1;
01775         }
01776 
01777         err = do_gethostbyname(argv[0], argv[1]);
01778 
01779         d_printf("do_gethostbyname returned %d\n", ERROR_DNS_V(err));
01780 #endif
01781         return 0;
01782 }
01783 
01784 static int net_ads_dns(int argc, const char *argv[])
01785 {
01786         struct functable func[] = {
01787                 {"REGISTER", net_ads_dns_register},
01788                 {"GETHOSTBYNAME", net_ads_dns_gethostbyname},
01789                 {NULL, NULL}
01790         };
01791 
01792         return net_run_function(argc, argv, func, net_ads_dns_usage);
01793 }
01794 
01795 /*******************************************************************
01796  ********************************************************************/
01797 
01798 int net_ads_printer_usage(int argc, const char **argv)
01799 {
01800         d_printf(
01801 "\nnet ads printer search <printer>"
01802 "\n\tsearch for a printer in the directory\n"
01803 "\nnet ads printer info <printer> <server>"
01804 "\n\tlookup info in directory for printer on server"
01805 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
01806 "\nnet ads printer publish <printername>"
01807 "\n\tpublish printer in directory"
01808 "\n\t(note: printer name is required)\n"
01809 "\nnet ads printer remove <printername>"
01810 "\n\tremove printer from directory"
01811 "\n\t(note: printer name is required)\n");
01812         return -1;
01813 }
01814 
01815 /*******************************************************************
01816  ********************************************************************/
01817 
01818 static int net_ads_printer_search(int argc, const char **argv)
01819 {
01820         ADS_STRUCT *ads;
01821         ADS_STATUS rc;
01822         LDAPMessage *res = NULL;
01823 
01824         if (!ADS_ERR_OK(ads_startup(False, &ads))) {
01825                 return -1;
01826         }
01827 
01828         rc = ads_find_printers(ads, &res);
01829 
01830         if (!ADS_ERR_OK(rc)) {
01831                 d_fprintf(stderr, "ads_find_printer: %s\n", ads_errstr(rc));
01832                 ads_msgfree(ads, res);
01833                 ads_destroy(&ads);
01834                 return -1;
01835         }
01836 
01837         if (ads_count_replies(ads, res) == 0) {
01838                 d_fprintf(stderr, "No results found\n");
01839                 ads_msgfree(ads, res);
01840                 ads_destroy(&ads);
01841                 return -1;
01842         }
01843 
01844         ads_dump(ads, res);
01845         ads_msgfree(ads, res);
01846         ads_destroy(&ads);
01847         return 0;
01848 }
01849 
01850 static int net_ads_printer_info(int argc, const char **argv)
01851 {
01852         ADS_STRUCT *ads;
01853         ADS_STATUS rc;
01854         const char *servername, *printername;
01855         LDAPMessage *res = NULL;
01856 
01857         if (!ADS_ERR_OK(ads_startup(False, &ads))) {
01858                 return -1;
01859         }
01860 
01861         if (argc > 0) {
01862                 printername = argv[0];
01863         } else {
01864                 printername = "*";
01865         }
01866 
01867         if (argc > 1) {
01868                 servername =  argv[1];
01869         } else {
01870                 servername = global_myname();
01871         }
01872 
01873         rc = ads_find_printer_on_server(ads, &res, printername, servername);
01874 
01875         if (!ADS_ERR_OK(rc)) {
01876                 d_fprintf(stderr, "Server '%s' not found: %s\n", 
01877                         servername, ads_errstr(rc));
01878                 ads_msgfree(ads, res);
01879                 ads_destroy(&ads);
01880                 return -1;
01881         }
01882 
01883         if (ads_count_replies(ads, res) == 0) {
01884                 d_fprintf(stderr, "Printer '%s' not found\n", printername);
01885                 ads_msgfree(ads, res);
01886                 ads_destroy(&ads);
01887                 return -1;
01888         }
01889 
01890         ads_dump(ads, res);
01891         ads_msgfree(ads, res);
01892         ads_destroy(&ads);
01893 
01894         return 0;
01895 }
01896 
01897 void do_drv_upgrade_printer(int msg_type, struct process_id src,
01898                             void *buf, size_t len, void *private_data)
01899 {
01900         return;
01901 }
01902 
01903 static int net_ads_printer_publish(int argc, const char **argv)
01904 {
01905         ADS_STRUCT *ads;
01906         ADS_STATUS rc;
01907         const char *servername, *printername;
01908         struct cli_state *cli;
01909         struct rpc_pipe_client *pipe_hnd;
01910         struct in_addr          server_ip;
01911         NTSTATUS nt_status;
01912         TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
01913         ADS_MODLIST mods = ads_init_mods(mem_ctx);
01914         char *prt_dn, *srv_dn, **srv_cn;
01915         char *srv_cn_escaped = NULL, *printername_escaped = NULL;
01916         LDAPMessage *res = NULL;
01917 
01918         if (!ADS_ERR_OK(ads_startup(True, &ads))) {
01919                 talloc_destroy(mem_ctx);
01920                 return -1;
01921         }
01922 
01923         if (argc < 1) {
01924                 talloc_destroy(mem_ctx);
01925                 return net_ads_printer_usage(argc, argv);
01926         }
01927         
01928         printername = argv[0];
01929 
01930         if (argc == 2) {
01931                 servername = argv[1];
01932         } else {
01933                 servername = global_myname();
01934         }
01935                 
01936         /* Get printer data from SPOOLSS */
01937 
01938         resolve_name(servername, &server_ip, 0x20);
01939 
01940         nt_status = cli_full_connection(&cli, global_myname(), servername, 
01941                                         &server_ip, 0,
01942                                         "IPC$", "IPC",  
01943                                         opt_user_name, opt_workgroup,
01944                                         opt_password ? opt_password : "", 
01945                                         CLI_FULL_CONNECTION_USE_KERBEROS, 
01946                                         Undefined, NULL);
01947 
01948         if (NT_STATUS_IS_ERR(nt_status)) {
01949                 d_fprintf(stderr, "Unable to open a connnection to %s to obtain data "
01950                          "for %s\n", servername, printername);
01951                 ads_destroy(&ads);
01952                 talloc_destroy(mem_ctx);
01953                 return -1;
01954         }
01955 
01956         /* Publish on AD server */
01957 
01958         ads_find_machine_acct(ads, &res, servername);
01959 
01960         if (ads_count_replies(ads, res) == 0) {
01961                 d_fprintf(stderr, "Could not find machine account for server %s\n", 
01962                          servername);
01963                 ads_destroy(&ads);
01964                 talloc_destroy(mem_ctx);
01965                 return -1;
01966         }
01967 
01968         srv_dn = ldap_get_dn((LDAP *)ads->ld, (LDAPMessage *)res);
01969         srv_cn = ldap_explode_dn(srv_dn, 1);
01970 
01971         srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
01972         printername_escaped = escape_rdn_val_string_alloc(printername);
01973         if (!srv_cn_escaped || !printername_escaped) {
01974                 SAFE_FREE(srv_cn_escaped);
01975                 SAFE_FREE(printername_escaped);
01976                 d_fprintf(stderr, "Internal error, out of memory!");
01977                 ads_destroy(&ads);
01978                 talloc_destroy(mem_ctx);
01979                 return -1;
01980         }
01981 
01982         asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn);
01983 
01984         SAFE_FREE(srv_cn_escaped);
01985         SAFE_FREE(printername_escaped);
01986 
01987         pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SPOOLSS, &nt_status);
01988         if (!pipe_hnd) {
01989                 d_fprintf(stderr, "Unable to open a connnection to the spoolss pipe on %s\n",
01990                          servername);
01991                 SAFE_FREE(prt_dn);
01992                 ads_destroy(&ads);
01993                 talloc_destroy(mem_ctx);
01994                 return -1;
01995         }
01996 
01997         if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
01998                                                               printername))) {
01999                 SAFE_FREE(prt_dn);
02000                 ads_destroy(&ads);
02001                 talloc_destroy(mem_ctx);
02002                 return -1;
02003         }
02004 
02005         rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
02006         if (!ADS_ERR_OK(rc)) {
02007                 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
02008                 SAFE_FREE(prt_dn);
02009                 ads_destroy(&ads);
02010                 talloc_destroy(mem_ctx);
02011                 return -1;
02012         }
02013  
02014         d_printf("published printer\n");
02015         SAFE_FREE(prt_dn);
02016         ads_destroy(&ads);
02017         talloc_destroy(mem_ctx);
02018  
02019         return 0;
02020 }
02021 
02022 static int net_ads_printer_remove(int argc, const char **argv)
02023 {
02024         ADS_STRUCT *ads;
02025         ADS_STATUS rc;
02026         const char *servername;
02027         char *prt_dn;
02028         LDAPMessage *res = NULL;
02029 
02030         if (!ADS_ERR_OK(ads_startup(True, &ads))) {
02031                 return -1;
02032         }
02033 
02034         if (argc < 1) {
02035                 return net_ads_printer_usage(argc, argv);
02036         }
02037 
02038         if (argc > 1) {
02039                 servername = argv[1];
02040         } else {
02041                 servername = global_myname();
02042         }
02043 
02044         rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
02045 
02046         if (!ADS_ERR_OK(rc)) {
02047                 d_fprintf(stderr, "ads_find_printer_on_server: %s\n", ads_errstr(rc));
02048                 ads_msgfree(ads, res);
02049                 ads_destroy(&ads);
02050                 return -1;
02051         }
02052 
02053         if (ads_count_replies(ads, res) == 0) {
02054                 d_fprintf(stderr, "Printer '%s' not found\n", argv[1]);
02055                 ads_msgfree(ads, res);
02056                 ads_destroy(&ads);
02057                 return -1;
02058         }
02059 
02060         prt_dn = ads_get_dn(ads, res);
02061         ads_msgfree(ads, res);
02062         rc = ads_del_dn(ads, prt_dn);
02063         ads_memfree(ads, prt_dn);
02064 
02065         if (!ADS_ERR_OK(rc)) {
02066                 d_fprintf(stderr, "ads_del_dn: %s\n", ads_errstr(rc));
02067                 ads_destroy(&ads);
02068                 return -1;
02069         }
02070 
02071         ads_destroy(&ads);
02072         return 0;
02073 }
02074 
02075 static int net_ads_printer(int argc, const char **argv)
02076 {
02077         struct functable func[] = {
02078                 {"SEARCH", net_ads_printer_search},
02079                 {"INFO", net_ads_printer_info},
02080                 {"PUBLISH", net_ads_printer_publish},
02081                 {"REMOVE", net_ads_printer_remove},
02082                 {NULL, NULL}
02083         };
02084         
02085         return net_run_function(argc, argv, func, net_ads_printer_usage);
02086 }
02087 
02088 
02089 static int net_ads_password(int argc, const char **argv)
02090 {
02091         ADS_STRUCT *ads;
02092         const char *auth_principal = opt_user_name;
02093         const char *auth_password = opt_password;
02094         char *realm = NULL;
02095         char *new_password = NULL;
02096         char *c, *prompt;
02097         const char *user;
02098         ADS_STATUS ret;
02099 
02100         if (opt_user_name == NULL || opt_password == NULL) {
02101                 d_fprintf(stderr, "You must supply an administrator username/password\n");
02102                 return -1;
02103         }
02104 
02105         if (argc < 1) {
02106                 d_fprintf(stderr, "ERROR: You must say which username to change password for\n");
02107                 return -1;
02108         }
02109 
02110         user = argv[0];
02111         if (!strchr_m(user, '@')) {
02112                 asprintf(&c, "%s@%s", argv[0], lp_realm());
02113                 user = c;
02114         }
02115 
02116         use_in_memory_ccache();    
02117         c = strchr_m(auth_principal, '@');
02118         if (c) {
02119                 realm = ++c;
02120         } else {
02121                 realm = lp_realm();
02122         }
02123 
02124         /* use the realm so we can eventually change passwords for users 
02125         in realms other than default */
02126         if (!(ads = ads_init(realm, opt_workgroup, opt_host))) {
02127                 return -1;
02128         }
02129 
02130         /* we don't actually need a full connect, but it's the easy way to
02131                 fill in the KDC's addresss */
02132         ads_connect(ads);
02133     
02134         if (!ads || !ads->config.realm) {
02135                 d_fprintf(stderr, "Didn't find the kerberos server!\n");
02136                 return -1;
02137         }
02138 
02139         if (argv[1]) {
02140                 new_password = (char *)argv[1];
02141         } else {
02142                 asprintf(&prompt, "Enter new password for %s:", user);
02143                 new_password = getpass(prompt);
02144                 free(prompt);
02145         }
02146 
02147         ret = kerberos_set_password(ads->auth.kdc_server, auth_principal, 
02148                                 auth_password, user, new_password, ads->auth.time_offset);
02149         if (!ADS_ERR_OK(ret)) {
02150                 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
02151                 ads_destroy(&ads);
02152                 return -1;
02153         }
02154 
02155         d_printf("Password change for %s completed.\n", user);
02156         ads_destroy(&ads);
02157 
02158         return 0;
02159 }
02160 
02161 int net_ads_changetrustpw(int argc, const char **argv)
02162 {    
02163         ADS_STRUCT *ads;
02164         char *host_principal;
02165         fstring my_name;
02166         ADS_STATUS ret;
02167 
02168         if (!secrets_init()) {
02169                 DEBUG(1,("Failed to initialise secrets database\n"));
02170                 return -1;
02171         }
02172 
02173         net_use_krb_machine_account();
02174 
02175         use_in_memory_ccache();
02176 
02177         if (!ADS_ERR_OK(ads_startup(True, &ads))) {
02178                 return -1;
02179         }
02180 
02181         fstrcpy(my_name, global_myname());
02182         strlower_m(my_name);
02183         asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm);
02184         d_printf("Changing password for principal: %s\n", host_principal);
02185 
02186         ret = ads_change_trust_account_password(ads, host_principal);
02187 
02188         if (!ADS_ERR_OK(ret)) {
02189                 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
02190                 ads_destroy(&ads);
02191                 SAFE_FREE(host_principal);
02192                 return -1;
02193         }
02194     
02195         d_printf("Password change for principal %s succeeded.\n", host_principal);
02196 
02197         if (lp_use_kerberos_keytab()) {
02198                 d_printf("Attempting to update system keytab with new password.\n");
02199                 if (ads_keytab_create_default(ads)) {
02200                         d_printf("Failed to update system keytab.\n");
02201                 }
02202         }
02203 
02204         ads_destroy(&ads);
02205         SAFE_FREE(host_principal);
02206 
02207         return 0;
02208 }
02209 
02210 /*
02211   help for net ads search
02212 */
02213 static int net_ads_search_usage(int argc, const char **argv)
02214 {
02215         d_printf(
02216                 "\nnet ads search <expression> <attributes...>\n"\
02217                 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
02218                 "The expression is a standard LDAP search expression, and the\n"\
02219                 "attributes are a list of LDAP fields to show in the results\n\n"\
02220                 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
02221                 );
02222         net_common_flags_usage(argc, argv);
02223         return -1;
02224 }
02225 
02226 
02227 /*
02228   general ADS search function. Useful in diagnosing problems in ADS
02229 */
02230 static int net_ads_search(int argc, const char **argv)
02231 {
02232         ADS_STRUCT *ads;
02233         ADS_STATUS rc;
02234         const char *ldap_exp;
02235         const char **attrs;
02236         LDAPMessage *res = NULL;
02237 
02238         if (argc < 1) {
02239                 return net_ads_search_usage(argc, argv);
02240         }
02241 
02242         if (!ADS_ERR_OK(ads_startup(False, &ads))) {
02243                 return -1;
02244         }
02245 
02246         ldap_exp = argv[0];
02247         attrs = (argv + 1);
02248 
02249         rc = ads_do_search_all(ads, ads->config.bind_path,
02250                                LDAP_SCOPE_SUBTREE,
02251                                ldap_exp, attrs, &res);
02252         if (!ADS_ERR_OK(rc)) {
02253                 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
02254                 ads_destroy(&ads);
02255                 return -1;
02256         }       
02257 
02258         d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
02259 
02260         /* dump the results */
02261         ads_dump(ads, res);
02262 
02263         ads_msgfree(ads, res);
02264         ads_destroy(&ads);
02265 
02266         return 0;
02267 }
02268 
02269 
02270 /*
02271   help for net ads search
02272 */
02273 static int net_ads_dn_usage(int argc, const char **argv)
02274 {
02275         d_printf(
02276                 "\nnet ads dn <dn> <attributes...>\n"\
02277                 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
02278                 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"\
02279                 "to show in the results\n\n"\
02280                 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
02281                 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
02282                 );
02283         net_common_flags_usage(argc, argv);
02284         return -1;
02285 }
02286 
02287 
02288 /*
02289   general ADS search function. Useful in diagnosing problems in ADS
02290 */
02291 static int net_ads_dn(int argc, const char **argv)
02292 {
02293         ADS_STRUCT *ads;
02294         ADS_STATUS rc;
02295         const char *dn;
02296         const char **attrs;
02297         LDAPMessage *res = NULL;
02298 
02299         if (argc < 1) {
02300                 return net_ads_dn_usage(argc, argv);
02301         }
02302 
02303         if (!ADS_ERR_OK(ads_startup(False, &ads))) {
02304                 return -1;
02305         }
02306 
02307         dn = argv[0];
02308         attrs = (argv + 1);
02309 
02310         rc = ads_do_search_all(ads, dn, 
02311                                LDAP_SCOPE_BASE,
02312                                "(objectclass=*)", attrs, &res);
02313         if (!ADS_ERR_OK(rc)) {
02314                 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
02315                 ads_destroy(&ads);
02316                 return -1;
02317         }       
02318 
02319         d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
02320 
02321         /* dump the results */
02322         ads_dump(ads, res);
02323 
02324         ads_msgfree(ads, res);
02325         ads_destroy(&ads);
02326 
02327         return 0;
02328 }
02329 
02330 /*
02331   help for net ads sid search
02332 */
02333 static int net_ads_sid_usage(int argc, const char **argv)
02334 {
02335         d_printf(
02336                 "\nnet ads sid <sid> <attributes...>\n"\
02337                 "\nperform a raw LDAP search on a ADS server and dump the results\n"\
02338                 "The SID is in string format, and the attributes are a list of LDAP fields \n"\
02339                 "to show in the results\n\n"\
02340                 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
02341                 );
02342         net_common_flags_usage(argc, argv);
02343         return -1;
02344 }
02345 
02346 
02347 /*
02348   general ADS search function. Useful in diagnosing problems in ADS
02349 */
02350 static int net_ads_sid(int argc, const char **argv)
02351 {
02352         ADS_STRUCT *ads;
02353         ADS_STATUS rc;
02354         const char *sid_string;
02355         const char **attrs;
02356         LDAPMessage *res = NULL;
02357         DOM_SID sid;
02358 
02359         if (argc < 1) {
02360                 return net_ads_sid_usage(argc, argv);
02361         }
02362 
02363         if (!ADS_ERR_OK(ads_startup(False, &ads))) {
02364                 return -1;
02365         }
02366 
02367         sid_string = argv[0];
02368         attrs = (argv + 1);
02369 
02370         if (!string_to_sid(&sid, sid_string)) {
02371                 d_fprintf(stderr, "could not convert sid\n");
02372                 ads_destroy(&ads);
02373                 return -1;
02374         }
02375 
02376         rc = ads_search_retry_sid(ads, &res, &sid, attrs);
02377         if (!ADS_ERR_OK(rc)) {
02378                 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
02379                 ads_destroy(&ads);
02380                 return -1;
02381         }       
02382 
02383         d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
02384 
02385         /* dump the results */
02386         ads_dump(ads, res);
02387 
02388         ads_msgfree(ads, res);
02389         ads_destroy(&ads);
02390 
02391         return 0;
02392 }
02393 
02394 
02395 static int net_ads_keytab_usage(int argc, const char **argv)
02396 {
02397         d_printf(
02398                 "net ads keytab <COMMAND>\n"\
02399 "<COMMAND> can be either:\n"\
02400 "  CREATE    Creates a fresh keytab\n"\
02401 "  ADD       Adds new service principal\n"\
02402 "  FLUSH     Flushes out all keytab entries\n"\
02403 "  HELP      Prints this help message\n"\
02404 "The ADD command will take arguments, the other commands\n"\
02405 "will not take any arguments.   The arguments given to ADD\n"\
02406 "should be a list of principals to add.  For example, \n"\
02407 "   net ads keytab add srv1 srv2\n"\
02408 "will add principals for the services srv1 and srv2 to the\n"\
02409 "system's keytab.\n"\
02410 "\n"
02411                 );
02412         return -1;
02413 }
02414 
02415 static int net_ads_keytab_flush(int argc, const char **argv)
02416 {
02417         int ret;
02418         ADS_STRUCT *ads;
02419 
02420         if (!ADS_ERR_OK(ads_startup(True, &ads))) {
02421                 return -1;
02422         }
02423         ret = ads_keytab_flush(ads);
02424         ads_destroy(&ads);
02425         return ret;
02426 }
02427 
02428 static int net_ads_keytab_add(int argc, const char **argv)
02429 {
02430         int i;
02431         int ret = 0;
02432         ADS_STRUCT *ads;
02433 
02434         d_printf("Processing principals to add...\n");
02435         if (!ADS_ERR_OK(ads_startup(True, &ads))) {
02436                 return -1;
02437         }
02438         for (i = 0; i < argc; i++) {
02439                 ret |= ads_keytab_add_entry(ads, argv[i]);
02440         }
02441         ads_destroy(&ads);
02442         return ret;
02443 }
02444 
02445 static int net_ads_keytab_create(int argc, const char **argv)
02446 {
02447         ADS_STRUCT *ads;
02448         int ret;
02449 
02450         if (!ADS_ERR_OK(ads_startup(True, &ads))) {
02451                 return -1;
02452         }
02453         ret = ads_keytab_create_default(ads);
02454         ads_destroy(&ads);
02455         return ret;
02456 }
02457 
02458 int net_ads_keytab(int argc, const char **argv)
02459 {
02460         struct functable func[] = {
02461                 {"CREATE", net_ads_keytab_create},
02462                 {"ADD", net_ads_keytab_add},
02463                 {"FLUSH", net_ads_keytab_flush},
02464                 {"HELP", net_ads_keytab_usage},
02465                 {NULL, NULL}
02466         };
02467 
02468         if (!lp_use_kerberos_keytab()) {
02469                 d_printf("\nWarning: \"use kerberos keytab\" must be set to \"true\" in order to \
02470 use keytab functions.\n");
02471         }
02472 
02473         return net_run_function(argc, argv, func, net_ads_keytab_usage);
02474 }
02475 
02476 int net_ads_help(int argc, const char **argv)
02477 {
02478         struct functable func[] = {
02479                 {"USER", net_ads_user_usage},
02480                 {"GROUP", net_ads_group_usage},
02481                 {"PRINTER", net_ads_printer_usage},
02482                 {"SEARCH", net_ads_search_usage},
02483                 {"INFO", net_ads_info},
02484                 {"JOIN", net_ads_join_usage},
02485                 {"DNS", net_ads_dns_usage},
02486                 {"LEAVE", net_ads_leave},
02487                 {"STATUS", net_ads_status},
02488                 {"PASSWORD", net_ads_password},
02489                 {"CHANGETRUSTPW", net_ads_changetrustpw},
02490                 {NULL, NULL}
02491         };
02492 
02493         return net_run_function(argc, argv, func, net_ads_usage);
02494 }
02495 
02496 int net_ads(int argc, const char **argv)
02497 {
02498         struct functable func[] = {
02499                 {"INFO", net_ads_info},
02500                 {"JOIN", net_ads_join},
02501                 {"TESTJOIN", net_ads_testjoin},
02502                 {"LEAVE", net_ads_leave},
02503                 {"STATUS", net_ads_status},
02504                 {"USER", net_ads_user},
02505                 {"GROUP", net_ads_group},
02506                 {"DNS", net_ads_dns},
02507                 {"PASSWORD", net_ads_password},
02508                 {"CHANGETRUSTPW", net_ads_changetrustpw},
02509                 {"PRINTER", net_ads_printer},
02510                 {"SEARCH", net_ads_search},
02511                 {"DN", net_ads_dn},
02512                 {"SID", net_ads_sid},
02513                 {"WORKGROUP", net_ads_workgroup},
02514                 {"LOOKUP", net_ads_lookup},
02515                 {"KEYTAB", net_ads_keytab},
02516                 {"GPO", net_ads_gpo},
02517                 {"HELP", net_ads_help},
02518                 {NULL, NULL}
02519         };
02520         
02521         return net_run_function(argc, argv, func, net_ads_usage);
02522 }
02523 
02524 #else
02525 
02526 static int net_ads_noads(void)
02527 {
02528         d_fprintf(stderr, "ADS support not compiled in\n");
02529         return -1;
02530 }
02531 
02532 int net_ads_keytab(int argc, const char **argv)
02533 {
02534         return net_ads_noads();
02535 }
02536 
02537 int net_ads_usage(int argc, const char **argv)
02538 {
02539         return net_ads_noads();
02540 }
02541 
02542 int net_ads_help(int argc, const char **argv)
02543 {
02544         return net_ads_noads();
02545 }
02546 
02547 int net_ads_changetrustpw(int argc, const char **argv)
02548 {
02549         return net_ads_noads();
02550 }
02551 
02552 int net_ads_join(int argc, const char **argv)
02553 {
02554         return net_ads_noads();
02555 }
02556 
02557 int net_ads_user(int argc, const char **argv)
02558 {
02559         return net_ads_noads();
02560 }
02561 
02562 int net_ads_group(int argc, const char **argv)
02563 {
02564         return net_ads_noads();
02565 }
02566 
02567 /* this one shouldn't display a message */
02568 int net_ads_check(void)
02569 {
02570         return -1;
02571 }
02572 
02573 int net_ads_check_our_domain(void)
02574 {
02575         return -1;
02576 }
02577 
02578 int net_ads(int argc, const char **argv)
02579 {
02580         return net_ads_usage(argc, argv);
02581 }
02582 
02583 #endif  /* WITH_ADS */

Sambaに対してSat Aug 29 21:23:28 2009に生成されました。  doxygen 1.4.7